"use client"; import Link from "next/link"; import { useCallback, useMemo, useState, type ReactElement } from "react"; import { useTranslation } from "react-i18next"; import { BarChart3, Flame, Landmark, Network, RefreshCw, Sparkles, Ticket, 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 { useAdminCurrencyCatalog } from "@/hooks/use-admin-currency-catalog"; import { adminHasAnyPermission } from "@/lib/admin-permissions"; import { PRD_AGENT_HUB_ACCESS_ANY, PRD_PLAYERS_ACCESS_ANY, PRD_REPORTS_VIEW_ACCESS_ANY, PRD_SETTLEMENT_AGENT_ACCESS_ANY, PRD_TICKETS_ACCESS_ANY, } from "@/lib/admin-prd"; import { normalizeAdminLanguage } from "@/i18n"; import { adminWeekdayKeyForDate, formatAdminCalendarToday } from "@/lib/admin-datetime"; import { cn } from "@/lib/utils"; import { useAdminProfile } from "@/stores/admin-session"; import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"; import { Button, buttonVariants } 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 { formatDashboardCreditMajor, formatDashboardMoneyMinor, } from "@/modules/dashboard/use-dashboard-analytics"; import type { AdminDashboardAgentOverview } from "@/types/api/admin-dashboard"; import type { DrawCurrentSnapshot } from "@/types/api/public-draw"; import { LotteryApiBizError } from "@/types/api/errors"; export function AgentDashboardConsole(): ReactElement { const { t, i18n } = useTranslation(["dashboard", "common", "agents"]); const tRef = useTranslationRef(["dashboard", "common"]); const formatDt = useAdminDateTimeFormatter(); const profile = useAdminProfile(); const agent = profile?.agent ?? null; const permissions = useMemo(() => profile?.permissions ?? [], [profile?.permissions]); 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]); useAdminCurrencyCatalog(); const playOptions = useCachedPlayTypeOptions(); const [loading, setLoading] = useState(true); const [refreshing, setRefreshing] = useState(false); const [error, setError] = useState(null); const [hall, setHall] = useState(null); const [drawId, setDrawId] = useState(null); const [overview, setOverview] = useState(null); const [canFinance, setCanFinance] = useState(false); const analyticsScope = useMemo( () => ({ siteCode: agent?.site_code ?? "", agentNodeId: agent?.id, }), [agent?.id, agent?.site_code], ); 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.agent_overview); setCanFinance(d.capabilities.draw_finance_risk); 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 currency = "NPR"; const displayCurrency = overview?.currency_code ?? currency; const quickLinks = useMemo(() => { const links: { href: string; label: string; icon: ReactElement }[] = []; if (adminHasAnyPermission(permissions, [...PRD_TICKETS_ACCESS_ANY])) { links.push({ href: "/admin/tickets", label: t("agent.quickLinks.tickets"), icon: , }); } if (adminHasAnyPermission(permissions, [...PRD_PLAYERS_ACCESS_ANY])) { links.push({ href: "/admin/players", label: t("agent.quickLinks.players"), icon: , }); } if (adminHasAnyPermission(permissions, [...PRD_REPORTS_VIEW_ACCESS_ANY])) { links.push({ href: "/admin/reports", label: t("agent.quickLinks.reports"), icon: , }); } if (adminHasAnyPermission(permissions, [...PRD_AGENT_HUB_ACCESS_ANY])) { links.push({ href: "/admin/agents", label: t("agent.quickLinks.agents"), icon: , }); } if (adminHasAnyPermission(permissions, [...PRD_SETTLEMENT_AGENT_ACCESS_ANY])) { links.push({ href: "/admin/settlement-center", label: t("agent.quickLinks.bills"), icon: , }); } return links; }, [permissions, t]); return (

{t("agent.title")}

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

{error ? ( {t("notice")} {error} ) : null} {loading ? (
{Array.from({ length: 4 }).map((_, i) => ( ))}
) : overview ? (

{t("agent.heroEyebrow")}

{t("agent.heroTitle", { name: overview.agent_name || overview.agent_code })}

{t("agent.todayBet")}

{formatDashboardMoneyMinor(overview.today_bet_minor, displayCurrency)}

{t("agent.todayPayout")}

{formatDashboardMoneyMinor(overview.today_payout_minor, displayCurrency)}

{t("agent.todayProfit")}

{formatDashboardMoneyMinor(overview.today_profit_minor, displayCurrency)}

{t("agent.activePlayersToday")}

{overview.active_player_count_today}

{t("agent.betOrdersToday")}

{overview.bet_order_count_today}

{t("agent.pendingBills")}

{overview.pending_bill_count}

{t("agent.shareRate", { rate: overview.total_share_rate })} {overview.latest_bet_at ? t("agent.latestBetAt", { time: formatDt(overview.latest_bet_at) }) : t("agent.noBetToday")}
{t("agent.creditTitle")}

{formatDashboardCreditMajor(overview.credit_limit, displayCurrency)}

{t("agent.creditAvailable", { amount: formatDashboardCreditMajor(overview.available_credit, displayCurrency), })}

{t("agent.creditAllocatedLabel")}

{formatDashboardCreditMajor(overview.allocated_credit, displayCurrency)}

{t("agent.creditUsedLabel")}

{formatDashboardCreditMajor(overview.used_credit, displayCurrency)}

{t("agent.pendingUnpaid", { amount: formatDashboardMoneyMinor(overview.pending_unpaid_minor, displayCurrency), })}

{t("agent.sevenDayTitle")}

{formatDashboardMoneyMinor(overview.seven_day_bet_minor, displayCurrency)}

{t("agent.sevenDayPayout", { amount: formatDashboardMoneyMinor(overview.seven_day_payout_minor, displayCurrency), })}

{t("agent.sevenDayProfit", { amount: formatDashboardMoneyMinor(overview.seven_day_profit_minor, displayCurrency), })}

{t("agent.teamTitle")}

{t("agent.directChildren")}

{overview.direct_child_count}

{t("agent.subtreeAgents")}

{overview.subtree_agent_count}

{t("agent.directPlayers")}

{overview.direct_player_count}

{t("agent.teamPlayers")}

{overview.team_player_count}

{t("agent.pendingBills")}

{overview.pending_bill_count}

{t("agent.pendingUnpaid", { amount: formatDashboardMoneyMinor(overview.pending_unpaid_minor, displayCurrency), })}

{t("agent.topMomentum")} {overview.top_agent_today ? ( <>

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

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

{t("agent.topMomentumHint", { profit: formatDashboardMoneyMinor( overview.top_agent_today.approx_house_gross_minor, displayCurrency, ), })}

) : (

{t("agent.noBetToday")}

)}
{t("agent.managementFocus")}

{t("agent.focusBet")}

{formatDashboardMoneyMinor(overview.today_bet_minor, displayCurrency)}

{t("agent.focusPlayers")}

{overview.active_player_count_today}

{t("agent.focusBills")}

{overview.pending_bill_count}

{t("agent.quickStatsTitle")}
{t("agent.canCreateChildAgent")} {overview.can_create_child_agent ? t("agent.yes") : t("agent.no")}
{t("agent.canCreatePlayer")} {overview.can_create_player ? t("agent.yes") : t("agent.no")}
{t("agent.lineDepth")} {overview.depth}
{adminHasAnyPermission(permissions, [...PRD_SETTLEMENT_AGENT_ACCESS_ANY]) ? ( {t("agent.viewBills")} ) : null}
) : null} {canFinance ? ( ) : ( {t("notice")} {t("warnings.drawPermission")} )} {quickLinks.length > 0 ? (
{quickLinks.map((link) => ( {link.icon} {link.label} ))}
) : null}
); }