Skip to content

Commit 70ebd6b

Browse files
Copilot0xrinegade
andcommitted
Fix critical null safety bugs causing UserStatistics crashes and navigation issues
Co-authored-by: 0xrinegade <[email protected]>
1 parent f1165fe commit 70ebd6b

File tree

3 files changed

+60
-45
lines changed

3 files changed

+60
-45
lines changed

src/components/UserProfile.js

Lines changed: 25 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -79,20 +79,25 @@ const UserProfile = ({ wallet: walletProp, network, initialTab = 'overview', onT
7979
// Process real blockchain data when available
8080
useEffect(() => {
8181
if (reputation && history && !reputationLoading && !historyLoading) {
82-
// Convert real blockchain data to profile format
82+
// Convert real blockchain data to profile format with null safety
83+
const safeReputation = reputation || {};
84+
const safeHistory = history || [];
85+
8386
const realProfileData = {
8487
reputation: {
85-
successfulTrades: reputation.successfulTrades,
86-
disputedTrades: reputation.disputedTrades,
87-
disputesWon: reputation.disputesWon,
88-
totalTrades: reputation.totalTrades,
89-
completionRate: reputation.successRate,
90-
averageRating: reputation.rating / 100, // Convert from 0-500 to 0-5 scale
88+
successfulTrades: safeReputation.successfulTrades || 0,
89+
disputedTrades: safeReputation.disputedTrades || 0,
90+
disputesWon: safeReputation.disputesWon || 0,
91+
totalTrades: safeReputation.totalTrades || 0,
92+
completionRate: safeReputation.successRate || 0,
93+
averageRating: (safeReputation.rating || 0) / 100, // Convert from 0-500 to 0-5 scale
9194
averageResponseTime: 'N/A', // Would need additional tracking
92-
disputeRate: reputation.disputedTrades / reputation.totalTrades * 100,
93-
lastUpdated: new Date(reputation.lastUpdated).toLocaleDateString()
95+
disputeRate: (safeReputation.totalTrades || 0) > 0 ?
96+
((safeReputation.disputedTrades || 0) / safeReputation.totalTrades * 100) : 0,
97+
lastUpdated: safeReputation.lastUpdated ?
98+
new Date(safeReputation.lastUpdated).toLocaleDateString() : 'Never'
9499
},
95-
transactions: history.slice(0, 10).map(trade => ({
100+
transactions: safeHistory.slice(0, 10).map(trade => ({
96101
id: trade.id,
97102
type: trade.type === 'sell' ? 'Sell' : 'Buy',
98103
solAmount: trade.solAmount,
@@ -113,23 +118,23 @@ const UserProfile = ({ wallet: walletProp, network, initialTab = 'overview', onT
113118
hideWalletAddress: false
114119
},
115120
tradingStats: {
116-
totalTrades: reputation.totalTrades,
117-
successfulTrades: reputation.successfulTrades,
118-
completionRate: reputation.successRate,
119-
totalVolume: history.reduce((sum, trade) => sum + trade.fiatAmount, 0),
120-
buyOrders: history.filter(trade => trade.type === 'buy').length,
121-
sellOrders: history.filter(trade => trade.type === 'sell').length,
122-
disputedTrades: reputation.disputedTrades,
123-
cancelledTrades: history.filter(trade => trade.status === 'Cancelled').length,
121+
totalTrades: safeReputation.totalTrades || 0,
122+
successfulTrades: safeReputation.successfulTrades || 0,
123+
completionRate: safeReputation.successRate || 0,
124+
totalVolume: safeHistory.reduce((sum, trade) => sum + (trade.fiatAmount || 0), 0),
125+
buyOrders: safeHistory.filter(trade => trade.type === 'buy').length,
126+
sellOrders: safeHistory.filter(trade => trade.type === 'sell').length,
127+
disputedTrades: safeReputation.disputedTrades || 0,
128+
cancelledTrades: safeHistory.filter(trade => trade.status === 'Cancelled').length,
124129
averageResponseTime: 'N/A',
125130
responseTimeRating: 'average',
126131
periodStart: 'All time',
127132
periodEnd: 'Today'
128133
},
129-
activities: history.slice(0, 5).map((trade, i) => ({
134+
activities: safeHistory.slice(0, 5).map((trade, i) => ({
130135
id: `activity-${trade.id}`,
131136
type: 'trade',
132-
message: `You ${trade.type === 'sell' ? 'sold' : 'bought'} ${trade.solAmount.toFixed(4)} SOL`,
137+
message: `You ${trade.type === 'sell' ? 'sold' : 'bought'} ${(trade.solAmount || 0).toFixed(4)} SOL`,
133138
timestamp: new Date(trade.createdAt).toISOString(),
134139
relatedId: trade.id,
135140
actionable: true,

src/components/UserStatistics.js

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -54,22 +54,23 @@ const UserStatistics = () => {
5454
);
5555
}
5656

57-
// Calculate additional statistics from history
58-
const totalVolume = history.reduce((sum, trade) => sum + trade.solAmount, 0);
59-
const totalValue = history.reduce((sum, trade) => sum + trade.fiatAmount, 0);
60-
const buyTrades = history.filter(trade => trade.type === 'buy');
61-
const sellTrades = history.filter(trade => trade.type === 'sell');
62-
const completedTrades = history.filter(trade => trade.status === 'Completed');
63-
const activeTrades = history.filter(trade =>
57+
// Calculate additional statistics from history - with null safety
58+
const safeHistory = history || [];
59+
const totalVolume = safeHistory.reduce((sum, trade) => sum + trade.solAmount, 0);
60+
const totalValue = safeHistory.reduce((sum, trade) => sum + trade.fiatAmount, 0);
61+
const buyTrades = safeHistory.filter(trade => trade.type === 'buy');
62+
const sellTrades = safeHistory.filter(trade => trade.type === 'sell');
63+
const completedTrades = safeHistory.filter(trade => trade.status === 'Completed');
64+
const activeTrades = safeHistory.filter(trade =>
6465
['Listed', 'Accepted', 'AwaitingFiatPayment', 'FiatSent'].includes(trade.status)
6566
);
6667

67-
const averageTradeSize = history.length > 0 ? totalVolume / history.length : 0;
68-
const averageTradeValue = history.length > 0 ? totalValue / history.length : 0;
68+
const averageTradeSize = safeHistory.length > 0 ? totalVolume / safeHistory.length : 0;
69+
const averageTradeValue = safeHistory.length > 0 ? totalValue / safeHistory.length : 0;
6970

7071
// Get recent activity (last 30 days)
7172
const thirtyDaysAgo = Date.now() - (30 * 24 * 60 * 60 * 1000);
72-
const recentTrades = history.filter(trade => trade.createdAt > thirtyDaysAgo);
73+
const recentTrades = safeHistory.filter(trade => trade.createdAt > thirtyDaysAgo);
7374

7475
const renderStatCard = (title, value, subtitle, tooltip, color = 'blue') => (
7576
<div className={`stat-card stat-card-${color}`}>
@@ -200,7 +201,7 @@ const UserStatistics = () => {
200201
{renderStatCard(
201202
'Recent Trades',
202203
recentTrades.length,
203-
history.length > 0 ? `${((recentTrades.length / history.length) * 100).toFixed(1)}% of total` : '0% of total',
204+
safeHistory.length > 0 ? `${((recentTrades.length / safeHistory.length) * 100).toFixed(1)}% of total` : '0% of total',
204205
'Number of trades in the last 30 days'
205206
)}
206207

@@ -215,7 +216,7 @@ const UserStatistics = () => {
215216
{renderStatCard(
216217
'Completed Trades',
217218
completedTrades.length,
218-
`${completedTrades.length > 0 ? ((completedTrades.length / history.length) * 100).toFixed(1) : 0}% completion rate`,
219+
`${completedTrades.length > 0 ? ((completedTrades.length / safeHistory.length) * 100).toFixed(1) : 0}% completion rate`,
219220
'Successfully completed trades',
220221
'green'
221222
)}
@@ -254,11 +255,11 @@ const UserStatistics = () => {
254255
)}
255256

256257
{/* Trade History */}
257-
{history.length > 0 && (
258+
{safeHistory.length > 0 && (
258259
<div className="trade-history-section">
259260
<h3>Recent Trade History</h3>
260261
<div className="trade-history-list">
261-
{history.slice(0, 5).map(trade => (
262+
{safeHistory.slice(0, 5).map(trade => (
262263
<div key={trade.id} className="trade-history-item">
263264
<div className="trade-info">
264265
<span className={`trade-type ${trade.type}`}>{trade.type.toUpperCase()}</span>
@@ -273,16 +274,16 @@ const UserStatistics = () => {
273274
</div>
274275
</div>
275276
))}
276-
{history.length > 5 && (
277+
{safeHistory.length > 5 && (
277278
<div className="view-all-trades">
278-
<button className="view-all-button">View All {history.length} Trades</button>
279+
<button className="view-all-button">View All {safeHistory.length} Trades</button>
279280
</div>
280281
)}
281282
</div>
282283
</div>
283284
)}
284285

285-
{history.length === 0 && !historyLoading && (
286+
{safeHistory.length === 0 && !historyLoading && (
286287
<div className="no-history">
287288
<h3>No Trading History</h3>
288289
<p>You haven't completed any trades yet. Start trading to build your reputation!</p>

src/components/profile/TradingStats.js

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,24 @@ const TradingStats = ({ stats }) => {
1414
router.push('/analytics');
1515
};
1616
// Prepare trading statistics data for PropertyValueTable
17+
const safeTotalTrades = stats?.totalTrades || 0;
1718
const tradingStatsData = [
18-
{ property: 'TOTAL TRADES', value: stats.totalTrades || 0 },
19-
{ property: 'SUCCESSFUL TRADES', value: stats.successfulTrades || 0, badge: 'SUCCESS', badgeClassName: 'badge-success' },
20-
{ property: 'COMPLETION RATE', value: `${stats.completionRate || 0}%`, valueClassName: 'completion-rate' },
21-
{ property: 'TOTAL VOLUME', value: `$${stats.totalVolume?.toFixed(2) || '0.00'}`, valueClassName: 'total-volume' },
22-
{ property: 'BUY ORDERS', value: stats.buyOrders || 0, description: `${((stats.buyOrders / stats.totalTrades) * 100).toFixed(1)}% of total trades` },
23-
{ property: 'SELL ORDERS', value: stats.sellOrders || 0, description: `${((stats.sellOrders / stats.totalTrades) * 100).toFixed(1)}% of total trades` },
24-
{ property: 'DISPUTED TRADES', value: stats.disputedTrades || 0, badge: stats.disputedTrades > 0 ? 'DISPUTED' : null, badgeClassName: 'badge-warning' },
25-
{ property: 'CANCELLED TRADES', value: stats.cancelledTrades || 0, badge: stats.cancelledTrades > 0 ? 'CANCELLED' : null, badgeClassName: 'badge-error' },
19+
{ property: 'TOTAL TRADES', value: safeTotalTrades },
20+
{ property: 'SUCCESSFUL TRADES', value: stats?.successfulTrades || 0, badge: 'SUCCESS', badgeClassName: 'badge-success' },
21+
{ property: 'COMPLETION RATE', value: `${stats?.completionRate || 0}%`, valueClassName: 'completion-rate' },
22+
{ property: 'TOTAL VOLUME', value: `$${stats?.totalVolume?.toFixed(2) || '0.00'}`, valueClassName: 'total-volume' },
23+
{
24+
property: 'BUY ORDERS',
25+
value: stats?.buyOrders || 0,
26+
description: safeTotalTrades > 0 ? `${(((stats?.buyOrders || 0) / safeTotalTrades) * 100).toFixed(1)}% of total trades` : '0% of total trades'
27+
},
28+
{
29+
property: 'SELL ORDERS',
30+
value: stats?.sellOrders || 0,
31+
description: safeTotalTrades > 0 ? `${(((stats?.sellOrders || 0) / safeTotalTrades) * 100).toFixed(1)}% of total trades` : '0% of total trades'
32+
},
33+
{ property: 'DISPUTED TRADES', value: stats?.disputedTrades || 0, badge: (stats?.disputedTrades || 0) > 0 ? 'DISPUTED' : null, badgeClassName: 'badge-warning' },
34+
{ property: 'CANCELLED TRADES', value: stats?.cancelledTrades || 0, badge: (stats?.cancelledTrades || 0) > 0 ? 'CANCELLED' : null, badgeClassName: 'badge-error' },
2635
];
2736

2837
// Prepare performance metrics data

0 commit comments

Comments
 (0)