import { useMemo } from 'react'; import { Link } from 'react-router-dom'; import { useTrades } from '../hooks/useTrades'; import { useWatchlist } from '../hooks/useWatchlist'; import { usePerformance } from '../hooks/usePerformance'; import { Callout } from '../components/ui/Callout'; import { Section } from '../components/ui/Section'; import { SkeletonCard, SkeletonTable } from '../components/ui/Skeleton'; import { formatPrice } from '../lib/format'; import { recommendationActionLabel } from '../lib/recommendation'; import type { TradeSetup } from '../lib/types'; function fmtR(value: number | null): string { if (value === null) return '—'; return `${value > 0 ? '+' : ''}${value.toFixed(2)}R`; } function rColor(value: number | null): string { if (value === null) return 'text-gray-400'; if (value > 0) return 'text-emerald-400'; if (value < 0) return 'text-red-400'; return 'text-gray-300'; } function Metric({ label, value, sub, valueClass = 'text-gray-100' }: { label: string; value: string; sub?: string; valueClass?: string; }) { return (

{label}

{value}

{sub &&

{sub}

}
); } function DirectionTag({ direction }: { direction: string }) { const isLong = direction === 'long'; return ( {direction} ); } export default function DashboardPage() { const trades = useTrades(); const watchlist = useWatchlist(); const performance = usePerformance(); const topSetups: TradeSetup[] = useMemo( () => (trades.data ?? []).slice(0, 5), [trades.data], ); const highConfidenceCount = useMemo( () => (trades.data ?? []).filter((t) => (t.confidence_score ?? 0) >= 70).length, [trades.data], ); const topWatchlist = useMemo( () => [...(watchlist.data ?? [])] .sort((a, b) => (b.composite_score ?? -1) - (a.composite_score ?? -1)) .slice(0, 6), [watchlist.data], ); const today = new Date().toLocaleDateString('en-US', { weekday: 'long', month: 'long', day: 'numeric', }); const stats = performance.data?.overall; return (
{/* Hero */}

{today}

Market overview

{/* Metric strip */} {(trades.isLoading || performance.isLoading) ? (
) : (
0 ? 'text-blue-300' : 'text-gray-100'} />
)}
{/* Top setups */}
{trades.isLoading && } {trades.isError && Failed to load setups} {trades.data && topSetups.length === 0 && ( No active setups. Run the scanner from the Signals page. )} {topSetups.length > 0 && (
{topSetups.map((setup) => ( ))}
Ticker Dir Entry R:R Conf. Action
{setup.symbol} {formatPrice(setup.entry_price)} {setup.rr_ratio.toFixed(1)}:1 {setup.confidence_score != null ? `${Math.round(setup.confidence_score)}%` : '—'} {recommendationActionLabel(setup.recommended_action)}
All setups →
)}
{/* Watchlist pulse */}
{watchlist.isLoading && } {watchlist.isError && Failed to load watchlist} {watchlist.data && topWatchlist.length === 0 && ( Watchlist is empty — add tickers on the Market page. )} {topWatchlist.length > 0 && (
    {topWatchlist.map((entry) => (
  • {entry.symbol} {entry.rr_ratio != null && ( {entry.rr_ratio.toFixed(1)}:1 )} {entry.composite_score != null ? entry.composite_score.toFixed(0) : '—'}
  • ))}
Full watchlist →
)}
); }