import { useEffect, useMemo, useState } from 'react'; import { cn } from '@/lib/utils'; import { useTranslation } from '@/contexts/language'; export type EventStatus = 'soon' | 'upcoming' | 'live' | 'ended'; interface CountdownInfo { status: EventStatus; label: string; } type Translate = (key: string, params?: Record) => string; function computeStatus(start: number, end: number | undefined, t: Translate): CountdownInfo { const now = Date.now() / 1000; const effectiveEnd = end ?? start + 3 * 3600; // assume ~3h if no end if (now >= start && now < effectiveEnd) { return { status: 'live', label: t('placesUi.countdown.happeningNow') }; } if (now >= effectiveEnd) { return { status: 'ended', label: t('placesUi.countdown.ended') }; } const diff = start - now; const days = Math.floor(diff / 86400); const hours = Math.floor((diff % 86400) / 3600); const mins = Math.floor((diff % 3600) / 60); if (days >= 1) { return { status: days <= 3 ? 'soon' : 'upcoming', label: days === 1 ? t('placesUi.countdown.tomorrow') : t('placesUi.countdown.inDays', { count: days }) }; } if (hours >= 1) { return { status: 'soon', label: t('placesUi.countdown.inHoursMins', { hours, mins }) }; } if (mins >= 1) { return { status: 'soon', label: t('placesUi.countdown.inMins', { count: mins }) }; } return { status: 'soon', label: t('placesUi.countdown.startingNow') }; } /** * Live status pill for an event — the single most valuable at-a-glance signal: * "IN 3 DAYS" / "IN 2H 14M" / "🔴 HAPPENING NOW" / "ENDED". Ticks every 30s. */ export function EventCountdown({ start, end, className, }: { start: number; end?: number; className?: string; }) { const [tick, forceTick] = useState(0); const { t } = useTranslation(); // Re-render periodically so the countdown stays fresh without a heavy timer. useEffect(() => { const id = setInterval(() => forceTick((n) => n + 1), 30_000); return () => clearInterval(id); }, []); // `tick` forces a periodic recompute; `t` so a language switch updates it. // eslint-disable-next-line react-hooks/exhaustive-deps const info = useMemo(() => computeStatus(start, end, t), [start, end, tick, t]); const styles: Record = { live: 'bg-[#ff0040] text-white border-[#ff0040] animate-pulse', soon: 'bg-[#ccff00] text-black border-[#ccff00]', upcoming: 'bg-white/10 text-white border-white/20', ended: 'bg-white/5 text-gray-400 border-white/10', }; return ( {info.status === 'live' && ( )} {info.label} ); }