"use client"; import Link from "next/link"; import { useCallback, useMemo, useState } from "react"; import { useTranslation } from "react-i18next"; import { useAsyncEffect } from "@/hooks/use-async-effect"; import { useTranslationRef } from "@/hooks/use-translation-ref"; import { toast } from "sonner"; import { getAdminDraw, getAdminDrawFinanceSummary, postAdminCancelDraw, postAdminManualCloseDraw, postAdminReopenDraw, postAdminRunDrawRng, } from "@/api/admin-draws"; import { postAdminRunDrawSettlement } from "@/api/admin-settlement"; import { Button } from "@/components/ui/button"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { AdminNoResourceState } from "@/components/admin/admin-no-resource-state"; import { AdminLoadingState } from "@/components/admin/admin-loading-state"; import { useAdminDateTimeFormatter } from "@/hooks/use-admin-datetime-formatter"; import { useConfirmAction } from "@/hooks/use-confirm-action"; import { LotteryApiBizError } from "@/types/api/errors"; import type { AdminDrawFinanceSummaryData } from "@/types/api/admin-draw-finance"; import type { AdminDrawShowData } from "@/types/api/admin-draws"; import { canManageDrawResults } from "@/lib/draw-access"; import { adminHasAnyPermission } from "@/lib/admin-permissions"; import { useAdminProfile } from "@/stores/admin-session"; import { signedMoneyClass } from "@/lib/admin-signed-money"; import { cn } from "@/lib/utils"; import { formatAdminMinorUnits } from "@/lib/money"; import { drawStatusLabel, hallPreviewDiffersFromDbStatus } from "./draw-display"; import { DrawStatusBadge } from "./draw-status-badge"; import { PRD_DRAW_REOPEN_MANAGE, PRD_PAYOUT_MANAGE, PRD_PAYOUT_REVIEW, } from "./draw-prd"; type ScheduleStep = { key: string; label: string; at: string | null | undefined; }; function ScheduleTimeline({ steps }: { steps: ScheduleStep[] }) { const formatDt = useAdminDateTimeFormatter(); return (
    {steps.map((step, index) => (
  1. {step.label}

    {formatDt(step.at)}

  2. ))}
); } export function DrawDetailConsole({ drawId }: { drawId: string }) { const { t } = useTranslation(["draws", "common"]); const tRef = useTranslationRef(["draws", "common"]); const idNum = Number(drawId); const profile = useAdminProfile(); const canManageDraw = canManageDrawResults(profile?.permissions); const canReopenDraw = adminHasAnyPermission(profile?.permissions, [PRD_DRAW_REOPEN_MANAGE]); const canRunSettlement = adminHasAnyPermission(profile?.permissions, [ PRD_PAYOUT_MANAGE, PRD_PAYOUT_REVIEW, ]); const [data, setData] = useState(null); const [error, setError] = useState(null); const [loading, setLoading] = useState(true); const [acting, setActing] = useState(null); const [financeSummary, setFinanceSummary] = useState(null); const { request: requestConfirm, ConfirmDialog } = useConfirmAction(); const load = useCallback(async () => { if (!Number.isFinite(idNum)) { setError(tRef.current("invalidDrawId")); setLoading(false); return; } setLoading(true); setError(null); try { const draw = await getAdminDraw(idNum); setData(draw); if (draw.capabilities?.can_view_draw_finance !== false) { try { setFinanceSummary(await getAdminDrawFinanceSummary(idNum)); } catch { setFinanceSummary(null); } } else { setFinanceSummary(null); } } catch (e) { setData(null); setFinanceSummary(null); setError(e instanceof LotteryApiBizError ? e.message : tRef.current("errors.loadFailed", { ns: "common" })); } finally { setLoading(false); } }, [idNum, tRef]); async function runAction(name: string, action: () => Promise): Promise { if (!Number.isFinite(idNum)) return; setActing(name); try { await action(); toast.success(t("actionSuccess", { name })); await load(); } catch (e) { toast.error(e instanceof LotteryApiBizError ? e.message : t("actionFailed", { name })); } finally { setActing(null); } } useAsyncEffect(() => { void load(); }, [idNum]); const scheduleSteps = useMemo((): ScheduleStep[] => { if (!data) return []; const steps: ScheduleStep[] = [ { key: "start", label: t("startTime"), at: data.start_time }, { key: "close", label: t("closeTime"), at: data.close_time }, { key: "draw", label: t("plannedDraw"), at: data.draw_time }, ]; if (data.cooling_end_time) { steps.push({ key: "cooling", label: t("coolingEndTime"), at: data.cooling_end_time, }); } return steps; }, [data, t]); const availableActions = useMemo(() => { if (!data) return []; type ActionDef = { key: string; label: string; variant: "outline" | "destructive"; enabled: boolean; onConfirm: () => Promise; confirmTitle: string; confirmDescription: string; confirmVariant?: "default" | "destructive"; }; const defs: ActionDef[] = []; if (canManageDraw) { defs.push( { key: "manualClose", label: t("manualClose"), variant: "outline", enabled: ["pending", "open"].includes(data.status), onConfirm: async () => { await postAdminManualCloseDraw(idNum); }, confirmTitle: t("confirm.manualCloseTitle"), confirmDescription: t("confirm.manualCloseDescription"), }, { key: "cancel", label: t("cancelBeforeDraw"), variant: "outline", enabled: ["pending", "open", "closing", "closed"].includes(data.status), onConfirm: async () => { await postAdminCancelDraw(idNum); }, confirmTitle: t("confirm.cancelDrawTitle"), confirmDescription: t("confirm.cancelDrawDescription"), }, { key: "rng", label: t("rngAutoGenerate"), variant: "outline", enabled: data.status === "closed", onConfirm: async () => { await postAdminRunDrawRng(idNum); }, confirmTitle: t("confirm.rngDrawTitle"), confirmDescription: t("confirm.rngDrawDescription"), }, ); } if (canReopenDraw) { defs.push({ key: "reopen", label: t("cooldownReopen"), variant: "destructive", enabled: data.status === "cooldown", onConfirm: async () => { await postAdminReopenDraw(idNum); }, confirmTitle: t("confirm.reopenTitle"), confirmDescription: t("confirm.reopenDescription"), confirmVariant: "destructive", }); } if (canRunSettlement) { defs.push({ key: "settlement", label: t("runSettlement"), variant: "outline", enabled: data.status === "settling", onConfirm: async () => { await postAdminRunDrawSettlement(idNum); }, confirmTitle: t("confirm.runSettlementTitle"), confirmDescription: t("confirm.runSettlementDescription"), }); } return defs.filter((d) => d.enabled); }, [canManageDraw, canReopenDraw, canRunSettlement, data, idNum, t]); if (loading && !data) { return ; } if (error) { return

{error}

; } if (!data) { return ; } const batch = data.result_batch_counts; const pendingReview = batch.pending_review ?? 0; const totalBatches = batch.total ?? batch.published; const financeCurrency = financeSummary?.currency_code ?? "NPR"; const hasResultActivity = (canManageDraw && (totalBatches > 0 || pendingReview > 0)) || batch.published > 0; const showActions = availableActions.length > 0 && (canManageDraw || canReopenDraw || canRunSettlement); return (
{t("backToList")}
{data.draw_no}

{t("detailSubtitle", { date: data.business_date, seq: data.sequence_no, })}

{hallPreviewDiffersFromDbStatus(data.status, data.hall_preview_status) ? ( <> {t("hallPreviewStatusLabel")} ) : null}

{t("overviewTitle")}

{t("overviewBetTotal")}

{formatAdminMinorUnits( financeSummary?.total_bet_minor ?? data.total_bet_minor ?? 0, financeCurrency, )}

{t("overviewPayoutTotal")}

{formatAdminMinorUnits( financeSummary?.total_payout_minor ?? data.total_payout_minor ?? 0, financeCurrency, )}

{t("overviewProfitLoss")}

{formatAdminMinorUnits( financeSummary?.approx_house_gross_minor ?? data.profit_loss_minor ?? 0, financeCurrency, )}

{t("scheduleTitle")}

{t("resultBatchesTitle")}

{hasResultActivity ? (
{canManageDraw ? ( {t("batchSummaryTotal", { count: totalBatches })} ) : null} {canManageDraw ? ( pendingReview > 0 ? ( {t("batchSummaryPending", { count: pendingReview })} ) : ( {t("batchSummaryPending", { count: 0 })} ) ) : null} {batch.published > 0 ? ( {t("batchSummaryPublished", { count: batch.published })} ) : ( {t("batchSummaryPublished", { count: 0 })} )}
) : (

{t("noResultBatchesYet")} {t("reviewQueueHint")} {canManageDraw ? ( <> {" "} {t("goToReviewTab")} ) : null}

)}
{showActions ? (

{t("drawActions")}

{availableActions.map((action) => ( ))}
) : null}
); }