"use client"; import Link from "next/link"; import { CalendarIcon, XIcon } from "lucide-react"; import { useCallback, useEffect, useMemo, useRef, useState } from "react"; import { useTranslation } from "react-i18next"; import { getDrawResults } from "@/api/draw"; import { Button } from "@/components/ui/button"; import { Calendar } from "@/components/ui/calendar"; import { Skeleton } from "@/components/ui/skeleton"; import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select"; import { PlayerPanel } from "@/components/layout/player-panel"; import { JackpotResultsStrip } from "@/features/results/jackpot-results-strip"; import { TwentyThreeResultsGrid } from "@/features/results/twenty-three-results-grid"; import { useCurrencyCatalog } from "@/hooks/use-currency-catalog"; import { formatPlayerInstant } from "@/lib/player-datetime"; import { useActivePlayerCurrency } from "@/hooks/use-active-player-currency"; import { resultsPrizeLabelKey, RESULTS_TOP_PRIZE_KEYS } from "@/lib/results-prize-labels"; import type { DrawResultListItem } from "@/types/api/draw-results"; const RESULTS_PAGE_SIZE = 10; const MONTH_OPTIONS = Array.from({ length: 12 }, (_, value) => ({ value, labelKey: `calendar.months.${value + 1}`, })); export function DrawResultsListScreen() { const { t } = useTranslation("player"); useCurrencyCatalog(); const [items, setItems] = useState(null); const [error, setError] = useState(null); const [date, setDate] = useState(""); const [datePickerOpen, setDatePickerOpen] = useState(false); const [calendarMonth, setCalendarMonth] = useState(() => new Date()); const [page, setPage] = useState(1); const [lastPage, setLastPage] = useState(1); const [loading, setLoading] = useState(true); const [loadingMore, setLoadingMore] = useState(false); const loadMoreRef = useRef(null); const selectedDate = useMemo(() => parseBusinessDate(date), [date]); const businessDate = /^\d{4}-\d{2}-\d{2}$/.test(date) ? date : undefined; const quickYears = useMemo(() => buildYearOptions(calendarMonth), [calendarMonth]); const featured = items?.[0] ?? null; const { activeCurrency } = useActivePlayerCurrency(); const jackpotCurrency = featured?.jackpot?.currency_code ?? activeCurrency; const fetchList = useCallback(async (targetPage = 1, append = false) => { setError(null); if (append) { setLoadingMore(true); } else { setLoading(true); } try { const res = await getDrawResults({ page: targetPage, size: RESULTS_PAGE_SIZE, business_date: businessDate, currency: activeCurrency, }); setItems((current) => (append && current ? [...current, ...res.items] : res.items)); setPage(res.page); setLastPage(res.last_page); } catch { setError(t("results.loadFailed")); if (!append) { setItems(null); } } finally { if (append) { setLoadingMore(false); } else { setLoading(false); } } }, [activeCurrency, businessDate, t]); useEffect(() => { queueMicrotask(() => { void fetchList(1, false); }); }, [fetchList]); useEffect(() => { const target = loadMoreRef.current; if (!target || loading || loadingMore || page >= lastPage) return; const observer = new IntersectionObserver( ([entry]) => { if (entry?.isIntersecting) { void fetchList(page + 1, true); } }, { rootMargin: "160px" }, ); observer.observe(target); return () => observer.disconnect(); }, [fetchList, lastPage, loading, loadingMore, page]); return (

{t("results.businessDate")}

{date || t("results.selectBusinessDate", { defaultValue: "选择日期", })} } />
{ if (!value) return; setDate(formatBusinessDate(value)); setCalendarMonth(value); setDatePickerOpen(false); }} className="rounded-lg" />
{date ? ( ) : null}
{loading ? (
) : error ? (

{error}

) : items && items.length === 0 ? (
{t("results.empty")}
) : (
{featured ? (

{t("results.detailTitle")}

{featured.draw_no}

{t("results.drawTime", { time: formatPlayerInstant( featured.draw_time_iso ?? featured.draw_time ?? null, ), })}

{t("results.openDetail", { defaultValue: "查看详情" })}
{t("results.viewMyWinning")}
) : null} {items?.slice(1).map((row) => (

{row.draw_no}

{formatPlayerInstant(row.draw_time_iso ?? row.draw_time ?? null)}

{t("results.detail")}
{RESULTS_TOP_PRIZE_KEYS.map((tier) => (

{t(resultsPrizeLabelKey(tier))}

{row.results[tier]}

))}
))}
{page < lastPage ? ( ) : items && items.length > 0 ? (

{t("results.noMore")}

) : null}
)}
); } function buildYearOptions(month: Date): number[] { const currentYear = new Date().getFullYear(); const visibleYear = month.getFullYear(); const start = Math.min(currentYear - 10, visibleYear - 2); const end = Math.max(currentYear + 2, visibleYear + 2); return Array.from({ length: end - start + 1 }, (_, index) => start + index); } function parseBusinessDate(value: string): Date | undefined { const match = /^(\d{4})-(\d{2})-(\d{2})$/.exec(value); if (!match) return undefined; const [, year, month, day] = match; return new Date(Number(year), Number(month) - 1, Number(day)); } function formatBusinessDate(value: Date): string { const year = value.getFullYear(); const month = String(value.getMonth() + 1).padStart(2, "0"); const day = String(value.getDate()).padStart(2, "0"); return `${year}-${month}-${day}`; }