feat(admin): enhance operations guidance and session handling
Some checks failed
lotteryadmin CI / build (push) Has been cancelled

This commit is contained in:
wchino
2026-07-22 20:53:43 +08:00
parent 98a3d0b68e
commit 85ad369cf9
55 changed files with 1477 additions and 342 deletions

View File

@@ -19,6 +19,8 @@ import { ConfigChipGroup } from "@/modules/config/config-chip-group";
import { ConfigDocPage, ConfigDocToolbar } from "@/modules/config/config-doc-page";
import { ConfirmableSwitch } from "@/components/admin/confirmable-switch";
import { AdminHelpText } from "@/components/admin/admin-field-label";
import { AdminPageGuideDialog } from "@/components/admin/admin-page-guide-dialog";
import {
Dialog,
DialogContent,
@@ -489,25 +491,68 @@ export function PlayConfigDocScreen() {
/>
}
actions={
<ConfigVersionActions
isDraft={isDraft}
canManage={canManage}
loadingList={loadingList}
loadingDetail={loadingDetail}
saving={saving}
onRefresh={() => void refreshList()}
onNewDraft={() => void handleNewDraft()}
onSaveDraft={() => void handleSaveDraft()}
onPublish={() =>
requestConfirm({
title: t("play.publishDialog.title", { ns: "config" }),
description: t("play.publishDialog.description", { ns: "config" }),
confirmLabel: t("play.publishDialog.confirm", { ns: "config" }),
confirmVariant: "destructive",
onConfirm: () => handlePublish(),
})
}
/>
<>
<AdminPageGuideDialog
triggerLabel={t("play.help.openGuide", { ns: "config" })}
title={t("play.help.guideTitle", { ns: "config" })}
description={t("play.help.guideDescription", { ns: "config" })}
sections={[
{
title: t("play.help.guide.settingsTitle", { ns: "config" }),
description: t("play.help.guide.settingsDescription", { ns: "config" }),
items: [
{
label: t("play.table.status", { ns: "config" }),
description: t("play.help.fields.status", { ns: "config" }),
},
{
label: t("play.table.displayName", { ns: "config" }),
description: t("play.help.fields.displayName", { ns: "config" }),
},
{
label: t("play.table.order", { ns: "config" }),
description: t("play.help.fields.order", { ns: "config" }),
},
{
label: t("play.table.minBet", { ns: "config" }),
description: t("play.help.fields.minBet", { ns: "config" }),
},
{
label: t("play.table.maxBet", { ns: "config" }),
description: t("play.help.fields.maxBet", { ns: "config" }),
},
],
},
{
title: t("play.help.guide.batchTitle", { ns: "config" }),
description: t("play.help.guide.batchDescription", { ns: "config" }),
},
{
title: t("play.help.guide.workflowTitle", { ns: "config" }),
description: t("play.help.guide.workflowDescription", { ns: "config" }),
},
]}
/>
<ConfigVersionActions
isDraft={isDraft}
canManage={canManage}
loadingList={loadingList}
loadingDetail={loadingDetail}
saving={saving}
onRefresh={() => void refreshList()}
onNewDraft={() => void handleNewDraft()}
onSaveDraft={() => void handleSaveDraft()}
onPublish={() =>
requestConfirm({
title: t("play.publishDialog.title", { ns: "config" }),
description: t("play.publishDialog.description", { ns: "config" }),
confirmLabel: t("play.publishDialog.confirm", { ns: "config" }),
confirmVariant: "destructive",
onConfirm: () => handlePublish(),
})
}
/>
</>
}
/>
}
@@ -578,17 +623,43 @@ export function PlayConfigDocScreen() {
</div>
{isDraft ? (
<div className="space-y-1.5">
<ConfigChipGroup label={t("play.batchSwitchesTitle", { ns: "config" })}>
<ConfigChipGroup
label={
<AdminHelpText
helpId="play-batch-switches"
helpText={t("play.help.fields.batchSwitches", { ns: "config" })}
helpAriaLabel={t("play.help.aria", {
ns: "config",
field: t("play.batchSwitchesTitle", { ns: "config" }),
})}
>
{t("play.batchSwitchesTitle", { ns: "config" })}
</AdminHelpText>
}
>
{batchSwitchStates.map((group) => {
const groupOn = group.allEnabled;
const isPartial =
group.total > 0 && group.enabledCount > 0 && group.enabledCount < group.total;
return (
<label
<div
key={group.key}
className="inline-flex cursor-pointer items-center gap-2 rounded-md border border-border/60 px-2.5 py-1.5 text-sm"
className="inline-flex items-center gap-2 rounded-md border border-border/60 px-2.5 py-1.5 text-sm"
>
<span>{group.label}</span>
<AdminHelpText
helpId={`play-batch-${group.key}`}
helpText={t("play.help.fields.batchGroup", {
ns: "config",
group: group.label,
count: group.total,
})}
helpAriaLabel={t("play.help.aria", {
ns: "config",
field: group.label,
})}
>
{group.label}
</AdminHelpText>
<span className="text-xs tabular-nums text-muted-foreground">
{t("play.batchEnabledCount", {
ns: "config",
@@ -622,7 +693,7 @@ export function PlayConfigDocScreen() {
});
}}
/>
</label>
</div>
);
})}
</ConfigChipGroup>
@@ -644,11 +715,71 @@ export function PlayConfigDocScreen() {
<TableRow>
<TableHead className="text-center">{t("play.table.playCode", { ns: "config" })}</TableHead>
<TableHead className="w-[100px] text-center">{t("play.table.category", { ns: "config" })}</TableHead>
<TableHead className="w-[88px] text-center">{t("play.table.status", { ns: "config" })}</TableHead>
<TableHead className="w-36 text-center">{t("play.table.displayName", { ns: "config" })}</TableHead>
<TableHead className="w-24 text-center">{t("play.table.order", { ns: "config" })}</TableHead>
<TableHead className="w-[110px] text-center">{t("play.table.minBet", { ns: "config" })}</TableHead>
<TableHead className="w-[110px] text-center">{t("play.table.maxBet", { ns: "config" })}</TableHead>
<TableHead className="w-[88px] text-center">
<AdminHelpText
helpId="play-status"
helpText={t("play.help.fields.status", { ns: "config" })}
helpAriaLabel={t("play.help.aria", {
ns: "config",
field: t("play.table.status", { ns: "config" }),
})}
className="justify-center"
>
{t("play.table.status", { ns: "config" })}
</AdminHelpText>
</TableHead>
<TableHead className="w-36 text-center">
<AdminHelpText
helpId="play-display-name"
helpText={t("play.help.fields.displayName", { ns: "config" })}
helpAriaLabel={t("play.help.aria", {
ns: "config",
field: t("play.table.displayName", { ns: "config" }),
})}
className="justify-center"
>
{t("play.table.displayName", { ns: "config" })}
</AdminHelpText>
</TableHead>
<TableHead className="w-24 text-center">
<AdminHelpText
helpId="play-display-order"
helpText={t("play.help.fields.order", { ns: "config" })}
helpAriaLabel={t("play.help.aria", {
ns: "config",
field: t("play.table.order", { ns: "config" }),
})}
className="justify-center"
>
{t("play.table.order", { ns: "config" })}
</AdminHelpText>
</TableHead>
<TableHead className="w-[110px] text-center">
<AdminHelpText
helpId="play-min-bet"
helpText={t("play.help.fields.minBet", { ns: "config" })}
helpAriaLabel={t("play.help.aria", {
ns: "config",
field: t("play.table.minBet", { ns: "config" }),
})}
className="justify-center"
>
{t("play.table.minBet", { ns: "config" })}
</AdminHelpText>
</TableHead>
<TableHead className="w-[110px] text-center">
<AdminHelpText
helpId="play-max-bet"
helpText={t("play.help.fields.maxBet", { ns: "config" })}
helpAriaLabel={t("play.help.aria", {
ns: "config",
field: t("play.table.maxBet", { ns: "config" }),
})}
className="justify-center"
>
{t("play.table.maxBet", { ns: "config" })}
</AdminHelpText>
</TableHead>
</TableRow>
</TableHeader>
<TableBody>