fix: Dashboard card UX — PnL montants, Trades du cycle avec origine pattern, Dernier Cycle 2x2

- PnL simulated: bottom half shows Investi/P&L € at 2xl (same size as %)
- Dernier Cycle: 2x2 grid bigger (patterns ajoutés + trades loggés en gros),
  scorés + fermés en secondaire
- Trades du cycle: header shows +N Trades (not patterns); iterates cyclePatterns
  to show each pattern as origin (✓ loggé / ○ non loggé) + trade details below

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
OpenSquared
2026-06-19 22:14:35 +02:00
parent d94052dd91
commit defff620b2

View File

@@ -354,29 +354,20 @@ export default function Dashboard() {
<div className="text-[10px] text-slate-600">{withPnl.length} pricés</div>
</div>
</div>
<div className="mt-2 pt-2 border-t border-slate-700/30 flex justify-between gap-2">
<div className="text-center">
<div className="text-[10px] text-slate-600">Ouvert</div>
<div className="text-xs font-bold text-slate-300">{openTrades.length}</div>
</div>
<div className="text-center">
<div className="text-[10px] text-slate-600">Fermé</div>
<div className="text-xs font-bold text-slate-400">{closedTrades.length}</div>
</div>
{totalCapital > 0 && (
<div className="text-center">
<div className="text-[10px] text-slate-600">Capital</div>
<div className="text-xs font-bold text-slate-300 font-mono">{totalCapital.toFixed(0)}</div>
<div className="mt-2 pt-2 border-t border-slate-700/30 flex justify-between items-end">
<div>
<div className="text-[10px] text-slate-500 mb-0.5">Investi</div>
<div className="text-2xl font-bold font-mono text-slate-300">
{totalCapital > 0 ? `${totalCapital.toFixed(0)}` : '—'}
</div>
)}
{totalCapital > 0 && (
<div className="text-center">
<div className="text-[10px] text-slate-600">Profit</div>
<div className={clsx('text-xs font-bold font-mono', totalProfit >= 0 ? 'text-emerald-400' : 'text-red-400')}>
{totalProfit >= 0 ? '+' : ''}{totalProfit.toFixed(0)}
</div>
</div>
<div className="text-right">
<div className="text-[10px] text-slate-500 mb-0.5">P&L </div>
<div className={clsx('text-2xl font-bold font-mono',
totalCapital === 0 ? 'text-slate-600' : totalProfit >= 0 ? 'text-emerald-400' : 'text-red-400')}>
{totalCapital > 0 ? `${totalProfit >= 0 ? '+' : ''}${totalProfit.toFixed(0)}` : '—'}
</div>
)}
</div>
</div>
</>
) : (
@@ -489,22 +480,22 @@ export default function Dashboard() {
<div className="text-xl font-bold text-blue-400 mt-0.5 font-mono">{elapsedStr}</div>
{last ? (
<>
<div className="mt-1.5 grid grid-cols-4 gap-1 text-center">
<div className="bg-dark-700/60 rounded px-1 py-1">
<div className="text-sm font-bold text-slate-200">+{patternsAdded}</div>
<div className="text-[9px] text-slate-600 leading-tight">patterns</div>
<div className="mt-2 grid grid-cols-2 gap-1.5 text-center">
<div className="bg-dark-700/60 rounded px-2 py-2">
<div className="text-xl font-bold text-slate-200">+{patternsAdded}</div>
<div className="text-[9px] text-slate-500 mt-0.5">patterns ajoutés</div>
</div>
<div className="bg-dark-700/60 rounded px-1 py-1">
<div className="text-sm font-bold text-emerald-400">{patternsScored}</div>
<div className="text-[9px] text-slate-600 leading-tight">scorés</div>
<div className="bg-dark-700/60 rounded px-2 py-2">
<div className="text-xl font-bold text-blue-400">{tradesLogged}</div>
<div className="text-[9px] text-slate-500 mt-0.5">trades loggés</div>
</div>
<div className="bg-dark-700/60 rounded px-1 py-1">
<div className="text-sm font-bold text-blue-400">{tradesLogged}</div>
<div className="text-[9px] text-slate-600 leading-tight">loggés</div>
<div className="bg-dark-700/60 rounded px-2 py-1.5">
<div className="text-base font-bold text-emerald-400">{patternsScored}</div>
<div className="text-[9px] text-slate-600">scorés</div>
</div>
<div className="bg-dark-700/60 rounded px-1 py-1">
<div className="text-sm font-bold text-slate-500">{tradesClosed}</div>
<div className="text-[9px] text-slate-600 leading-tight">fermés</div>
<div className="bg-dark-700/60 rounded px-2 py-1.5">
<div className="text-base font-bold text-slate-500">{tradesClosed}</div>
<div className="text-[9px] text-slate-600">fermés</div>
</div>
</div>
{commentary?.commentary && (
@@ -600,39 +591,66 @@ export default function Dashboard() {
{/* Trades du dernier cycle — détaillé */}
{(() => {
const patternsAdded: number = lastCycle?.patterns_added ?? 0
const tradeCount = cycleTrades.length
// Build a map: pattern_id → trade for quick lookup
const tradeByPattern: Record<string, any> = {}
for (const t of cycleTrades) {
if (t.pattern_id) tradeByPattern[t.pattern_id] = t
}
// Show cyclePatterns with their trade status (loggé or not)
const rows = cyclePatterns.length > 0
? cyclePatterns
: cycleTrades.map((t: any) => ({ id: t.pattern_id, name: t.pattern_name }))
return (
<Link to="/journal" className="card block hover:border-slate-600/60 transition-all cursor-pointer">
<div className="flex items-center justify-between mb-1">
<span className="section-title mb-0 text-[10px]">📥 Trades du cycle</span>
<ArrowUpRight className="w-3 h-3 text-slate-600" />
</div>
<div className="text-xl font-bold text-emerald-400 font-mono">+{patternsAdded} patterns</div>
{cycleTrades.length > 0 ? (
<div className="space-y-1 mt-1.5">
{cycleTrades.slice(0, 3).map((t: any, i) => {
const pnl: number | null = t.pnl_pct ?? null
const ev: number | null = t.ev_net ?? t.ev_at_entry ?? null
const isBear = t.strategy?.toLowerCase().includes('put') || t.strategy?.toLowerCase().includes('bear')
<div className="text-xl font-bold text-emerald-400 font-mono">
{tradeCount > 0 ? `+${tradeCount} Trade${tradeCount > 1 ? 's' : ''}` : lastCycle ? '+0 Trades' : '—'}
</div>
{rows.length > 0 ? (
<div className="space-y-1.5 mt-1.5">
{rows.slice(0, 3).map((p: any, i: number) => {
const t = tradeByPattern[p.id]
const logged = !!t
const ev: number | null = t?.ev_net ?? t?.ev_at_entry ?? null
const score: number | null = t?.score_at_entry ?? scoreMap[p.id]?.score ?? null
const pnl: number | null = t?.pnl_pct ?? null
const isBear = t?.strategy?.toLowerCase().includes('put') || t?.strategy?.toLowerCase().includes('bear')
return (
<div key={i} className="flex items-center gap-1.5 text-[10px]">
<span className="shrink-0">{isBear ? '🐻' : '🐂'}</span>
<span className="font-mono text-slate-300 font-semibold w-10 truncate">{t.underlying ?? '—'}</span>
<span className="text-slate-600 truncate flex-1">{t.strategy ?? ''}</span>
{ev !== null && (
<span className={clsx('font-mono shrink-0 text-[9px]', ev >= 0.5 ? 'text-emerald-400' : ev >= 0 ? 'text-yellow-400' : 'text-red-400')}>
EV{ev >= 0 ? '+' : ''}{ev.toFixed(2)}
<div key={i} className="text-[10px]">
{/* Pattern name (origin) */}
<div className="flex items-center gap-1 mb-0.5">
<span className={clsx('text-[8px] font-bold shrink-0 w-3', logged ? 'text-emerald-400' : 'text-slate-600')}>
{logged ? '✓' : '○'}
</span>
<span className="text-slate-400 truncate flex-1 italic">{p.name}</span>
{score !== null && (
<span className={clsx('font-mono shrink-0 text-[9px] font-bold', scoreColor(score))}>{score}</span>
)}
</div>
{/* Trade details if logged */}
{logged && (
<div className="flex items-center gap-1.5 ml-3">
<span className="shrink-0 text-[9px]">{isBear ? '🐻' : '🐂'}</span>
<span className="font-mono text-slate-300 font-semibold">{t.underlying ?? '—'}</span>
<span className="text-slate-600 truncate flex-1">{t.strategy ?? ''}</span>
{ev !== null && (
<span className={clsx('font-mono shrink-0 text-[9px]', ev >= 0.5 ? 'text-emerald-400' : ev >= 0 ? 'text-yellow-400' : 'text-red-400')}>
EV{ev >= 0 ? '+' : ''}{ev.toFixed(2)}
</span>
)}
{pnl !== null && (
<span className={clsx('font-mono font-bold shrink-0', pnl >= 0 ? 'text-emerald-400' : 'text-red-400')}>
{pnl >= 0 ? '+' : ''}{pnl.toFixed(1)}%
</span>
)}
</div>
)}
{t.score_at_entry != null && (
<span className={clsx('font-mono shrink-0 text-[9px]', scoreColor(t.score_at_entry))}>
{t.score_at_entry}
</span>
)}
{pnl !== null && (
<span className={clsx('font-mono font-bold shrink-0', pnl >= 0 ? 'text-emerald-400' : 'text-red-400')}>
{pnl >= 0 ? '+' : ''}{pnl.toFixed(1)}%
</span>
{!logged && (
<div className="ml-3 text-[9px] text-slate-700">score insuffisant non loggé</div>
)}
</div>
)
@@ -640,7 +658,7 @@ export default function Dashboard() {
</div>
) : (
<div className="text-[10px] text-slate-600 mt-1">
{scoringRunId ? 'Aucun trade loggé ce cycle' : 'En attente du prochain cycle'}
{lastCycle ? 'Aucun pattern ajouté ce cycle' : 'En attente du prochain cycle'}
</div>
)}
</Link>