refactor: 引入 SWR 统一钱包余额查询与轮询逻辑

This commit is contained in:
2026-06-10 13:58:26 +08:00
parent 4707101da4
commit 20d2befa55
12 changed files with 255 additions and 268 deletions

View File

@@ -2,8 +2,9 @@
import { Wallet } from "lucide-react";
import Image from "next/image";
import { useCallback, useEffect, useRef, useState } from "react";
import { useEffect, useRef } from "react";
import { useTranslation } from "react-i18next";
import { useSWRConfig } from "swr";
import { getWalletBalance } from "@/api/wallet";
import { Skeleton } from "@/components/ui/skeleton";
@@ -12,76 +13,51 @@ import {
TransferOutDialog,
} from "@/features/wallet/wallet-transfer-dialogs";
import { useActivePlayerCurrency } from "@/hooks/use-active-player-currency";
import { useApiQuery } from "@/hooks/use-api-query";
import { formatMinorAsCurrency } from "@/lib/money";
import { PLAYER_CURRENCY_CHANGE_EVENT } from "@/lib/player-currency-preference";
import { cn } from "@/lib/utils";
import { useNetworkConnectionStore } from "@/stores/network-connection-store";
import type { WalletBalanceData } from "@/types/api/wallet-balance";
const BALANCE_KEY = (currency: string) => ["wallet/balance", currency];
export function HallWalletStrip() {
const mode = useNetworkConnectionStore((s) => s.mode);
const { t } = useTranslation("player");
const { activeCurrency } = useActivePlayerCurrency();
const [balance, setBalance] = useState<WalletBalanceData | null>(null);
const [loading, setLoading] = useState(true);
const { mutate } = useSWRConfig();
const degradedWalletPollRef = useRef<number | null>(null);
const currency = activeCurrency;
const isDegraded = mode === "polling" || mode === "offline";
const refresh = useCallback(async () => {
const b = await getWalletBalance({ currency: activeCurrency });
setBalance(b);
}, [activeCurrency]);
const { data: balance, isLoading: loading } = useApiQuery(
BALANCE_KEY(currency),
() => getWalletBalance({ currency }),
{
// 降级模式下 60 秒自动刷新SWR 内置定时器代替手动 setInterval
refreshInterval: isDegraded ? 60_000 : undefined,
},
);
// 全局事件触发刷新(下注后、币种切换等场景)
useEffect(() => {
let cancelled = false;
void (async () => {
setLoading(true);
try {
await refresh();
} finally {
if (!cancelled) setLoading(false);
}
})();
return () => {
cancelled = true;
};
}, [refresh]);
useEffect(() => {
const onRefresh = () => void refresh();
const onRefresh = () => void mutate(BALANCE_KEY(currency));
window.addEventListener("lottery-wallet-refresh", onRefresh);
window.addEventListener(PLAYER_CURRENCY_CHANGE_EVENT, onRefresh);
return () => {
window.removeEventListener("lottery-wallet-refresh", onRefresh);
window.removeEventListener(PLAYER_CURRENCY_CHANGE_EVENT, onRefresh);
};
}, [refresh]);
}, [mutate, currency]);
// 非降级模式时清理遗留计时器refreshInterval 已由 SWR 管理)
useEffect(() => {
if (mode !== "polling" && mode !== "offline") {
if (degradedWalletPollRef.current !== null) {
window.clearInterval(degradedWalletPollRef.current);
degradedWalletPollRef.current = null;
}
return;
if (!isDegraded && degradedWalletPollRef.current !== null) {
window.clearInterval(degradedWalletPollRef.current);
degradedWalletPollRef.current = null;
}
if (degradedWalletPollRef.current !== null) {
return;
}
degradedWalletPollRef.current = window.setInterval(() => {
void refresh();
}, 60_000);
return () => {
if (degradedWalletPollRef.current !== null) {
window.clearInterval(degradedWalletPollRef.current);
degradedWalletPollRef.current = null;
}
};
}, [mode, refresh]);
}, [isDegraded]);
const availableMinor = Number(balance?.available_balance ?? balance?.balance ?? 0);
const isCreditPlayer =
@@ -136,7 +112,7 @@ export function HallWalletStrip() {
currency={currency}
lotteryMinor={availableMinor}
mainMinor={mainMinor}
onSuccess={refresh}
onSuccess={async () => { await mutate(BALANCE_KEY(currency)); }}
/>
<TransferOutDialog
idPrefix="hall-"
@@ -145,7 +121,7 @@ export function HallWalletStrip() {
triggerClassName="h-12 rounded-lg text-base font-bold"
currency={currency}
availableMinor={availableMinor}
onSuccess={refresh}
onSuccess={async () => { await mutate(BALANCE_KEY(currency)); }}
/>
</div>
)}