/** * 상품 「게임하기 / 구매하기 / 바로구매」 클릭 연결 * - 게임하기 → 즉시 추첨(mode=game) * - 구매하기 → 상품 상세 * - 결제 승인·추첨 미완료 주문이 있으면 「추첨하기」로 바꾸고 구매 추첨 화면으로 이동 */ (function () { var pendingByProduct = null; var loadPromise = null; var applyTimer = null; var mapLoadedOk = false; function getLoginUser() { try { var raw = localStorage.getItem('loginUser'); return raw ? JSON.parse(raw) : null; } catch (e) { return null; } } function isLoggedIn() { return localStorage.getItem('isLoggedIn') === 'true'; } function waitForFirebase(maxMs) { var maxWait = maxMs || 10000; return new Promise(function (resolve) { var start = Date.now(); function check() { if (typeof firebase !== 'undefined' && firebase.apps && firebase.apps.length > 0) { resolve(true); return; } if (Date.now() - start > maxWait) { resolve(false); return; } setTimeout(check, 80); } check(); }); } function waitForAuthUser(maxMs) { var maxWait = maxMs || 5000; return new Promise(function (resolve) { if (!firebase.auth) { resolve(null); return; } var existing = firebase.auth().currentUser; if (existing) { resolve(existing); return; } var done = false; var timer = setTimeout(function () { if (done) return; done = true; unsub && unsub(); resolve(firebase.auth().currentUser || null); }, maxWait); var unsub = firebase.auth().onAuthStateChanged(function (user) { if (done) return; done = true; clearTimeout(timer); unsub && unsub(); resolve(user || null); }); }); } function purchaseLotteryUrl(orderId, productId) { var url = 'game-lottery.html?mode=purchase&orderId=' + encodeURIComponent(orderId || ''); if (productId) { url += '&id=' + encodeURIComponent(productId); } return url; } function goPurchaseLottery(orderId, productId) { if (!orderId) return; try { sessionStorage.setItem('purchaseLotteryOrderId', orderId); if (productId) sessionStorage.setItem('selectedProductId', productId); } catch (e) { /* ignore */ } var url = purchaseLotteryUrl(orderId, productId); if (!isLoggedIn()) { window.location.href = 'login.html?redirect=' + encodeURIComponent(url); return; } window.location.href = url; } function goLottery(productId, mode) { if (!productId) return; var nextMode = mode || 'game'; try { sessionStorage.setItem('selectedProductId', productId); // 게임하기는 구매 추첨 주문 ID와 섞이면 안 됨 if (nextMode === 'game') { sessionStorage.removeItem('purchaseLotteryOrderId'); } } catch (e) { /* ignore */ } var url = 'game-lottery.html?id=' + encodeURIComponent(productId) + '&mode=' + encodeURIComponent(nextMode); if (!isLoggedIn()) { window.location.href = 'login.html?redirect=' + encodeURIComponent(url); return; } window.location.href = url; } function goProductDetail(productId) { if (!productId) return; try { sessionStorage.setItem('selectedProductId', productId); } catch (e) { /* ignore */ } var url = 'product-detail.html?id=' + encodeURIComponent(productId); if (!isLoggedIn()) { window.location.href = 'login.html?redirect=' + encodeURIComponent(url); return; } window.location.href = url; } function isOrderOwnedByUser(order, ids) { if (!order || !ids) return false; var orderUser = String(order.userId || '').trim(); var orderMember = String(order.memberId || '').trim(); var candidates = [ids.userId, ids.docId, ids.authUid].filter(Boolean).map(String); for (var i = 0; i < candidates.length; i++) { var c = candidates[i]; if (orderUser === c || orderMember === c) return true; } return false; } function getCurrentProductIdFromPage() { try { var params = new URLSearchParams(window.location.search); var id = params.get('id') || ''; if (id) return String(id).trim(); } catch (e) { /* ignore */ } try { return String(sessionStorage.getItem('selectedProductId') || '').trim(); } catch (e2) { return ''; } } function orderTimeMs(order) { var t = order && (order.createdAt || order.approvedAt || order.updatedAt); if (!t) return 0; if (typeof t.toMillis === 'function') return t.toMillis(); if (t.seconds != null) return t.seconds * 1000; var n = Number(t); return isFinite(n) ? n : 0; } function normalizeProductId(value) { return String(value == null ? '' : value).trim(); } async function resolveMemberIds(user, authUser) { var ids = { userId: String((user && user.userId) || '').trim(), docId: String((user && (user.docId || user.uid)) || '').trim(), authUid: String((authUser && authUser.uid) || '').trim(), }; if (ids.docId || !ids.userId || !firebase.firestore) return ids; try { var snap = await firebase .firestore() .collection('members') .where('userId', '==', ids.userId) .limit(1) .get(); if (!snap.empty) { ids.docId = snap.docs[0].id; } } catch (e) { console.warn('[product-game-buttons] members 조회 실패:', e); } if (!ids.docId && ids.authUid) ids.docId = ids.authUid; return ids; } function collectFromSnap(snap, ids, best) { if (!snap || !snap.docs) return; snap.docs.forEach(function (doc) { var d = doc.data() || {}; var status = String(d.status || '').trim(); if (status !== 'approved') return; if (d.lotteryCompleted === true) return; if (!isOrderOwnedByUser(d, ids)) return; var productId = normalizeProductId(d.productId); if (!productId) return; var row = { orderId: doc.id, productId: productId, createdAtMs: orderTimeMs(d), }; var prev = best[productId]; if (!prev || row.createdAtMs >= prev.createdAtMs) { best[productId] = row; } }); } async function loadPendingLotteryByProduct() { if (!isLoggedIn()) return {}; var user = getLoginUser(); if (!user || !user.userId) return {}; var ready = await waitForFirebase(); if (!ready || !firebase.firestore) return {}; var authUser = await waitForAuthUser(4000); var ids = await resolveMemberIds(user, authUser); var db = firebase.firestore(); var best = {}; var queries = []; // 본인 주문만 조회 (전체 approved limit은 본인 주문이 빠질 수 있음) if (ids.userId) { queries.push( db.collection('orders').where('userId', '==', ids.userId).limit(100).get() ); } if (ids.docId && ids.docId !== ids.userId) { queries.push( db.collection('orders').where('memberId', '==', ids.docId).limit(100).get() ); } if (ids.authUid && ids.authUid !== ids.docId && ids.authUid !== ids.userId) { queries.push( db.collection('orders').where('memberId', '==', ids.authUid).limit(100).get() ); queries.push( db.collection('orders').where('userId', '==', ids.authUid).limit(100).get() ); } if (queries.length === 0) return {}; try { var results = await Promise.all( queries.map(function (p) { return p.catch(function (err) { console.warn('[product-game-buttons] 주문 조회 실패:', err); return null; }); }) ); results.forEach(function (snap) { collectFromSnap(snap, ids, best); }); mapLoadedOk = true; return best; } catch (e) { console.warn('[product-game-buttons] 추첨 대기 주문 조회 실패:', e); mapLoadedOk = false; return {}; } } function ensurePendingMap(forceReload) { if (!forceReload && pendingByProduct && mapLoadedOk) { return Promise.resolve(pendingByProduct); } if (!forceReload && loadPromise) return loadPromise; loadPromise = loadPendingLotteryByProduct().then(function (map) { pendingByProduct = map || {}; loadPromise = null; return pendingByProduct; }); return loadPromise; } function setBuyButtonLotteryState(btn, orderInfo, defaultLabelHtml) { if (!btn) return; if (orderInfo && orderInfo.orderId) { btn.setAttribute('data-lottery-order-id', orderInfo.orderId); if (orderInfo.productId) { btn.setAttribute('data-product-id', orderInfo.productId); } btn.classList.add('is-lottery-ready'); if (btn.classList.contains('btn-buy') || btn.classList.contains('btn-buy-fixed')) { btn.innerHTML = ' 추첨하기'; } else { btn.textContent = '추첨하기'; } } else { btn.removeAttribute('data-lottery-order-id'); btn.classList.remove('is-lottery-ready'); if (defaultLabelHtml != null) { if (btn.classList.contains('btn-product-buy')) { btn.textContent = '구매하기'; } else { btn.innerHTML = defaultLabelHtml; } } else if ( btn.classList.contains('btn-buy') || btn.classList.contains('btn-buy-fixed') ) { btn.innerHTML = ' 바로구매'; } else { btn.textContent = '구매하기'; } } } function applyLotteryButtonLabels(map) { map = map || {}; document.querySelectorAll('.btn-product-buy').forEach(function (btn) { var productId = normalizeProductId(btn.getAttribute('data-product-id')); setBuyButtonLotteryState(btn, map[productId] || null, '구매하기'); }); var pageProductId = getCurrentProductIdFromPage(); document.querySelectorAll('.btn-buy, .btn-buy-fixed').forEach(function (btn) { var productId = normalizeProductId(btn.getAttribute('data-product-id')) || pageProductId; if (productId) btn.setAttribute('data-product-id', productId); setBuyButtonLotteryState( btn, productId ? map[productId] || null : null, ' 바로구매' ); }); } function refreshLotteryButtons(forceReload) { var force = !!forceReload; if (force) { pendingByProduct = null; loadPromise = null; mapLoadedOk = false; } return ensurePendingMap(force).then(function (map) { applyLotteryButtonLabels(map); return map; }); } function scheduleRefresh(forceReload) { if (applyTimer) clearTimeout(applyTimer); applyTimer = setTimeout(function () { refreshLotteryButtons(!!forceReload); }, 120); } document.addEventListener( 'click', function (e) { var playBtn = e.target.closest && e.target.closest('.btn-product-game'); if (playBtn) { e.preventDefault(); e.stopPropagation(); goLottery(playBtn.getAttribute('data-product-id'), 'game'); return; } var lotteryBtn = e.target.closest && e.target.closest( '.btn-product-buy.is-lottery-ready, .btn-buy.is-lottery-ready, .btn-buy-fixed.is-lottery-ready' ); if (lotteryBtn) { e.preventDefault(); e.stopPropagation(); goPurchaseLottery( lotteryBtn.getAttribute('data-lottery-order-id'), lotteryBtn.getAttribute('data-product-id') || getCurrentProductIdFromPage() ); return; } var buyBtn = e.target.closest && e.target.closest('.btn-product-buy'); if (buyBtn) { e.preventDefault(); e.stopPropagation(); goProductDetail(buyBtn.getAttribute('data-product-id')); } }, true ); function boot() { scheduleRefresh(true); setTimeout(function () { scheduleRefresh(true); }, 1000); setTimeout(function () { scheduleRefresh(true); }, 3000); } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', boot); } else { boot(); } window.ProductGameButtons = { refresh: function (forceReload) { return refreshLotteryButtons(forceReload !== false); }, }; })();