From 456f0c4823268dd1047a0de7660e1f7bed4f29ce Mon Sep 17 00:00:00 2001 From: PorunC <09982.misaka@gmail.com> Date: Wed, 29 Oct 2025 20:46:08 +0800 Subject: [PATCH] Fix: Add comprehensive null safety checks to CompetitionPage component MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Root cause analysis: The previous fix (0cb1f37) only addressed App.tsx Debug Info section, but missed CompetitionPage.tsx which also directly accesses trader data fields without null safety checks. When competition data is loading or incomplete, trader objects may exist but contain undefined fields (total_pnl, total_equity, etc.), causing: "TypeError: Cannot read properties of undefined (reading 'total_pnl')" Fixed locations in CompetitionPage.tsx: 1. Line 76-77: Leader display in header (total_pnl, total_pnl_pct) 2. Line 142: Leaderboard total_equity display 3. Line 151-157: Leaderboard P&L section (total_pnl checks and displays) 4. Line 229-230: Head-to-Head comparison (total_pnl display) Changes applied: - Replace direct property access with optional chaining (?.) - Use nullish coalescing (?? 0) for numeric comparisons - Add fallback values ('0.00') for undefined fields - Ensure consistent null safety across all trader data displays This completes the null safety coverage for the entire frontend. Fixes: TypeError in CompetitionPage at index-R21Yay1P.js:116:51447 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: tinkle-community --- web/src/components/CompetitionPage.tsx | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/web/src/components/CompetitionPage.tsx b/web/src/components/CompetitionPage.tsx index a72f6dfb..bc549e38 100644 --- a/web/src/components/CompetitionPage.tsx +++ b/web/src/components/CompetitionPage.tsx @@ -73,8 +73,8 @@ export function CompetitionPage() {
{t('leader', language)}
{leader?.trader_name}
-
= 0 ? '#0ECB81' : '#F6465D' }}> - {leader.total_pnl >= 0 ? '+' : ''}{leader.total_pnl_pct.toFixed(2)}% +
= 0 ? '#0ECB81' : '#F6465D' }}> + {(leader?.total_pnl ?? 0) >= 0 ? '+' : ''}{leader?.total_pnl_pct?.toFixed(2) || '0.00'}%
@@ -139,7 +139,7 @@ export function CompetitionPage() {
{t('equity', language)}
- {trader.total_equity.toFixed(2)} + {trader.total_equity?.toFixed(2) || '0.00'}
@@ -148,13 +148,13 @@ export function CompetitionPage() {
{t('pnl', language)}
= 0 ? '#0ECB81' : '#F6465D' }} + style={{ color: (trader.total_pnl ?? 0) >= 0 ? '#0ECB81' : '#F6465D' }} > - {trader.total_pnl >= 0 ? '+' : ''} - {trader.total_pnl_pct.toFixed(2)}% + {(trader.total_pnl ?? 0) >= 0 ? '+' : ''} + {trader.total_pnl_pct?.toFixed(2) || '0.00'}%
- {trader.total_pnl >= 0 ? '+' : ''}{trader.total_pnl.toFixed(2)} + {(trader.total_pnl ?? 0) >= 0 ? '+' : ''}{trader.total_pnl?.toFixed(2) || '0.00'}
@@ -226,8 +226,8 @@ export function CompetitionPage() { > {trader.trader_name} -
= 0 ? '#0ECB81' : '#F6465D' }}> - {trader.total_pnl >= 0 ? '+' : ''}{trader.total_pnl_pct.toFixed(2)}% +
= 0 ? '#0ECB81' : '#F6465D' }}> + {(trader.total_pnl ?? 0) >= 0 ? '+' : ''}{trader.total_pnl_pct?.toFixed(2) || '0.00'}%
{isWinning && gap > 0 && (