@@ -36,23 +36,23 @@ const periods: Array<{ value: TimePeriod; label: string }> = [
3636// Helper function to format values for mobile display
3737const 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