/* ============================================================ FIFA EDGE — reusable components ============================================================ */ const { useState, useEffect, useMemo, useRef } = React; /* ----- Icons (inline SVG, 16px) ----- */ const Icon = ({ name, size = 16 }) => { const paths = { home: <>, live: <>, signals: <>, trophy: <>, stats: <>, perf: <>, settings: <>, search: <>, bell: <>, arrow_up: <>, arrow_dn: <>, filter: <>, refresh: <>, expand: <>, telegram: <>, play: <>, pause: <>, dot: , chev: <>, }; return ( {paths[name]} ); }; /* ----- Sparkline ----- */ const Sparkline = ({ data, w = 72, h = 28, color = 'currentColor' }) => { const max = Math.max(...data), min = Math.min(...data); const range = max - min || 1; const step = w / (data.length - 1); const points = data.map((v, i) => `${i*step},${h - ((v - min) / range) * (h - 4) - 2}`).join(' '); const areaPoints = `0,${h} ${points} ${w},${h}`; return ( ); }; /* ----- KPI tile ----- */ const Kpi = ({ label, value, unit, delta, spark, sparkColor }) => (
{label}
{value}{unit && {unit}}
{delta !== undefined && (
= 0 ? 'pos' : 'neg'}`}> = 0 ? 'arrow_up' : 'arrow_dn'} size={10} /> {delta >= 0 ? '+' : ''}{delta}%
)} {spark && }
); /* ----- EV circular meter ----- */ const EvMeter = ({ value, conf }) => { const pct = Math.max(0, Math.min(100, (value / 20) * 100)); const r = 18, C = 2 * Math.PI * r; const off = C - (C * pct) / 100; return (
+{value.toFixed(1)}
); }; /* ----- Form dots (W/D/L) ----- */ const FormDots = ({ form }) => ( {form.slice(-10).map((r, i) => {r.toUpperCase()})} ); /* ----- Match row (for Today list) ----- */ const MatchRow = ({ m, showEv }) => { const oddKey = m.ev.pick === '1' ? 'h' : m.ev.pick === 'X' ? 'd' : m.ev.pick === '2' ? 'a' : null; const pill = m.ev.value >= 7 ? 'pos' : m.ev.value >= 3 ? 'mid' : 'flat'; return (
window.openH2H && window.openH2H(m.id)}>
{window.fmtHM(m.kickoff)}
T-{m.minuteToKO}m
{m.home.handle}{m.home.team}{m.home.elo}
{m.away.handle}{m.away.team}{m.away.elo}
{m.league}
1{m.odds.h.toFixed(2)}
X{m.odds.d.toFixed(2)}
2{m.odds.a.toFixed(2)}
{showEv && ( m.ev.pick ? {m.ev.pick} · +{m.ev.value.toFixed(1)}% : no edge )}
); }; /* ----- Signal queue item ----- */ const SignalQueueItem = ({ m }) => { const [countdown, setCountdown] = useState(m.minuteToKO * 60 - 15 * 60); // seconds until T-15min dispatch useEffect(() => { const t = setInterval(() => setCountdown(c => Math.max(0, c - 1)), 1000); return () => clearInterval(t); }, []); const mm = Math.floor(Math.abs(countdown) / 60).toString().padStart(2,'0'); const ss = Math.floor(Math.abs(countdown) % 60).toString().padStart(2,'0'); const oddPicked = m.ev.pick === '1' ? m.odds.h : m.ev.pick === 'X' ? m.odds.d : m.ev.pick === '2' ? m.odds.a : null; const status = countdown > 0 ? 'queued' : 'dispatched'; return (
{m.league} · Kickoff {window.fmtHM(m.kickoff)} · {status === 'queued' ? Dispara em {mm}:{ss} : dispatched}
{m.home.handle} vs {m.away.handle}
ELO{m.home.elo}/{m.away.elo} Conf{m.ev.conf}% Stake2.0u
{m.ev.pick && ( TIP{m.ev.pick}@{oddPicked && oddPicked.toFixed(2)} )}
); }; /* ----- Live match row ----- */ const LiveRow = ({ m }) => (
{m.minute.toFixed(1)}'
{m.home.handle} {m.home.team}{m.score.h}
{m.away.handle} {m.away.team}{m.score.a}
{m.odds.h.toFixed(2)}
{m.odds.d.toFixed(2)}
{m.odds.a.toFixed(2)}
); /* ----- Heatmap ----- */ const Heat = ({ data }) => (
{data.map((v, i) =>
)}
); /* ----- Sidebar ----- */ const Sidebar = ({ current, onNav }) => { const nav = [ { id: 'today', label: 'Hoje', icon: 'home', count: MATCHES.length }, { id: 'live', label: 'Ao Vivo', icon: 'live', live: true }, { id: 'signals', label: 'Sinais', icon: 'signals', count: SIGNALS.length }, { id: 'elo', label: 'Leaderboard', icon: 'trophy' }, { id: 'stats', label: 'Estatísticas', icon: 'stats' }, { id: 'perf', label: 'Performance', icon: 'perf' }, ]; const secondary = []; return ( ); }; /* ----- Topbar ----- */ const Topbar = ({ section }) => { const labels = { today:'Hoje', live:'Ao Vivo', signals:'Sinais', elo:'Leaderboard', stats:'Estatísticas', perf:'Performance' }; const ov = (typeof OVERVIEW !== 'undefined' ? OVERVIEW : {}) || {}; const roi = ov.roi_14d; const wr = ov.winrate; const n14 = ov.signals_14d ?? 0; const fmt = (v, d=1) => v == null ? '—' : v.toFixed(d); const roiCls = roi == null ? '' : roi >= 0 ? 'pos' : 'neg'; const roiStr = roi == null ? '—' : (roi >= 0 ? '+' : '') + roi.toFixed(1) + '%'; return (
FIFA_EDGE / e-Soccer / {labels[section]}
⌘K
ROI 14d {roiStr} WR {fmt(wr)}% Sinais 14d {n14}
AD
Admin
OPERATOR
); }; Object.assign(window, { Icon, Sparkline, Kpi, EvMeter, FormDots, MatchRow, SignalQueueItem, LiveRow, Heat, Sidebar, Topbar });