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.
100 lines
2.8 KiB
TypeScript
100 lines
2.8 KiB
TypeScript
"use client";
|
|
|
|
import { useEffect, useMemo, useRef, useState } from "react";
|
|
import { useTranslation } from "react-i18next";
|
|
import { toast } from "sonner";
|
|
|
|
import { updateAdminSettingsBatch, type AdminSettingBatchItem } from "@/api/admin-settings";
|
|
import { setCachedApplyRebateToPayoutSetting } from "@/lib/admin-settlement-settings-cache";
|
|
import { useAdminSettingsData } from "@/modules/settings/admin-settings-data-context";
|
|
import { SETTLEMENT_KEYS } from "@/modules/settings/settings-keys";
|
|
import { LotteryApiBizError } from "@/types/api/errors";
|
|
|
|
export function useSettingsSection<TDraft>(options: {
|
|
initialDraft: TDraft;
|
|
fromKv: (kv: Record<string, unknown>) => TDraft;
|
|
buildDirtyItems: (draft: TDraft, saved: TDraft) => AdminSettingBatchItem[];
|
|
saveSuccessKey: string;
|
|
saveFailedKey: string;
|
|
}) {
|
|
const { t } = useTranslation(["config"]);
|
|
const tRef = useRef(t);
|
|
tRef.current = t;
|
|
|
|
const { kv, loading, patchKv } = useAdminSettingsData();
|
|
const [draft, setDraft] = useState(options.initialDraft);
|
|
const [saved, setSaved] = useState(options.initialDraft);
|
|
const [saving, setSaving] = useState(false);
|
|
const hydratedRef = useRef(false);
|
|
|
|
const { fromKv, buildDirtyItems, saveSuccessKey, saveFailedKey } = options;
|
|
|
|
const dirty = useMemo(
|
|
() => buildDirtyItems(draft, saved).length > 0,
|
|
[draft, saved, buildDirtyItems],
|
|
);
|
|
|
|
useEffect(() => {
|
|
if (kv === null) {
|
|
return;
|
|
}
|
|
const next = fromKv(kv);
|
|
setDraft(next);
|
|
setSaved(next);
|
|
hydratedRef.current = true;
|
|
}, [kv, fromKv]);
|
|
|
|
const updateField = <K extends keyof TDraft>(field: K, value: TDraft[K]) => {
|
|
setDraft((prev) => ({ ...prev, [field]: value }));
|
|
};
|
|
|
|
const discard = () => {
|
|
setDraft(saved);
|
|
};
|
|
|
|
const save = async (): Promise<boolean> => {
|
|
const items = buildDirtyItems(draft, saved);
|
|
if (items.length === 0) {
|
|
return true;
|
|
}
|
|
|
|
setSaving(true);
|
|
try {
|
|
await updateAdminSettingsBatch(items);
|
|
const updates: Record<string, unknown> = {};
|
|
for (const item of items) {
|
|
updates[item.key] = item.value;
|
|
if (item.key === SETTLEMENT_KEYS.APPLY_REBATE_TO_PAYOUT) {
|
|
setCachedApplyRebateToPayoutSetting(Boolean(item.value));
|
|
}
|
|
}
|
|
patchKv(updates);
|
|
setSaved(draft);
|
|
toast.success(tRef.current(saveSuccessKey, { ns: "config" }));
|
|
return true;
|
|
} catch (error) {
|
|
toast.error(
|
|
error instanceof LotteryApiBizError
|
|
? error.message
|
|
: tRef.current(saveFailedKey, { ns: "config" }),
|
|
);
|
|
return false;
|
|
} finally {
|
|
setSaving(false);
|
|
}
|
|
};
|
|
|
|
const sectionLoading = loading || (kv !== null && !hydratedRef.current);
|
|
|
|
return {
|
|
draft,
|
|
saved,
|
|
loading: sectionLoading,
|
|
saving,
|
|
dirty,
|
|
updateField,
|
|
discard,
|
|
save,
|
|
};
|
|
}
|