feat(api, i18n): add agent_node_id to various admin queries and enhance multi-language support
Introduced the agent_node_id field in AdminDrawListQuery, AdminPlayerListQuery, AdminSettlementBatchListQuery, TicketItemsListQuery, and TransferOrderListQuery to improve filtering capabilities. Updated the admin-breadcrumb and admin-sidebar components to include new translations for agent-related terms in English, Nepali, and Chinese, enhancing the overall user experience and multi-language support across the admin interface.
This commit is contained in:
@@ -1,8 +1,10 @@
|
||||
"use client";
|
||||
|
||||
import Link from "next/link";
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
import { useCallback, 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 {
|
||||
@@ -14,6 +16,8 @@ import {
|
||||
postAdminRejectSettlementBatch,
|
||||
} from "@/api/admin-settlement";
|
||||
import { AdminListPaginationFooter } from "@/components/admin/admin-list-pagination-footer";
|
||||
import { AdminAgentFilter } from "@/components/admin/admin-agent-filter";
|
||||
import { AdminAgentIdentityCells, AdminAgentIdentityHeads } from "@/components/admin/admin-agent-columns";
|
||||
import { AdminPlayerIdentityCells, AdminPlayerIdentityHeads } from "@/components/admin/admin-player-identity-columns";
|
||||
import { AdminStatusBadge } from "@/components/admin/admin-status-badge";
|
||||
import { ModuleScaffold } from "@/components/admin/module-scaffold";
|
||||
@@ -37,6 +41,7 @@ import {
|
||||
TableRow,
|
||||
} from "@/components/ui/table";
|
||||
import { Textarea } from "@/components/ui/textarea";
|
||||
import { AdminLoadingState, AdminLoadingInline, AdminTableLoadingRow } from "@/components/admin/admin-loading-state";
|
||||
import { useAdminCurrencyCatalog } from "@/hooks/use-admin-currency-catalog";
|
||||
import { useAdminPlayCodeLabel } from "@/hooks/use-admin-play-type-catalog";
|
||||
import { useAdminDateTimeFormatter } from "@/hooks/use-admin-datetime-formatter";
|
||||
@@ -72,6 +77,7 @@ function settlementReviewStatusText(value: string | null, t: (key: string) => st
|
||||
|
||||
export function SettlementBatchDetailsConsole({ batchId }: Props) {
|
||||
const { t } = useTranslation(["settlement", "common"]);
|
||||
const tRef = useTranslationRef(["settlement", "common"]);
|
||||
const profile = useAdminProfile();
|
||||
useAdminCurrencyCatalog();
|
||||
const playCodeLabel = useAdminPlayCodeLabel();
|
||||
@@ -84,6 +90,8 @@ export function SettlementBatchDetailsConsole({ batchId }: Props) {
|
||||
const [err, setErr] = useState<string | null>(null);
|
||||
const [page, setPage] = useState(1);
|
||||
const [perPage, setPerPage] = useState(10);
|
||||
const [agentNodeId, setAgentNodeId] = useState<number | undefined>(undefined);
|
||||
const [appliedAgentNodeId, setAppliedAgentNodeId] = useState<number | undefined>(undefined);
|
||||
const [acting, setActing] = useState<string | null>(null);
|
||||
const [pendingAction, setPendingAction] = useState<SettlementAction | null>(null);
|
||||
const [reviewRemark, setReviewRemark] = useState("");
|
||||
@@ -95,18 +103,22 @@ export function SettlementBatchDetailsConsole({ batchId }: Props) {
|
||||
try {
|
||||
const [s, d] = await Promise.all([
|
||||
getAdminSettlementBatch(batchId),
|
||||
getAdminSettlementBatchDetails(batchId, { page, per_page: perPage }),
|
||||
getAdminSettlementBatchDetails(batchId, {
|
||||
page,
|
||||
per_page: perPage,
|
||||
agent_node_id: appliedAgentNodeId,
|
||||
}),
|
||||
]);
|
||||
setSummary(s);
|
||||
setDetails(d);
|
||||
} catch (e) {
|
||||
setErr(e instanceof LotteryApiBizError ? e.message : t("loadFailed"));
|
||||
setErr(e instanceof LotteryApiBizError ? e.message : tRef.current("loadFailed"));
|
||||
setSummary(null);
|
||||
setDetails(null);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}, [batchId, page, perPage, t]);
|
||||
}, [batchId, page, perPage, appliedAgentNodeId]);
|
||||
|
||||
async function runAction(label: string, action: () => Promise<unknown>): Promise<void> {
|
||||
setActing(label);
|
||||
@@ -173,10 +185,9 @@ export function SettlementBatchDetailsConsole({ batchId }: Props) {
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
const t = window.setTimeout(() => void load(), 0);
|
||||
return () => window.clearTimeout(t);
|
||||
}, [load]);
|
||||
useAsyncEffect(() => {
|
||||
void load();
|
||||
}, [batchId, page, perPage, appliedAgentNodeId]);
|
||||
|
||||
return (
|
||||
<ModuleScaffold>
|
||||
@@ -322,7 +333,7 @@ export function SettlementBatchDetailsConsole({ batchId }: Props) {
|
||||
</CardContent>
|
||||
</Card>
|
||||
) : loading ? (
|
||||
<p className="text-muted-foreground text-sm">{t("loadingSummary")}</p>
|
||||
<AdminLoadingState minHeight="6rem" className="py-4" label={t("loadingSummary")} />
|
||||
) : null}
|
||||
|
||||
<Card>
|
||||
@@ -332,11 +343,30 @@ export function SettlementBatchDetailsConsole({ batchId }: Props) {
|
||||
<CardContent>
|
||||
{details ? (
|
||||
<>
|
||||
<div className="mb-4 flex flex-wrap items-end gap-3">
|
||||
<AdminAgentFilter
|
||||
id="settlement-details-agent-filter"
|
||||
className="w-[14rem]"
|
||||
value={agentNodeId}
|
||||
onChange={setAgentNodeId}
|
||||
/>
|
||||
<Button
|
||||
type="button"
|
||||
size="sm"
|
||||
onClick={() => {
|
||||
setAppliedAgentNodeId(agentNodeId);
|
||||
setPage(1);
|
||||
}}
|
||||
>
|
||||
{t("search", { ns: "common", defaultValue: "Search" })}
|
||||
</Button>
|
||||
</div>
|
||||
<Table id={`settlement-details-table-${batchId}`}>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead>{t("ticketNo")}</TableHead>
|
||||
<TableHead>{t("playCode")}</TableHead>
|
||||
<AdminAgentIdentityHeads />
|
||||
<AdminPlayerIdentityHeads />
|
||||
<TableHead>{t("matchedTier")}</TableHead>
|
||||
<TableHead className="text-center">{t("regularPayout")}</TableHead>
|
||||
@@ -348,6 +378,7 @@ export function SettlementBatchDetailsConsole({ batchId }: Props) {
|
||||
<TableRow key={r.id}>
|
||||
<TableCell className="font-mono text-xs">{r.ticket_no ?? "—"}</TableCell>
|
||||
<TableCell className="text-xs">{playCodeLabel(r.play_code)}</TableCell>
|
||||
<AdminAgentIdentityCells row={r} />
|
||||
<AdminPlayerIdentityCells row={r} />
|
||||
<TableCell className="text-xs">{r.matched_prize_tier ?? "—"}</TableCell>
|
||||
<TableCell className="text-center font-mono text-xs tabular-nums">
|
||||
@@ -379,7 +410,11 @@ export function SettlementBatchDetailsConsole({ batchId }: Props) {
|
||||
</>
|
||||
) : (
|
||||
<p className="text-muted-foreground text-sm">
|
||||
{loading ? t("loadingDetails") : t("states.noData", { ns: "common" })}
|
||||
{loading ? (
|
||||
<AdminLoadingInline label={t("loadingDetails")} />
|
||||
) : (
|
||||
t("states.noData", { ns: "common" })
|
||||
)}
|
||||
</p>
|
||||
)}
|
||||
</CardContent>
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
"use client";
|
||||
|
||||
import { Check, Eye, HandCoins, X } from "lucide-react";
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
import { useCallback, useState } from "react";
|
||||
import { useExportLabels } from "@/hooks/use-export-labels";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useAsyncEffect } from "@/hooks/use-async-effect";
|
||||
import { useTranslationRef } from "@/hooks/use-translation-ref";
|
||||
import { toast } from "sonner";
|
||||
|
||||
import {
|
||||
@@ -12,6 +14,7 @@ import {
|
||||
postAdminPayoutSettlementBatch,
|
||||
postAdminRejectSettlementBatch,
|
||||
} from "@/api/admin-settlement";
|
||||
import { AdminAgentFilter } from "@/components/admin/admin-agent-filter";
|
||||
import { AdminListPaginationFooter } from "@/components/admin/admin-list-pagination-footer";
|
||||
import { AdminRowActionsMenu } from "@/components/admin/admin-row-actions-menu";
|
||||
import { AdminStatusBadge } from "@/components/admin/admin-status-badge";
|
||||
@@ -45,6 +48,7 @@ import {
|
||||
TableRow,
|
||||
} from "@/components/ui/table";
|
||||
import { Textarea } from "@/components/ui/textarea";
|
||||
import { AdminLoadingState, AdminLoadingInline, AdminTableLoadingRow } from "@/components/admin/admin-loading-state";
|
||||
import { useAdminCurrencyCatalog } from "@/hooks/use-admin-currency-catalog";
|
||||
import { adminHasAnyPermission } from "@/lib/admin-permissions";
|
||||
import { formatAdminMinorUnits } from "@/lib/money";
|
||||
@@ -87,6 +91,7 @@ function settlementReviewStatusText(value: string | null, t: (key: string) => st
|
||||
|
||||
export function SettlementBatchesConsole() {
|
||||
const { t } = useTranslation(["settlement", "common"]);
|
||||
const tRef = useTranslationRef(["settlement", "common"]);
|
||||
const exportLabels = useExportLabels("settlementBatches");
|
||||
const profile = useAdminProfile();
|
||||
useAdminCurrencyCatalog();
|
||||
@@ -99,6 +104,8 @@ export function SettlementBatchesConsole() {
|
||||
const [appliedDrawNo, setAppliedDrawNo] = useState("");
|
||||
const [draftStatus, setDraftStatus] = useState(STATUS_ALL);
|
||||
const [appliedStatus, setAppliedStatus] = useState(STATUS_ALL);
|
||||
const [agentNodeId, setAgentNodeId] = useState<number | undefined>(undefined);
|
||||
const [appliedAgentNodeId, setAppliedAgentNodeId] = useState<number | undefined>(undefined);
|
||||
const [page, setPage] = useState(1);
|
||||
const [perPage, setPerPage] = useState(10);
|
||||
const [actingId, setActingId] = useState<number | null>(null);
|
||||
@@ -117,24 +124,25 @@ export function SettlementBatchesConsole() {
|
||||
appliedStatus === STATUS_ALL || appliedStatus.trim() === ""
|
||||
? undefined
|
||||
: appliedStatus.trim(),
|
||||
agent_node_id: appliedAgentNodeId,
|
||||
});
|
||||
setData(d);
|
||||
} catch (e) {
|
||||
setError(e instanceof LotteryApiBizError ? e.message : t("loadFailed"));
|
||||
setError(e instanceof LotteryApiBizError ? e.message : tRef.current("loadFailed"));
|
||||
setData(null);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}, [page, perPage, appliedDrawNo, appliedStatus, t]);
|
||||
}, [page, perPage, appliedDrawNo, appliedStatus, appliedAgentNodeId]);
|
||||
|
||||
useEffect(() => {
|
||||
const t = window.setTimeout(() => void load(), 0);
|
||||
return () => window.clearTimeout(t);
|
||||
}, [load]);
|
||||
useAsyncEffect(() => {
|
||||
void load();
|
||||
}, [page, perPage, appliedDrawNo, appliedStatus, appliedAgentNodeId]);
|
||||
|
||||
const applyFilters = () => {
|
||||
setAppliedDrawNo(draftDrawNo);
|
||||
setAppliedStatus(draftStatus);
|
||||
setAppliedAgentNodeId(agentNodeId);
|
||||
setPage(1);
|
||||
};
|
||||
|
||||
@@ -193,6 +201,12 @@ export function SettlementBatchesConsole() {
|
||||
<CardTitle className="admin-list-title">{t("batchList")}</CardTitle>
|
||||
</div>
|
||||
<div className="admin-list-toolbar">
|
||||
<AdminAgentFilter
|
||||
id="settlement-batches-agent-filter"
|
||||
className="admin-list-field sm:w-[14rem]"
|
||||
value={agentNodeId}
|
||||
onChange={setAgentNodeId}
|
||||
/>
|
||||
<div className="admin-list-field">
|
||||
<Label htmlFor="sb-draw-no" className="sm:w-10 sm:shrink-0">
|
||||
{t("drawNo")}
|
||||
@@ -234,10 +248,7 @@ export function SettlementBatchesConsole() {
|
||||
</CardHeader>
|
||||
<CardContent className="admin-list-content pt-0">
|
||||
{error ? <p className="text-destructive text-sm">{error}</p> : null}
|
||||
{loading && !data ? (
|
||||
<p className="text-muted-foreground text-sm">{t("states.loading", { ns: "common" })}</p>
|
||||
) : (
|
||||
<div className="admin-table-shell">
|
||||
<div className="admin-table-shell">
|
||||
<Table id="settlement-batches-table">
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
@@ -253,6 +264,7 @@ export function SettlementBatchesConsole() {
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{loading && !data ? <AdminTableLoadingRow colSpan={9} /> : null}
|
||||
{(data?.items ?? []).map((row: AdminSettlementBatchRow) => (
|
||||
<TableRow key={row.id}>
|
||||
<TableCell className="font-mono text-xs">{row.id}</TableCell>
|
||||
@@ -333,7 +345,6 @@ export function SettlementBatchesConsole() {
|
||||
</TableBody>
|
||||
</Table>
|
||||
</div>
|
||||
)}
|
||||
{data ? (
|
||||
<AdminListPaginationFooter
|
||||
selectId="settlement-batches-per-page"
|
||||
|
||||
Reference in New Issue
Block a user