661 lines
21 KiB
JavaScript
661 lines
21 KiB
JavaScript
// scripts/app.js 상단
|
|
import products from '../data/index.js';
|
|
|
|
// 이제 products는 모든 카테고리가 합쳐지고 날짜순으로 정렬된 상태입니다.
|
|
console.log('Total products loaded:', products.length);
|
|
|
|
const ITEMS_PER_PAGE = 20;
|
|
let currentPage = 1;
|
|
let activeCategories = new Set(['All']);
|
|
let visibleProducts = products;
|
|
let searchKeyword = '';
|
|
|
|
const VISIBILITY_CONFIG = {
|
|
showUnlisted: false, // 🔥 미판매 노출 여부
|
|
showSold: true, // 🔥 판매완료 노출 여부
|
|
};
|
|
|
|
const STATUS_META = {
|
|
미판매: {
|
|
selectable: false,
|
|
defaultVisible: false,
|
|
soldOut: false,
|
|
},
|
|
판매예정: {
|
|
selectable: true,
|
|
defaultVisible: true,
|
|
soldOut: false,
|
|
},
|
|
판매중: {
|
|
selectable: true,
|
|
defaultVisible: true,
|
|
soldOut: false,
|
|
},
|
|
판매완료: {
|
|
selectable: true,
|
|
defaultVisible: false,
|
|
soldOut: true,
|
|
},
|
|
};
|
|
|
|
const STATUS_FILTERS = [
|
|
{
|
|
key: '판매중',
|
|
label: '판매중',
|
|
defaultActive: true,
|
|
visible: true,
|
|
},
|
|
{
|
|
key: '판매예정',
|
|
label: '판매 예정',
|
|
defaultActive: true,
|
|
visible: true,
|
|
},
|
|
{
|
|
key: '미판매',
|
|
label: '미판매',
|
|
defaultActive: false,
|
|
visible: VISIBILITY_CONFIG.showUnlisted,
|
|
},
|
|
{
|
|
key: '판매완료',
|
|
label: '판매완료',
|
|
defaultActive: false,
|
|
visible: VISIBILITY_CONFIG.showSold,
|
|
},
|
|
];
|
|
|
|
const STATUS_ORDER = {
|
|
판매중: 0,
|
|
판매예정: 1,
|
|
미판매: 2,
|
|
판매완료: 3, // 🔥 항상 맨 뒤
|
|
};
|
|
|
|
const STATUS_COLOR = {
|
|
판매중: 'bg-primary/10 text-primary border-primary/30',
|
|
판매예정: 'bg-amber-400/10 text-amber-600 border-amber-400/30',
|
|
판매완료: 'bg-slate-400/10 text-slate-500 border-slate-400/30',
|
|
미판매: 'bg-slate-200/10 text-slate-400 border-slate-300/30',
|
|
};
|
|
|
|
let activeStatuses = new Set(
|
|
Object.entries(STATUS_META)
|
|
.filter(([_, meta]) => meta.defaultVisible)
|
|
.map(([status]) => status),
|
|
);
|
|
|
|
// openModal 함수 내부에 추가하거나 전역으로 설정
|
|
const copyBtn = document.getElementById('copy-link-btn');
|
|
const copyBtnText = document.getElementById('copy-btn-text');
|
|
|
|
copyBtn.onclick = () => {
|
|
// 현재 도메인 + 제품 ID 쿼리 조합
|
|
const shareUrl = `${window.location.origin}${window.location.pathname}?id=${product.id}`;
|
|
|
|
navigator.clipboard.writeText(shareUrl).then(() => {
|
|
copyBtnText.textContent = '링크가 복사되었습니다!';
|
|
copyBtn.classList.replace('bg-slate-900', 'bg-green-600');
|
|
|
|
setTimeout(() => {
|
|
copyBtnText.textContent = '상품 링크 복사하기';
|
|
copyBtn.classList.replace('bg-green-600', 'bg-slate-900');
|
|
}, 2000);
|
|
});
|
|
};
|
|
|
|
function getStatusChipClass(status, isActive) {
|
|
const base = STATUS_COLOR[status] ?? '';
|
|
|
|
if (isActive) {
|
|
return `
|
|
${base}
|
|
opacity-100
|
|
shadow-sm
|
|
`;
|
|
}
|
|
|
|
// 🔥 비활성
|
|
return `
|
|
bg-slate-50
|
|
text-slate-400
|
|
border-slate-200
|
|
opacity-30
|
|
grayscale
|
|
hover:opacity-50
|
|
`;
|
|
}
|
|
|
|
function renderStatusChips() {
|
|
const container = document.getElementById('status-chips');
|
|
if (!container) return;
|
|
|
|
container.innerHTML = '';
|
|
|
|
STATUS_FILTERS.filter((f) => f.visible).forEach(({ key, label }) => {
|
|
const isActive = activeStatuses.has(key);
|
|
|
|
const chip = document.createElement('button');
|
|
chip.className = `
|
|
status-chip
|
|
px-4 py-2
|
|
rounded-full
|
|
text-sm font-medium
|
|
transition-all duration-200
|
|
border
|
|
${getStatusChipClass(key, isActive)}
|
|
`;
|
|
|
|
chip.textContent = label;
|
|
chip.onclick = () => toggleStatusFilter(key);
|
|
|
|
container.appendChild(chip);
|
|
});
|
|
}
|
|
|
|
function toggleStatusFilter(status) {
|
|
if (activeStatuses.has(status)) {
|
|
activeStatuses.delete(status);
|
|
} else {
|
|
activeStatuses.add(status);
|
|
}
|
|
|
|
// 최소 1개는 유지
|
|
if (activeStatuses.size === 0) {
|
|
STATUS_FILTERS.filter((f) => f.defaultActive).forEach((f) => activeStatuses.add(f.key));
|
|
}
|
|
|
|
applyFilters();
|
|
renderStatusChips();
|
|
}
|
|
|
|
const searchInput = document.getElementById('search-input');
|
|
|
|
if (searchInput) {
|
|
searchInput.addEventListener('input', (e) => {
|
|
searchKeyword = e.target.value.trim().toLowerCase();
|
|
applyFilters();
|
|
});
|
|
}
|
|
|
|
function applyFilters() {
|
|
currentPage = 1;
|
|
|
|
visibleProducts = products
|
|
.filter((product) => {
|
|
// 🔒 미판매 강제 차단
|
|
if (product.status === '미판매' && !VISIBILITY_CONFIG.showUnlisted) {
|
|
return false;
|
|
}
|
|
|
|
// 🔒 판매완료 기본 숨김
|
|
if (product.status === '판매완료' && !VISIBILITY_CONFIG.showSold) {
|
|
return false;
|
|
}
|
|
|
|
const statusMatch = activeStatuses.has(product.status);
|
|
const categoryMatch = activeCategories.has('All') || activeCategories.has(product.category);
|
|
const searchMatch = searchKeyword === '' || product.title.toLowerCase().includes(searchKeyword);
|
|
|
|
return statusMatch && categoryMatch && searchMatch;
|
|
})
|
|
// 🔥 여기서 정렬
|
|
.sort((a, b) => {
|
|
const aOrder = STATUS_ORDER[a.status] ?? 999;
|
|
const bOrder = STATUS_ORDER[b.status] ?? 999;
|
|
return aOrder - bOrder;
|
|
});
|
|
|
|
renderProducts(currentPage);
|
|
}
|
|
|
|
/**
|
|
* 1. 상품 목록 렌더링
|
|
*/
|
|
export function renderProducts(page) {
|
|
const grid = document.getElementById('product-grid');
|
|
if (!grid) return;
|
|
grid.innerHTML = '';
|
|
|
|
const startIndex = (page - 1) * ITEMS_PER_PAGE;
|
|
const pagedProducts = visibleProducts.slice(startIndex, startIndex + ITEMS_PER_PAGE);
|
|
|
|
pagedProducts.forEach((product) => {
|
|
const isSold = STATUS_META[product.status]?.soldOut === true;
|
|
const cardHtml = `
|
|
<div class="group flex flex-col gap-4 cursor-pointer" onclick="openModal('${product.id}')">
|
|
<div class="relative w-full aspect-[4/5] bg-slate-50 dark:bg-slate-800 rounded-xl overflow-hidden shadow-sm group-hover:shadow-md transition-shadow">
|
|
<div class="w-full h-full bg-center bg-no-repeat bg-cover transform ${isSold ? 'grayscale opacity-80' : 'group-hover:scale-105'} transition-transform duration-500"
|
|
style="background-image: url('${product.images[0]}')"></div>
|
|
<div class="absolute top-3 left-3">
|
|
<span class="px-2 py-1 text-[10px] uppercase tracking-wider font-bold rounded ${isSold ? 'bg-slate-900/10 text-slate-500' : 'bg-primary/10 text-primary'} backdrop-blur-md border border-primary/20">
|
|
${product.status}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
<div class="flex flex-col gap-1">
|
|
<div class="flex justify-between items-start">
|
|
<h3 class="text-slate-900 dark:text-white text-base font-semibold ${isSold ? 'line-through text-slate-400' : ''}">${product.title}</h3>
|
|
<p class="text-slate-900 dark:text-white text-base font-bold text-nowrap">${product.currency}${product.price.toLocaleString()}</p>
|
|
</div>
|
|
<p class="text-slate-500 dark:text-slate-400 text-sm font-normal">${product.description}</p>
|
|
</div>
|
|
</div>
|
|
`;
|
|
grid.insertAdjacentHTML('beforeend', cardHtml);
|
|
});
|
|
|
|
renderPagination();
|
|
}
|
|
|
|
/**
|
|
* 2. 모달 열기 및 데이터 채우기
|
|
*/
|
|
window.openModal = (id) => {
|
|
const product = products.find((p) => p.id === id);
|
|
if (!product) return;
|
|
|
|
const modal = document.getElementById('product-modal');
|
|
const images = product.images;
|
|
|
|
// --- 1. 이미지 및 UI 초기화 로직 ---
|
|
const loopImages = [images[images.length - 1], ...images, images[0]];
|
|
const mainImagesHtml = loopImages
|
|
.map(
|
|
(img) => `
|
|
<div class="flex-shrink-0 w-full h-full snap-center flex items-center justify-center p-4 select-none">
|
|
<img src="${img}" draggable="false" class="max-w-full max-h-full object-contain pointer-events-none shadow-sm rounded-lg">
|
|
</div>
|
|
`,
|
|
)
|
|
.join('');
|
|
|
|
const thumbnailsHtml = product.images
|
|
.map(
|
|
(img, idx) => `
|
|
<div onclick="scrollToImage(${idx})"
|
|
class="modal-thumb-item size-16 rounded-lg border-2 ${idx === 0 ? 'border-primary' : 'border-transparent'}
|
|
bg-cover bg-center overflow-hidden cursor-pointer ${idx === 0 ? 'opacity-100' : 'opacity-70'}
|
|
hover:opacity-100 transition-all flex-shrink-0"
|
|
style="background-image: url('${img}');"></div>
|
|
`,
|
|
)
|
|
.join('');
|
|
|
|
const dotsHtml = product.images
|
|
.map(
|
|
(_, idx) => `
|
|
<div class="modal-dot-item ${idx === 0 ? 'w-4 bg-primary' : 'w-2 bg-gray-300 dark:bg-gray-700'} h-2 rounded-full transition-all"></div>
|
|
`,
|
|
)
|
|
.join('');
|
|
|
|
// --- 2. 데이터 주입 ---
|
|
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;
|
|
document.getElementById('modal-price').textContent = `${product.currency}${product.price.toLocaleString()}`;
|
|
|
|
// 카테고리 및 상태
|
|
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 = 'px-2.5 py-1 rounded-lg text-xs font-bold uppercase tracking-wider ' + (statusStyles[product.status] || statusStyles['미판매']);
|
|
}
|
|
|
|
// 커스텀 태그
|
|
const customTagElement = document.getElementById('modal-custom-tag');
|
|
if (product.customTag?.trim()) {
|
|
customTagElement.textContent = product.customTag;
|
|
customTagElement.classList.remove('hidden');
|
|
} else {
|
|
customTagElement.classList.add('hidden');
|
|
}
|
|
|
|
// 상세 설명
|
|
const modalDesc = document.getElementById('modal-desc');
|
|
if (modalDesc) {
|
|
modalDesc.innerHTML = Array.isArray(product.fullDescription) ? product.fullDescription.join('<br>') : product.fullDescription || '';
|
|
}
|
|
|
|
// --- 3. [핵심] 링크 복사 버튼 이벤트 바인딩 ---
|
|
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);
|
|
});
|
|
};
|
|
}
|
|
|
|
// --- 4. 모달 활성화 및 초기 위치 설정 ---
|
|
modal.classList.remove('hidden');
|
|
document.body.style.overflow = 'hidden';
|
|
|
|
const container = document.getElementById('modal-main-carousel-container');
|
|
container.style.scrollBehavior = 'auto';
|
|
container.scrollLeft = container.clientWidth;
|
|
|
|
// 캐러셀 초기화
|
|
initBetterCarousel(container, images.length);
|
|
};
|
|
|
|
/**
|
|
* 모달 닫기 (URL 정리 기능 포함)
|
|
*/
|
|
window.closeModal = () => {
|
|
document.getElementById('product-modal').classList.add('hidden');
|
|
document.body.style.overflow = 'auto';
|
|
|
|
const cleanUrl = window.location.origin + window.location.pathname;
|
|
window.history.replaceState(null, '', cleanUrl);
|
|
};
|
|
|
|
function initBetterCarousel(container, originalLength) {
|
|
let isDragging = false;
|
|
let startX = 0;
|
|
let startScroll = 0;
|
|
let startTime = 0;
|
|
|
|
const width = () => container.clientWidth;
|
|
|
|
container.addEventListener('mousedown', start);
|
|
container.addEventListener('touchstart', start, { passive: true });
|
|
|
|
function start(e) {
|
|
isDragging = true;
|
|
startX = e.touches ? e.touches[0].pageX : e.pageX;
|
|
startScroll = container.scrollLeft;
|
|
startTime = Date.now();
|
|
}
|
|
|
|
container.addEventListener('mousemove', move);
|
|
container.addEventListener('touchmove', move, { passive: false });
|
|
|
|
function move(e) {
|
|
if (!isDragging) return;
|
|
const x = e.touches ? e.touches[0].pageX : e.pageX;
|
|
container.scrollLeft = startScroll - (x - startX);
|
|
}
|
|
|
|
container.addEventListener('mouseup', end);
|
|
container.addEventListener('mouseleave', end);
|
|
container.addEventListener('touchend', end);
|
|
|
|
function end(e) {
|
|
if (!isDragging) return;
|
|
isDragging = false;
|
|
|
|
const delta = container.scrollLeft - startScroll;
|
|
const elapsed = Date.now() - startTime;
|
|
|
|
const direction = Math.abs(delta) > width() * 0.1 || elapsed < 200 ? (delta > 0 ? 1 : -1) : 0;
|
|
|
|
let index = Math.round(startScroll / width()) + direction;
|
|
|
|
container.style.scrollBehavior = 'smooth';
|
|
container.scrollTo({ left: index * width() });
|
|
|
|
// 무한 루프 보정
|
|
setTimeout(() => {
|
|
container.style.scrollBehavior = 'auto';
|
|
if (index === 0) {
|
|
container.scrollLeft = width() * originalLength;
|
|
}
|
|
if (index === originalLength + 1) {
|
|
container.scrollLeft = width();
|
|
}
|
|
syncModalUI(originalLength);
|
|
}, 300);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 이미지 슬라이드와 UI(Dots, Thumbs) 동기화
|
|
*/
|
|
function syncModalUI(originalLength) {
|
|
const container = document.getElementById('modal-main-carousel-container');
|
|
const index = getRealIndex(container, originalLength);
|
|
|
|
document.querySelectorAll('.modal-thumb-item').forEach((t, i) => {
|
|
t.classList.toggle('border-primary', i === index);
|
|
t.classList.toggle('opacity-100', i === index);
|
|
t.classList.toggle('opacity-70', i !== index);
|
|
});
|
|
|
|
document.querySelectorAll('.modal-dot-item').forEach((d, i) => {
|
|
d.classList.toggle('bg-primary', i === index);
|
|
d.classList.toggle('w-4', i === index);
|
|
d.classList.toggle('bg-gray-300', i !== index);
|
|
d.classList.toggle('w-2', i !== index);
|
|
});
|
|
|
|
ensureThumbnailVisible(index);
|
|
}
|
|
|
|
/**
|
|
* 3. 모달 내 이미지 스크롤 및 UI 동기화
|
|
*/
|
|
window.scrollToImage = (index) => {
|
|
const container = document.getElementById('modal-main-carousel-container');
|
|
if (!container) return;
|
|
|
|
container.scrollTo({
|
|
left: container.clientWidth * (index + 1), // 🔥 중요
|
|
behavior: 'smooth',
|
|
});
|
|
};
|
|
|
|
/**
|
|
* 5. 기타 (페이지네이션, 모달 닫기)
|
|
*/
|
|
function renderPagination() {
|
|
const container = document.getElementById('pagination');
|
|
if (!container) return;
|
|
const totalPages = Math.ceil(visibleProducts.length / ITEMS_PER_PAGE);
|
|
|
|
let html = `<button onclick="changePage(${currentPage - 1})" class="size-10 flex items-center justify-center ${currentPage === 1 ? 'invisible' : ''}"><svg viewBox="0 0 24 24" fill="none"
|
|
stroke="#64748B" stroke-width="3"
|
|
stroke-linecap="round" stroke-linejoin="round"
|
|
class="w-5 h-5">
|
|
<path d="M15 18l-6-6 6-6" />
|
|
</svg>
|
|
</button>`;
|
|
for (let i = 1; i <= totalPages; i++) {
|
|
html += `<button onclick="changePage(${i})" class="size-10 font-bold rounded-lg ${i === currentPage ? 'bg-primary text-white' : 'text-slate-500'}">${i}</button>`;
|
|
}
|
|
html += `<button onclick="changePage(${currentPage + 1})" class="size-10 flex items-center justify-center ${currentPage === totalPages ? 'invisible' : ''}"><svg viewBox="0 0 24 24" fill="none"
|
|
stroke="#64748B" stroke-width="3"
|
|
stroke-linecap="round" stroke-linejoin="round"
|
|
class="w-5 h-5">
|
|
<path d="M9 18l6-6-6-6" />
|
|
</svg>
|
|
</button>`;
|
|
container.innerHTML = html;
|
|
}
|
|
|
|
window.changePage = (page) => {
|
|
currentPage = page;
|
|
renderProducts(currentPage);
|
|
window.scrollTo({ top: 0, behavior: 'smooth' });
|
|
};
|
|
|
|
// 초기 실행
|
|
document.addEventListener('DOMContentLoaded', () => renderProducts(currentPage));
|
|
|
|
document.addEventListener('keydown', (e) => {
|
|
if (e.key !== 'Escape') return;
|
|
|
|
const modal = document.getElementById('product-modal');
|
|
if (!modal || modal.classList.contains('hidden')) return;
|
|
|
|
closeModal();
|
|
});
|
|
|
|
const thumbnailContainer = document.getElementById('modal-thumbnails');
|
|
|
|
function ensureThumbnailVisible(index) {
|
|
const container = document.getElementById('modal-thumbnails');
|
|
if (!container) return;
|
|
|
|
const thumbs = container.querySelectorAll('.modal-thumb-item');
|
|
const active = thumbs[index];
|
|
if (!active) return;
|
|
|
|
const cRect = container.getBoundingClientRect();
|
|
const tRect = active.getBoundingClientRect();
|
|
|
|
const isVisible = tRect.top >= cRect.top && tRect.bottom <= cRect.bottom;
|
|
|
|
if (!isVisible) {
|
|
active.scrollIntoView({
|
|
behavior: 'smooth',
|
|
block: 'center',
|
|
});
|
|
}
|
|
}
|
|
|
|
function getRealIndex(container, originalLength) {
|
|
let rawIndex = Math.round(container.scrollLeft / container.clientWidth);
|
|
let index = rawIndex - 1; // 클론 보정
|
|
|
|
if (index < 0) index = originalLength - 1;
|
|
if (index >= originalLength) index = 0;
|
|
|
|
return index;
|
|
}
|
|
|
|
// 카테고리 필터
|
|
function getCategories(products) {
|
|
return ['All', ...new Set(products.map((p) => p.category))];
|
|
}
|
|
|
|
function renderCategoryChips(products) {
|
|
const container = document.getElementById('filter-chips');
|
|
if (!container) return;
|
|
|
|
const categories = ['All', ...new Set(products.map((p) => p.category))];
|
|
|
|
container.innerHTML = '';
|
|
|
|
categories.forEach((cat) => {
|
|
const isActive = activeCategories.has(cat);
|
|
|
|
const chip = document.createElement('button');
|
|
chip.className = `
|
|
filter-chip px-4 py-2 rounded-full text-sm font-medium transition
|
|
border
|
|
${isActive ? 'bg-primary text-white border-primary' : 'bg-slate-50 text-slate-600 border-slate-200'}
|
|
`;
|
|
chip.textContent = cat;
|
|
chip.dataset.category = cat;
|
|
|
|
chip.onclick = () => {
|
|
toggleCategory(cat);
|
|
};
|
|
|
|
container.appendChild(chip);
|
|
});
|
|
}
|
|
|
|
function toggleCategory(category) {
|
|
if (category === 'All') {
|
|
activeCategories.clear();
|
|
activeCategories.add('All');
|
|
} else {
|
|
activeCategories.delete('All');
|
|
activeCategories.has(category) ? activeCategories.delete(category) : activeCategories.add(category);
|
|
|
|
if (activeCategories.size === 0) {
|
|
activeCategories.add('All');
|
|
}
|
|
}
|
|
|
|
renderCategoryChips(products);
|
|
applyFilters();
|
|
}
|
|
|
|
function bindCategoryFilter(products) {
|
|
const chips = document.querySelectorAll('.filter-chip');
|
|
|
|
chips.forEach((chip) => {
|
|
chip.addEventListener('click', () => {
|
|
const category = chip.dataset.category;
|
|
|
|
if (category === 'All') {
|
|
activeCategories.clear();
|
|
activeCategories.add('All');
|
|
} else {
|
|
activeCategories.delete('All');
|
|
|
|
if (activeCategories.has(category)) {
|
|
activeCategories.delete(category);
|
|
} else {
|
|
activeCategories.add(category);
|
|
}
|
|
|
|
// 아무 것도 없으면 All로 복귀
|
|
if (activeCategories.size === 0) {
|
|
activeCategories.add('All');
|
|
}
|
|
}
|
|
|
|
applyFilters();
|
|
});
|
|
});
|
|
}
|
|
|
|
// 카테고리 필터
|
|
renderCategoryChips(products);
|
|
bindCategoryFilter(products);
|
|
// updateChipUI();
|
|
|
|
// 상태 필터 (정책 기반)
|
|
renderStatusChips();
|
|
|
|
// 🔥 최초 필터 적용 (이게 첫 렌더)
|
|
applyFilters();
|
|
|
|
// 초기 실행 시 호출
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
renderProducts(currentPage);
|
|
checkUrlAndOpenModal();
|
|
});
|
|
|
|
function checkUrlAndOpenModal() {
|
|
const params = new URLSearchParams(window.location.search);
|
|
const productId = params.get('id'); // URL에서 가져온 ID (문자열)
|
|
|
|
if (productId) {
|
|
// 데이터의 id와 URL의 id를 모두 문자열로 변환하여 비교
|
|
const product = products.find((p) => String(p.id) === productId);
|
|
|
|
if (product) {
|
|
// DOM 렌더링 시간을 고려해 약간의 지연 후 모달 오픈
|
|
setTimeout(() => openModal(product.id), 100);
|
|
}
|
|
}
|
|
}
|
|
|
|
// [최종 ID 생성기] 매번 완전히 새로운 8자리 난수 출력
|
|
const newId = Math.random().toString(36).substring(2, 10);
|
|
|
|
console.log(`%c[NEW ID for data.js]: ${newId}`, 'color: #137fec; font-weight: bold; border: 1px solid #137fec; padding: 2px 5px; border-radius: 4px;');
|