diff --git a/src/App.vue b/src/App.vue index 852d51b..735b153 100644 --- a/src/App.vue +++ b/src/App.vue @@ -1,8 +1,43 @@ <template> <div class="app max-w-[900px] mx-auto p-10"> <main> - <router-view /> + <router-view v-slot="{ Component }"> + <template v-if="Component"> + <keep-alive> + <div + v-if="error" + class="flex flex-row space-x-2 items-center content-center justify-center m-20 text-red-500" + > + <IconError class="w-4 h-4" /> + <span>Es ist ein Fehler aufgetreten...</span> + </div> + <suspense v-else> + <template #default> + <component :is="Component"></component> + </template> + <template #fallback> + <div + class="flex flex-row space-x-2 items-center content-center justify-center m-20" + > + <IconSpinner class="w-4 h-4" /> + <span> Lade... </span> + </div> + </template> + </suspense> + </keep-alive> + </template> + </router-view> </main> <modal-overlay /> </div> </template> +<script setup lang="ts"> +import { onErrorCaptured } from 'vue' +import useAxios from './composables/useAxios' +import { IconSpinner, IconError } from '@/components/icons' +const { error } = useAxios() +onErrorCaptured((e: any) => { + error.value = e + return true +}) +</script> diff --git a/src/composables/useAxios.ts b/src/composables/useAxios.ts new file mode 100644 index 0000000..38ae217 --- /dev/null +++ b/src/composables/useAxios.ts @@ -0,0 +1,45 @@ +import axios, { AxiosInstance, AxiosRequestConfig } from 'axios' +import { apiConfig } from '@/config' +import { ref } from 'vue' + +const isLoading = ref(false) +const error = ref(null) + +const config: AxiosRequestConfig = { + baseURL: apiConfig.baseURL, +} + +const client: AxiosInstance = axios.create(config) + +client.interceptors.request.use( + function (config) { + isLoading.value = true + error.value = null + return config + }, + function (err) { + isLoading.value = false + error.value = err + return Promise.reject(err) + } +) + +client.interceptors.response.use( + function (response) { + isLoading.value = false + return response + }, + function (err) { + isLoading.value = false + error.value = err + return Promise.reject(err) + } +) + +export default () => { + return { + client, + isLoading, + error, + } +} diff --git a/src/composables/useWishlistStore.ts b/src/composables/useWishlistStore.ts index 2d347da..71ccfbf 100644 --- a/src/composables/useWishlistStore.ts +++ b/src/composables/useWishlistStore.ts @@ -1,35 +1,23 @@ -import apiService from '@/services/apiService' +import useAxios from '@/composables/useAxios' import { Wishlist, WishlistItem } from '@/types' import { ref } from 'vue' -const apiClient = apiService.getClient() +const { client } = useAxios() const refState = ref<Wishlist | any>({}) -const isLoading = ref(false) -const hasError = ref(false) -const fetchBySlugUrl = async (slugText: string): Promise<void> => { - isLoading.value = true - try { - const { data } = await apiClient.get(`/wishlist/${slugText}`) - refState.value = data - } catch (error: any) { - console.error(error) - hasError.value = true - } finally { - isLoading.value = false - } +const fetch = async (slugText: string): Promise<void> => { + const { data } = await client.get(`/wishlist/${slugText}`) + refState.value = data } const updateItem = async (item: WishlistItem): Promise<void> => { - await apiClient.put(`/wishlist/${item.wishlistId}/item/${item.id}`, item) + await client.put(`/wishlist/${item.wishlistId}/item/${item.id}`, item) } -export const useWishlistStore = (slugText: string) => { - fetchBySlugUrl(slugText) +export const useWishlistStore = () => { return { list: refState, - isLoading, - hasError, + fetch, updateItem, } } diff --git a/src/composables/useWishlistsStore.ts b/src/composables/useWishlistsStore.ts index 4d87206..9ef34c6 100644 --- a/src/composables/useWishlistsStore.ts +++ b/src/composables/useWishlistsStore.ts @@ -1,30 +1,19 @@ -import apiService from '@/services/apiService' +import useAxios from '@/composables/useAxios' import { Wishlist } from '@/types' import { ref } from 'vue' -const apiClient = apiService.getClient() +const { client } = useAxios() const prefix = '/wishlist' const refState = ref<Wishlist[]>([]) -const isLoading = ref(false) -const hasError = ref(false) -export const loadAll = async (): Promise<void> => { - isLoading.value = true - try { - const { data } = await apiClient.get(prefix) - refState.value = data - } catch (error: any) { - hasError.value = true - } finally { - isLoading.value = false - } +export const fetch = async (): Promise<void> => { + const { data } = await client.get(prefix) + refState.value = data } export const useWishlistsStore = () => { - loadAll() return { lists: refState, - hasError, - isLoading, + fetch, } } diff --git a/src/services/apiService.ts b/src/services/apiService.ts deleted file mode 100644 index c5ee69f..0000000 --- a/src/services/apiService.ts +++ /dev/null @@ -1,14 +0,0 @@ -import axios, { AxiosInstance, AxiosRequestConfig } from 'axios' -import { apiConfig } from '@/config' - -const config: AxiosRequestConfig = { - baseURL: apiConfig.baseURL, -} - -const client: AxiosInstance = axios.create(config) - -export default { - getClient: () => { - return client - }, -} diff --git a/src/views/DetailView.vue b/src/views/DetailView.vue index fd044b7..cd4a6b2 100644 --- a/src/views/DetailView.vue +++ b/src/views/DetailView.vue @@ -1,19 +1,16 @@ <script setup lang="ts"> import { WishlistItem as WishlistItemType } from '@/types' -import { computed, watchEffect } from 'vue' +import { computed } from 'vue' import { useRoute } from 'vue-router' -import { useTitle } from '@vueuse/core' import { useWishlistStore, useModal } from '@/composables' import Tile from '@/components/Tile.vue' -import { IconSpinner, IconError } from '@/components/icons' import WishlistItem from '@/components/WishlistItem.vue' const route = useRoute() const modal = useModal() -const { list, isLoading, hasError, updateItem } = useWishlistStore( - route.params.slug as string -) +const { list, fetch, updateItem } = useWishlistStore() +await fetch(route.params.slug as string) const notBoughtItems = computed(() => { return list.value.items.filter( @@ -34,21 +31,7 @@ const bought = async (item: WishlistItemType): Promise<void> => { </script> <template> - <div - v-if="isLoading" - class="flex flex-row space-x-2 items-center content-center justify-center m-20" - > - <IconSpinner class="w-4 h-4" /> - <span> Lade Wunschliste... </span> - </div> - <div - v-else-if="hasError" - class="flex flex-row space-x-2 items-center content-center justify-center m-20 text-red-500" - > - <IconError class="w-4 - h-4" /> - <span> Es ist ein Fehler aufgetreten... </span> - </div> - <div v-else> + <div v-if="list.id"> <div class="flex flex-col md:flex-row space-x-0 md:space-x-6 space-y-2 md:space-y-0 items-center" > diff --git a/src/views/HomeView.vue b/src/views/HomeView.vue index fad7b60..6aa39f3 100644 --- a/src/views/HomeView.vue +++ b/src/views/HomeView.vue @@ -1,27 +1,13 @@ <script setup lang="ts"> import Tile from '@/components/Tile.vue' -import { IconSpinner, IconError } from '@/components/icons' import { useWishlistsStore } from '@/composables' -const { lists, isLoading, hasError } = useWishlistsStore() +const { lists, fetch } = useWishlistsStore() +await fetch() </script> <template> <h1 class="text-3xl text-center">Wunschlisten</h1> - <div - v-if="isLoading" - class="flex flex-row space-x-2 items-center content-center justify-center m-20" - > - <IconSpinner class="w-4 h-4" /> - <span> Lade Wunschlisten... </span> - </div> - <div - v-else-if="hasError" - class="flex flex-row space-x-2 items-center content-center justify-center m-20 text-red-500" - > - <IconError class="w-4 - h-4" /> - <span> Es ist ein Fehler aufgetreten... </span> - </div> - <div v-else class="flex flex-row flex-wrap justify-around p-10"> + <div v-if="lists" class="flex flex-row flex-wrap justify-around p-10"> <router-link v-for="(item, index) in lists" :key="index"