diff --git a/samples/web-csr/dressca-frontend/consumer/src/main.ts b/samples/web-csr/dressca-frontend/consumer/src/main.ts index 99e176776..1c4fc159c 100644 --- a/samples/web-csr/dressca-frontend/consumer/src/main.ts +++ b/samples/web-csr/dressca-frontend/consumer/src/main.ts @@ -1,7 +1,8 @@ import { createApp } from 'vue'; import { createPinia } from 'pinia'; import { authenticationGuard } from '@/shared/authentication/authentication-guard'; -import { errorHandlerPlugin } from '@/shared/error-handler/error-handler-plugin'; +import { globalErrorHandler } from '@/shared/error-handler/global-error-handler'; +import { createCustomErrorHandler } from '@/shared/error-handler/custom-error-handler'; import App from './App.vue'; import { router } from './router'; @@ -13,7 +14,8 @@ const app = createApp(App); app.use(createPinia()); app.use(router); -app.use(errorHandlerPlugin); +app.use(globalErrorHandler); +app.use(createCustomErrorHandler()); authenticationGuard(router); diff --git a/samples/web-csr/dressca-frontend/consumer/src/shared/error-handler/custom-error-handler.ts b/samples/web-csr/dressca-frontend/consumer/src/shared/error-handler/custom-error-handler.ts new file mode 100644 index 000000000..7fcaae96e --- /dev/null +++ b/samples/web-csr/dressca-frontend/consumer/src/shared/error-handler/custom-error-handler.ts @@ -0,0 +1,73 @@ +import type { App } from 'vue'; +import { showToast } from '@/services/notification/notificationService'; +import { useRoutingStore } from '@/stores/routing/routing'; +import { router } from '@/router'; +import { customErrorHandlerKey } from '@/shared/injection-symbols'; +import { + CustomErrorBase, + UnauthorizedError, + NetworkError, + ServerError, +} from './custom-error'; + +export interface CustomErrorHandler { + install(app: App): void; + handle( + error: unknown, + callback: () => void, + handlingUnauthorizedError?: (() => void) | null, + handlingNetworkError?: (() => void) | null, + handlingServerError?: (() => void) | null, + ): void; +} + +export function createCustomErrorHandler(): CustomErrorHandler { + const customErrorHandler: CustomErrorHandler = { + install: (app: App) => { + app.provide(customErrorHandlerKey, customErrorHandler); + }, + handle: ( + error: unknown, + callback: () => void, + handlingUnauthorizedError: (() => void) | null = null, + handlingNetworkError: (() => void) | null = null, + handlingServerError: (() => void) | null = null, + ) => { + // ハンドリングできるエラーの場合はコールバックを実行 + if (error instanceof CustomErrorBase) { + callback(); + + // エラーの種類によって共通処理を行う + // switch だと instanceof での判定ができないため if 文で判定 + if (error instanceof UnauthorizedError) { + if (handlingUnauthorizedError) { + handlingUnauthorizedError(); + } else { + const routingStore = useRoutingStore(); + routingStore.setRedirectFrom( + router.currentRoute.value.path.slice(1), + ); + router.push({ name: 'authentication/login' }); + showToast('ログインしてください。'); + } + } else if (error instanceof NetworkError) { + if (handlingNetworkError) { + handlingNetworkError(); + } else { + showToast('ネットワークエラーが発生しました。'); + } + } else if (error instanceof ServerError) { + if (handlingServerError) { + handlingServerError(); + } else { + showToast('サーバーエラーが発生しました。'); + } + } + } else { + // ハンドリングできないエラーの場合は上位にエラーを投げる + throw error; + } + }, + }; + return customErrorHandler; +} diff --git a/samples/web-csr/dressca-frontend/consumer/src/shared/error-handler/error-handler.ts b/samples/web-csr/dressca-frontend/consumer/src/shared/error-handler/error-handler.ts deleted file mode 100644 index bf89ce9b3..000000000 --- a/samples/web-csr/dressca-frontend/consumer/src/shared/error-handler/error-handler.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { useRouter } from 'vue-router'; -import { showToast } from '@/services/notification/notificationService'; -import { useRoutingStore } from '@/stores/routing/routing'; -import { - CustomErrorBase, - UnauthorizedError, - NetworkError, - ServerError, -} from './custom-error'; - -export function errorHandler( - error: unknown, - callback: () => void, - handlingUnauthorizedError: (() => void) | null = null, - handlingNetworkError: (() => void) | null = null, - handlingServerError: (() => void) | null = null, -) { - // ハンドリングできるエラーの場合はコールバックを実行 - if (error instanceof CustomErrorBase) { - callback(); - - // エラーの種類によって共通処理を行う - // switch だと instanceof での判定ができないため if 文で判定 - if (error instanceof UnauthorizedError) { - if (handlingUnauthorizedError) { - handlingUnauthorizedError(); - } else { - const router = useRouter(); - const routingStore = useRoutingStore(); - routingStore.setRedirectFrom(router.currentRoute.value.path.slice(1)); - router.push({ name: 'authentication/login' }); - showToast('ログインしてください。'); - } - } else if (error instanceof NetworkError) { - if (handlingNetworkError) { - handlingNetworkError(); - } else { - showToast('ネットワークエラーが発生しました。'); - } - } else if (error instanceof ServerError) { - if (handlingServerError) { - handlingServerError(); - } else { - showToast('サーバーエラーが発生しました。'); - } - } - } else { - // ハンドリングできないエラーの場合は上位にエラーを投げる - throw error; - } -} diff --git a/samples/web-csr/dressca-frontend/consumer/src/shared/error-handler/error-handler-plugin.ts b/samples/web-csr/dressca-frontend/consumer/src/shared/error-handler/global-error-handler.ts similarity index 96% rename from samples/web-csr/dressca-frontend/consumer/src/shared/error-handler/error-handler-plugin.ts rename to samples/web-csr/dressca-frontend/consumer/src/shared/error-handler/global-error-handler.ts index e55e83977..b8c58fb5f 100644 --- a/samples/web-csr/dressca-frontend/consumer/src/shared/error-handler/error-handler-plugin.ts +++ b/samples/web-csr/dressca-frontend/consumer/src/shared/error-handler/global-error-handler.ts @@ -1,7 +1,7 @@ import type { App, ComponentPublicInstance } from 'vue'; import { router } from '../../router'; -export const errorHandlerPlugin = { +export const globalErrorHandler = { /* eslint no-param-reassign: 0 */ install(app: App) { app.config.errorHandler = ( diff --git a/samples/web-csr/dressca-frontend/consumer/src/shared/error-handler/use-custom-error-handler.ts b/samples/web-csr/dressca-frontend/consumer/src/shared/error-handler/use-custom-error-handler.ts new file mode 100644 index 000000000..2462dcd45 --- /dev/null +++ b/samples/web-csr/dressca-frontend/consumer/src/shared/error-handler/use-custom-error-handler.ts @@ -0,0 +1,7 @@ +import { inject } from 'vue'; +import type { CustomErrorHandler } from './custom-error-handler'; +import { customErrorHandlerKey } from '../injection-symbols'; + +export function useCustomErrorHandler(): CustomErrorHandler { + return inject(customErrorHandlerKey)!; +} diff --git a/samples/web-csr/dressca-frontend/consumer/src/shared/injection-symbols.ts b/samples/web-csr/dressca-frontend/consumer/src/shared/injection-symbols.ts new file mode 100644 index 000000000..873548703 --- /dev/null +++ b/samples/web-csr/dressca-frontend/consumer/src/shared/injection-symbols.ts @@ -0,0 +1,6 @@ +import type { InjectionKey } from 'vue'; +import type { CustomErrorHandler } from './error-handler/custom-error-handler'; + +export const customErrorHandlerKey = Symbol( + 'customErrorHandler', +) as InjectionKey; diff --git a/samples/web-csr/dressca-frontend/consumer/src/views/basket/BasketView.vue b/samples/web-csr/dressca-frontend/consumer/src/views/basket/BasketView.vue index 2a47ea4c7..89cac7d1e 100644 --- a/samples/web-csr/dressca-frontend/consumer/src/views/basket/BasketView.vue +++ b/samples/web-csr/dressca-frontend/consumer/src/views/basket/BasketView.vue @@ -13,7 +13,7 @@ import Loading from '@/components/common/LoadingSpinner.vue'; import { currencyHelper } from '@/shared/helpers/currencyHelper'; import { assetHelper } from '@/shared/helpers/assetHelper'; import { storeToRefs } from 'pinia'; -import { errorHandler } from '@/shared/error-handler/error-handler'; +import { useCustomErrorHandler } from '@/shared/error-handler/use-custom-error-handler'; const state = reactive({ showLoading: true, @@ -23,6 +23,7 @@ const basketStore = useBasketStore(); const { getBasket, getAddedItem, getAddedItemId } = storeToRefs(basketStore); const router = useRouter(); +const customErrorHandler = useCustomErrorHandler(); const { toCurrencyJPY } = currencyHelper(); const { getFirstAssetUrl } = assetHelper(); @@ -38,7 +39,7 @@ const update = async (catalogItemId: number, newQuantity: number) => { try { await updateItemInBasket(catalogItemId, newQuantity); } catch (error) { - errorHandler(error, () => { + customErrorHandler.handle(error, () => { showToast('数量の変更に失敗しました。'); }); } @@ -49,7 +50,7 @@ const remove = async (catalogItemId: number) => { try { await removeItemFromBasket(catalogItemId); } catch (error) { - errorHandler(error, () => { + customErrorHandler.handle(error, () => { showToast('商品の削除に失敗しました。'); }); } @@ -64,7 +65,7 @@ onMounted(async () => { try { await fetchBasket(); } catch (error) { - errorHandler(error, () => { + customErrorHandler.handle(error, () => { showToast('カートの取得に失敗しました。'); }); } finally { diff --git a/samples/web-csr/dressca-frontend/consumer/src/views/catalog/CatalogView.vue b/samples/web-csr/dressca-frontend/consumer/src/views/catalog/CatalogView.vue index 4657a7331..f2c6d2acf 100644 --- a/samples/web-csr/dressca-frontend/consumer/src/views/catalog/CatalogView.vue +++ b/samples/web-csr/dressca-frontend/consumer/src/views/catalog/CatalogView.vue @@ -14,7 +14,7 @@ import Loading from '@/components/common/LoadingSpinner.vue'; import { useRouter } from 'vue-router'; import { currencyHelper } from '@/shared/helpers/currencyHelper'; import { assetHelper } from '@/shared/helpers/assetHelper'; -import { errorHandler } from '@/shared/error-handler/error-handler'; +import { useCustomErrorHandler } from '@/shared/error-handler/use-custom-error-handler'; const specialContentStore = useSpecialContentStore(); const catalogStore = useCatalogStore(); @@ -22,6 +22,7 @@ const catalogStore = useCatalogStore(); const { getSpecialContents } = storeToRefs(specialContentStore); const { getCategories, getBrands, getItems } = storeToRefs(catalogStore); const router = useRouter(); +const customErrorHandler = useCustomErrorHandler(); const state = reactive({ selectedCategory: 0, @@ -38,7 +39,7 @@ const addBasket = async (catalogItemId: number) => { await addItemToBasket(catalogItemId); router.push({ name: 'basket' }); } catch (error) { - errorHandler(error, () => { + customErrorHandler.handle(error, () => { showToast('カートに追加できませんでした。'); }); } @@ -50,7 +51,7 @@ onMounted(async () => { try { await fetchItems(selectedCategory.value, selectedBrand.value); } catch (error) { - errorHandler(error, () => { + customErrorHandler.handle(error, () => { showToast('商品の取得に失敗しました。'); }); } diff --git a/samples/web-csr/dressca-frontend/consumer/src/views/ordering/CheckoutView.vue b/samples/web-csr/dressca-frontend/consumer/src/views/ordering/CheckoutView.vue index 09ac06bf3..48575743a 100644 --- a/samples/web-csr/dressca-frontend/consumer/src/views/ordering/CheckoutView.vue +++ b/samples/web-csr/dressca-frontend/consumer/src/views/ordering/CheckoutView.vue @@ -10,7 +10,7 @@ import { useRouter } from 'vue-router'; import { currencyHelper } from '@/shared/helpers/currencyHelper'; import { assetHelper } from '@/shared/helpers/assetHelper'; import { storeToRefs } from 'pinia'; -import { errorHandler } from '@/shared/error-handler/error-handler'; +import { useCustomErrorHandler } from '@/shared/error-handler/use-custom-error-handler'; const userStore = useUserStore(); const basketStore = useBasketStore(); @@ -18,6 +18,7 @@ const basketStore = useBasketStore(); const { getBasket } = storeToRefs(basketStore); const { getAddress } = storeToRefs(userStore); const router = useRouter(); +const customErrorHandler = useCustomErrorHandler(); const { toCurrencyJPY } = currencyHelper(); const { getFirstAssetUrl } = assetHelper(); @@ -32,7 +33,7 @@ const checkout = async () => { ); router.push({ name: 'ordering/done', params: { orderId } }); } catch (error) { - errorHandler(error, () => { + customErrorHandler.handle(error, () => { showToast('注文に失敗しました。'); router.push({ name: 'error' }); }); diff --git a/samples/web-csr/dressca-frontend/consumer/src/views/ordering/DoneView.vue b/samples/web-csr/dressca-frontend/consumer/src/views/ordering/DoneView.vue index 37fb406c8..125253f30 100644 --- a/samples/web-csr/dressca-frontend/consumer/src/views/ordering/DoneView.vue +++ b/samples/web-csr/dressca-frontend/consumer/src/views/ordering/DoneView.vue @@ -6,9 +6,10 @@ import { showToast } from '@/services/notification/notificationService'; import type { OrderResponse } from '@/generated/api-client/models/order-response'; import { currencyHelper } from '@/shared/helpers/currencyHelper'; import { assetHelper } from '@/shared/helpers/assetHelper'; -import { errorHandler } from '@/shared/error-handler/error-handler'; +import { useCustomErrorHandler } from '@/shared/error-handler/use-custom-error-handler'; const router = useRouter(); +const customErrorHandler = useCustomErrorHandler(); const props = defineProps<{ orderId: number; }>(); @@ -28,7 +29,7 @@ onMounted(async () => { try { state.lastOrdered = await getOrder(props.orderId); } catch (error) { - errorHandler(error, () => { + customErrorHandler.handle(error, () => { showToast('注文情報の取得に失敗しました。'); router.push('/'); });