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,11 +1,13 @@
|
||||
"use client";
|
||||
|
||||
import { Pencil, Trash2 } from "lucide-react";
|
||||
import { useCallback, useEffect, useMemo, useState } from "react";
|
||||
import { useCallback, useMemo, useState } from "react";
|
||||
import { useConfirmAction } from "@/hooks/use-confirm-action";
|
||||
import { useAdminDateTimeFormatter } from "@/hooks/use-admin-datetime-formatter";
|
||||
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 {
|
||||
@@ -16,6 +18,8 @@ import {
|
||||
postAdminPlayerUnfreeze,
|
||||
putAdminPlayer,
|
||||
} from "@/api/admin-player";
|
||||
import { AdminAgentFilter } from "@/components/admin/admin-agent-filter";
|
||||
import { AdminAgentCell, AdminAgentHead } from "@/components/admin/admin-agent-columns";
|
||||
import { AdminListPaginationFooter } from "@/components/admin/admin-list-pagination-footer";
|
||||
import { AdminRowActionsMenu } from "@/components/admin/admin-row-actions-menu";
|
||||
import { AdminTableExportButton } from "@/components/admin/admin-table-export-button";
|
||||
@@ -33,6 +37,7 @@ import {
|
||||
} from "@/components/ui/dialog";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { AdminLoadingState, AdminLoadingInline, AdminTableLoadingRow } from "@/components/admin/admin-loading-state";
|
||||
import { adminHasAnyPermission } from "@/lib/admin-permissions";
|
||||
import { PRD_PLAYER_FREEZE_MANAGE, PRD_USERS_MANAGE } from "@/lib/admin-prd";
|
||||
import { useAdminProfile } from "@/stores/admin-session";
|
||||
@@ -81,6 +86,7 @@ const PLAYER_STATUS_OPTIONS = [
|
||||
|
||||
export function PlayersConsole(): React.ReactElement {
|
||||
const { t } = useTranslation(["players", "common"]);
|
||||
const tRef = useTranslationRef(["players", "common"]);
|
||||
const { request: requestConfirm, ConfirmDialog, busy: confirmBusy } = useConfirmAction();
|
||||
const formatDt = useAdminDateTimeFormatter();
|
||||
const exportLabels = useExportLabels("players");
|
||||
@@ -95,6 +101,8 @@ export function PlayersConsole(): React.ReactElement {
|
||||
const [query, setQuery] = useState("");
|
||||
const [siteCode, setSiteCode] = useState("");
|
||||
const [appliedSiteCode, setAppliedSiteCode] = useState("");
|
||||
const [agentNodeId, setAgentNodeId] = useState<number | undefined>(undefined);
|
||||
const [appliedAgentNodeId, setAppliedAgentNodeId] = useState<number | undefined>(undefined);
|
||||
|
||||
const [items, setItems] = useState<AdminPlayerRow[]>([]);
|
||||
const [total, setTotal] = useState(0);
|
||||
@@ -131,12 +139,13 @@ export function PlayersConsole(): React.ReactElement {
|
||||
per_page: perPage,
|
||||
keyword: query.trim() || undefined,
|
||||
site_code: appliedSiteCode.trim() || undefined,
|
||||
agent_node_id: appliedAgentNodeId,
|
||||
});
|
||||
setItems(data.items);
|
||||
setTotal(data.meta.total);
|
||||
setLastPage(Math.max(1, data.meta.last_page));
|
||||
} catch (e) {
|
||||
const msg = e instanceof LotteryApiBizError ? e.message : t("loadFailed");
|
||||
const msg = e instanceof LotteryApiBizError ? e.message : tRef.current("loadFailed");
|
||||
setErr(msg);
|
||||
setItems([]);
|
||||
setTotal(0);
|
||||
@@ -144,13 +153,11 @@ export function PlayersConsole(): React.ReactElement {
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}, [page, perPage, query, appliedSiteCode, t]);
|
||||
}, [page, perPage, query, appliedSiteCode, appliedAgentNodeId]);
|
||||
|
||||
useEffect(() => {
|
||||
queueMicrotask(() => {
|
||||
void load();
|
||||
});
|
||||
}, [load]);
|
||||
useAsyncEffect(() => {
|
||||
void load();
|
||||
}, [page, perPage, query, appliedSiteCode, appliedAgentNodeId]);
|
||||
|
||||
function openCreateAccount(): void {
|
||||
setAccountMode("create");
|
||||
@@ -334,6 +341,12 @@ export function PlayersConsole(): React.ReactElement {
|
||||
</Select>
|
||||
</div>
|
||||
) : null}
|
||||
<AdminAgentFilter
|
||||
id="players-agent-filter"
|
||||
className="admin-list-field sm:w-[14rem]"
|
||||
value={agentNodeId}
|
||||
onChange={setAgentNodeId}
|
||||
/>
|
||||
<div className="admin-list-field xl:min-w-0">
|
||||
<Label htmlFor="player-search" className="sm:w-20 sm:shrink-0">
|
||||
{t("search")}
|
||||
@@ -349,6 +362,7 @@ export function PlayersConsole(): React.ReactElement {
|
||||
setPage(1);
|
||||
setQuery(keyword.trim());
|
||||
setAppliedSiteCode(siteCode.trim());
|
||||
setAppliedAgentNodeId(agentNodeId);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
@@ -365,6 +379,7 @@ export function PlayersConsole(): React.ReactElement {
|
||||
setPage(1);
|
||||
setQuery(keyword.trim());
|
||||
setAppliedSiteCode(siteCode.trim());
|
||||
setAppliedAgentNodeId(agentNodeId);
|
||||
}}
|
||||
>
|
||||
{t("search")}
|
||||
@@ -377,15 +392,13 @@ export function PlayersConsole(): React.ReactElement {
|
||||
</CardHeader>
|
||||
<CardContent className="admin-list-content">
|
||||
{err ? <p className="text-sm text-red-600 dark:text-red-400">{err}</p> : null}
|
||||
{loading && items.length === 0 ? (
|
||||
<p className="text-sm text-muted-foreground">{t("states.loading", { ns: "common" })}</p>
|
||||
) : null}
|
||||
<div className="admin-table-shell">
|
||||
<Table id="players-table">
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead className="w-16">{t("table.id", { ns: "common" })}</TableHead>
|
||||
<TableHead>{t("site")}</TableHead>
|
||||
<AdminAgentHead />
|
||||
<TableHead>{t("sitePlayerId")}</TableHead>
|
||||
<TableHead>{t("username")}</TableHead>
|
||||
<TableHead>{t("nickname")}</TableHead>
|
||||
@@ -398,9 +411,11 @@ export function PlayersConsole(): React.ReactElement {
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{items.length === 0 && !loading ? (
|
||||
{loading && items.length === 0 ? (
|
||||
<AdminTableLoadingRow colSpan={12} />
|
||||
) : items.length === 0 ? (
|
||||
<TableRow>
|
||||
<TableCell colSpan={11} className="text-muted-foreground">
|
||||
<TableCell colSpan={12} className="text-muted-foreground">
|
||||
{t("states.noData", { ns: "common" })}
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
@@ -413,6 +428,7 @@ export function PlayersConsole(): React.ReactElement {
|
||||
<TableCell>
|
||||
<span className="font-mono text-xs">{row.site_code}</span>
|
||||
</TableCell>
|
||||
<AdminAgentCell row={row} />
|
||||
<TableCell>
|
||||
<span className="font-mono text-xs">{row.site_player_id}</span>
|
||||
</TableCell>
|
||||
|
||||
Reference in New Issue
Block a user