fix: add Entrée date and Durée/maturité columns to Dashboard grid view

This commit is contained in:
OpenSquared
2026-06-18 10:58:01 +02:00
parent cf45d9fb52
commit be9834d70b

View File

@@ -169,7 +169,7 @@ function TradeCard({ item, onAdd, macroInfo, addedInfo, profiles }: {
item: TradeItem
onAdd: (item: TradeItem) => void
macroInfo?: { dominant: string; label: string; color: string; emoji: string; assetBias: Record<string, string> } | null
addedInfo?: { entry_date: string } | null
addedInfo?: { entry_date: string; expiry_days?: number } | null
profiles?: any[]
}) {
const [expanded, setExpanded] = useState(false)
@@ -392,7 +392,7 @@ function TradeRow({ item, onAdd, macroInfo, addedInfo, profiles, rank }: {
item: TradeItem
onAdd: (item: TradeItem) => void
macroInfo?: { dominant: string; label: string; color: string; emoji: string; assetBias: Record<string, string> } | null
addedInfo?: { entry_date: string } | null
addedInfo?: { entry_date: string; expiry_days?: number } | null
profiles?: any[]
rank: number
}) {
@@ -414,6 +414,17 @@ function TradeRow({ item, onAdd, macroInfo, addedInfo, profiles, rank }: {
? Math.round(Math.abs(maxLoss) * gainPct / 100)
: (trade.target_gain_eur ?? scoreInfo?.recommended_trade?.target_gain_eur)
const daysHeld = addedInfo?.entry_date
? Math.floor((Date.now() - new Date(addedInfo.entry_date).getTime()) / 86400000)
: null
const horizon = addedInfo?.expiry_days ?? null
const maturityPct = daysHeld !== null && horizon ? Math.min(100, Math.round(daysHeld / horizon * 100)) : null
const maturityColor = maturityPct === null ? 'text-slate-700'
: maturityPct >= 75 ? 'text-orange-400'
: maturityPct >= 35 ? 'text-emerald-400'
: maturityPct >= 10 ? 'text-yellow-400'
: 'text-slate-500'
return (
<Fragment>
<tr
@@ -488,6 +499,28 @@ function TradeRow({ item, onAdd, macroInfo, addedInfo, profiles, rank }: {
</td>
{/* Macro */}
<td className="px-2 py-2 text-[10px]" style={{ color: bd.color }}>{bd.label}</td>
{/* Date entrée */}
<td className="px-2 py-2 text-right text-[10px] whitespace-nowrap">
{addedInfo?.entry_date
? <span className="text-slate-500">{format(new Date(addedInfo.entry_date), "d MMM", { locale: fr })}</span>
: <span className="text-slate-800"></span>}
</td>
{/* Durée / maturité */}
<td className="px-2 py-2 text-right text-[10px]">
{daysHeld !== null ? (
<div className="flex flex-col items-end gap-0.5">
<span className={clsx('font-mono font-semibold', maturityColor)}>
{daysHeld}j{horizon ? `/${horizon}j` : ''}
</span>
{maturityPct !== null && (
<div className="w-12 h-1 bg-slate-800 rounded-full overflow-hidden">
<div className={clsx('h-full rounded-full', maturityPct >= 75 ? 'bg-orange-500' : maturityPct >= 35 ? 'bg-emerald-500' : 'bg-yellow-500')}
style={{ width: `${maturityPct}%` }} />
</div>
)}
</div>
) : <span className="text-slate-800"></span>}
</td>
{/* Expand chevron */}
<td className="pr-3 py-2 text-slate-600 text-right">
{expanded ? <ChevronUp className="w-3.5 h-3.5 inline" /> : <ChevronDown className="w-3.5 h-3.5 inline" />}
@@ -495,7 +528,7 @@ function TradeRow({ item, onAdd, macroInfo, addedInfo, profiles, rank }: {
</tr>
{expanded && (
<tr className="bg-dark-900/60">
<td colSpan={11} className="px-0 py-0 border-b border-blue-700/20">
<td colSpan={13} className="px-0 py-0 border-b border-blue-700/20">
<div className="p-4 grid grid-cols-3 gap-4 text-xs">
{/* Col 1: score justification */}
<div className="col-span-2">
@@ -603,16 +636,17 @@ export default function Dashboard() {
// key1 = geo_trigger (pattern name) + strategy → survives underlying normalization
// key2 = underlying + strategy → direct ticker match fallback
const addedMap = useMemo(() => {
const map: Record<string, { entry_date: string }> = {}
const upsert = (key: string, entry_date: string) => {
if (!map[key] || entry_date > map[key].entry_date) map[key] = { entry_date }
const map: Record<string, { entry_date: string; expiry_days?: number }> = {}
const upsert = (key: string, entry_date: string, expiry_days?: number) => {
if (!map[key] || entry_date > map[key].entry_date) map[key] = { entry_date, expiry_days }
}
for (const pos of (positions as any[] ?? [])) {
const strategy = (pos.strategy ?? '').toLowerCase()
const trigger = (pos.geo_trigger ?? '').toLowerCase()
const underly = (pos.underlying ?? '').toLowerCase()
if (trigger) upsert(`trigger:${trigger}:${strategy}`, pos.entry_date ?? '')
if (underly) upsert(`ticker:${underly}:${strategy}`, pos.entry_date ?? '')
const strategy = (pos.strategy ?? '').toLowerCase()
const trigger = (pos.geo_trigger ?? '').toLowerCase()
const underly = (pos.underlying ?? '').toLowerCase()
const expiry_days = pos.expiry_days ?? undefined
if (trigger) upsert(`trigger:${trigger}:${strategy}`, pos.entry_date ?? '', expiry_days)
if (underly) upsert(`ticker:${underly}:${strategy}`, pos.entry_date ?? '', expiry_days)
}
return map
}, [positions])
@@ -985,6 +1019,8 @@ export default function Dashboard() {
<th className="px-2 py-2 text-right">Max/Cible</th>
<th className="px-2 py-2">Profil</th>
<th className="px-2 py-2">Macro</th>
<th className="px-2 py-2 text-right">Entrée</th>
<th className="px-2 py-2 text-right">Durée</th>
<th className="pr-3 py-2 w-6"></th>
</tr>
</thead>