import React, { useState, useEffect, useContext } from 'react'; import { getShortName } from '../utils/teams'; import { PlayerContext } from '../PlayerContext'; export default function Fixtures() { const [fixtures, setFixtures] = useState([]); const [isLoading, setIsLoading] = useState(true); useEffect(() => { fetch('https://anayshukla-fpl-solver.hf.space/api/fixtures') .then(res => res.json()) .then(data => { setFixtures(data); setIsLoading(false); }); }, []); if (isLoading) return
Loading fixtures...
; const { effectiveFixtures } = useContext(PlayerContext); const TEAM_MAP = { "Arsenal": 1, "Aston Villa": 2, "Burnley": 3, "AFC Bournemouth": 4, "Brentford": 5, "Brighton": 6, "Brighton and Hove Albion": 6, "Chelsea": 7, "Crystal Palace": 8, "Everton": 9, "Fulham": 10, "Leeds United": 11, "Liverpool": 12, "Man City": 13, "Manchester City": 13, "Man Utd": 14, "Manchester United": 14, "Newcastle": 15, "Newcastle United": 15, "Nott'm Forest": 16, "Nottingham Forest": 16, "Sunderland": 17, "Spurs": 18, "Tottenham": 18, "Tottenham Hotspur": 18, "West Ham": 19, "West Ham United": 19, "Wolves": 20, "Wolverhampton Wanderers": 20 }; const expandedFixtures = []; fixtures.forEach(match => { const hId = match.home_team_id || TEAM_MAP[match.home_team] || match.home_team; const aId = match.away_team_id || TEAM_MAP[match.away_team] || match.away_team; const matchId = `${hId}_vs_${aId}`; const override = effectiveFixtures?.[matchId]; if (override) { Object.entries(override).forEach(([gw, prob]) => { // THE FIX: Prevent floating point ghost fixtures (must be >= 0.5%) if (Number(prob) >= 0.005) { expandedFixtures.push({ ...match, GW: Number(gw), shiftProb: Number(prob) }); } }); } else { expandedFixtures.push({ ...match, shiftProb: 1.0 }); } }); const groupedFixtures = expandedFixtures.reduce((acc, match) => { (acc[match.GW] = acc[match.GW] || []).push(match); return acc; }, {}); return (
{Object.entries(groupedFixtures).map(([gw, matches]) => (

Gameweek {gw}

{matches.map((match, idx) => { const hw = match.home_win_prob; const aw = match.away_win_prob; const isGhost = match.shiftProb < 0.995; const homeBox = hw > aw ? 'text-emerald-400 bg-emerald-900/30' : (hw < aw ? 'text-rose-400 bg-rose-900/30' : 'text-slate-300 bg-slate-800/50'); const awayBox = aw > hw ? 'text-emerald-400 bg-emerald-900/30' : (aw < hw ? 'text-rose-400 bg-rose-900/30' : 'text-slate-300 bg-slate-800/50'); const ghostStyles = isGhost ? "border-dashed border-indigo-500/50 opacity-80 bg-[repeating-linear-gradient(45deg,transparent,transparent_10px,rgba(99,102,241,0.05)_10px,rgba(99,102,241,0.05)_20px)]" : "border-slate-800/80 hover:border-slate-600"; return (
{isGhost && (
{Math.round(match.shiftProb * 100)}% Chance
)} {/* Header: Teams & xG */}
{getShortName(match.home_team)} {/* UPDATED: Larger, bolder xG text */} {match.expected_home_goals.toFixed(2)} xG
vs
{getShortName(match.away_team)} {/* UPDATED: Larger, bolder xG text */} {match.expected_away_goals.toFixed(2)} xG
{/* Body: Probabilities & Clean Sheets */}
HOME WIN {(match.home_win_prob * 100).toFixed(1)}%
DRAW {(match.draw_prob * 100).toFixed(1)}%
AWAY WIN {(match.away_win_prob * 100).toFixed(1)}%
{/* Clean Sheet Odds */}
Home CS: {(match.home_clean_sheet_odds * 100).toFixed(1)}%
Away CS: {(match.away_clean_sheet_odds * 100).toFixed(1)}%
); })}
))}
); }