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,13 +1,12 @@
|
||||
"use client";
|
||||
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
import { useCallback, useEffect, useRef, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { toast } from "sonner";
|
||||
|
||||
import {
|
||||
getAdminSettings,
|
||||
updateAdminSetting,
|
||||
} from "@/api/admin-settings";
|
||||
import { getAdminSettings, updateAdminSettingsBatch } from "@/api/admin-settings";
|
||||
import { useOptionalAdminSettingsData } from "@/modules/settings/admin-settings-data-context";
|
||||
import { WALLET_GROUP, WALLET_KEYS } from "@/modules/settings/settings-keys";
|
||||
import { useConfirmAction } from "@/hooks/use-confirm-action";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { ConfigDocPage } from "@/modules/config/config-doc-page";
|
||||
@@ -15,15 +14,6 @@ import { Input } from "@/components/ui/input";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { LotteryApiBizError } from "@/types/api/errors";
|
||||
|
||||
const WALLET_GROUP = "wallet";
|
||||
|
||||
const KEYS = {
|
||||
IN_MIN: "wallet.transfer_in_min_minor",
|
||||
IN_MAX: "wallet.transfer_in_max_minor",
|
||||
OUT_MIN: "wallet.transfer_out_min_minor",
|
||||
OUT_MAX: "wallet.transfer_out_max_minor",
|
||||
} as const;
|
||||
|
||||
function minorUnitsToDisplay(n: unknown, decimals = 2): string {
|
||||
const num = Number(n);
|
||||
if (!Number.isFinite(num)) return "";
|
||||
@@ -43,12 +33,24 @@ interface Draft {
|
||||
outMax: string;
|
||||
}
|
||||
|
||||
function draftFromKv(kv: Record<string, unknown>): Draft {
|
||||
return {
|
||||
inMin: minorUnitsToDisplay(kv[WALLET_KEYS.IN_MIN] ?? 100),
|
||||
inMax: minorUnitsToDisplay(kv[WALLET_KEYS.IN_MAX] ?? 0),
|
||||
outMin: minorUnitsToDisplay(kv[WALLET_KEYS.OUT_MIN] ?? 100),
|
||||
outMax: minorUnitsToDisplay(kv[WALLET_KEYS.OUT_MAX] ?? 0),
|
||||
};
|
||||
}
|
||||
|
||||
type WalletConfigDocScreenProps = {
|
||||
embedded?: boolean;
|
||||
};
|
||||
|
||||
export function WalletConfigDocScreen({ embedded = false }: WalletConfigDocScreenProps) {
|
||||
const { t } = useTranslation(["config", "adminUsers", "common"]);
|
||||
const tRef = useRef(t);
|
||||
tRef.current = t;
|
||||
const shared = useOptionalAdminSettingsData();
|
||||
const { request: requestConfirm, ConfirmDialog } = useConfirmAction();
|
||||
const [draft, setDraft] = useState<Draft>({
|
||||
inMin: "",
|
||||
@@ -57,55 +59,81 @@ export function WalletConfigDocScreen({ embedded = false }: WalletConfigDocScree
|
||||
outMax: "",
|
||||
});
|
||||
const [saved, setSaved] = useState<Draft>({ inMin: "", inMax: "", outMin: "", outMax: "" });
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [standaloneLoading, setStandaloneLoading] = useState(!embedded);
|
||||
const [saving, setSaving] = useState(false);
|
||||
const [dirty, setDirty] = useState(false);
|
||||
const dirty =
|
||||
draft.inMin !== saved.inMin ||
|
||||
draft.inMax !== saved.inMax ||
|
||||
draft.outMin !== saved.outMin ||
|
||||
draft.outMax !== saved.outMax;
|
||||
|
||||
const load = useCallback(async () => {
|
||||
setLoading(true);
|
||||
const loading = embedded ? (shared?.loading ?? true) : standaloneLoading;
|
||||
|
||||
const loadStandalone = useCallback(async () => {
|
||||
setStandaloneLoading(true);
|
||||
try {
|
||||
const res = await getAdminSettings(WALLET_GROUP);
|
||||
const kv: Record<string, unknown> = {};
|
||||
for (const item of res.items) {
|
||||
kv[item.key] = item.value;
|
||||
}
|
||||
const d: Draft = {
|
||||
inMin: minorUnitsToDisplay(kv[KEYS.IN_MIN] ?? 100),
|
||||
inMax: minorUnitsToDisplay(kv[KEYS.IN_MAX] ?? 0),
|
||||
outMin: minorUnitsToDisplay(kv[KEYS.OUT_MIN] ?? 100),
|
||||
outMax: minorUnitsToDisplay(kv[KEYS.OUT_MAX] ?? 0),
|
||||
};
|
||||
const d = draftFromKv(kv);
|
||||
setDraft(d);
|
||||
setSaved(d);
|
||||
setDirty(false);
|
||||
} catch {
|
||||
toast.error(t("wallet.loadFailed", { ns: "config" }));
|
||||
toast.error(tRef.current("wallet.loadFailed", { ns: "config" }));
|
||||
} finally {
|
||||
setLoading(false);
|
||||
setStandaloneLoading(false);
|
||||
}
|
||||
}, [t]);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
queueMicrotask(() => {
|
||||
void load();
|
||||
});
|
||||
}, [load]);
|
||||
if (!embedded) {
|
||||
void loadStandalone();
|
||||
}
|
||||
}, [embedded, loadStandalone]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!embedded || shared?.kv === null || shared?.kv === undefined) {
|
||||
return;
|
||||
}
|
||||
const d = draftFromKv(shared.kv);
|
||||
setDraft(d);
|
||||
setSaved(d);
|
||||
}, [embedded, shared?.kv]);
|
||||
|
||||
const handleChange = (field: keyof Draft, value: string) => {
|
||||
setDraft((prev) => ({ ...prev, [field]: value }));
|
||||
setDirty(true);
|
||||
};
|
||||
|
||||
const handleSave = async () => {
|
||||
const items = [];
|
||||
if (draft.inMin !== saved.inMin) {
|
||||
items.push({ key: WALLET_KEYS.IN_MIN, value: displayToMinorUnits(draft.inMin) });
|
||||
}
|
||||
if (draft.inMax !== saved.inMax) {
|
||||
items.push({ key: WALLET_KEYS.IN_MAX, value: displayToMinorUnits(draft.inMax) });
|
||||
}
|
||||
if (draft.outMin !== saved.outMin) {
|
||||
items.push({ key: WALLET_KEYS.OUT_MIN, value: displayToMinorUnits(draft.outMin) });
|
||||
}
|
||||
if (draft.outMax !== saved.outMax) {
|
||||
items.push({ key: WALLET_KEYS.OUT_MAX, value: displayToMinorUnits(draft.outMax) });
|
||||
}
|
||||
if (items.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
setSaving(true);
|
||||
try {
|
||||
await updateAdminSetting(KEYS.IN_MIN, displayToMinorUnits(draft.inMin));
|
||||
await updateAdminSetting(KEYS.IN_MAX, displayToMinorUnits(draft.inMax));
|
||||
await updateAdminSetting(KEYS.OUT_MIN, displayToMinorUnits(draft.outMin));
|
||||
await updateAdminSetting(KEYS.OUT_MAX, displayToMinorUnits(draft.outMax));
|
||||
await updateAdminSettingsBatch(items);
|
||||
const updates: Record<string, unknown> = {};
|
||||
for (const item of items) {
|
||||
updates[item.key] = item.value;
|
||||
}
|
||||
shared?.patchKv(updates);
|
||||
toast.success(t("wallet.saveSuccess", { ns: "config" }));
|
||||
setSaved(draft);
|
||||
setDirty(false);
|
||||
} catch (error) {
|
||||
toast.error(
|
||||
error instanceof LotteryApiBizError ? error.message : t("wallet.saveFailed", { ns: "config" }),
|
||||
@@ -186,13 +214,7 @@ export function WalletConfigDocScreen({ embedded = false }: WalletConfigDocScree
|
||||
{saving ? t("saving", { ns: "adminUsers" }) : t("actions.save", { ns: "adminUsers" })}
|
||||
</Button>
|
||||
{dirty && (
|
||||
<Button
|
||||
variant="outline"
|
||||
onClick={() => {
|
||||
setDraft(saved);
|
||||
setDirty(false);
|
||||
}}
|
||||
>
|
||||
<Button variant="outline" onClick={() => setDraft(saved)} disabled={saving}>
|
||||
{t("wallet.discard", { ns: "config" })}
|
||||
</Button>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user