(() => { // 오류 핸들링 const handler = { authCodes: ['CECO003', 'CECO005', 'CECO007', 'O0020', 'CECA003', 'CEDI001', 'PPVE0004', 'CEOR024'], orderAuthCodes: ['O3336', 'O3338'], adultCodes: ['CEPR006'], adultConfirmCodes: ['O0037'], homeCodes: ['CEST008', 'CEST006', 'CEST007', 'B0018'], mallExpiredCodes: ['M0009'], replacePageRequiredHandlerKey: ['AUTH', 'AUTH_AGE'], redirectUrl: { HOME: '/', AUTH: '/pages/sign-in/sign-in.html', AUTH_AGE: '/pages/intro/adult-certification.html', EXPIRED_MALL: '/pages/error/expired-mall.html', SERVICE_CHECK: '/pages/error/service-check.html', ORDER_AUTH: '/pages/sign-in/member-authentication.html', }, isUnauthorized: (error) => handler.authCodes.includes(error.code) || error.status === ShopbySkin.constants.HTTP_STATUS.UNAUTHORIZED, getStatus: ({ status, error }) => { if (status === ShopbySkin.constants.HTTP_STATUS.OK) { return error?.status ?? error?.serverError?.status; } return status ?? error?.status ?? error?.serverError?.status; }, isShopApiRequest: ({ error, url, isShopApiRequest: _isShopApiRequest }) => // ncp_pay.js 등에서 직접 전달하는 경우 _isShopApiRequest ?? // API 호출 시 발생하는 에러 응답 error?.serverError?.isShopApiRequest ?? // 중첩된 에러 응답. API 성공 후 onSuccess 콜백에서 API 호출 시 에러가 발생하는 경우 error?.serverError?.error?.serverError?.isShopApiRequest ?? // API url 기반으로 판별 ShopbySkin.utils.isShopApiRequest(url), getServiceErrorKey: ({ status: _status, error, url, isShopApiRequest: _isShopApiRequest }) => { const status = handler.getStatus({ status: _status, error }); const isShopApiRequest = handler.isShopApiRequest({ error, url, isShopApiRequest: _isShopApiRequest }); if (!error?.code && !isShopApiRequest) return null; const { HTTP_STATUS: { PAYMENT_REQUIRED, SERVICE_UNAVAILABLE }, } = ShopbySkin.constants; if (status === PAYMENT_REQUIRED || handler.mallExpiredCodes.includes(error?.code)) return 'EXPIRED_MALL'; if (status === SERVICE_UNAVAILABLE) return 'SERVICE_CHECK'; return null; }, getHandlerKey: ({ error, payload }) => { if (!error?.code) return null; if (handler.isUnauthorized(error)) return 'AUTH'; if (handler.orderAuthCodes.includes(error.code)) { ShopbySkin.utils.setLocalStorage('REGISTER_ORDER_AFTER_AUTHENTICATION', JSON.stringify(payload)); return 'ORDER_AUTH'; } if (handler.adultCodes.includes(error.code)) return 'AUTH_AGE'; if (handler.homeCodes.includes(error.code)) return 'HOME'; return null; }, getHandlerConfirmKey: (error) => { if (!error?.code) return null; if (handler.adultConfirmCodes.includes(error.code)) return { message: '해당 상품은 성인전용 상품입니다.
성인인증 후 상품을 구매하시겠습니까?', onConfirm: () => { handler.redirect('AUTH_AGE'); }, }; return null; }, getHandlerMyPayAuthErrorKey: (error) => { if (!error.code) return null; const message = error?.error?.description || error?.message || error?.description; if (handler.isUnauthorized(error)) return { nextPath: 'AUTH', message }; return null; }, // eslint-disable-next-line complexity getHandlerAppCardAuthErrorKey: (error) => { const errorCode = error?.error?.code ?? error.code; if (!errorCode) return null; if (errorCode === 'ACEC0001') { return { message: '앱카드 결제가 불가합니다. 다른 결제수단으로 다시 시도해 주세요.' }; } if (errorCode === 'PROVIDER_SERVER_ERROR') { return { nextPath: ShopbySkin.utils.getFromUrl(), message: '앱카드 인증에 실패하였습니다. 다시 시도해 주세요.', }; } return null; }, redirect: (handlerKey) => { const url = `${handler.redirectUrl[handlerKey]}?from=${encodeURIComponent(location.href)}`; if (handler.replacePageRequiredHandlerKey.includes(handlerKey)) { location.replace(url); } else { location.href = url; } }, getRedirectUrl: (handlerKey) => { const redirectUrl = handler.redirectUrl[handlerKey] !== location.pathname ? `${handler.redirectUrl[handlerKey]}?from=${encodeURIComponent(location.href)}` : ''; return redirectUrl; }, }; const locationHandler = { map: { '/display/events': { next: -1, }, '/claims': { next: -1, exceptCodes: ['CL0058'], // 주문목록은 클레임 API 실패와 무관하게 목록 자체가 정상 렌더되므로 이전 페이지로 되돌리지 않는다 exceptPages: ['/pages/my/order-list.html'], }, '/product-detail': { next: '/', }, '/products': { next: '/', }, '/display/sections': { next: '/', checkReplacementStatus: (reason) => { if (reason?.error?.serverError?.status === ShopbySkin.constants.HTTP_STATUS.NOT_FOUND) { return true; } if (reason?.error?.code === 'PSEC0002') { return true; } return false; }, }, '/boards/posts': { next: '/', }, }, getLocationInfo: (reason) => { const locationMap = locationHandler.map; const { path } = reason.error?.serverError ?? {}; return locationMap[Object.keys(locationMap).find((key) => path?.includes(key))] ?? {}; }, isExceptError: (reason) => { const { code } = reason.error?.serverError ?? {}; const { exceptCodes, exceptPages } = locationHandler.getLocationInfo(reason); if (exceptPages?.some?.((page) => location.pathname === page)) { return true; } return exceptCodes?.includes?.(code); }, getNextPath: (reason) => { const { next } = locationHandler.getLocationInfo(reason); return next ?? null; }, getReplacementStatus: (reason) => { const { checkReplacementStatus } = locationHandler.getLocationInfo(reason); return checkReplacementStatus?.(reason); }, }; const unexpectedHandler = { getMessage: (reason) => reason?.error?.description ?? reason?.message, isServerError: (reason) => { const isClientError = reason?.error?.code && reason.error.code !== reason?.serverError?.code; if (isClientError) { return !isClientError; } return Boolean(reason?.error?.serverError?.code); }, }; const redirectActionHandler = { AUTH: (handlerKey) => { const redirect = handler.getRedirectUrl(handlerKey); ShopbySkin.utils.removeOpenIdDormantCallback(); ShopbySkin.utils.signOut({ redirect, replace: true, }); }, COMMON: (handlerKey) => { handler.redirect(handlerKey); }, }; // eslint-disable-next-line complexity const goNext = (next, replacementStatus) => { if (next !== -1) { if (replacementStatus) { location.replace(next); } else { location.href = next; } return; } if (history.state && history.state.idx === 0) { location.href = '/'; return; } const safeReferrer = ShopbySkin.utils.getSafeReferrerUrl(); // referrer 가 없거나 자기 자신이면 무한 루프 방지 위해 메인으로 폴백 if (!safeReferrer || location.href === safeReferrer) { location.replace(ShopbySkin.constants.PAGE.MAIN); return; } if (ShopbySkin.utils.isSignedIn() && safeReferrer.includes('sign-in.html?from=')) { location.href = ShopbySkin.constants.PAGE.MAIN; return; } location.href = safeReferrer; }; const goHome = (reason) => { const isServerError = unexpectedHandler.isServerError(reason); if (!isServerError) { return; } location.href = '/'; }; // eslint-disable-next-line complexity const handleRejection = ({ reason }) => { const serviceErrorKey = handler.getServiceErrorKey(reason); if (serviceErrorKey) { handler.redirect(serviceErrorKey); return; } const handlerKey = handler.getHandlerKey(reason); if (handlerKey) { ShopbySkin.EventManager.fire('MODAL_ALERT_OPEN', { noticeType: 'CAUTION', message: `${reason.error.description}`, onClose: () => { const redirectAction = redirectActionHandler[handlerKey]; if (redirectAction) { redirectAction(handlerKey); } else { redirectActionHandler.COMMON(handlerKey); } }, }); return; } const handlerConfirm = handler.getHandlerConfirmKey(reason); if (handlerConfirm) { ShopbySkin.EventManager.fire('MODAL_CONFIRM_OPEN', { noticeType: 'CAUTION', message: `${handlerConfirm?.message}`, confirmLabel: handlerConfirm.confirmLabel, cancelLabel: handlerConfirm.cancelLabel, onConfirm: handlerConfirm.onConfirm, }); return; } const handlerMyPayAuthError = handler.getHandlerMyPayAuthErrorKey(reason); if (handlerMyPayAuthError) { const { nextPath, message } = handlerMyPayAuthError; ShopbySkin.EventManager.fire('MODAL_ALERT_OPEN', { noticeType: 'CAUTION', message: `${message}`, onClose: () => { const redirectAction = redirectActionHandler[nextPath]; if (redirectAction) { redirectAction(nextPath); } else { redirectActionHandler.COMMON(nextPath); } }, }); return; } const handlerAppCardAuthError = handler.getHandlerAppCardAuthErrorKey(reason); if (handlerAppCardAuthError) { const { nextPath, message } = handlerAppCardAuthError; ShopbySkin.EventManager.fire('MODAL_ALERT_OPEN', { noticeType: 'CAUTION', message: `${message}`, onClose: () => { const redirectAction = redirectActionHandler[nextPath]; if (redirectAction) { redirectAction(nextPath); return; } if (nextPath) { goNext(nextPath, true); } }, }); return; } const next = locationHandler.getNextPath(reason); const replacementStatus = locationHandler.getReplacementStatus(reason); const errorMessage = unexpectedHandler.getMessage(reason); if (errorMessage) { ShopbySkin.EventManager.fire('MODAL_ALERT_OPEN', { noticeType: 'CAUTION', message: `${errorMessage}`, label: '확인', onClose: () => { if (locationHandler.isExceptError(reason)) { return; } if (reason.code === 'CEDI007') { location.replace('/'); return; } if (next) { goNext(next, replacementStatus); } else { goHome(reason); } }, }); } else { console.error(reason); } }; const handleError = ({ error }) => { if (error?.code && error?.message) { ShopbySkin.EventManager.fire('MODAL_ALERT_OPEN', { message: error?.message, label: '확인', }); } else { console.error(error?.message); } }; window.addEventListener('unhandledrejection', handleRejection); window.addEventListener('error', handleError); })();