|
|
|
|
@@ -1,7 +1,7 @@
|
|
|
|
|
"use client";
|
|
|
|
|
|
|
|
|
|
import Link from "next/link";
|
|
|
|
|
import { useCallback, useState } from "react";
|
|
|
|
|
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";
|
|
|
|
|
@@ -15,25 +15,18 @@ import {
|
|
|
|
|
postAdminRunDrawRng,
|
|
|
|
|
} from "@/api/admin-draws";
|
|
|
|
|
import { postAdminRunDrawSettlement } from "@/api/admin-settlement";
|
|
|
|
|
import { Button, buttonVariants } from "@/components/ui/button";
|
|
|
|
|
import { Button } from "@/components/ui/button";
|
|
|
|
|
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
|
|
|
|
import { Label } from "@/components/ui/label";
|
|
|
|
|
import { Separator } from "@/components/ui/separator";
|
|
|
|
|
import { AdminLoadingState, AdminLoadingInline, AdminTableLoadingRow } from "@/components/admin/admin-loading-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 { AdminDrawShowData } from "@/types/api/admin-draws";
|
|
|
|
|
import { adminHasAnyPermission } from "@/lib/admin-permissions";
|
|
|
|
|
import { useAdminProfile } from "@/stores/admin-session";
|
|
|
|
|
|
|
|
|
|
import { cn } from "@/lib/utils";
|
|
|
|
|
|
|
|
|
|
import {
|
|
|
|
|
drawResultSourceLabel,
|
|
|
|
|
drawStatusLabel,
|
|
|
|
|
hallPreviewDiffersFromDbStatus,
|
|
|
|
|
} from "./draw-display";
|
|
|
|
|
import { drawStatusLabel, hallPreviewDiffersFromDbStatus } from "./draw-display";
|
|
|
|
|
import { DrawStatusBadge } from "./draw-status-badge";
|
|
|
|
|
import {
|
|
|
|
|
PRD_DRAW_REOPEN_MANAGE,
|
|
|
|
|
@@ -42,12 +35,31 @@ import {
|
|
|
|
|
PRD_PAYOUT_REVIEW,
|
|
|
|
|
} from "./draw-prd";
|
|
|
|
|
|
|
|
|
|
function Field({ label, children }: { label: string; children: React.ReactNode }) {
|
|
|
|
|
type ScheduleStep = {
|
|
|
|
|
key: string;
|
|
|
|
|
label: string;
|
|
|
|
|
at: string | null | undefined;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
function ScheduleTimeline({ steps }: { steps: ScheduleStep[] }) {
|
|
|
|
|
const formatDt = useAdminDateTimeFormatter();
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<div className="grid gap-1 sm:grid-cols-[10rem_1fr] sm:items-start">
|
|
|
|
|
<Label className="text-muted-foreground">{label}</Label>
|
|
|
|
|
<div className="text-sm">{children}</div>
|
|
|
|
|
</div>
|
|
|
|
|
<ol className="grid gap-3 sm:grid-cols-3">
|
|
|
|
|
{steps.map((step, index) => (
|
|
|
|
|
<li
|
|
|
|
|
key={step.key}
|
|
|
|
|
className={cn(
|
|
|
|
|
"relative rounded-lg border bg-muted/20 px-3 py-2.5",
|
|
|
|
|
index < steps.length - 1 &&
|
|
|
|
|
"sm:after:absolute sm:after:top-1/2 sm:after:left-full sm:after:h-px sm:after:w-3 sm:after:-translate-y-1/2 sm:after:bg-border",
|
|
|
|
|
)}
|
|
|
|
|
>
|
|
|
|
|
<p className="text-xs font-medium text-muted-foreground">{step.label}</p>
|
|
|
|
|
<p className="mt-1 font-mono text-sm tabular-nums">{formatDt(step.at)}</p>
|
|
|
|
|
</li>
|
|
|
|
|
))}
|
|
|
|
|
</ol>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -62,7 +74,6 @@ export function DrawDetailConsole({ drawId }: { drawId: string }) {
|
|
|
|
|
PRD_PAYOUT_MANAGE,
|
|
|
|
|
PRD_PAYOUT_REVIEW,
|
|
|
|
|
]);
|
|
|
|
|
const formatDt = useAdminDateTimeFormatter();
|
|
|
|
|
const [data, setData] = useState<AdminDrawShowData | null>(null);
|
|
|
|
|
const [error, setError] = useState<string | null>(null);
|
|
|
|
|
const [loading, setLoading] = useState(true);
|
|
|
|
|
@@ -105,6 +116,99 @@ export function DrawDetailConsole({ drawId }: { drawId: string }) {
|
|
|
|
|
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<void>;
|
|
|
|
|
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: () => 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: () => postAdminCancelDraw(idNum),
|
|
|
|
|
confirmTitle: t("confirm.cancelDrawTitle"),
|
|
|
|
|
confirmDescription: t("confirm.cancelDrawDescription"),
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
key: "rng",
|
|
|
|
|
label: t("rngAutoGenerate"),
|
|
|
|
|
variant: "outline",
|
|
|
|
|
enabled: data.status === "closed",
|
|
|
|
|
onConfirm: () => 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: () => 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: () => 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 <AdminLoadingState minHeight="6rem" className="py-6" />;
|
|
|
|
|
}
|
|
|
|
|
@@ -113,164 +217,122 @@ export function DrawDetailConsole({ drawId }: { drawId: string }) {
|
|
|
|
|
return <p className="text-sm text-destructive">{error ?? t("states.noData", { ns: "common" })}</p>;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const batch = data.result_batch_counts;
|
|
|
|
|
const hasResultActivity = batch.total > 0 || batch.pending_review > 0 || batch.published > 0;
|
|
|
|
|
const showActions =
|
|
|
|
|
availableActions.length > 0 && (canManageDraw || canReopenDraw || canRunSettlement);
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<div className="space-y-6">
|
|
|
|
|
<Card className="overflow-hidden">
|
|
|
|
|
<CardHeader className="border-b bg-muted/30 pb-4">
|
|
|
|
|
<div className="flex flex-wrap items-center justify-between gap-3">
|
|
|
|
|
<div>
|
|
|
|
|
<CardTitle className="text-xl">{data.draw_no}</CardTitle>
|
|
|
|
|
<p className="mt-1 text-sm text-muted-foreground">{t("drawDetail")}</p>
|
|
|
|
|
<div className="space-y-4">
|
|
|
|
|
<Card>
|
|
|
|
|
<CardHeader className="pb-4">
|
|
|
|
|
<div className="flex flex-wrap items-start justify-between gap-3">
|
|
|
|
|
<div className="min-w-0">
|
|
|
|
|
<CardTitle className="font-mono text-xl tracking-tight">{data.draw_no}</CardTitle>
|
|
|
|
|
<p className="mt-1 text-sm text-muted-foreground">
|
|
|
|
|
{t("detailSubtitle", {
|
|
|
|
|
date: data.business_date,
|
|
|
|
|
seq: data.sequence_no,
|
|
|
|
|
})}
|
|
|
|
|
</p>
|
|
|
|
|
</div>
|
|
|
|
|
<div className="flex flex-col items-end gap-1 text-right">
|
|
|
|
|
<div className="flex flex-wrap items-center gap-2">
|
|
|
|
|
<DrawStatusBadge
|
|
|
|
|
status={data.status}
|
|
|
|
|
label={drawStatusLabel(data.status, t)}
|
|
|
|
|
/>
|
|
|
|
|
{hallPreviewDiffersFromDbStatus(data.status, data.hall_preview_status) ? (
|
|
|
|
|
<p className="flex flex-wrap items-center justify-end gap-2 text-sm text-muted-foreground">
|
|
|
|
|
<span>{t("hallPreviewStatusLabel")}</span>
|
|
|
|
|
<>
|
|
|
|
|
<span className="text-xs text-muted-foreground">{t("hallPreviewStatusLabel")}</span>
|
|
|
|
|
<DrawStatusBadge
|
|
|
|
|
status={data.hall_preview_status}
|
|
|
|
|
label={drawStatusLabel(data.hall_preview_status, t)}
|
|
|
|
|
/>
|
|
|
|
|
</p>
|
|
|
|
|
</>
|
|
|
|
|
) : null}
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</CardHeader>
|
|
|
|
|
<CardContent className="grid gap-6 p-6 lg:grid-cols-[minmax(0,1.2fr)_minmax(0,0.8fr)]">
|
|
|
|
|
<div className="space-y-4">
|
|
|
|
|
<div className="grid gap-4 sm:grid-cols-2">
|
|
|
|
|
<Field label={t("businessDate")}>{data.business_date}</Field>
|
|
|
|
|
<Field label={t("sequenceNo")}>{data.sequence_no}</Field>
|
|
|
|
|
<Field label={t("startTime")}>{formatDt(data.start_time)}</Field>
|
|
|
|
|
<Field label={t("closeTime")}>{formatDt(data.close_time)}</Field>
|
|
|
|
|
<Field label={t("plannedDraw")}>{formatDt(data.draw_time)}</Field>
|
|
|
|
|
<Field label={t("coolingEndTime")}>{formatDt(data.cooling_end_time)}</Field>
|
|
|
|
|
</div>
|
|
|
|
|
<Separator />
|
|
|
|
|
<div className="grid gap-4 sm:grid-cols-2">
|
|
|
|
|
<Field label={t("resultSource")}>{drawResultSourceLabel(data.result_source, t)}</Field>
|
|
|
|
|
<Field label={t("currentResultVersion")}>{data.current_result_version}</Field>
|
|
|
|
|
<Field label={t("settleVersion")}>{data.settle_version}</Field>
|
|
|
|
|
<Field label={t("isReopened")}>{data.is_reopened ? t("yes") : t("no")}</Field>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div className="rounded-xl border bg-muted/20 p-4">
|
|
|
|
|
<p className="text-sm font-medium text-muted-foreground">{t("batchStats")}</p>
|
|
|
|
|
<div className="mt-3 grid gap-3 text-sm">
|
|
|
|
|
<div className="flex items-center justify-between rounded-lg bg-background px-3 py-2">
|
|
|
|
|
<span>{t("batchTotal")}</span>
|
|
|
|
|
<span className="font-semibold">{data.result_batch_counts.total}</span>
|
|
|
|
|
<CardContent className="space-y-6 border-t pt-6">
|
|
|
|
|
<section className="space-y-3">
|
|
|
|
|
<h3 className="text-sm font-medium">{t("scheduleTitle")}</h3>
|
|
|
|
|
<ScheduleTimeline steps={scheduleSteps} />
|
|
|
|
|
</section>
|
|
|
|
|
|
|
|
|
|
<section className="space-y-3">
|
|
|
|
|
<h3 className="text-sm font-medium">{t("resultBatchesTitle")}</h3>
|
|
|
|
|
{hasResultActivity ? (
|
|
|
|
|
<div className="flex flex-wrap items-center gap-2 text-sm">
|
|
|
|
|
<span className="rounded-md bg-muted px-2.5 py-1">
|
|
|
|
|
{t("batchSummaryTotal", { count: batch.total })}
|
|
|
|
|
</span>
|
|
|
|
|
{batch.pending_review > 0 ? (
|
|
|
|
|
<Link
|
|
|
|
|
href={`/admin/draws/${drawId}/review`}
|
|
|
|
|
className="rounded-md bg-amber-500/15 px-2.5 py-1 font-medium text-amber-800 dark:text-amber-200"
|
|
|
|
|
>
|
|
|
|
|
{t("batchSummaryPending", { count: batch.pending_review })}
|
|
|
|
|
</Link>
|
|
|
|
|
) : (
|
|
|
|
|
<span className="rounded-md bg-muted px-2.5 py-1 text-muted-foreground">
|
|
|
|
|
{t("batchSummaryPending", { count: 0 })}
|
|
|
|
|
</span>
|
|
|
|
|
)}
|
|
|
|
|
{batch.published > 0 ? (
|
|
|
|
|
<Link
|
|
|
|
|
href={`/admin/draws/${drawId}/results`}
|
|
|
|
|
className="rounded-md bg-emerald-500/15 px-2.5 py-1 font-medium text-emerald-800 dark:text-emerald-200"
|
|
|
|
|
>
|
|
|
|
|
{t("batchSummaryPublished", { count: batch.published })}
|
|
|
|
|
</Link>
|
|
|
|
|
) : (
|
|
|
|
|
<span className="rounded-md bg-muted px-2.5 py-1 text-muted-foreground">
|
|
|
|
|
{t("batchSummaryPublished", { count: 0 })}
|
|
|
|
|
</span>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
<div className="flex items-center justify-between rounded-lg bg-background px-3 py-2 text-amber-600 dark:text-amber-400">
|
|
|
|
|
<span>{t("pendingReview")}</span>
|
|
|
|
|
<span className="font-semibold">{data.result_batch_counts.pending_review}</span>
|
|
|
|
|
) : (
|
|
|
|
|
<p className="text-sm text-muted-foreground">
|
|
|
|
|
{t("noResultBatchesYet")}{" "}
|
|
|
|
|
<Link
|
|
|
|
|
href={`/admin/draws/${drawId}/review`}
|
|
|
|
|
className="font-medium text-primary underline-offset-4 hover:underline"
|
|
|
|
|
>
|
|
|
|
|
{t("goToReviewTab")}
|
|
|
|
|
</Link>
|
|
|
|
|
</p>
|
|
|
|
|
)}
|
|
|
|
|
</section>
|
|
|
|
|
|
|
|
|
|
{showActions ? (
|
|
|
|
|
<section className="space-y-3 border-t pt-6">
|
|
|
|
|
<h3 className="text-sm font-medium">{t("drawActions")}</h3>
|
|
|
|
|
<div className="flex flex-wrap gap-2">
|
|
|
|
|
{availableActions.map((action) => (
|
|
|
|
|
<Button
|
|
|
|
|
key={action.key}
|
|
|
|
|
type="button"
|
|
|
|
|
size="sm"
|
|
|
|
|
variant={action.variant}
|
|
|
|
|
disabled={acting !== null}
|
|
|
|
|
onClick={() =>
|
|
|
|
|
requestConfirm({
|
|
|
|
|
title: action.confirmTitle,
|
|
|
|
|
description: action.confirmDescription,
|
|
|
|
|
confirmVariant: action.confirmVariant,
|
|
|
|
|
onConfirm: () => runAction(action.label, action.onConfirm),
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
>
|
|
|
|
|
{acting === action.label ? t("processing") : action.label}
|
|
|
|
|
</Button>
|
|
|
|
|
))}
|
|
|
|
|
</div>
|
|
|
|
|
<div className="flex items-center justify-between rounded-lg bg-background px-3 py-2 text-emerald-600 dark:text-emerald-400">
|
|
|
|
|
<span>{t("published")}</span>
|
|
|
|
|
<span className="font-semibold">{data.result_batch_counts.published}</span>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<Link
|
|
|
|
|
href={`/admin/draws/${drawId}/finance`}
|
|
|
|
|
className={cn(buttonVariants({ variant: "outline", size: "sm" }), "mt-4 w-full")}
|
|
|
|
|
>
|
|
|
|
|
{t("viewFinance")}
|
|
|
|
|
</Link>
|
|
|
|
|
</div>
|
|
|
|
|
</section>
|
|
|
|
|
) : null}
|
|
|
|
|
</CardContent>
|
|
|
|
|
</Card>
|
|
|
|
|
|
|
|
|
|
{(canManageDraw || canReopenDraw || canRunSettlement) ? (
|
|
|
|
|
<Card>
|
|
|
|
|
<CardHeader>
|
|
|
|
|
<CardTitle className="text-base">{t("drawActions")}</CardTitle>
|
|
|
|
|
</CardHeader>
|
|
|
|
|
<CardContent className="flex flex-wrap gap-2">
|
|
|
|
|
<Button
|
|
|
|
|
type="button"
|
|
|
|
|
variant="outline"
|
|
|
|
|
size="sm"
|
|
|
|
|
disabled={!canManageDraw || acting !== null || !["pending", "open"].includes(data.status)}
|
|
|
|
|
onClick={() =>
|
|
|
|
|
requestConfirm({
|
|
|
|
|
title: t("confirm.manualCloseTitle"),
|
|
|
|
|
description: t("confirm.manualCloseDescription"),
|
|
|
|
|
onConfirm: () => runAction(t("manualClose"), () => postAdminManualCloseDraw(idNum)),
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
>
|
|
|
|
|
{acting === t("manualClose") ? t("processing") : t("manualClose")}
|
|
|
|
|
</Button>
|
|
|
|
|
<Button
|
|
|
|
|
type="button"
|
|
|
|
|
variant="outline"
|
|
|
|
|
size="sm"
|
|
|
|
|
disabled={!canManageDraw || acting !== null || !["pending", "open", "closing", "closed"].includes(data.status)}
|
|
|
|
|
onClick={() =>
|
|
|
|
|
requestConfirm({
|
|
|
|
|
title: t("confirm.cancelDrawTitle"),
|
|
|
|
|
description: t("confirm.cancelDrawDescription"),
|
|
|
|
|
onConfirm: () => runAction(t("cancelDraw"), () => postAdminCancelDraw(idNum)),
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
>
|
|
|
|
|
{acting === t("cancelDraw") ? t("processing") : t("cancelBeforeDraw")}
|
|
|
|
|
</Button>
|
|
|
|
|
<Button
|
|
|
|
|
type="button"
|
|
|
|
|
variant="outline"
|
|
|
|
|
size="sm"
|
|
|
|
|
disabled={!canManageDraw || acting !== null || data.status !== "closed"}
|
|
|
|
|
onClick={() =>
|
|
|
|
|
requestConfirm({
|
|
|
|
|
title: t("confirm.rngDrawTitle"),
|
|
|
|
|
description: t("confirm.rngDrawDescription"),
|
|
|
|
|
onConfirm: () => runAction(t("rngDraw"), () => postAdminRunDrawRng(idNum)),
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
>
|
|
|
|
|
{acting === t("rngDraw") ? t("generating") : t("rngAutoGenerate")}
|
|
|
|
|
</Button>
|
|
|
|
|
{canReopenDraw ? (
|
|
|
|
|
<Button
|
|
|
|
|
type="button"
|
|
|
|
|
variant="destructive"
|
|
|
|
|
size="sm"
|
|
|
|
|
disabled={acting !== null || data.status !== "cooldown"}
|
|
|
|
|
onClick={() =>
|
|
|
|
|
requestConfirm({
|
|
|
|
|
title: t("confirm.reopenTitle"),
|
|
|
|
|
description: t("confirm.reopenDescription"),
|
|
|
|
|
confirmVariant: "destructive",
|
|
|
|
|
onConfirm: () => runAction(t("reopen"), () => postAdminReopenDraw(idNum)),
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
>
|
|
|
|
|
{acting === t("reopen") ? t("processing") : t("cooldownReopen")}
|
|
|
|
|
</Button>
|
|
|
|
|
) : null}
|
|
|
|
|
<Button
|
|
|
|
|
type="button"
|
|
|
|
|
variant="outline"
|
|
|
|
|
size="sm"
|
|
|
|
|
disabled={!canRunSettlement || acting !== null || data.status !== "settling"}
|
|
|
|
|
onClick={() =>
|
|
|
|
|
requestConfirm({
|
|
|
|
|
title: t("confirm.runSettlementTitle"),
|
|
|
|
|
description: t("confirm.runSettlementDescription"),
|
|
|
|
|
onConfirm: () => runAction(t("runSettlement"), () => postAdminRunDrawSettlement(idNum)),
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
>
|
|
|
|
|
{acting === t("runSettlement") ? t("processing") : t("runSettlement")}
|
|
|
|
|
</Button>
|
|
|
|
|
</CardContent>
|
|
|
|
|
</Card>
|
|
|
|
|
) : null}
|
|
|
|
|
<ConfirmDialog />
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
|