Skip to content

Commit ab04013

Browse files
committed
update UI
1 parent 7ed120e commit ab04013

File tree

2 files changed

+159
-138
lines changed

2 files changed

+159
-138
lines changed

src/components/PerformanceChart.tsx

Lines changed: 55 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -36,23 +36,23 @@ const periods: Array<{ value: TimePeriod; label: string }> = [
3636
// Helper function to format values for mobile display
3737
const formatValue = (value: number | undefined, isMobile: boolean = false): string => {
3838
if (value === undefined || value === null) return 'Loading...';
39-
39+
4040
if (!isMobile) {
4141
// Desktop: show full formatted number
4242
return value.toLocaleString();
4343
}
44-
44+
4545
// Mobile: shorten large numbers
4646
const absValue = Math.abs(value);
47-
47+
4848
if (absValue >= 1000000) {
4949
return `${(value / 1000000).toFixed(1)}M`;
5050
} else if (absValue >= 10000) {
5151
return `${Math.round(value / 1000)}K`;
5252
} else if (absValue >= 1000) {
5353
return `${(value / 1000).toFixed(1)}K`;
5454
}
55-
55+
5656
// For smaller values, just format with commas
5757
return value.toLocaleString();
5858
};
@@ -73,12 +73,12 @@ const PerformanceChart = React.memo(({ selectedStock: propSelectedStock, selecte
7373
const hasConfiguredAlpaca = useMemo(() => hasAlpacaCredentials(apiSettings), [apiSettings]);
7474
const [hasAlpacaConfig, setHasAlpacaConfig] = useState(hasConfiguredAlpaca);
7575
const { toast } = useToast();
76-
76+
7777
// Internal state for selected stock (can be from prop or from search)
7878
const [internalSelectedStock, setInternalSelectedStock] = useState<string | undefined>(propSelectedStock);
7979
const [tickerInput, setTickerInput] = useState<string>("");
8080
const [stockDescription, setStockDescription] = useState<string>(selectedStockDescription || "");
81-
81+
8282
// Use prop or internal state
8383
const selectedStock = propSelectedStock || internalSelectedStock;
8484

@@ -138,15 +138,15 @@ const PerformanceChart = React.memo(({ selectedStock: propSelectedStock, selecte
138138
}
139139
}));
140140
}
141-
141+
142142
// Fetch stock description if not already fetched
143143
if (!stockDescription && hasConfiguredAlpaca) {
144144
try {
145145
const assetInfo = await alpacaAPI.getAsset(selectedStock).catch(err => {
146146
console.warn(`Could not fetch asset info for ${selectedStock}:`, err);
147147
return null;
148148
});
149-
149+
150150
if (assetInfo?.name) {
151151
setStockDescription(assetInfo.name);
152152
}
@@ -168,41 +168,41 @@ const PerformanceChart = React.memo(({ selectedStock: propSelectedStock, selecte
168168
// Try to fetch metrics only once (not period-specific)
169169
if (!metricsLoaded.current) {
170170
const metricsData = await alpacaAPI.calculateMetrics().catch(err => {
171-
console.warn("Failed to calculate metrics:", err);
172-
// Check if it's a configuration error
173-
if (err.message?.includes('API settings not found') ||
174-
err.message?.includes('not configured')) {
175-
console.log("Alpaca API not configured");
176-
setHasAlpacaConfig(false);
177-
setError(null); // Clear error for missing API config
178-
} else if (err.message?.includes('timeout') ||
179-
err.message?.includes('504') ||
180-
err.message?.includes('503') ||
181-
err.message?.includes('Unable to connect to Alpaca') ||
182-
err.message?.includes('Alpaca services appear to be down') ||
183-
err.message?.includes('Alpaca rate limit') ||
184-
err.message?.includes('https://app.alpaca.markets/dashboard/overview')) {
185-
console.log("Alpaca API appears to be down or rate limited:", err.message);
186-
187-
// Extract the meaningful error message
188-
let errorMessage = err.message;
189-
if (err.message?.includes('https://app.alpaca.markets/dashboard/overview')) {
190-
// Already has the full message with link
191-
errorMessage = err.message;
192-
} else if (err.message?.includes('503') || err.message?.includes('504')) {
193-
errorMessage = "Unable to connect to Alpaca. Please check if Alpaca services are operational at https://app.alpaca.markets/dashboard/overview";
194-
}
171+
console.warn("Failed to calculate metrics:", err);
172+
// Check if it's a configuration error
173+
if (err.message?.includes('API settings not found') ||
174+
err.message?.includes('not configured')) {
175+
console.log("Alpaca API not configured");
176+
setHasAlpacaConfig(false);
177+
setError(null); // Clear error for missing API config
178+
} else if (err.message?.includes('timeout') ||
179+
err.message?.includes('504') ||
180+
err.message?.includes('503') ||
181+
err.message?.includes('Unable to connect to Alpaca') ||
182+
err.message?.includes('Alpaca services appear to be down') ||
183+
err.message?.includes('Alpaca rate limit') ||
184+
err.message?.includes('https://app.alpaca.markets/dashboard/overview')) {
185+
console.log("Alpaca API appears to be down or rate limited:", err.message);
186+
187+
// Extract the meaningful error message
188+
let errorMessage = err.message;
189+
if (err.message?.includes('https://app.alpaca.markets/dashboard/overview')) {
190+
// Already has the full message with link
191+
errorMessage = err.message;
192+
} else if (err.message?.includes('503') || err.message?.includes('504')) {
193+
errorMessage = "Unable to connect to Alpaca. Please check if Alpaca services are operational at https://app.alpaca.markets/dashboard/overview";
194+
}
195195

196-
toast({
197-
title: "Alpaca Connection Error",
198-
description: errorMessage,
199-
variant: "destructive",
200-
duration: 10000, // Show for 10 seconds
201-
});
202-
setError(null);
203-
}
204-
return null;
205-
});
196+
toast({
197+
title: "Alpaca Connection Error",
198+
description: errorMessage,
199+
variant: "destructive",
200+
duration: 10000, // Show for 10 seconds
201+
});
202+
setError(null);
203+
}
204+
return null;
205+
});
206206

207207
// Positions are now included in metrics data
208208
const positionsData = metricsData?.positions || [];
@@ -272,21 +272,21 @@ const PerformanceChart = React.memo(({ selectedStock: propSelectedStock, selecte
272272
setPositionsLoading(false);
273273
return;
274274
}
275-
275+
276276
const fetchKey = `${selectedStock || 'portfolio'}-${selectedPeriod}`;
277-
277+
278278
// Avoid duplicate fetches for the same configuration
279279
if (fetchedRef.current === fetchKey) {
280280
return;
281281
}
282-
282+
283283
fetchedRef.current = fetchKey;
284-
284+
285285
// Add a small delay on initial mount to ensure session is settled
286286
const timeoutId = setTimeout(() => {
287287
fetchData(selectedPeriod);
288288
}, 500);
289-
289+
290290
return () => clearTimeout(timeoutId);
291291
}, [selectedStock, selectedPeriod, fetchData, isAuthenticated, hasConfiguredAlpaca]);
292292

@@ -333,7 +333,7 @@ const PerformanceChart = React.memo(({ selectedStock: propSelectedStock, selecte
333333
const marketValue = position.marketValue !== undefined ? position.marketValue : (parseFloat(position.market_value || '0') || 0);
334334
const unrealizedPL = position.unrealizedPL !== undefined ? position.unrealizedPL : (parseFloat(position.unrealized_pl || '0') || 0);
335335
const unrealizedPLPercent = position.unrealizedPLPct !== undefined ? position.unrealizedPLPct : ((parseFloat(position.unrealized_plpc || '0') || 0) * 100);
336-
336+
337337
// For intraday P/L, calculate from day change if not directly available
338338
const dayChange = position.dayChange !== undefined ? position.dayChange : 0;
339339
const todayPL = position.unrealized_intraday_pl !== undefined ? parseFloat(position.unrealized_intraday_pl || '0') : (dayChange * shares * currentPrice / 100);
@@ -385,7 +385,7 @@ const PerformanceChart = React.memo(({ selectedStock: propSelectedStock, selecte
385385
}, [selectedStock, stockData, selectedPeriod, portfolioData]);
386386

387387
const currentData = useMemo(() => getCurrentData(), [getCurrentData]);
388-
388+
389389
// Custom tick formatter for X-axis based on period
390390
const formatXAxisTick = useCallback((value: string) => {
391391
// For 1M period, show abbreviated format
@@ -396,15 +396,15 @@ const PerformanceChart = React.memo(({ selectedStock: propSelectedStock, selecte
396396
}
397397
return value;
398398
}, [selectedPeriod]);
399-
399+
400400
const latestValue = currentData[currentData.length - 1] || { value: 0, pnl: 0 };
401401
const firstValue = currentData[0] || { value: 0, pnl: 0 };
402402
const totalReturn = latestValue.pnl || (latestValue.value - firstValue.value);
403403
const totalReturnPercent = 'pnlPercent' in latestValue && latestValue.pnlPercent ?
404404
parseFloat(String(latestValue.pnlPercent)).toFixed(2) :
405405
(firstValue.value > 0 ? ((totalReturn / firstValue.value) * 100).toFixed(2) : '0.00');
406406
const isPositive = totalReturn >= 0;
407-
407+
408408
// Debug log for 1D period
409409
if (selectedStock && selectedPeriod === '1D' && currentData.length > 0) {
410410
console.log(`[PerformanceChart] ${selectedStock} 1D data:`, {
@@ -474,7 +474,7 @@ const PerformanceChart = React.memo(({ selectedStock: propSelectedStock, selecte
474474
}, [currentData, selectedStock, selectedPeriod, firstValue]);
475475

476476
const yAxisDomain = useMemo(() => getYAxisDomain(), [getYAxisDomain]);
477-
477+
478478
// For 1D view with selected stock, use the reference price (previous close)
479479
// which would make the first value show 0 change
480480
const startPrice = selectedPeriod === '1D' && selectedStock && firstValue?.pnl === 0
@@ -541,7 +541,7 @@ const PerformanceChart = React.memo(({ selectedStock: propSelectedStock, selecte
541541
placeholder="Search stock..."
542542
className="flex-1"
543543
/>
544-
<Button
544+
<Button
545545
size="sm"
546546
onClick={handleViewStock}
547547
disabled={!tickerInput.trim()}
@@ -554,7 +554,7 @@ const PerformanceChart = React.memo(({ selectedStock: propSelectedStock, selecte
554554
<div className="text-xs text-muted-foreground">
555555
Data may be incomplete or delayed.{' '}
556556
<a
557-
href={selectedStock
557+
href={selectedStock
558558
? `https://app.alpaca.markets/trade/${selectedStock}`
559559
: 'https://app.alpaca.markets/dashboard/overview'
560560
}
@@ -745,7 +745,7 @@ const PerformanceChart = React.memo(({ selectedStock: propSelectedStock, selecte
745745
</p>
746746
</div>
747747
<div>
748-
<p className="text-xs text-muted-foreground">Max DD</p>
748+
<p className="text-xs text-muted-foreground">Max Draw Down</p>
749749
<p className="text-sm sm:text-base font-semibold text-danger">
750750
-{metrics?.maxDrawdown?.toFixed(1) || 'Loading...'}%
751751
</p>

0 commit comments

Comments
 (0)