diff --git a/src/app/admin/(shell)/config/integration-sites/page.tsx b/src/app/admin/(shell)/config/integration-sites/page.tsx
index cf48f17..41e61e8 100644
--- a/src/app/admin/(shell)/config/integration-sites/page.tsx
+++ b/src/app/admin/(shell)/config/integration-sites/page.tsx
@@ -1,6 +1,8 @@
+import { AdminPermissionGate } from "@/components/admin/admin-permission-gate";
import { ModuleScaffold } from "@/components/admin/module-scaffold";
import { IntegrationSitesConsole } from "@/modules/integration/integration-sites-console";
import { buildPageMetadata } from "@/lib/page-metadata";
+import { PRD_INTEGRATION_ACCESS_ANY } from "@/lib/admin-prd";
import type { Metadata } from "next";
export const metadata: Metadata = buildPageMetadata("config", "integrationSites.title");
@@ -8,7 +10,9 @@ export const metadata: Metadata = buildPageMetadata("config", "integrationSites.
export default function AdminIntegrationSitesPage() {
return (
-
+
+
+
);
}
diff --git a/src/app/admin/(shell)/draws/[drawId]/finance/page.tsx b/src/app/admin/(shell)/draws/[drawId]/finance/page.tsx
index 196f60f..1fdf3e6 100644
--- a/src/app/admin/(shell)/draws/[drawId]/finance/page.tsx
+++ b/src/app/admin/(shell)/draws/[drawId]/finance/page.tsx
@@ -1,4 +1,6 @@
+import { AdminPermissionGate } from "@/components/admin/admin-permission-gate";
import { DrawFinanceConsole } from "@/modules/draws/draw-finance-console";
+import { PRD_DRAW_ACCESS_ANY } from "@/lib/admin-prd";
import { buildPageMetadata } from "@/lib/page-metadata";
import type { Metadata } from "next";
@@ -8,5 +10,9 @@ export default async function AdminDrawFinancePage(props: {
params: Promise<{ drawId: string }>;
}) {
const { drawId } = await props.params;
- return ;
+ return (
+
+
+
+ );
}
diff --git a/src/app/admin/(shell)/draws/[drawId]/page.tsx b/src/app/admin/(shell)/draws/[drawId]/page.tsx
index e1b646c..9d1dd87 100644
--- a/src/app/admin/(shell)/draws/[drawId]/page.tsx
+++ b/src/app/admin/(shell)/draws/[drawId]/page.tsx
@@ -1,8 +1,14 @@
+import { AdminPermissionGate } from "@/components/admin/admin-permission-gate";
import { DrawDetailConsole } from "@/modules/draws/draw-detail-console";
+import { PRD_DRAW_ACCESS_ANY } from "@/lib/admin-prd";
export default async function AdminDrawDetailPage(props: {
params: Promise<{ drawId: string }>;
}) {
const { drawId } = await props.params;
- return ;
+ return (
+
+
+
+ );
}
diff --git a/src/app/admin/(shell)/draws/[drawId]/results/page.tsx b/src/app/admin/(shell)/draws/[drawId]/results/page.tsx
index 5e3b75a..e17201e 100644
--- a/src/app/admin/(shell)/draws/[drawId]/results/page.tsx
+++ b/src/app/admin/(shell)/draws/[drawId]/results/page.tsx
@@ -1,8 +1,14 @@
+import { AdminPermissionGate } from "@/components/admin/admin-permission-gate";
import { DrawResultsConsole } from "@/modules/draws/draw-results-console";
+import { PRD_DRAW_ACCESS_ANY } from "@/lib/admin-prd";
export default async function AdminDrawResultsPage(props: {
params: Promise<{ drawId: string }>;
}) {
const { drawId } = await props.params;
- return ;
+ return (
+
+
+
+ );
}
diff --git a/src/app/admin/(shell)/draws/[drawId]/review/page.tsx b/src/app/admin/(shell)/draws/[drawId]/review/page.tsx
index 5d69050..dd46b43 100644
--- a/src/app/admin/(shell)/draws/[drawId]/review/page.tsx
+++ b/src/app/admin/(shell)/draws/[drawId]/review/page.tsx
@@ -1,8 +1,14 @@
+import { AdminPermissionGate } from "@/components/admin/admin-permission-gate";
import { DrawReviewConsole } from "@/modules/draws/draw-review-console";
+import { PRD_DRAW_ACCESS_ANY } from "@/lib/admin-prd";
export default async function AdminDrawReviewPage(props: {
params: Promise<{ drawId: string }>;
}) {
const { drawId } = await props.params;
- return ;
+ return (
+
+
+
+ );
}
diff --git a/src/app/admin/(shell)/draws/page.tsx b/src/app/admin/(shell)/draws/page.tsx
index 8061e61..db7dc83 100644
--- a/src/app/admin/(shell)/draws/page.tsx
+++ b/src/app/admin/(shell)/draws/page.tsx
@@ -1,5 +1,7 @@
import { ModuleScaffold } from "@/components/admin/module-scaffold";
+import { AdminPermissionGate } from "@/components/admin/admin-permission-gate";
import { DrawsIndexConsole } from "@/modules/draws/draws-index-console";
+import { PRD_DRAW_ACCESS_ANY } from "@/lib/admin-prd";
import { buildPageMetadata } from "@/lib/page-metadata";
import type { Metadata } from "next";
@@ -7,8 +9,10 @@ export const metadata: Metadata = buildPageMetadata("draws", "statusListTitle");
export default function AdminDrawsPage() {
return (
-
-
-
+
+
+
+
+
);
}
diff --git a/src/app/admin/(shell)/settlement-batches/[batchId]/details/page.tsx b/src/app/admin/(shell)/settlement-batches/[batchId]/details/page.tsx
index 5f72ed8..f2816db 100644
--- a/src/app/admin/(shell)/settlement-batches/[batchId]/details/page.tsx
+++ b/src/app/admin/(shell)/settlement-batches/[batchId]/details/page.tsx
@@ -1,5 +1,7 @@
+import { AdminPermissionGate } from "@/components/admin/admin-permission-gate";
import { InvalidSettlementBatchId } from "@/modules/settlement/invalid-settlement-batch-id";
import { SettlementBatchDetailsConsole } from "@/modules/settlement/settlement-batch-details-console";
+import { PRD_PAYOUT_ACCESS_ANY } from "@/lib/admin-prd";
import { buildPageMetadata } from "@/lib/page-metadata";
import type { Metadata } from "next";
@@ -14,5 +16,9 @@ export default async function AdminSettlementBatchDetailsPage(props: {
return ;
}
- return ;
+ return (
+
+
+
+ );
}
diff --git a/src/app/admin/(shell)/settlement-batches/page.tsx b/src/app/admin/(shell)/settlement-batches/page.tsx
index 09155dc..77a248c 100644
--- a/src/app/admin/(shell)/settlement-batches/page.tsx
+++ b/src/app/admin/(shell)/settlement-batches/page.tsx
@@ -1,9 +1,15 @@
+import { AdminPermissionGate } from "@/components/admin/admin-permission-gate";
import { SettlementBatchesConsole } from "@/modules/settlement/settlement-batches-console";
+import { PRD_PAYOUT_ACCESS_ANY } from "@/lib/admin-prd";
import { buildPageMetadata } from "@/lib/page-metadata";
import type { Metadata } from "next";
export const metadata: Metadata = buildPageMetadata("settlement", "batchList");
export default function AdminSettlementBatchesPage() {
- return ;
+ return (
+
+
+
+ );
}
diff --git a/src/components/admin/admin-breadcrumb.tsx b/src/components/admin/admin-breadcrumb.tsx
index bc60072..f14445f 100644
--- a/src/components/admin/admin-breadcrumb.tsx
+++ b/src/components/admin/admin-breadcrumb.tsx
@@ -40,6 +40,8 @@ const NAV_TRANSLATION_KEYS: Record = {
tickets: "tickets",
audit: "audit",
settings: "settings",
+ integration: "integration",
+ config: "config",
};
const RULES_ROUTE_LABELS: Record = {
@@ -55,6 +57,16 @@ const SETTINGS_ROUTE_LABELS: Record = {
currencies: "currencies.title",
};
+const CONFIG_ROUTE_LABELS: Record = {
+ "integration-sites": "integrationSites.title",
+ plays: "nav.items.plays",
+ odds: "nav.items.odds",
+ rebate: "nav.items.rebate",
+ jackpot: "nav.items.jackpot",
+ "risk-cap": "nav.items.risk-cap",
+ wallet: "wallet.title",
+};
+
function titleCase(value: string): string {
return value
.split("-")
@@ -146,6 +158,11 @@ export function AdminBreadcrumb() {
ns: "config",
defaultValue: titleCase(subSegment),
});
+ } else if (businessSegment === "config" && subSegment) {
+ const key = CONFIG_ROUTE_LABELS[subSegment];
+ subLabel = key
+ ? t(key, { ns: "config", defaultValue: titleCase(subSegment) })
+ : titleCase(subSegment);
} else {
subLabel = subSegment
? t(`subnav.${subSegment}`, {
diff --git a/src/hooks/use-admin-site-code-options.ts b/src/hooks/use-admin-site-code-options.ts
index 2a6499b..cdf166e 100644
--- a/src/hooks/use-admin-site-code-options.ts
+++ b/src/hooks/use-admin-site-code-options.ts
@@ -4,6 +4,7 @@ import { useCallback, useEffect, useState } from "react";
import { getAdminIntegrationSites } from "@/api/admin-integration-sites";
import { adminHasAnyPermission } from "@/lib/admin-permissions";
+import { PRD_INTEGRATION_ACCESS_ANY } from "@/lib/admin-prd";
import { useAdminProfile } from "@/stores/admin-session";
export type AdminSiteCodeOption = {
@@ -21,10 +22,7 @@ export function useAdminSiteCodeOptions(): {
reload: () => Promise;
} {
const profile = useAdminProfile();
- const canLoad = adminHasAnyPermission(profile?.permissions, [
- "prd.integration.view",
- "prd.integration.manage",
- ]);
+ const canLoad = adminHasAnyPermission(profile?.permissions, PRD_INTEGRATION_ACCESS_ANY);
const [sites, setSites] = useState([]);
const [loading, setLoading] = useState(false);
diff --git a/src/i18n/locales/en/common.json b/src/i18n/locales/en/common.json
index 03295b1..8631d46 100644
--- a/src/i18n/locales/en/common.json
+++ b/src/i18n/locales/en/common.json
@@ -147,7 +147,9 @@
"tickets": "Ticket list",
"audit": "Audit Logs",
"settings": "Settings",
- "account": "Account settings"
+ "account": "Account settings",
+ "integration": "Integration sites",
+ "config": "Operations config"
},
"sidebar": {
"workspace": "Workspace"
diff --git a/src/i18n/locales/ne/common.json b/src/i18n/locales/ne/common.json
index 9885e72..7389c01 100644
--- a/src/i18n/locales/ne/common.json
+++ b/src/i18n/locales/ne/common.json
@@ -147,7 +147,9 @@
"tickets": "टिकट सूची",
"audit": "अडिट लग",
"settings": "सेटिङ",
- "account": "खाता सेटिङ"
+ "account": "खाता सेटिङ",
+ "integration": "मुख्य साइट एकीकरण",
+ "config": "सञ्चालन कन्फिगरेसन"
},
"sidebar": {
"workspace": "कार्यस्थान"
diff --git a/src/i18n/locales/ne/config.json b/src/i18n/locales/ne/config.json
index db5c4ae..b52a6a3 100644
--- a/src/i18n/locales/ne/config.json
+++ b/src/i18n/locales/ne/config.json
@@ -29,7 +29,77 @@
"jackpotTitle": "Jackpot",
"jackpotDesc": "पूल प्यारामिटर र लेजर",
"riskCapTitle": "जोखिम क्याप",
- "riskCapDesc": "नम्बर क्याप र ओगट उपस्थिति"
+ "riskCapDesc": "नम्बर क्याप र ओगट उपस्थिति",
+ "integrationTitle": "मुख्य साइट एकीकरण",
+ "integrationDesc": "site_code, JWT गोप्य, पार्टनर वालेट URL र iframe श्वेतसूची"
+ },
+ "integrationSites": {
+ "title": "मुख्य साइट एकीकरण साइटहरू",
+ "description": "एडमिनमा पार्टनर एकीकरण सेटिङ मिलाउनुहोस्। site_code सिर्जना पछि परिवर्तन गर्न मिल्दैन।",
+ "create": "नयाँ साइट",
+ "edit": "सम्पादन",
+ "save": "बचत",
+ "saving": "बचत हुँदैछ…",
+ "cancel": "रद्द",
+ "copy": "प्रतिलिपि",
+ "loading": "लोड हुँदैछ…",
+ "empty": "कुनै एकीकरण साइट छैन",
+ "loadFailed": "एकीकरण साइट लोड असफल",
+ "saveFailed": "बचत असफल",
+ "createSuccess": "साइट {{code}} सिर्जना भयो",
+ "updateSuccess": "साइट {{code}} अद्यावधिक भयो",
+ "connectivityTest": "जडान परीक्षण",
+ "connectivityTitle": "पार्टनर वालेट जडान परीक्षण",
+ "connectivityDescription": "परीक्षण खेलाडीबाट साइट {{code}} को balance API कल गर्नुहोस्।",
+ "connectivityPlayerId": "परीक्षण site_player_id",
+ "connectivityRun": "परीक्षण सुरु",
+ "connectivityRunning": "परीक्षण हुँदैछ…",
+ "connectivitySuccess": "जडान सफल",
+ "connectivityFailed": "जडान असफल",
+ "exportParams": "प्यारामिटर निर्यात",
+ "exportSuccess": "{{code}} को प्यारामिटर चिट्ठा निर्यात भयो",
+ "exportFailed": "निर्यात असफल",
+ "rotateSecrets": "गोप्य कुञ्जी पुनः सिर्जना",
+ "rotateSuccess": "साइट {{code}} का गोप्य कुञ्जी पुनः सिर्जना भयो",
+ "rotateFailed": "गोप्य कुञ्जी पुनः सिर्जना असफल",
+ "rotateConfirmTitle": "गोप्य कुञ्जी पुनः सिर्जना गर्ने?",
+ "rotateConfirmDescription": "साइट {{code}} का नयाँ SSO र वालेट कुञ्जी सिर्जना हुन्छ। पुराना कुञ्जी तुरुन्त अमान्य हुन्छन्।",
+ "rotateConfirm": "पुष्टि",
+ "secretsTitle": "गोप्य कुञ्जी अहिले नै सुरक्षित राख्नुहोस्",
+ "secretsDescription": "साइट {{code}} का गोप्य कुञ्जी एक पटक मात्र देखिन्छ।",
+ "secretsDismiss": "सुरक्षित गरिसके",
+ "copied": "{{field}} प्रतिलिपि भयो",
+ "copyFailed": "प्रतिलिपि असफल",
+ "noPermission": "एकीकरण साइट हेर्ने अनुमति छैन",
+ "codeImmutable": "site_code सिर्जना पछि परिवर्तन गर्न मिल्दैन",
+ "statusEnabled": "सक्रिय",
+ "statusDisabled": "निष्क्रिय",
+ "dialogCreateTitle": "नयाँ एकीकरण साइट",
+ "dialogEditTitle": "एकीकरण साइट सम्पादन",
+ "dialogDescription": "पार्टनरले अनुकूल URL नभएसम्म पूर्वनिर्धारित वालेट path प्रयोग गर्न सकिन्छ।",
+ "form": {
+ "required": "साइट नाम अनिवार्य छ",
+ "codeRequired": "site_code अनिवार्य छ"
+ },
+ "columns": {
+ "code": "site_code",
+ "name": "नाम",
+ "status": "स्थिति",
+ "walletUrl": "वालेट API",
+ "actions": "कार्य"
+ },
+ "fields": {
+ "code": "site_code",
+ "name": "साइट नाम",
+ "currency": "पूर्वनिर्धारित मुद्रा",
+ "status": "स्थिति",
+ "walletApiUrl": "पार्टनर वालेट आधार URL",
+ "lotteryH5BaseUrl": "लटरी H5 आधार URL (वैकल्पिक)",
+ "iframeOrigins": "iframe श्वेतसूची (प्रति लाइन एक origin)",
+ "notes": "टिप्पणी",
+ "ssoSecret": "SSO गोप्य",
+ "walletApiKey": "वालेट API कुञ्जी"
+ }
},
"versionStatus": {
"active": "सक्रिय",
diff --git a/src/i18n/locales/zh/common.json b/src/i18n/locales/zh/common.json
index 9327e63..1110bc8 100644
--- a/src/i18n/locales/zh/common.json
+++ b/src/i18n/locales/zh/common.json
@@ -147,7 +147,9 @@
"tickets": "注单列表",
"audit": "审计日志",
"settings": "系统设置",
- "account": "账号设置"
+ "account": "账号设置",
+ "integration": "主站接入站点",
+ "config": "运营配置"
},
"sidebar": {
"workspace": "工作台"
diff --git a/src/lib/admin-permission-bundles.ts b/src/lib/admin-permission-bundles.ts
new file mode 100644
index 0000000..41f3e97
--- /dev/null
+++ b/src/lib/admin-permission-bundles.ts
@@ -0,0 +1,41 @@
+import { PRD_INTEGRATION_MANAGE, PRD_INTEGRATION_VIEW } from "@/lib/admin-prd";
+
+export type AdminPermissionBundleKey = "view" | "manage" | "audit" | "export" | "privilege";
+
+export type AdminPageKey = "integration-sites";
+
+/**
+ * “页面权限包”是把运营/管理员能理解的词汇(查看/管理/审核/导出/特权)
+ * 映射到系统真实用的 `prd.*` 权限 slug。
+ *
+ * 目前只落地 integration-sites;其它页面按同样方式逐步接入。
+ */
+export const ADMIN_PERMISSION_BUNDLES = {
+ "integration-sites": {
+ view: [PRD_INTEGRATION_VIEW] as const,
+ manage: [PRD_INTEGRATION_MANAGE] as const,
+ audit: [] as const,
+ // 导出接口的资源鉴权仍落在 view/manage,因此这里复用 view。
+ export: [PRD_INTEGRATION_VIEW] as const,
+ privilege: [] as const,
+ },
+} satisfies Record>;
+
+export const ADMIN_PAGE_REQUIRED_ANY = {
+ "integration-sites": [
+ ...ADMIN_PERMISSION_BUNDLES["integration-sites"].view,
+ ...ADMIN_PERMISSION_BUNDLES["integration-sites"].manage,
+ ] as const,
+} satisfies Record;
+
+export function getAdminPageRequiredAny(page: AdminPageKey): readonly string[] {
+ return ADMIN_PAGE_REQUIRED_ANY[page];
+}
+
+export function getAdminPageBundle(
+ page: AdminPageKey,
+ bundle: AdminPermissionBundleKey,
+): readonly string[] {
+ return ADMIN_PERMISSION_BUNDLES[page][bundle] ?? [];
+}
+
diff --git a/src/lib/admin-prd.ts b/src/lib/admin-prd.ts
index 3c1d52a..cf45841 100644
--- a/src/lib/admin-prd.ts
+++ b/src/lib/admin-prd.ts
@@ -10,6 +10,10 @@ export const PRD_PLAYER_FREEZE_MANAGE = "prd.player_freeze.manage" as const;
export const PRD_CURRENCY_MANAGE = "prd.currency.manage" as const;
+/** 接入站点(integration-sites) */
+export const PRD_INTEGRATION_VIEW = "prd.integration.view" as const;
+export const PRD_INTEGRATION_MANAGE = "prd.integration.manage" as const;
+
export const PRD_WALLET_RECONCILE_MANAGE = "prd.wallet_reconcile.manage" as const;
export const PRD_WALLET_RECONCILE_VIEW = "prd.wallet_reconcile.view" as const;
export const PRD_WALLET_RECONCILE_VIEW_CS = "prd.wallet_reconcile.view_cs" as const;
@@ -105,8 +109,25 @@ export const PRD_RULES_ODDS_ACCESS_ANY = [
PRD_REBATE_VIEW,
] as const;
+/** 开奖页面入口 */
+export const PRD_DRAW_ACCESS_ANY = [
+ PRD_DRAW_RESULT_VIEW,
+ PRD_DRAW_RESULT_MANAGE,
+ PRD_DRAW_REOPEN_MANAGE,
+] as const;
+
/** 封顶配置页 */
export const PRD_RISK_CAP_ACCESS_ANY = [PRD_RISK_CAP_MANAGE, PRD_RISK_CAP_VIEW] as const;
/** Jackpot 配置页 */
export const PRD_JACKPOT_ACCESS_ANY = [PRD_JACKPOT_MANAGE, PRD_JACKPOT_VIEW] as const;
+
+/** 派彩 / 结算页面入口 */
+export const PRD_PAYOUT_ACCESS_ANY = [
+ PRD_PAYOUT_VIEW,
+ PRD_PAYOUT_REVIEW,
+ PRD_PAYOUT_MANAGE,
+] as const;
+
+/** 接入站点配置页 */
+export const PRD_INTEGRATION_ACCESS_ANY = [PRD_INTEGRATION_VIEW, PRD_INTEGRATION_MANAGE] as const;
diff --git a/src/modules/config/config-hub-screen.tsx b/src/modules/config/config-hub-screen.tsx
index 2a42d21..23f0bbe 100644
--- a/src/modules/config/config-hub-screen.tsx
+++ b/src/modules/config/config-hub-screen.tsx
@@ -6,6 +6,7 @@ import { ChevronRight } from "lucide-react";
import { ModuleScaffold } from "@/components/admin/module-scaffold";
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
+import { PRD_INTEGRATION_ACCESS_ANY } from "@/lib/admin-prd";
import { useAdminProfile } from "@/stores/admin-session";
import { adminHasAnyPermission } from "@/lib/admin-permissions";
@@ -45,7 +46,7 @@ const HUB_CARDS: HubCard[] = [
href: "/admin/config/integration-sites",
titleKey: "hub.integrationTitle",
descKey: "hub.integrationDesc",
- requiredAny: ["prd.integration.view", "prd.integration.manage"],
+ requiredAny: PRD_INTEGRATION_ACCESS_ANY,
},
];
diff --git a/src/modules/draws/draw-finance-console.tsx b/src/modules/draws/draw-finance-console.tsx
index 018a1fb..14af6df 100644
--- a/src/modules/draws/draw-finance-console.tsx
+++ b/src/modules/draws/draw-finance-console.tsx
@@ -27,6 +27,7 @@ import type { AdminDrawFinanceSummaryData } from "@/types/api/admin-draw-finance
import { toast } from "sonner";
import { useAdminCurrencyCatalog } from "@/hooks/use-admin-currency-catalog";
+import { useAdminDateTimeFormatter } from "@/hooks/use-admin-datetime-formatter";
import { useConfirmAction } from "@/hooks/use-confirm-action";
import { useExportLabels } from "@/hooks/use-export-labels";
import { formatAdminMinorUnits } from "@/lib/money";
@@ -44,6 +45,7 @@ export function DrawFinanceConsole({ drawId }: { drawId: string }): React.ReactE
PRD_PAYOUT_REVIEW,
]);
const [data, setData] = useState(null);
+ const formatTs = useAdminDateTimeFormatter();
const exportLabels = useExportLabels("drawFinance", { drawNo: data?.draw_no ?? drawId });
const [err, setErr] = useState(null);
const [loading, setLoading] = useState(true);
@@ -219,8 +221,8 @@ export function DrawFinanceConsole({ drawId }: { drawId: string }): React.ReactE
{formatMoney(b.total_jackpot_payout_amount)}
-
- {b.finished_at ?? "—"}
+
+ {formatTs(b.finished_at)}
))}
diff --git a/src/modules/draws/draw-results-console.tsx b/src/modules/draws/draw-results-console.tsx
index 4604eb8..95af0c5 100644
--- a/src/modules/draws/draw-results-console.tsx
+++ b/src/modules/draws/draw-results-console.tsx
@@ -15,6 +15,7 @@ import {
TableHeader,
TableRow,
} from "@/components/ui/table";
+import { useAdminDateTimeFormatter } from "@/hooks/use-admin-datetime-formatter";
import { cn } from "@/lib/utils";
import { adminHasAnyPermission } from "@/lib/admin-permissions";
import { useAdminProfile } from "@/stores/admin-session";
@@ -103,6 +104,7 @@ export function DrawResultsConsole({ drawId }: { drawId: string }) {
function BatchTable({ batch }: { batch: AdminDrawBatchRow }) {
const { t } = useTranslation("draws");
+ const formatDt = useAdminDateTimeFormatter();
return (
@@ -112,7 +114,7 @@ function BatchTable({ batch }: { batch: AdminDrawBatchRow }) {
source: batch.source_type === "manual" ? t("manualEntry") : t("rng"),
})}{" "}
· {t("rngSummary", { hash: batch.rng_seed_hash ?? "—" })} ·{" "}
- {t("confirmedAt", { time: batch.confirmed_at ?? "—" })}
+ {t("confirmedAt", { time: formatDt(batch.confirmed_at) })}
diff --git a/src/modules/integration/integration-sites-console.tsx b/src/modules/integration/integration-sites-console.tsx
index e191f77..1e6f550 100644
--- a/src/modules/integration/integration-sites-console.tsx
+++ b/src/modules/integration/integration-sites-console.tsx
@@ -36,11 +36,15 @@ import {
} from "@/components/ui/table";
import { Textarea } from "@/components/ui/textarea";
import { adminHasAnyPermission } from "@/lib/admin-permissions";
+import { getAdminPageBundle } from "@/lib/admin-permission-bundles";
import { useAdminProfile } from "@/stores/admin-session";
import { LotteryApiBizError } from "@/types/api/errors";
import type {
+ AdminIntegrationSiteCreatePayload,
AdminIntegrationSiteConnectivityResult,
+ AdminIntegrationSiteUpdatePayload,
AdminIntegrationSiteRow,
+ AdminIntegrationSiteDetail,
AdminIntegrationSiteSecrets,
AdminIntegrationSiteWithSecrets,
} from "@/types/api/admin-integration-site";
@@ -86,7 +90,7 @@ function textToOrigins(text: string): string[] {
.filter(Boolean);
}
-function rowToForm(row: AdminIntegrationSiteRow & Partial): FormState {
+function rowToForm(row: AdminIntegrationSiteDetail): FormState {
return {
code: row.code,
name: row.name,
@@ -103,7 +107,12 @@ function rowToForm(row: AdminIntegrationSiteRow & Partial): FormState
};
}
-function formToPayload(form: FormState, includeCode: boolean) {
+function formToPayload(form: FormState, includeCode: true): AdminIntegrationSiteCreatePayload;
+function formToPayload(form: FormState, includeCode: false): AdminIntegrationSiteUpdatePayload;
+function formToPayload(
+ form: FormState,
+ includeCode: boolean,
+): AdminIntegrationSiteCreatePayload | AdminIntegrationSiteUpdatePayload {
const base = {
name: form.name.trim(),
currency_code: form.currency_code.trim() || "NPR",
@@ -128,11 +137,10 @@ function formToPayload(form: FormState, includeCode: boolean) {
export function IntegrationSitesConsole() {
const { t } = useTranslation("config");
const profile = useAdminProfile();
- const canView = adminHasAnyPermission(profile?.permissions, [
- "prd.integration.view",
- "prd.integration.manage",
- ]);
- const canManage = adminHasAnyPermission(profile?.permissions, ["prd.integration.manage"]);
+ const canManage = adminHasAnyPermission(
+ profile?.permissions,
+ getAdminPageBundle("integration-sites", "manage"),
+ );
const [items, setItems] = useState([]);
const [loading, setLoading] = useState(true);
@@ -158,12 +166,6 @@ export function IntegrationSitesConsole() {
const [exportBusyId, setExportBusyId] = useState(null);
const load = useCallback(async () => {
- if (!canView) {
- setItems([]);
- setLoading(false);
- return;
- }
-
setLoading(true);
try {
const data = await getAdminIntegrationSites();
@@ -175,7 +177,7 @@ export function IntegrationSitesConsole() {
} finally {
setLoading(false);
}
- }, [canView, t]);
+ }, [t]);
useEffect(() => {
queueMicrotask(() => {
@@ -334,14 +336,6 @@ export function IntegrationSitesConsole() {
}
}
- if (!canView) {
- return (
-
- {t("integrationSites.noPermission")}
-
- );
- }
-
return (
<>
{row.name}
+ tone={row.status === 1 ? "success" : "neutral"}
+ >
+ {row.status === 1
+ ? t("integrationSites.statusEnabled")
+ : t("integrationSites.statusDisabled")}
+
{row.wallet_api_url ?? "—"}
@@ -407,9 +400,16 @@ export function IntegrationSitesConsole() {
>
{t("integrationSites.exportParams")}
-
+ {canManage ? (
+
+ ) : null}
{canManage ? (