/* ═══════════════════════════════════════════════════════════════ SignalCard — the heart of FoxBot Pro States: active, wait, invalid, executing ═══════════════════════════════════════════════════════════════ */ const { useState: useStateSC } = React; function SignalCard({ signal, onAction }) { const isLong = signal.direction === "LONG"; const dirColor = isLong ? "var(--bull)" : "var(--bear)"; const state = signal.state; return (
{state === "wait" && (
{signal.waitReason || "WAIT · attente confirmation"} WAIT
)} {state === "invalid" && (
SIGNAL INVALIDÉ {signal.note}
)} {/* HEADER */}
{signal.pair}/USDT
= 0 ? "bull" : "bear"} style={{ fontFamily: "var(--font-mono)" }}> {fmtPct(signal.chg24h)} 24h · x{signal.leverage}
{/* BODY — 2-column data */}
SIGNAL · TECH
70 ? "bear" : signal.rsi < 30 ? "bull" : "accent"} /> {signal.macd.dir === "up" ? "▲" : "▼"} {fmtNum(signal.macd.v, { sign: true, decimals: 4 })} } /> 100 ? "warn" : "accent"} hint="vs MA20" /> {fmtNum(signal.bb[0])} · {fmtNum(signal.bb[1])} · {fmtNum(signal.bb[2])} } />
PLAN DE TRADE
R/R = 2 ? "rr-premium" : ""}`}> {signal.rr.toFixed(1)}
{/* TRADE TRACK — horizontal visualization */} {/* QUICK PILLS — valeurs uniques par crypto */}
Perte max −€{(signal.riskEur || 0).toFixed(2)}
Gain TP1 +€{(signal.gainEur || 0).toFixed(2)}
Gain TP2 +€{(signal.gainTp2Eur || 0).toFixed(2)}
Position €{signal.notional ? signal.notional.toFixed(0) : (signal.capital * signal.leverage).toFixed(0)}
Risque
{/* ACTIONS — 2x2 grid */}
onAction?.("paper-long", signal)}> PAPER LONG onAction?.("paper-short", signal)}> PAPER SHORT onAction?.("real-long", signal)}> RÉEL LONG onAction?.("real-short", signal)}> RÉEL SHORT
); } function DataRow({ label, value, bar, barColor = "accent", hint }) { return (
{label}
{bar !== undefined && (
)} {hint && {hint}}
{value}
); } function PlanRow({ label, value, kind, accent }) { let cls = "plan-value mono"; if (kind === "sl") cls += " bear"; else if (kind === "tp") cls += " bull"; else if (accent) cls += " primary"; return (
{label} {fmtNum(value)}
); } /* ─── Trade track (horizontal SL → ENTRY → TP1 → TP2) ─── */ function TradeTrack({ signal }) { const isLong = signal.direction === "LONG"; const { sl, entry, tp1, tp2 } = signal; // For LONG: SL < entry < TP1 < TP2. For SHORT: SL > entry > TP1 > TP2. const points = isLong ? [sl, entry, tp1, tp2] : [tp2, tp1, entry, sl]; const min = Math.min(...points); const max = Math.max(...points); const range = max - min || 1; const pos = (v) => ((v - min) / range) * 100; // For LONG: red zone left of entry, green right. // For SHORT: red zone right of entry, green left. const entryPos = pos(entry); return (
{/* zones */} {isLong ? ( <>
) : ( <>
)} {/* baseline */}
{/* markers */}
); } function TrackMarker({ pos, label, value, color, big, align = "bottom" }) { return (
{label} {fmtNum(value)}
); } /* ─── Action button (paper/real long/short) ─── */ function ActionBtn({ children, variant, onClick, disabled, loading }) { return ( ); } Object.assign(window, { SignalCard });