diff --git a/apps/ai-game-creator-shell/src/App.tsx b/apps/ai-game-creator-shell/src/App.tsx index d2d06d4d7..2b650855d 100644 --- a/apps/ai-game-creator-shell/src/App.tsx +++ b/apps/ai-game-creator-shell/src/App.tsx @@ -75,6 +75,7 @@ import { selectGameCreationAppReadyTasks, } from '../../../packages/shared/src/contracts/gameCreationApp'; import type { + ProfileDashboardSummary, ProfileMudPointBalance, ProfileRechargeCenterResponse, ProfileRechargeProduct, @@ -5359,8 +5360,8 @@ export function WorkspaceLauncher({ const [runtimeConfigOpen, setRuntimeConfigOpen] = useState(false); const [pendingNonEmptyProject, setPendingNonEmptyProject] = useState(null); - const [walletBalance, setWalletBalance] = useState(null); - const walletBalanceRevisionRef = useRef(0); + const [profileDashboard, setProfileDashboard] = + useState(null); const [mudPointBalance, setMudPointBalance] = useState(null); const [mudPointBalanceStatus, setMudPointBalanceStatus] = useState< @@ -5829,25 +5830,18 @@ export function WorkspaceLauncher({ useEffect(() => { let disposed = false; - const walletBalanceRevision = walletBalanceRevisionRef.current; void getClientProfileDashboard() .then((dashboard) => { - if ( - disposed || - walletBalanceRevisionRef.current !== walletBalanceRevision - ) { + if (disposed) { return; } - setWalletBalance(dashboard.walletBalance); + setProfileDashboard(dashboard); }) .catch((error) => { - if ( - disposed || - walletBalanceRevisionRef.current !== walletBalanceRevision - ) { + if (disposed) { return; } - setWalletBalance(null); + setProfileDashboard(null); setMudPointBalanceError( error instanceof Error ? error.message : '泥点读取失败', ); @@ -6204,8 +6198,9 @@ export function WorkspaceLauncher({ try { const center = await getClientProfileRechargeCenter(); setMudPointBalance(center.mudPointBalance ?? null); - walletBalanceRevisionRef.current += 1; - setWalletBalance(center.walletBalance); + setProfileDashboard((current) => + current ? { ...current, walletBalance: center.walletBalance } : current, + ); setMudPointBalanceStatus('ready'); } catch (error) { setMudPointBalance(null); @@ -6241,8 +6236,9 @@ export function WorkspaceLauncher({ setMudPointBalance(center.mudPointBalance ?? null); setMudPointBalanceStatus('ready'); setMudPointBalanceError(''); - walletBalanceRevisionRef.current += 1; - setWalletBalance(center.walletBalance); + setProfileDashboard((current) => + current ? { ...current, walletBalance: center.walletBalance } : current, + ); } async function loadRechargeCenter() { @@ -8686,7 +8682,7 @@ export function WorkspaceLauncher({
{ it('opens the shared recharge modal from the wallet and sidebar entries', async () => { const rechargeCenter = { walletBalance: 120, + mudPointBalance: { + totalPoints: 120, + permanentPoints: 100, + limitedPoints: 20, + limitedExpiresAt: '2026-08-01T00:00:00Z', + dailyFreePoints: 0, + dailyFreeResetPoints: 20, + dailyFreeResetsAt: '2026-07-18T00:00:00Z', + }, membership: { status: 'inactive', tier: 'normal', @@ -1622,14 +1631,13 @@ describe('AI 游戏创作 App 界面边界', () => { }; let rechargeOrderRequestCount = 0; let releaseLateRechargeOrder: (() => void) | null = null; - let resolveInitialDashboard: ((response: Response) => void) | null = null; const fetchSpy = vi .spyOn(globalThis, 'fetch') .mockImplementation(async (input: RequestInfo | URL) => { const url = String(input); if (url === '/api/profile/dashboard') { - return new Promise((resolve) => { - resolveInitialDashboard = resolve; + return new Response(JSON.stringify({ walletBalance: 120 }), { + status: 200, }); } if (url === '/api/profile/recharge-center') { @@ -1690,13 +1698,9 @@ describe('AI 游戏创作 App 界面边界', () => { ...rechargeCenter, walletBalance: 180, mudPointBalance: { + ...rechargeCenter.mudPointBalance, totalPoints: 180, permanentPoints: 160, - limitedPoints: 20, - limitedExpiresAt: '2026-08-01T00:00:00Z', - dailyFreePoints: 0, - dailyFreeResetPoints: 20, - dailyFreeResetsAt: '2026-07-18T00:00:00Z', }, }, }), @@ -1713,7 +1717,6 @@ describe('AI 游戏创作 App 界面边界', () => { await screen.findByRole('dialog', { name: '购买更多泥点' }), ).not.toBeNull(); expect(screen.getByText('当前余额 120 泥点')).not.toBeNull(); - expect(screen.getByRole('button', { name: '泥点 120' })).not.toBeNull(); fireEvent.click(screen.getByRole('button', { name: '关闭购买更多泥点' })); fireEvent.click(screen.getByRole('button', { name: '我的' })); @@ -1745,14 +1748,6 @@ describe('AI 游戏创作 App 界面边界', () => { expect(screen.queryByRole('dialog', { name: '微信扫码支付' })).toBeNull(); }); expect(screen.getByText('当前余额 180 泥点')).not.toBeNull(); - expect(screen.getByRole('button', { name: '泥点 180' })).not.toBeNull(); - - await act(async () => { - resolveInitialDashboard?.( - new Response(JSON.stringify({ walletBalance: 40 }), { status: 200 }), - ); - }); - expect(screen.getByRole('button', { name: '泥点 180' })).not.toBeNull(); fireEvent.click(screen.getByRole('button', { name: /60泥点.*购买/ })); await waitFor(() => {