/** 상품 상세 모달 (열기/닫기·콘텐츠 채우기·링크 복사) */ import { productsData } from './state.js'; import { initBetterCarousel } from './carousel.js'; import { TAG_STYLES, TAG_DEFAULT_STYLE, PRODUCT_CONDITIONS } from './config.js'; export function openModal(id) { const product = productsData.find((p) => p.id === id); if (!product) return; const modal = document.getElementById('product-modal'); modal.classList.remove('hidden'); modal.classList.add('flex'); const images = product.images; const loopImages = [images[images.length - 1], ...images, images[0]]; const mainImagesHtml = loopImages .map( (img) => `
`, ) .join(''); const thumbnailsHtml = product.images .map( (img, idx) => ` `, ) .join(''); const dotsHtml = product.images .map( (_, idx) => ` `, ) .join(''); document.getElementById('modal-main-carousel').innerHTML = mainImagesHtml; document.getElementById('modal-thumbnails').innerHTML = thumbnailsHtml; document.getElementById('modal-dots').innerHTML = dotsHtml; document.getElementById('modal-title').textContent = product.title; const modalCategory = document.getElementById('modal-category'); if (modalCategory) modalCategory.textContent = product.category; const modalStatus = document.getElementById('modal-status'); if (modalStatus) { modalStatus.textContent = product.status; const statusStyles = { 판매중: 'bg-green-100 text-green-700 dark:bg-green-900/30 dark:text-green-400', 판매예정: 'bg-blue-100 text-blue-700 dark:bg-blue-900/30 dark:text-blue-400', 판매완료: 'bg-red-100 text-red-700 dark:bg-red-900/30 dark:text-red-400', 미판매: 'bg-gray-100 text-gray-700 dark:bg-gray-800 dark:text-gray-400', }; modalStatus.className = 'inline-flex shrink-0 px-2 py-0.5 sm:px-2.5 sm:py-1 rounded-md sm:rounded-lg text-[10px] sm:text-[11px] md:text-xs font-bold uppercase tracking-wider whitespace-nowrap ' + (statusStyles[product.status] || statusStyles['미판매']); } const customTagElement = document.getElementById('modal-custom-tag'); const tagText = product.customTag?.trim(); if (tagText) { customTagElement.textContent = tagText; customTagElement.classList.remove('hidden'); customTagElement.className = `inline-flex shrink-0 px-2 py-0.5 sm:px-2.5 sm:py-1 rounded-md sm:rounded-lg text-[10px] sm:text-[11px] md:text-xs font-bold uppercase tracking-wider whitespace-nowrap ${TAG_STYLES[tagText] || TAG_DEFAULT_STYLE}`; } else { customTagElement.classList.add('hidden'); } // 구매일자: 값이 있을 때만 행 노출 const modalDate = document.getElementById('modal-date'); const modalDateRow = document.getElementById('modal-date-row'); const pDate = product.specs?.purchaseDate; if (pDate && String(pDate).trim() !== '' && String(pDate) !== 'null') { if (modalDate) modalDate.textContent = pDate; if (modalDateRow) { modalDateRow.classList.remove('hidden'); modalDateRow.classList.add('flex'); } } else { if (modalDateRow) { modalDateRow.classList.add('hidden'); modalDateRow.classList.remove('flex'); } } // 제품 상태(specs.condition): 값이 있을 때만 행 노출 const conditionKey = product.specs?.condition; const isVerified = product.specs?.isVerified; // PRODUCT_CONDITIONS에서 라벨을 가져오되, 없으면 원본 키 표시 const conditionData = PRODUCT_CONDITIONS[conditionKey]; // 데이터가 객체라면 .label을 쓰고, 아니면 원본 키를 씁니다. const conditionLabel = conditionData?.label || conditionKey || ''; const conditionValueEl = document.getElementById('modal-condition'); const conditionRowEl = document.getElementById('modal-condition-row'); const conditionRowWrap = conditionRowEl?.parentElement; // 라벨+값 전체 행 const verifiedIcon = document.getElementById('modal-verified-icon'); if (conditionKey && String(conditionKey).trim() !== '') { if (conditionValueEl) conditionValueEl.textContent = conditionLabel; if (conditionRowWrap) { conditionRowWrap.classList.remove('hidden'); conditionRowWrap.classList.add('flex'); } if (verifiedIcon) { if (isVerified) verifiedIcon.classList.remove('hidden'); else verifiedIcon.classList.add('hidden'); } } else { if (conditionRowWrap) { conditionRowWrap.classList.add('hidden'); conditionRowWrap.classList.remove('flex'); } } // 가격 표시 로직 수정 const priceValueEl = document.getElementById('modal-price'); const priceRowEl = document.getElementById('modal-price-row'); const priceRowWrap = priceRowEl?.parentElement; if (priceValueEl && priceRowWrap) { // [중요] 새로운 상품을 열 때마다 일단 hidden을 제거하여 초기화합니다. priceRowWrap.classList.remove('hidden'); // 1. 최우선 순위: 미판매 상태 체크 if (product.status === '미판매') { priceValueEl.textContent = 'NOT FOR SALE'; priceValueEl.classList.add('text-gray-500'); } // 2. 가격 데이터가 아예 없는 경우 (null, undefined, 빈 문자열) // 숫자 0은 가격으로 인정하고 싶다면 (product.price === null || product.price === undefined)로 씁니다. else if (product.price === null || product.price === undefined || product.price === '') { priceRowWrap.classList.add('hidden'); } // 3. 가격이 존재하는 경우 (0원을 포함하여 값이 있는 경우) else { const currency = product.currency || '₩'; priceValueEl.textContent = `${currency}${Number(product.price).toLocaleString()}`; priceValueEl.classList.remove('text-gray-500'); } } // (선택 사항) 미판매 상품일 때 상세 설명 부분에 대체 텍스트를 넣거나 숨기고 싶다면: const modalDesc = document.getElementById('modal-desc'); if (modalDesc) { if (product.status === '미판매') { modalDesc.innerHTML = '

판매중인 상품이 아니기에 정보가 제공되지 않습니다.

'; } else { modalDesc.innerHTML = Array.isArray(product.fullDescription) ? product.fullDescription.join('
') : product.fullDescription || ''; } } const copyBtn = document.getElementById('copy-link-btn'); const copyBtnText = document.getElementById('copy-btn-text'); if (copyBtn) { copyBtn.onclick = () => { const shareUrl = `${window.location.origin}${window.location.pathname}?id=${product.id}`; navigator.clipboard.writeText(shareUrl).then(() => { if (copyBtnText) copyBtnText.textContent = '링크가 복사되었습니다!'; copyBtn.classList.add('!bg-green-600'); setTimeout(() => { if (copyBtnText) copyBtnText.textContent = '상품 링크 복사하기'; copyBtn.classList.remove('!bg-green-600'); }, 2000); }); }; } window.history.pushState({ modalOpen: true }, '', ''); modal.classList.remove('hidden'); // document.body.style.overflow = 'hidden'; document.body.classList.add('modal-open'); const container = document.getElementById('modal-main-carousel-container'); container.style.scrollBehavior = 'auto'; container.scrollLeft = container.clientWidth; initBetterCarousel(container, images.length); } export function closeModal() { const modal = document.getElementById('product-modal'); // 1. 이미지 캐러셀 영역 초기화 const carouselContainer = document.getElementById('modal-main-carousel-container'); if (carouselContainer) { carouselContainer.scrollLeft = 0; } // 2. 우측 상세 정보 스크롤 영역 초기화 (추가된 부분) const contentScroll = document.getElementById('modal-content-scroll'); if (contentScroll) { contentScroll.scrollTo(0, 0); // 스크롤을 맨 위로! } // 모달 닫기 로직 modal.classList.add('hidden'); document.body.classList.remove('modal-open'); // 히스토리 및 URL 정리 if (window.history.state && window.history.state.modalOpen) { window.history.back(); } const cleanUrl = window.location.origin + window.location.pathname; window.history.replaceState(null, '', cleanUrl); } // --- 뒤로가기 감지 이벤트 리스너 --- // 사용자가 브라우저 뒤로가기 버튼(또는 모바일 뒤로가기 제스처)을 누를 때 실행됩니다. window.addEventListener('popstate', (event) => { const modal = document.getElementById('product-modal'); // 모달이 열려있는 상태에서 뒤로가기가 발생했다면 모달만 닫음 if (!modal.classList.contains('hidden')) { // 이때 closeModal()을 호출하되, 이미 뒤로 이동한 상태이므로 // closeModal 내부의 history.back()이 중복 실행되지 않게 주의 modal.classList.add('hidden'); document.body.classList.remove('modal-open'); } });