Spaces:
Running
Running
Commit ·
1e125cd
1
Parent(s): 2f19576
updates
Browse files
frontend/src/components/Fixtures.jsx
CHANGED
|
@@ -21,11 +21,11 @@ export default function Fixtures() {
|
|
| 21 |
|
| 22 |
const TEAM_MAP = {
|
| 23 |
"Arsenal": 1, "Aston Villa": 2, "Burnley": 3, "AFC Bournemouth": 4, "Brentford": 5,
|
| 24 |
-
"Brighton": 6, "Chelsea": 7, "Crystal Palace": 8, "Everton": 9, "Fulham": 10,
|
| 25 |
-
"Leeds United": 11, "Liverpool": 12, "Man City": 13, "Manchester City": 13,
|
| 26 |
"Man Utd": 14, "Manchester United": 14, "Newcastle": 15, "Newcastle United": 15,
|
| 27 |
-
"Nott'm Forest": 16, "Nottingham Forest": 16, "Sunderland": 17,
|
| 28 |
-
"Spurs": 18, "Tottenham": 18, "Tottenham Hotspur": 18,
|
| 29 |
"West Ham": 19, "West Ham United": 19, "Wolves": 20, "Wolverhampton Wanderers": 20
|
| 30 |
};
|
| 31 |
|
|
@@ -60,24 +60,24 @@ export default function Fixtures() {
|
|
| 60 |
{Object.entries(groupedFixtures).map(([gw, matches]) => (
|
| 61 |
<div key={gw} className="bg-slate-900/40 p-6 rounded-xl border border-slate-800 backdrop-blur-sm shadow-xl">
|
| 62 |
<h3 className="text-xl font-bold text-luigi-400 mb-4 border-b border-slate-800 pb-2">Gameweek {gw}</h3>
|
| 63 |
-
|
| 64 |
<div className="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-4">
|
| 65 |
{matches.map((match, idx) => {
|
| 66 |
-
|
| 67 |
const hw = match.home_win_prob;
|
| 68 |
const aw = match.away_win_prob;
|
| 69 |
const isGhost = match.shiftProb < 0.995;
|
| 70 |
|
| 71 |
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');
|
| 72 |
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');
|
| 73 |
-
|
| 74 |
-
const ghostStyles = isGhost
|
| 75 |
-
? "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)]"
|
| 76 |
: "border-slate-800/80 hover:border-slate-600";
|
| 77 |
|
| 78 |
return (
|
| 79 |
-
<div
|
| 80 |
-
key={`${idx}-${match.shiftProb}`}
|
| 81 |
title={isGhost ? `${Math.round(match.shiftProb * 100)}% chance of playing in GW${gw}` : `Confirmed Fixture`}
|
| 82 |
className={`relative bg-slate-950 rounded-lg border overflow-hidden shadow-lg transition-colors ${ghostStyles}`}
|
| 83 |
>
|
|
@@ -86,7 +86,7 @@ export default function Fixtures() {
|
|
| 86 |
{Math.round(match.shiftProb * 100)}% Chance
|
| 87 |
</div>
|
| 88 |
)}
|
| 89 |
-
|
| 90 |
{/* Header: Teams & xG */}
|
| 91 |
<div className="bg-slate-900/80 px-4 py-3 flex justify-between items-center border-b border-slate-800">
|
| 92 |
<div className="flex flex-col items-center w-1/3">
|
|
@@ -96,9 +96,9 @@ export default function Fixtures() {
|
|
| 96 |
{match.expected_home_goals.toFixed(2)} xG
|
| 97 |
</span>
|
| 98 |
</div>
|
| 99 |
-
|
| 100 |
<span className="text-slate-600 text-xs font-bold uppercase tracking-widest bg-slate-950 px-2 py-1 rounded-full border border-slate-800">vs</span>
|
| 101 |
-
|
| 102 |
<div className="flex flex-col items-center w-1/3">
|
| 103 |
<span className="text-lg font-bold text-slate-100">{getShortName(match.away_team)}</span>
|
| 104 |
{/* UPDATED: Larger, bolder xG text */}
|
|
|
|
| 21 |
|
| 22 |
const TEAM_MAP = {
|
| 23 |
"Arsenal": 1, "Aston Villa": 2, "Burnley": 3, "AFC Bournemouth": 4, "Brentford": 5,
|
| 24 |
+
"Brighton": 6, "Brighton and Hove Albion": 6, "Chelsea": 7, "Crystal Palace": 8, "Everton": 9, "Fulham": 10,
|
| 25 |
+
"Leeds United": 11, "Liverpool": 12, "Man City": 13, "Manchester City": 13,
|
| 26 |
"Man Utd": 14, "Manchester United": 14, "Newcastle": 15, "Newcastle United": 15,
|
| 27 |
+
"Nott'm Forest": 16, "Nottingham Forest": 16, "Sunderland": 17,
|
| 28 |
+
"Spurs": 18, "Tottenham": 18, "Tottenham Hotspur": 18,
|
| 29 |
"West Ham": 19, "West Ham United": 19, "Wolves": 20, "Wolverhampton Wanderers": 20
|
| 30 |
};
|
| 31 |
|
|
|
|
| 60 |
{Object.entries(groupedFixtures).map(([gw, matches]) => (
|
| 61 |
<div key={gw} className="bg-slate-900/40 p-6 rounded-xl border border-slate-800 backdrop-blur-sm shadow-xl">
|
| 62 |
<h3 className="text-xl font-bold text-luigi-400 mb-4 border-b border-slate-800 pb-2">Gameweek {gw}</h3>
|
| 63 |
+
|
| 64 |
<div className="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-4">
|
| 65 |
{matches.map((match, idx) => {
|
| 66 |
+
|
| 67 |
const hw = match.home_win_prob;
|
| 68 |
const aw = match.away_win_prob;
|
| 69 |
const isGhost = match.shiftProb < 0.995;
|
| 70 |
|
| 71 |
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');
|
| 72 |
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');
|
| 73 |
+
|
| 74 |
+
const ghostStyles = isGhost
|
| 75 |
+
? "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)]"
|
| 76 |
: "border-slate-800/80 hover:border-slate-600";
|
| 77 |
|
| 78 |
return (
|
| 79 |
+
<div
|
| 80 |
+
key={`${idx}-${match.shiftProb}`}
|
| 81 |
title={isGhost ? `${Math.round(match.shiftProb * 100)}% chance of playing in GW${gw}` : `Confirmed Fixture`}
|
| 82 |
className={`relative bg-slate-950 rounded-lg border overflow-hidden shadow-lg transition-colors ${ghostStyles}`}
|
| 83 |
>
|
|
|
|
| 86 |
{Math.round(match.shiftProb * 100)}% Chance
|
| 87 |
</div>
|
| 88 |
)}
|
| 89 |
+
|
| 90 |
{/* Header: Teams & xG */}
|
| 91 |
<div className="bg-slate-900/80 px-4 py-3 flex justify-between items-center border-b border-slate-800">
|
| 92 |
<div className="flex flex-col items-center w-1/3">
|
|
|
|
| 96 |
{match.expected_home_goals.toFixed(2)} xG
|
| 97 |
</span>
|
| 98 |
</div>
|
| 99 |
+
|
| 100 |
<span className="text-slate-600 text-xs font-bold uppercase tracking-widest bg-slate-950 px-2 py-1 rounded-full border border-slate-800">vs</span>
|
| 101 |
+
|
| 102 |
<div className="flex flex-col items-center w-1/3">
|
| 103 |
<span className="text-lg font-bold text-slate-100">{getShortName(match.away_team)}</span>
|
| 104 |
{/* UPDATED: Larger, bolder xG text */}
|
frontend/src/components/ProjectionsTable.jsx
CHANGED
|
@@ -278,7 +278,12 @@ export default function ProjectionsTable() {
|
|
| 278 |
if (setGlobalPlayers) {
|
| 279 |
setGlobalPlayers(prev => prev.map(p => {
|
| 280 |
const newBaseline = type === 'baseline' ? (valueStr === '' ? null : value) : (activeBaseline !== undefined ? activeBaseline : p.baseline_xMins);
|
| 281 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 282 |
return p;
|
| 283 |
}));
|
| 284 |
}
|
|
|
|
| 278 |
if (setGlobalPlayers) {
|
| 279 |
setGlobalPlayers(prev => prev.map(p => {
|
| 280 |
const newBaseline = type === 'baseline' ? (valueStr === '' ? null : value) : (activeBaseline !== undefined ? activeBaseline : p.baseline_xMins);
|
| 281 |
+
|
| 282 |
+
if (p.ID === playerId) {
|
| 283 |
+
// THE FIX: Protect the original match dictionary so Python doesn't wipe out the DGW tags!
|
| 284 |
+
const pristineMatches = p.match_projections;
|
| 285 |
+
return { ...p, ...updatedRow, match_projections: pristineMatches, baseline_xMins: newBaseline };
|
| 286 |
+
}
|
| 287 |
return p;
|
| 288 |
}));
|
| 289 |
}
|