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:
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user