"use client"; import { useCallback, useMemo, useState, type ReactElement } from "react"; import { useTranslation } from "react-i18next"; import { BarChart3, RefreshCw, TrendingUp, Users, Wallet } from "lucide-react"; import { getAdminDashboard } from "@/api/admin-dashboard"; import { useAsyncEffect } from "@/hooks/use-async-effect"; import { useAdminDateTimeFormatter } from "@/hooks/use-admin-datetime-formatter"; import { useTranslationRef } from "@/hooks/use-translation-ref"; import { useCachedPlayTypeOptions } from "@/hooks/use-cached-play-type-options"; import { adminHasAnyPermission } from "@/lib/admin-permissions"; import { PRD_DASHBOARD_ANALYTICS_ACCESS_ANY } from "@/lib/admin-prd"; import { normalizeAdminLanguage } from "@/i18n"; import { adminWeekdayKeyForDate, formatAdminBusinessDateIso, formatAdminCalendarToday } from "@/lib/admin-datetime"; import { cn } from "@/lib/utils"; import { useAdminProfile } from "@/stores/admin-session"; import { AdminNoResourceState } from "@/components/admin/admin-no-resource-state"; import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"; import { Button } from "@/components/ui/button"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Skeleton } from "@/components/ui/skeleton"; import { DashboardCurrentDrawCard } from "@/modules/dashboard/dashboard-current-draw-card"; import { DashboardAnalyticsPanel } from "@/modules/dashboard/dashboard-analytics-panel"; import { DashboardKpiCard, DashboardScopeMetric, DashboardSignedStatRow, DashboardStatRow, } from "@/modules/dashboard/dashboard-visuals"; import { formatDashboardMoneyMinor, } from "@/modules/dashboard/use-dashboard-analytics"; import type { AdminDashboardSiteOverview, AdminDashboardWarning } from "@/types/api/admin-dashboard"; import type { DrawCurrentSnapshot } from "@/types/api/public-draw"; import { LotteryApiBizError } from "@/types/api/errors"; function buildTodayBetHint( businessDate: string, latestBetAt: string | null, t: (key: string, opts?: Record) => string, formatDt: (iso: string) => string, ): string { const dateHint = t("todayBusinessDateHint", { date: businessDate }); if (latestBetAt) { return `${dateHint} · ${t("site.latestBetAt", { time: formatDt(latestBetAt) })}`; } return `${dateHint} · ${t("site.noBetToday")}`; } export function SiteDashboardConsole(): ReactElement { const { t, i18n } = useTranslation(["dashboard", "common"]); const tRef = useTranslationRef(["dashboard", "common"]); const formatDt = useAdminDateTimeFormatter(); const profile = useAdminProfile(); const site = profile?.site ?? null; const permissions = useMemo(() => profile?.permissions ?? [], [profile?.permissions]); const businessDateToday = useMemo(() => formatAdminBusinessDateIso(), []); const todayLabel = useMemo(() => { const locale = normalizeAdminLanguage(i18n.resolvedLanguage ?? i18n.language); const weekday = t(`date.weekdays.${adminWeekdayKeyForDate()}`, { ns: "common" }); return formatAdminCalendarToday(locale, weekday); }, [i18n.language, i18n.resolvedLanguage, t]); const playOptions = useCachedPlayTypeOptions(); const [loading, setLoading] = useState(true); const [refreshing, setRefreshing] = useState(false); const [error, setError] = useState(null); const [apiWarnings, setApiWarnings] = useState([]); const [hall, setHall] = useState(null); const [drawId, setDrawId] = useState(null); const [overview, setOverview] = useState(null); const analyticsScope = useMemo( () => ({ siteCode: site?.code ?? overview?.site_code ?? "", agentNodeId: undefined, }), [overview?.site_code, site?.code], ); const canAnalytics = adminHasAnyPermission(permissions, [...PRD_DASHBOARD_ANALYTICS_ACCESS_ANY]); const load = useCallback(async (isRefresh = false) => { if (isRefresh) { setRefreshing(true); } else { setLoading(true); } setError(null); try { const d = await getAdminDashboard(); setHall(d.hall); setOverview(d.site_overview); setApiWarnings(d.warnings ?? []); if (d.resolved_draw != null) { setDrawId(d.resolved_draw.id); } else { setDrawId(null); } } catch (e) { const msg = e instanceof LotteryApiBizError ? e.message : tRef.current("warnings.loadFailed"); setError(msg); } finally { setLoading(false); setRefreshing(false); } }, [tRef]); useAsyncEffect(() => { void load(false); }, []); const displayCurrency = overview?.currency_code ?? "NPR"; return (

{t("site.title")}

{site ? t("site.subtitle", { name: site.name || site.code }) : todayLabel}

{error ? ( {t("notice")} {error} ) : null} {!loading && apiWarnings.length > 0 ? ( {t("notice")} {apiWarnings.map((w) => w.message).join(" ")} ) : null} {loading ? (
{Array.from({ length: 4 }).map((_, i) => ( ))}
) : overview ? (
} hint={buildTodayBetHint(businessDateToday, overview.latest_bet_at, t, formatDt)} /> } hint={t("todayPayoutHint", { amount: formatDashboardMoneyMinor(overview.today_payout_minor, displayCurrency), })} /> } hint={t("site.betOrdersTodayHint", { count: overview.bet_order_count_today })} /> } hint={t("site.pendingUnpaid", { amount: formatDashboardMoneyMinor(overview.pending_unpaid_minor, displayCurrency), })} accent={overview.pending_bill_count > 0 ? "destructive" : "muted"} />
{t("site.sevenDayTitle")}

{t("site.profitScopeHint")}

{t("site.scaleTitle")} {overview.top_agent_today ? (

{t("site.topAgentTodayLabel")}

{overview.top_agent_today.agent_name || overview.top_agent_today.agent_code}

{formatDashboardMoneyMinor( overview.top_agent_today.total_bet_minor, displayCurrency, )}

) : null}
) : ( {t("site.overviewEmpty")} )} {canAnalytics ? ( ) : null}
); }