+
+
-
{children}
+
{children}
);
}
diff --git a/src/modules/config/doc/odds-config-doc-screen.tsx b/src/modules/config/doc/odds-config-doc-screen.tsx
index 59c33f6..b87141f 100644
--- a/src/modules/config/doc/odds-config-doc-screen.tsx
+++ b/src/modules/config/doc/odds-config-doc-screen.tsx
@@ -15,7 +15,9 @@ import {
putOddsItems,
} from "@/api/admin-config";
import { Button } from "@/components/ui/button";
-import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
+import { ConfigChip, ConfigChipGroup } from "@/modules/config/config-chip-group";
+import { ConfigContextBanner, ConfigContextEmphasis } from "@/modules/config/config-context-banner";
+import { ConfigDocPage, ConfigDocToolbar } from "@/modules/config/config-doc-page";
import {
Dialog,
DialogContent,
@@ -29,7 +31,6 @@ import { Label } from "@/components/ui/label";
import { ConfigReadonlyValue } from "@/modules/config/config-readonly-value";
import { ConfigVersionActions } from "@/modules/config/config-version-actions";
import { ConfigVersionSwitcher } from "@/modules/config/config-version-switcher";
-import { cn } from "@/lib/utils";
import { useAdminDateTimeFormatter } from "@/hooks/use-admin-datetime-formatter";
import { LotteryApiBizError } from "@/types/api/errors";
import type {
@@ -395,105 +396,90 @@ export function OddsConfigDocScreen() {
];
return (
-
-
- {t("nav.items.odds", { ns: "config" })}
-
-
-
- {t("odds.category", { ns: "config" })}
- {catTabs.map((t) => (
-
- ))}
-
-
-
-
{t("odds.playType", { ns: "config" })}
-
+
+
+ {catTabs.map((tab) => (
+ setCatTab(tab.id)}
+ >
+ {tab.label}
+
+ ))}
+
+
{filteredTypes.length === 0 ? (
- {t("odds.noPlayTypes", { ns: "config" })}
+ {t("odds.noPlayTypes", { ns: "config" })}
) : (
- filteredTypes.map((t) => (
-
+ {type.display_name_zh ?? type.play_code}
+
))
)}
-
+
-
-
-
-
- void refreshList()}
- onNewDraft={() => void handleNewDraft()}
- onSaveDraft={() => void handleSave()}
- onPublish={() => void requestPublishConfirm()}
- />
-
-
- {detail ? (
-
-
- {t("odds.activeVersionPrefix", { ns: "config" })}
- {activeHead ? (
- <>
- v{activeHead.version_no}
- {activeHead.effective_at ? ` · ${formatDt(activeHead.effective_at)}` : ""}
- >
- ) : (
- "—"
- )}
- {!isDraft ? (
-
- {" "}
- - {t("odds.readOnlyHint", { ns: "config" })}
-
- ) : null}
-
-
- ) : null}
-
- {error ? {error}
: null}
+ }
+ toolbar={
+
+ }
+ actions={
+ void refreshList()}
+ onNewDraft={() => void handleNewDraft()}
+ onSaveDraft={() => void handleSave()}
+ onPublish={() => void requestPublishConfirm()}
+ />
+ }
+ />
+ }
+ context={
+ detail ? (
+
+ {t("odds.activeVersionPrefix", { ns: "config" })}
+ {activeHead ? (
+ <>
+ v{activeHead.version_no}
+ {activeHead.effective_at ? ` · ${formatDt(activeHead.effective_at)}` : ""}
+ >
+ ) : (
+ "—"
+ )}
+ {!isDraft ? (
+ <>
+ {" "}
+ — {t("odds.readOnlyHint", { ns: "config" })}
+ >
+ ) : null}
+
+ ) : null
+ }
+ >
+ {error ? {error}
: null}
{loadingDetail || loadingTypes ? (
@@ -566,8 +552,6 @@ export function OddsConfigDocScreen() {
) : null}
-
-
-
+
);
}
diff --git a/src/modules/config/doc/play-config-doc-screen.tsx b/src/modules/config/doc/play-config-doc-screen.tsx
index 10d8d30..0971e4b 100644
--- a/src/modules/config/doc/play-config-doc-screen.tsx
+++ b/src/modules/config/doc/play-config-doc-screen.tsx
@@ -14,7 +14,10 @@ import {
putPlayConfigItems,
} from "@/api/admin-config";
import { Button } from "@/components/ui/button";
-import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
+import { ConfigChipGroup } from "@/modules/config/config-chip-group";
+import { ConfigContextBanner, ConfigContextEmphasis } from "@/modules/config/config-context-banner";
+import { ConfigDocPage, ConfigDocToolbar } from "@/modules/config/config-doc-page";
+import { ConfigSection } from "@/modules/config/config-section";
import { Checkbox } from "@/components/ui/checkbox";
import {
Dialog,
@@ -375,36 +378,37 @@ export function PlayConfigDocScreen() {
}
return (
-
-
- {t("nav.items.plays", { ns: "config" })}
-
-
-
-
-
- void refreshList()}
- onNewDraft={() => void handleNewDraft()}
- onSaveDraft={() => void handleSaveDraft()}
- onPublish={() => void handlePublish()}
- />
-
-
- {detail ? (
-
+
+ }
+ actions={
+ void refreshList()}
+ onNewDraft={() => void handleNewDraft()}
+ onSaveDraft={() => void handleSaveDraft()}
+ onPublish={() => void handlePublish()}
+ />
+ }
+ />
+ }
+ context={
+ detail ? (
+
{activeHead ? (
<>
{t("play.activeVersion", { ns: "config", version: activeHead.version_no })}
@@ -412,65 +416,61 @@ export function PlayConfigDocScreen() {
>
) : null}
{!isDraft ? (
-
+ <>
{activeHead ? " — " : ""}
- {t("play.readOnlyHint", { ns: "config" })}
-
+ {t("play.readOnlyHint", { ns: "config" })}
+ >
) : null}
-
- ) : null}
-
- {detail ? (
-
-
-
{t("play.batchSwitchesTitle", { ns: "config" })}
- {!isDraft ? (
-
- {t("play.readOnlyDraftHint", { ns: "config" })}
-
- ) : null}
-
-
- {batchSwitchStates.map((group) => (
-
-
-
{group.label}
-
- {group.total > 0
- ? t("play.batchEnabledCount", {
- ns: "config",
- enabledCount: group.enabledCount,
- total: group.total,
- })
- : t("play.noPlayTypes", { ns: "config" })}
-
-
-
+
+ ) : null
+ }
+ >
+ {detail ? (
+
+
+ {batchSwitchStates.map((group) => (
+
+
+
{group.label}
+
+ {group.total > 0
+ ? t("play.batchEnabledCount", {
+ ns: "config",
+ enabledCount: group.enabledCount,
+ total: group.total,
+ })
+ : t("play.noPlayTypes", { ns: "config" })}
+
- ))}
-
-
- ) : null}
+
+
+ ))}
+
+
+ ) : null}
- {error ?
{error}
: null}
+ {error ?
{error}
: null}
- {loadingDetail ? (
-
{t("states.loading", { ns: "common" })}
- ) : (
-
+ {loadingDetail ? (
+ {t("states.loading", { ns: "common" })}
+ ) : (
+
{t("play.table.playCode", { ns: "config" })}
@@ -601,9 +601,8 @@ export function PlayConfigDocScreen() {
))}
-
- )}
-
+
+ )}
-
+
);
}
diff --git a/src/modules/config/doc/rebate-config-doc-screen.tsx b/src/modules/config/doc/rebate-config-doc-screen.tsx
index d05833b..e941324 100644
--- a/src/modules/config/doc/rebate-config-doc-screen.tsx
+++ b/src/modules/config/doc/rebate-config-doc-screen.tsx
@@ -14,7 +14,8 @@ import {
publishOddsVersion,
putOddsItems,
} from "@/api/admin-config";
-import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
+import { ConfigContextBanner, ConfigContextEmphasis } from "@/modules/config/config-context-banner";
+import { ConfigDocPage, ConfigDocToolbar } from "@/modules/config/config-doc-page";
import { Checkbox } from "@/components/ui/checkbox";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
@@ -266,55 +267,60 @@ export function RebateConfigDocScreen() {
}
return (
-
-
- {t("nav.items.rebate", { ns: "config" })}
-
-
-
-
-
-
void refreshList()}
- onNewDraft={() => void handleNewDraft()}
- onSaveDraft={() => void handleSave()}
- onPublish={() => void handlePublish()}
- />
-
- {detail ? (
-
- {t("rebate.editingVersion", {
- ns: "config",
- version: detail.version_no,
- status:
- detail.status === "draft"
- ? t("versionStatus.draft", { ns: "config" })
- : detail.status === "active"
- ? t("versionStatus.active", { ns: "config" })
- : t("versionStatus.archived", { ns: "config" }),
- })}
- {!isDraft ? (
- - {t("rebate.readOnlyHint", { ns: "config" })}
- ) : null}
-
- ) : null}
-
-
-
+
+ }
+ actions={
+
void refreshList()}
+ onNewDraft={() => void handleNewDraft()}
+ onSaveDraft={() => void handleSave()}
+ onPublish={() => void handlePublish()}
+ />
+ }
+ />
+ }
+ context={
+ detail ? (
+
+ {t("rebate.editingVersion", {
+ ns: "config",
+ version: detail.version_no,
+ status:
+ detail.status === "draft"
+ ? t("versionStatus.draft", { ns: "config" })
+ : detail.status === "active"
+ ? t("versionStatus.active", { ns: "config" })
+ : t("versionStatus.archived", { ns: "config" }),
+ })}
+ {!isDraft ? (
+ <>
+ {" "}
+ — {t("rebate.readOnlyHint", { ns: "config" })}
+ >
+ ) : null}
+
+ ) : null
+ }
+ >
+
{isDraft ? (
@@ -387,10 +393,9 @@ export function RebateConfigDocScreen() {
- {loading || loadingDetail ? (
-
{t("states.loading", { ns: "common" })}
- ) : null}
-
-
+ {loading || loadingDetail ? (
+
{t("states.loading", { ns: "common" })}
+ ) : null}
+
);
}
diff --git a/src/modules/config/doc/risk-cap-doc-screen.tsx b/src/modules/config/doc/risk-cap-doc-screen.tsx
index b784299..2684755 100644
--- a/src/modules/config/doc/risk-cap-doc-screen.tsx
+++ b/src/modules/config/doc/risk-cap-doc-screen.tsx
@@ -14,7 +14,9 @@ import {
putRiskCapItems,
} from "@/api/admin-config";
import { Button } from "@/components/ui/button";
-import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
+import { ConfigContextBanner, ConfigContextEmphasis } from "@/modules/config/config-context-banner";
+import { ConfigDocPage, ConfigDocToolbar } from "@/modules/config/config-doc-page";
+import { ConfigSection } from "@/modules/config/config-section";
import {
Dialog,
DialogContent,
@@ -327,55 +329,53 @@ export function RiskCapDocScreen() {
}
return (
-
-
-
- {t("nav.items.risk-cap", { ns: "config" })}
- {detail ? (
-
- {" "}
- · v{detail.version_no}
-
- ) : null}
-
-
-
-
-
+
+ }
+ actions={
+
void refreshList()}
+ onNewDraft={() => void handleNewDraft()}
+ onSaveDraft={() => void handleSave()}
+ onPublish={() => void handlePublish()}
+ />
+ }
+ />
+ }
+ context={
+ detail ? (
+
+ {t("riskCap.effectiveAt", { ns: "config", value: detail.effective_at ? formatDt(detail.effective_at) : "—" })}
+ {!isDraft ? (
+ <>
+ {" "}
+ — {t("riskCap.readOnlyHint", { ns: "config" })}
+ >
+ ) : null}
+
+ ) : null
+ }
+ contentClassName="space-y-8"
+ >
+ {error ? {error}
: null}
- void refreshList()}
- onNewDraft={() => void handleNewDraft()}
- onSaveDraft={() => void handleSave()}
- onPublish={() => void handlePublish()}
- />
-
- {detail ? (
-
- {t("riskCap.effectiveAt", { ns: "config", value: detail.effective_at ? formatDt(detail.effective_at) : "—" })}
- {!isDraft ? (
- - {t("riskCap.readOnlyHint", { ns: "config" })}
- ) : null}
-
- ) : null}
-
-
- {error ? {error}
: null}
-
-
- {t("riskCap.defaultCap.title", { ns: "config" })}
+
@@ -401,22 +401,23 @@ export function RiskCapDocScreen() {
) : null}
-
+
-
-
-
{t("riskCap.specialCaps.title", { ns: "config" })}
- {isDraft ? (
-
- ) : null}
-
+ setDraftRows((prev) => [...prev, newRow()])}
+ >
+ {t("riskCap.actions.addSpecialCap", { ns: "config" })}
+
+ ) : null
+ }
+ >
{loadingDetail ? (
{t("riskCap.loadingDetails", { ns: "config" })}
) : specialRows.length === 0 ? (
@@ -494,10 +495,9 @@ export function RiskCapDocScreen() {
)}
-
+
-
- {t("riskCap.occupancy.title", { ns: "config" })}
+
@@ -548,8 +548,7 @@ export function RiskCapDocScreen() {
))}
-
-
+
-
+
);
}
diff --git a/src/modules/config/doc/wallet-config-doc-screen.tsx b/src/modules/config/doc/wallet-config-doc-screen.tsx
index e71a272..526d3c4 100644
--- a/src/modules/config/doc/wallet-config-doc-screen.tsx
+++ b/src/modules/config/doc/wallet-config-doc-screen.tsx
@@ -9,7 +9,7 @@ import {
updateAdminSetting,
} from "@/api/admin-settings";
import { Button } from "@/components/ui/button";
-import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
+import { ConfigDocPage } from "@/modules/config/config-doc-page";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { LotteryApiBizError } from "@/types/api/errors";
@@ -193,11 +193,6 @@ export function WalletConfigDocScreen({ embedded = false }: WalletConfigDocScree
}
return (
-
-
- {t("wallet.title", { ns: "config" })}
-
- {content}
-
+ {content}
);
}