"use client"; import type { ReactElement, ReactNode } from "react"; import { useTranslation } from "react-i18next"; import { AdminStatusBadge } from "@/components/admin/admin-status-badge"; import { cn } from "@/lib/utils"; import type { AdminDrawFinanceSummaryData } from "@/types/api/admin-draw-finance"; import type { AdminRiskPoolRow } from "@/types/api/admin-risk"; import type { AdminDashboardDrawPanel, AdminDashboardSoldOutBuckets, } from "@/types/api/admin-dashboard"; export type SoldOutBuckets = AdminDashboardSoldOutBuckets; type MoneyFormatter = (minor: number, currency: string | null) => string; export function StatCard({ label, value, hint, icon, accent = "primary", }: { label: string; value: ReactNode; hint?: ReactNode; icon: ReactNode; accent?: "primary" | "destructive" | "muted"; }): ReactElement { const accentClass = accent === "destructive" ? "bg-destructive text-destructive-foreground" : accent === "muted" ? "bg-muted text-foreground" : "bg-primary text-primary-foreground"; return (
{label}
{value}
{hint ?{t("lockedAndCap", { locked: formatMoney(locked, currency), cap: formatMoney(cap, currency), })}
{t("noFinanceActivity")}
; } const winW = (win / bet) * 100; const jpW = (jackpot / bet) * 100; const grossW = Math.max(0, (gross / bet) * 100); const payoutRate = ((payout / bet) * 100).toFixed(1); const segments = [ { key: "win", width: winW, className: "bg-emerald-500", label: t("winPayout"), value: win }, { key: "jackpot", width: jpW, className: "bg-violet-500", label: t("jackpotPayout"), value: jackpot }, { key: "gross", width: grossW, className: "bg-primary", label: t("houseGross"), value: gross }, ].filter((s) => s.width > 0.05); return ({t("payoutRateOfBet", { rate: payoutRate })}
{s.label}
{formatMoney(s.value, currency)}
{t("noPayoutYet")}
; } const winPct = (win / total) * 100; const winColor = "oklch(0.62 0.17 162)"; const jackpotColor = "oklch(0.56 0.22 303)"; const items = [ { label: t("winPayout"), value: win, pct: winPct, className: "bg-emerald-500", color: winColor }, { label: t("jackpotPayout"), value: jackpot, pct: 100 - winPct, className: "bg-violet-500", color: jackpotColor, }, ]; return ({formatMoney(item.value, currency)}
{t("noPoolData")}
; } return ({t("noSoldOutNumbers")}
; } let acc = 0; const parts = entries .filter((e) => buckets[e.key] > 0) .map((e) => { const frac = buckets[e.key] / total; const start = acc; acc += frac; return { ...e, frac, start }; }); const gradientStops = parts.length === 1 ? `${parts[0].color} 0deg 360deg` : parts .map((p) => { const a0 = p.start * 360; const a1 = (p.start + p.frac) * 360; return `${p.color} ${a0}deg ${a1}deg`; }) .join(", "); return ({total}
{t("soldOutTotal")}
{pending_review}
{t("batchPending")}
{published}
{t("batchPublished")}
{total}
{t("batchTotal")}
{t("noSettlementBatches")}
; } const counts = new Map