(() => { const { pageHelper, EventManager, utils, actions } = ShopbySkin; const searchParams = new URLSearchParams(location.search); const productNo = Number(searchParams.get('productNo')); const channelType = searchParams.get('channelType'); const trackingKey = searchParams.get('trackingKey'); const sortType = searchParams.get('sortType'); const cartAction = actions.getCartAction(); const productOptionAction = actions.getProductOptionAction(); const productOptionEl = document.querySelector('product-purchase-v2'); const { productDetailHelper } = pageHelper; const { initialize, deleteProductInquiryBy, searchReviews } = productDetailHelper(); EventManager.on('QUERY_PRODUCT_DETAIL', async (product) => { await productOptionAction.fetchOptions(productNo, { productInfo: product, }); productOptionAction.fetchOptionSelector(); // 외부스크립트 등록 기능. 삭제금지 ShopbyExternalScript?.setGlobalObjectSb({ product }); }); EventManager.on('PRODUCT_DETAIL_CONTENT_LOADED', () => { const imgs = document.querySelector('product-detail').querySelectorAll('img'); utils.lazyLoad({ imgEls: imgs }); }); initialize({ productNo, channelType, sortType, cartAction, productOptionAction, }); const redirectLoginPage = () => { const nextUrl = `${location.origin}/pages/sign-in/sign-in.html`; location.href = `${nextUrl}?from=${encodeURIComponent(location.href)}`; }; const productLike = (productNo, { onSuccess }) => { if (!utils.isSignIn()) { EventManager.fire('MODAL_CONFIRM_OPEN', { message: '로그인 후 이용할 수 있습니다.', onConfirm: redirectLoginPage, }); return; } ShopbySkin.actions.toggleLikeStatus({ productNo, onSuccess, }); }; const getController = (target) => { const controllerId = target.getAttribute('shopby-controller-id') || target.closest('[shopby-controller-id]').getAttribute('shopby-controller-id'); if (!controllerId) { return null; } const { data } = productOptionAction.fetchOptionSelector(controllerId); return data; }; let shopbyCommonData = {}; EventManager.on('PAGE_LOAD_COMPLETED', (commonData) => { shopbyCommonData = commonData; // 외부스크립트 등록 기능. 삭제금지 ShopbyExternalScript?.setPageScriptType('PRODUCT'); }); const ACTION_HANDLER_MAP = { COUPON_DOWNLOAD: () => { if (!utils.isSignIn()) { ShopbySkin.EventManager.fire('MODAL_ALERT_OPEN', { message: '로그인 후 이용할 수 있습니다.', onClose: redirectLoginPage, }); } ShopbySkin.EventManager.fire('OPEN_LAYER_MODAL', { title: '쿠폰 다운받기', name: 'coupon-download', data: { productNo, channelType: utils.getChannelType(), }, isFull: false, onClose: () => null, }); }, INQUIRY_DETAIL: (target) => { const readable = target.getAttribute('shopby-readable') === 'true'; if (!readable) { EventManager.fire('MODAL_ALERT_OPEN', { message: '비밀글 조회 권한이 없습니다.', }); return; } target.closest('[shopby-active]').classList.toggle('active'); }, PRODUCT_INQUIRY_WRITE: (target) => { if (!utils.isSignIn()) { EventManager.fire('MODAL_ALERT_OPEN', { message: '먼저 로그인을 해주세요.', onClose: redirectLoginPage, }); return; } const productName = target.closest('[shopby-product-name]')?.getAttribute('shopby-product-name'); const imageUrl = target.closest('[shopby-image-url]')?.getAttribute('shopby-image-url'); const imageType = target.closest('[shopby-image-type]')?.getAttribute('shopby-image-type'); EventManager.fire('OPEN_LAYER_MODAL', { name: 'product-inquiry-form', title: '상품문의', modalAddClass: 'product-inquiry-form-modal', isFull: false, data: { productNo, productName, imageUrl, imageType, isModify: false, commonData: shopbyCommonData, useSelectProduct: false, }, onClose: ({ reason }) => { if (reason === 'DID_SUBMIT') { EventManager.fire('MODAL_ALERT_OPEN', { noticeType: 'success', message: '상품문의가 등록됐습니다.', onClose: () => { location.reload(); }, }); } }, }); }, INQUIRY_DELETE: (target) => { const inquiryNo = target.getAttribute('shopby-inquiry-no'); EventManager.fire('MODAL_CONFIRM_OPEN', { noticeType: 'warning', message: '

삭제 시 복구가 불가능합니다.
정말 삭제하시겠습니까?

', onConfirm: async () => { await deleteProductInquiryBy({ inquiryNo }); EventManager.fire('MODAL_ALERT_OPEN', { noticeType: 'success', message: '삭제되었습니다.', onClose: () => { location.reload(); }, }); }, }); }, INQUIRY_MODIFY: (target) => { const inquiryNo = target.getAttribute('shopby-inquiry-no'); EventManager.fire('OPEN_LAYER_MODAL', { name: 'product-inquiry-form', title: '상품문의', modalAddClass: 'product-inquiry-form-modal', isFull: false, data: { productNo, inquiryNo, isModify: true, commonData: shopbyCommonData, }, onClose: ({ reason }) => { if (reason === 'DID_MODIFY') { EventManager.fire('MODAL_ALERT_OPEN', { noticeType: 'success', message: '수정이 완료되었습니다.', onClose: () => { location.reload(); }, }); } }, }); }, WRITE_REVIEW: (target) => { const reviewableCount = Number(target.getAttribute('shopby-reviewable-count')); const usesAttachment = target.getAttribute('shopby-uses-attachment') === 'true'; EventManager.fire('OPEN_LAYER_MODAL', { name: 'product-review-form', title: '상품후기', modalAddClass: 'product-review-form-modal', isFull: false, data: { productNo, isModify: false, useSelectOrderProduct: reviewableCount > 1, usesAttachment, }, onClose: ({ reason }) => { if (reason === 'DID_SUBMIT') { EventManager.fire('MODAL_ALERT_OPEN', { noticeType: 'success', message: '상품후기가 작성되었습니다.', onClose: () => { location.reload(); }, }); } }, }); }, REVIEW_DETAIL: (target) => { const reviewNo = target.closest('[shopby-review-no]')?.getAttribute('shopby-review-no'); const targetEl = document.querySelector(`[shopby-target="REVIEW-OPEN-${reviewNo}"]`); targetEl.classList.toggle('is-open'); }, REVIEW_DETAIL_POPUP: (target) => { const reviewNo = target.closest('[shopby-review-no]')?.getAttribute('shopby-review-no'); ShopbySkin.EventManager.fire('OPEN_LAYER_MODAL', { name: 'product-review-detail', title: '상품후기 상세', data: { productNo, reviewNo, queryParams: { boardType: 'ALL', }, }, }); }, PHOTO_REVIEW_MORE: async () => { const { data } = await searchReviews({ productNo, channelType, sortType: 'RECOMMEND', hasAttachmentFile: true, pageSize: 20, }); const photoCollections = data.reviews.map(({ images, reviewNo }) => ({ urls: images, attachedFileCount: images.length, productNo, reviewNo, })); EventManager.fire('OPEN_LAYER_MODAL', { name: 'product-review-photos', title: `포토(${photoCollections.length})`, isFull: true, data: { images: photoCollections, }, }); }, REVIEW_MODIFY: (target) => { const reviewNo = target.closest('[shopby-review-no]')?.getAttribute('shopby-review-no'); const boardName = target.closest('[shopby-board-name]')?.getAttribute('shopby-board-name'); const usesAttachment = target.closest('[shopby-uses-attachment]')?.getAttribute('shopby-uses-attachment') === 'true'; EventManager.fire('OPEN_LAYER_MODAL', { name: 'product-review-form', title: boardName, modalAddClass: 'product-review-form-modal', isFull: false, data: { productNo, reviewNo, isModify: true, usesAttachment }, onClose: ({ reason }) => { if (reason === 'DID_MODIFY') { EventManager.fire('MODAL_ALERT_OPEN', { noticeType: 'success', message: '수정이 완료되었습니다.', onClose: () => { location.reload(); }, }); } }, }); }, REVIEW_DELETE: (target) => { const reviewNo = target.closest('[shopby-review-no]')?.getAttribute('shopby-review-no'); const givenAccumulation = target.getAttribute('shopby-given-accumulation'); const confirmMessage = givenAccumulation.toUpperCase() === 'Y' ? '

삭제 시 복구가 불가하며,
지급된 적립금이 차감됩니다.
정말 삭제하시겠습니까?

' : '

삭제 시 복구가 불가능합니다.
정말 삭제하시겠습니까?

'; const myProductReviewListHelper = pageHelper.myProductReviewListHelper(); myProductReviewListHelper.initialize(); EventManager.fire('MODAL_CONFIRM_OPEN', { noticeType: 'warning', message: confirmMessage, onConfirm: async () => { await myProductReviewListHelper.deleteReview({ productNo, reviewNo }); EventManager.fire('MODAL_ALERT_OPEN', { noticeType: 'success', message: '삭제되었습니다.', onClose: () => { location.reload(); }, }); }, }); }, ADD_CART: async () => { const { data } = productOptionAction.fetchUserOptionSelections(); const { addCart } = pageHelper.productDetailHelper(); await addCart( data.map((item) => ({ ...item, channelType, productNo, orderCnt: item.count, })) ); EventManager.fire('MODAL_CONFIRM_OPEN', { message: '

상품이 장바구니에 담겼습니다. 바로 확인하시겠습니까?

', cancelLabel: '쇼핑계속하기', confirmLabel: '장바구니 가기', onConfirm: () => { location.href = '/pages/order/cart.html'; }, }); }, PRODUCT_ORDER: async () => { const { isSignedIn } = utils; const { data } = productOptionAction.fetchUserOptionSelections(); const { requestOrderSheet } = pageHelper.productDetailHelper(); const { orderSheetNo } = await requestOrderSheet({ cartNos: null, channelType, productCoupons: null, trackingKey, products: data.map((item) => ({ ...item, productNo, orderCnt: item.count, additionalProductNo: 0, channelType, })), }); const orderSheetNoURL = `${location.origin}/pages/order/order-sheet-form.html?ordersheetNo=${orderSheetNo}`; const nextUrl = isSignedIn() ? orderSheetNoURL : `${location.origin}/pages/sign-in/sign-in.html?from=${orderSheetNoURL}`; window.location.href = nextUrl; }, SORT_TAB: (target) => { const sortType = target.getAttribute('shopby-sort-type'); const params = new URLSearchParams({ productNo, sortType, }); EventManager.fire('CHANGE_SORT_REVIEWS', { value: sortType }); history.pushState(null, null, `?${params.toString()}#PRODUCT_REVIEW`); }, REVIEW_CONTENT_TEXT: (target) => { target.closest('[shopby-element]').classList.toggle('open'); }, TOGGLE_DISCOUNT_DETAIL: () => { document.querySelector("[shopby-element='discount-tooltip']").classList.toggle('active'); }, RECOMMEND: () => { if (!utils.isSignIn()) { ShopbySkin.EventManager.fire('MODAL_ALERT_OPEN', { message: '로그인 후 이용할 수 있습니다.', onClose: redirectLoginPage, }); } }, PRODUCT_LIKE: (event) => { event.preventDefault(); const { target } = event; productLike(productNo, { onSuccess: (isLiked) => { const el = target.closest('[type=button]'); const messageEl = document.querySelector('[shopby-element="like-action-message"]'); messageEl.classList.remove('like-message'); // 페이드 아웃 메시지 setTimeout(() => { const actionMessage = isLiked ? '상품이 좋아요 리스트에 추가되었습니다.' : '상품이 좋아요 리스트에 제거되었습니다.'; messageEl.innerText = actionMessage; messageEl.classList.add('like-message'); }, 20); if (isLiked) { el.classList.add('is-active'); return; } el.classList.remove('is-active'); }, }); }, RELATED_PRODUCT_LIKE: (event) => { event.preventDefault(); const { target } = event; const productNo = target.closest('[shopby-product-no]')?.getAttribute('shopby-product-no'); if (!productNo) { return; } productLike(productNo, { onSuccess: (isLiked) => { const el = target.closest('[type=button]'); if (isLiked) { el.classList.add('is-active'); return; } el.classList.remove('is-active'); }, }); }, WRITE_REVIEW_REPORT: (target) => { const reviewNo = target.closest('[shopby-review-no]')?.getAttribute('shopby-review-no'); if (!utils.isSignedIn()) { EventManager.fire('MODAL_CONFIRM_OPEN', { noticeType: 'WARNING', message: '로그인 후 이용할 수 있습니다.', onConfirm: () => { utils.moveTo({ url: `/pages/sign-in/sign-in.html?from=${encodeURIComponent(location.href)}` }); }, }); return; } EventManager.fire('OPEN_LAYER_MODAL', { name: 'report-form', title: '신고하기', isFull: false, onClose: ({ reason }) => { if (reason === 'DID_SUBMIT') { location.reload(); } }, onConfirm: async ({ reportReasonType, content }) => { const { status } = await actions.postProductReviewReport({ productNo, reviewNo, reportReasonCd: reportReasonType, content, }); if (status === 204) { EventManager.fire('MODAL_ALERT_OPEN', { noticeType: 'success', message: '신고 되었습니다.', onClose: () => { location.reload(); }, }); } }, }); }, CANCEL_REVIEW_REPORT: (target) => { const reviewNo = target.closest('[shopby-review-no]')?.getAttribute('shopby-review-no'); if (!utils.isSignedIn()) { EventManager.fire('MODAL_CONFIRM_OPEN', { noticeType: 'WARNING', message: '로그인 후 이용할 수 있습니다.', onConfirm: () => { utils.moveTo({ url: `/pages/sign-in/sign-in.html?from=${encodeURIComponent(location.href)}` }); }, }); return; } EventManager.fire('MODAL_CONFIRM_OPEN', { noticeType: 'WARNING', message: '신고를 취소 하시겠습니까?', confirmLabel: '확인', onConfirm: async () => { const { status } = await actions.deleteProductReviewReport({ productNo, reviewNo, }); if (status === 204) { EventManager.fire('MODAL_ALERT_OPEN', { noticeType: 'success', message: '신고가 취소되었습니다.', onClose: () => { location.reload(); }, }); } }, }); }, // 상품 문의 신고 WRITE_INQUIRY_REPORT: (target) => { const inquiryNo = target.closest('[shopby-inquiry-no]')?.getAttribute('shopby-inquiry-no'); if (!utils.isSignedIn()) { EventManager.fire('MODAL_CONFIRM_OPEN', { noticeType: 'WARNING', message: '로그인 후 이용할 수 있습니다.', onConfirm: () => { utils.moveTo({ url: `/pages/sign-in/sign-in.html?from=${encodeURIComponent(location.href)}` }); }, }); return; } EventManager.fire('OPEN_LAYER_MODAL', { name: 'report-form', title: '신고하기', isFull: false, onClose: ({ reason }) => { if (reason === 'DID_SUBMIT') { location.reload(); } }, onConfirm: async ({ reportReasonType, content }) => { const { status } = await actions.postProductInquiryReport({ productNo, inquiryNo, reportType: reportReasonType, reason: content, }); if (status === 204) { EventManager.fire('MODAL_ALERT_OPEN', { noticeType: 'success', message: '신고 되었습니다.', onClose: () => { location.reload(); }, }); } }, }); }, // 상품 문의 신고 취소 CANCEL_INQUIRY_REPORT: (target) => { const inquiryNo = target.closest('[shopby-inquiry-no]')?.getAttribute('shopby-inquiry-no'); if (!utils.isSignedIn()) { EventManager.fire('MODAL_CONFIRM_OPEN', { noticeType: 'WARNING', message: '로그인 후 이용할 수 있습니다.', onConfirm: () => { utils.moveTo({ url: `/pages/sign-in/sign-in.html?from=${encodeURIComponent(location.href)}` }); }, }); return; } EventManager.fire('MODAL_CONFIRM_OPEN', { noticeType: 'WARNING', message: '신고를 취소 하시겠습니까?', confirmLabel: '확인', onConfirm: async () => { const { status } = await actions.deleteProductInquiryReport({ productNo, inquiryNo, }); if (status === 204) { EventManager.fire('MODAL_ALERT_OPEN', { noticeType: 'success', message: '신고가 취소 되었습니다.', onClose: () => { location.reload(); }, }); } }, }); }, }; const CLICK_ACTION_HANDLER_MAP = { HANDLE_COUNT_BTN_CLICK: (target) => { const controller = getController(target); if (!controller) { return; } const controllerEl = target.closest('[shopby-controller-id]'); const optionId = controllerEl.getAttribute('shopby-option-id'); const count = Number(controllerEl.getAttribute('shopby-count')); const incremental = target.getAttribute('shopby-variation') === 'INCREASE'; controller.changeCount({ optionId, count: incremental ? count + 1 : count - 1, }); productOptionAction.fetchOptionSelector(); }, REMOVE_OPTION: (target) => { const controller = getController(target); if (!controller) { return; } const controllerEl = target.closest('[shopby-controller-id]'); const optionId = controllerEl.getAttribute('shopby-option-id'); controller.removeOption({ optionId }); productOptionAction.fetchOptionSelector(); }, TOGGLE_TEXT_OPTIONS_BY_QUANTITY: (target) => { const controller = getController(target); if (!controller) { return; } const controllerEl = target.closest('[shopby-controller-id]'); const optionId = controllerEl.getAttribute('shopby-option-id'); const inputNo = Number(controllerEl.getAttribute('shopby-input-no')); const type = controllerEl.getAttribute('shopby-text-option-type'); const count = Number(controllerEl.getAttribute('shopby-count')); controller.toggleTextOptionType({ optionId, inputNo, type, count, }); productOptionAction.fetchOptionSelector(); }, }; const CHANGE_ACTION_HANDLER_MAP = { SELECT_OPTION: (target) => { const controller = getController(target); if (!controller) { return; } const labelId = target.getAttribute('shopby-label-id'); const index = Number(target.getAttribute('shopby-index')); const optionId = target.value; controller.selectOption({ labelId, optionId, index, }); productOptionAction.fetchOptionSelector(); }, CHANGE_COUNT: (target) => { const controller = getController(target); if (!controller) { return; } const controllerEl = target.closest('[shopby-controller-id]'); const optionId = controllerEl.getAttribute('shopby-option-id'); const count = Number(target.value); controller.changeCount({ optionId, count, }); productOptionAction.fetchOptionSelector(); }, INPUT_TEXT_OPTION: (target) => { const controller = getController(target); if (!controller) { return; } const controllerEl = target.closest('[shopby-controller-id]'); const optionId = controllerEl.getAttribute('shopby-option-id'); const inputNo = Number(controllerEl.getAttribute('shopby-input-no')); const textOptionId = target.getAttribute('shopby-text-option-id'); const maxLength = target.getAttribute('shopby-max-length'); controller.inputTextOption({ value: target.value, optionId, inputNo, textOptionId, maxLength, }); productOptionAction.fetchOptionSelector(); }, }; const INPUT_ACTION_HANDLER_MAP = { INPUT_TEXT_OPTION: (target) => { const counterEl = target.closest('[shopby-counter]'); const countEl = counterEl.querySelector('[shopby-count]'); const errorMessageEl = counterEl.querySelector('[shopby-error-message]'); countEl.textContent = target.value.length; if (target.value.length > 100) { errorMessageEl.textContent = '텍스트옵션 입력글자수를 초과하였습니다.'; } else { errorMessageEl.textContent = ''; } }, }; document.querySelector('product-summary')?.addEventListener('click', ({ target }) => { ACTION_HANDLER_MAP[target.getAttribute('shopby-action')]?.(); }); document.querySelector('product-purchase-v2')?.addEventListener('click', (event) => { ACTION_HANDLER_MAP[event.target.getAttribute('shopby-action')]?.(event); }); document.querySelector('product-detail-review-list')?.addEventListener('click', ({ target }) => { ACTION_HANDLER_MAP[target.getAttribute('shopby-action')]?.(target); }); document.querySelector('product-detail-board-button')?.addEventListener('click', ({ target }) => { ACTION_HANDLER_MAP[target.getAttribute('shopby-action')]?.(target); }); document.querySelector('product-detail-inquiry-list')?.addEventListener('click', ({ target }) => { ACTION_HANDLER_MAP[target.getAttribute('shopby-action')]?.(target); }); document.querySelector('related-product')?.addEventListener('click', (event) => { ACTION_HANDLER_MAP[event.target.getAttribute('shopby-action')]?.(event); }); productOptionEl?.addEventListener('click', ({ target }) => { CLICK_ACTION_HANDLER_MAP[target.getAttribute('shopby-action')]?.(target); }); productOptionEl?.addEventListener('change', ({ target }) => { CHANGE_ACTION_HANDLER_MAP[target.getAttribute('shopby-action')]?.(target); }); productOptionEl?.addEventListener('input', ({ target }) => { INPUT_ACTION_HANDLER_MAP[target.getAttribute('shopby-action')]?.(target); }); })();