解耦账单与充值请求生命周期
为 AI Game Creator 账单读取使用独立 lifecycle token,并在账号切换时失效旧请求。 补充充值弹窗变化期间账单仍可正常收尾的回归测试。
This commit is contained in:
@@ -43,7 +43,10 @@ export function useAccountWallet(currentUserId: string) {
|
||||
const [nativeRechargePayment, setNativeRechargePayment] =
|
||||
useState<PlatformProfileRechargeNativePaymentState | null>(null);
|
||||
const rechargeLifecycleRef = useRef(0);
|
||||
const walletLedgerLifecycleRef = useRef(0);
|
||||
const [walletUiOwnerUserId, setWalletUiOwnerUserId] = useState(currentUserId);
|
||||
const currentUserIdRef = useRef(currentUserId);
|
||||
currentUserIdRef.current = currentUserId;
|
||||
const walletOwnerMatchesCurrentUser =
|
||||
Boolean(currentUserId) && ownerUserId === currentUserId;
|
||||
const walletUiOwnerMatchesCurrentUser =
|
||||
@@ -79,6 +82,7 @@ export function useAccountWallet(currentUserId: string) {
|
||||
|
||||
useEffect(() => {
|
||||
rechargeLifecycleRef.current += 1;
|
||||
walletLedgerLifecycleRef.current += 1;
|
||||
setWalletUiOwnerUserId(currentUserId);
|
||||
setWalletLedgerOpen(false);
|
||||
setWalletLedger(null);
|
||||
@@ -93,16 +97,23 @@ export function useAccountWallet(currentUserId: string) {
|
||||
}, [currentUserId]);
|
||||
|
||||
async function loadWalletLedger() {
|
||||
const rechargeLifecycle = rechargeLifecycleRef.current;
|
||||
const walletLedgerLifecycle = ++walletLedgerLifecycleRef.current;
|
||||
const snapshotOwnerUserId = currentUserId;
|
||||
setWalletLedgerLoading(true);
|
||||
setWalletLedgerError(null);
|
||||
try {
|
||||
const ledger = await getClientProfileWalletLedger();
|
||||
if (rechargeLifecycleRef.current === rechargeLifecycle) {
|
||||
if (
|
||||
walletLedgerLifecycleRef.current === walletLedgerLifecycle &&
|
||||
currentUserIdRef.current === snapshotOwnerUserId
|
||||
) {
|
||||
setWalletLedger(ledger);
|
||||
}
|
||||
} catch (error) {
|
||||
if (rechargeLifecycleRef.current !== rechargeLifecycle) {
|
||||
if (
|
||||
walletLedgerLifecycleRef.current !== walletLedgerLifecycle ||
|
||||
currentUserIdRef.current !== snapshotOwnerUserId
|
||||
) {
|
||||
return;
|
||||
}
|
||||
setWalletLedger(null);
|
||||
@@ -110,7 +121,10 @@ export function useAccountWallet(currentUserId: string) {
|
||||
error instanceof Error ? error.message : '读取泥点账单失败',
|
||||
);
|
||||
} finally {
|
||||
if (rechargeLifecycleRef.current === rechargeLifecycle) {
|
||||
if (
|
||||
walletLedgerLifecycleRef.current === walletLedgerLifecycle &&
|
||||
currentUserIdRef.current === snapshotOwnerUserId
|
||||
) {
|
||||
setWalletLedgerLoading(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -246,6 +246,35 @@ describe('useWalletStore', () => {
|
||||
});
|
||||
});
|
||||
|
||||
test('keeps ledger loading independent from the recharge lifecycle', async () => {
|
||||
let resolveLedger!: (value: { entries: [] }) => void;
|
||||
clientApi.getClientProfileRechargeCenter.mockResolvedValue({
|
||||
walletBalance: 18,
|
||||
mudPointBalance: detailedBalance(18),
|
||||
});
|
||||
clientApi.getClientProfileWalletLedger.mockImplementation(
|
||||
() =>
|
||||
new Promise((resolve) => {
|
||||
resolveLedger = resolve;
|
||||
}),
|
||||
);
|
||||
const { result } = renderHook(() => useAccountWallet('user-a'));
|
||||
await act(async () => undefined);
|
||||
|
||||
act(() => {
|
||||
result.current.openWalletLedger();
|
||||
result.current.openRecharge();
|
||||
});
|
||||
expect(result.current.walletLedgerLoading).toBe(true);
|
||||
|
||||
await act(async () => {
|
||||
resolveLedger({ entries: [] });
|
||||
});
|
||||
|
||||
expect(result.current.walletLedger).toEqual({ entries: [] });
|
||||
expect(result.current.walletLedgerLoading).toBe(false);
|
||||
});
|
||||
|
||||
test('hides account-owned dialogs and data when the account changes', async () => {
|
||||
clientApi.getClientProfileRechargeCenter.mockResolvedValue({
|
||||
walletBalance: 18,
|
||||
|
||||
Reference in New Issue
Block a user