import api from '../api'; import { usePlayerProfile } from './usePlayerProfile'; import { usePlayerMessages } from './usePlayerMessages'; interface DepositOrderRow { id: string; orderNo: string; amount: string; status: string; rejectReason?: string | null; } const POLL_FAST_MS = 8_000; const POLL_SLOW_MS = 30_000; const TRACKED_STORAGE_KEY = 'player_deposit_tracked_pending'; const lastStatus = new Map(); const trackedPending = new Set(); const notifiedKeys = new Set(); let pollTimer: ReturnType | null = null; let pollingActive = false; function notifyKey(orderId: string, type: 'approved' | 'rejected') { return `${orderId}:${type}`; } function loadTrackedFromStorage() { try { const raw = sessionStorage.getItem(TRACKED_STORAGE_KEY); if (!raw) return; const ids: string[] = JSON.parse(raw); for (const id of ids) { if (id) trackedPending.add(String(id)); } } catch { /* ignore */ } } function persistTrackedToStorage() { try { sessionStorage.setItem(TRACKED_STORAGE_KEY, JSON.stringify([...trackedPending])); } catch { /* ignore */ } } function addTracked(orderId: string) { trackedPending.add(orderId); persistTrackedToStorage(); } function removeTracked(orderId: string) { if (!trackedPending.delete(orderId)) return; persistTrackedToStorage(); } function hasPendingInterest() { return trackedPending.size > 0; } function schedulePoll(intervalMs: number) { if (pollTimer) clearInterval(pollTimer); pollTimer = setInterval(() => { void pollOnce(); }, intervalMs); } function adjustPollInterval() { if (!pollingActive) return; schedulePoll(hasPendingInterest() ? POLL_FAST_MS : POLL_SLOW_MS); } function trackPendingOrder(orderId: string) { const id = String(orderId); if (!id) return; addTracked(id); lastStatus.set(id, 'PENDING'); adjustPollInterval(); void pollOnce(); } function shouldNotify(orderId: string, prev: string | undefined, next: string) { if (next !== 'APPROVED' && next !== 'REJECTED') return false; if (prev === 'PENDING') return true; if (trackedPending.has(orderId)) return true; return false; } function handleStatusChange(order: DepositOrderRow): boolean { const prev = lastStatus.get(order.id); const next = order.status; lastStatus.set(order.id, next); if (next === 'PENDING') { addTracked(order.id); return false; } removeTracked(order.id); if (!shouldNotify(order.id, prev, next)) return false; const type = next === 'APPROVED' ? 'approved' : 'rejected'; const key = notifyKey(order.id, type); if (notifiedKeys.has(key)) return false; notifiedKeys.add(key); void usePlayerMessages().refreshUnreadCount(); return next === 'APPROVED'; } async function pollOnce() { try { const { data } = await api.get('/player/deposit-orders', { params: { page: 1 } }); const items: DepositOrderRow[] = data.data?.items ?? []; const { refreshProfile } = usePlayerProfile(); let needsProfileRefresh = false; for (const order of items) { if (handleStatusChange(order)) needsProfileRefresh = true; } if (needsProfileRefresh) await refreshProfile(); adjustPollInterval(); } catch { /* silent retry on next tick */ } } function onVisibilityChange() { if (!document.hidden && pollingActive) void pollOnce(); } function startPolling() { if (pollingActive) { void pollOnce(); return; } pollingActive = true; loadTrackedFromStorage(); for (const id of trackedPending) { if (!lastStatus.has(id)) lastStatus.set(id, 'PENDING'); } document.addEventListener('visibilitychange', onVisibilityChange); void pollOnce(); schedulePoll(hasPendingInterest() ? POLL_FAST_MS : POLL_SLOW_MS); } function stopPolling() { pollingActive = false; trackedPending.clear(); lastStatus.clear(); notifiedKeys.clear(); try { sessionStorage.removeItem(TRACKED_STORAGE_KEY); } catch { /* ignore */ } if (pollTimer) { clearInterval(pollTimer); pollTimer = null; } document.removeEventListener('visibilitychange', onVisibilityChange); } export function useDepositNotifications() { return { trackPendingOrder, startPolling, stopPolling, pollOnce, }; }