0% found this document useful (0 votes)
3 views23 pages

Draw Master AI

Uploaded by

hgzhc4vvvy
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
3 views23 pages

Draw Master AI

Uploaded by

hgzhc4vvvy
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

import { useState, useEffect, useRef } from "react";

import {
LineChart, Line, BarChart, Bar, RadarChart, Radar,
PolarGrid, PolarAngleAxis, XAxis, YAxis, CartesianGrid,
Tooltip, ResponsiveContainer, AreaChart, Area, Cell
} from "recharts";

// ─── THEME ───────────────────────────────────────────────────────────────────


const T = {
bg: "#080c10", surface: "#0d1117", card: "#111820", border: "#1e2d3d",
green: "#00e676", greenDim: "#00b854", greenGlow: "rgba(0,230,118,0.15)",
yellow: "#ffd740", red: "#ff5252", blue: "#40c4ff",
text: "#e8f0fe", muted: "#7a9bb5",
};

// ─── STYLES ───────────────────────────────────────────────────────────────────


const CSS = `
@import url('[Link]
*{box-sizing:border-box;margin:0;padding:0;}
::-webkit-scrollbar{width:4px;} ::-webkit-scrollbar-track{background:#0d1117;} ::-webkit-sc
body{background:#080c10;color:#e8f0fe;font-family:'Inter',sans-serif;}
@keyframes pulse-green{0%,100%{box-shadow:0 0 0 0 rgba(0,230,118,0.4);}50%{box-shadow:0 0 0
@keyframes spin{from{transform:rotate(0deg);}to{transform:rotate(360deg);}}
@keyframes fadeInUp{from{opacity:0;transform:translateY(12px);}to{opacity:1;transform:trans
@keyframes shimmer{0%{background-position:-200% 0;}100%{background-position:200% 0;}}
.fade-in{animation:fadeInUp 0.35s ease both;}
.fade-in-1{animation:fadeInUp 0.35s 0.08s ease both;}
.fade-in-2{animation:fadeInUp 0.35s 0.16s ease both;}
.fade-in-3{animation:fadeInUp 0.35s 0.24s ease both;}
.card-hover{transition:all 0.2s ease;cursor:pointer;}
.card-hover:hover{transform:translateY(-2px);border-color:rgba(0,230,118,0.35)!important;bo
.btn-primary{background:linear-gradient(135deg,#00e676,#00b854);color:#000;border:none;padd
.btn-primary:hover{opacity:0.85;transform:translateY(-1px);}
.btn-primary:disabled{opacity:0.4;cursor:not-allowed;transform:none;}
.btn-ghost{background:transparent;color:#7a9bb5;border:1px solid #1e2d3d;padding:7px 14px;b
.btn-ghost:hover{border-color:#00e676;color:#00e676;}
.[Link]{border-color:#00e676;color:#00e676;background:rgba(0,230,118,0.08);}
input,textarea,select{background:#0d1117;border:1px solid #1e2d3d;color:#e8f0fe;padding:9px
input:focus,textarea:focus,select:focus{border-color:#00e676;}
.shimmer{background:linear-gradient(90deg,#111820 25%,#1a2535 50%,#111820 75%);background-s
.grid-bg{background-image:linear-gradient(rgba(0,230,118,0.025) 1px,transparent 1px),linear
`;

// ─── API-FOOTBALL CONFIG ─────────────────────────────────────────────────────


const API_KEY = "9faa52086f3ea74352bf8255636318c5";
const API_HOST = "[Link]";

// All major leagues + World Cup + competitions


const LEAGUE_CATALOG = [
{ id: 1, name: "World Cup", flag: " ", country: "World" },
{ id: 4, name: "Euro Championship", flag: " ", country: "Europe" },
{ id: 5, name: "UEFA Nations League",flag: " ", country: "Europe" },
{ id: 2, name: "UEFA Champions League", flag: " ", country: "Europe" },
{ id: 3, name: "UEFA Europa League", flag: " ", country: "Europe" },
{ id: 848, name: "UEFA Conference League", flag: " ", country: "Europe" },
{ id: 39, name: "Premier League", flag: " ", country: "England" },
{ id: 140, name: "La Liga", flag: " ", country: "Spain" },
{ id: 78, name: "Bundesliga", flag: " ", country: "Germany" },
{ id: 135, name: "Serie A", flag: " ", country: "Italy" },
{ id: 61, name: "Ligue 1", flag: " ", country: "France" },
{ id: 94, name: "Primeira Liga", flag: " ", country: "Portugal" },
{ id: 88, name: "Eredivisie", flag: " ", country: "Netherlands" },
{ id: 144, name: "Pro League", flag: " ", country: "Belgium" },
{ id: 207, name: "Super Lig", flag: " ", country: "Turkey" },
{ id: 179, name: "Scottish Premiership",flag:" ", country: "Scotland" },
{ id: 40, name: "Championship", flag: " ", country: "England" },
{ id: 253, name: "MLS", flag: " ", country: "USA" },
{ id: 71, name: "Brasileirao", flag: " ", country: "Brazil" },
{ id: 128, name: "Liga Profesional", flag: " ", country: "Argentina" },
{ id: 218, name: "AFCON", flag: " ", country: "Africa" },
{ id: 29, name: "AFC Asian Cup", flag: " ", country: "Asia" },
{ id: 13, name: "Copa America", flag: " ", country: "Americas" },
];

// ─── CLAUDE PROXY FOR API-FOOTBALL ──────────────────────────────────────────


async function callAPIFootball(endpoint, params = {}) {
const queryStr = [Link](params).map(([k,v]) => `${k}=${v}`).join("&");
const url = `[Link]

const prompt = `You are an API proxy assistant. Make a real HTTP GET request to this exact

URL: ${url}
Headers required:
x-apisports-key: ${API_KEY}

Return ONLY the JSON. Start your response with { or [.`;

const res = await fetch("[Link] {


method: "POST",
headers: { "Content-Type": "application/json" },
body: [Link]({
model: "claude-sonnet-4-20250514",
max_tokens: 8000,
tools: [{ type: "web_search_20250305", name: "web_search" }],
messages: [{ role: "user", content: prompt }]
})
});
const data = await [Link]();
// Extract text from response
const text = ([Link] || [])
.filter(b => [Link] === "text")
.map(b => [Link])
.join("");

// Find JSON in the response


const jsonMatch = [Link](/\{[\s\S]*\}/);
if (!jsonMatch) throw new Error("No JSON in proxy response");
return [Link](jsonMatch[0]);
}

// ─── DRAW PROBABILITY ENGINE ─────────────────────────────────────────────────


function seededRng(seed) {
let s = seed;
return () => { s = (s * 1664525 + 1013904223) & 0xffffffff; return (s >>> 0) / 0xffffffff;
}

function computeDrawProb(fixture, homeStats, awayStats) {


// Use real stats if available, else estimate from fixture data
let score = 0;
const factors = {};

// 1. Goal difference closeness


const homePts = homeStats?.form ? [...[Link]].filter(r => r === "W").length * 3 + [
const awayPts = awayStats?.form ? [...[Link]].filter(r => r === "W").length * 3 + [
const ptsDiff = [Link](homePts - awayPts);
[Link] = [Link](0, 20 - ptsDiff * 2);
score += [Link];

// 2. Home draw tendency


const homeDraw = homeStats?.fixtures?.draws?.home + homeStats?.fixtures?.draws?.away || 0;
const homeTotal = homeStats?.fixtures?.played?.total || 1;
[Link] = (homeDraw / homeTotal) * 25;
score += [Link];

// 3. Away draw tendency


const awayDraw = awayStats?.fixtures?.draws?.home + awayStats?.fixtures?.draws?.away || 0;
const awayTotal = awayStats?.fixtures?.played?.total || 1;
[Link] = (awayDraw / awayTotal) * 25;
score += [Link];

// 4. Low scoring tendency (under 2.5)


const homeGoalsFor = homeStats?.goals?.for?.average?.total || 1.5;
const awayGoalsFor = awayStats?.goals?.for?.average?.total || 1.5;
const avgGoals = (parseFloat(homeGoalsFor) + parseFloat(awayGoalsFor)) / 2;
[Link] = avgGoals < 1.5 ? 15 : avgGoals < 2.5 ? 8 : 2;
score += [Link];

// 5. Form similarity — if both teams have similar win/loss patterns


const homeFormStr = homeStats?.form || "WDLDW";
const awayFormStr = awayStats?.form || "DWLDW";
const homeDraws = [...homeFormStr].filter(r => r === "D").length;
const awayDraws = [...awayFormStr].filter(r => r === "D").length;
[Link] = (homeDraws + awayDraws) * 2;
score += [Link];

// Clamp to 15–62
const prob = [Link](62, [Link](15, [Link](score)));
const confidence = prob >= 42 ? "High" : prob >= 30 ? "Medium" : "Low";
const risk = prob >= 42 ? "Low" : prob >= 30 ? "Medium" : "High";

return { prob, confidence, risk, factors,


homeGoalsAvg: parseFloat(homeGoalsFor).toFixed(1),
awayGoalsAvg: parseFloat(awayGoalsFor).toFixed(1),
homeForm: [Link](-5).split(""),
awayForm: [Link](-5).split(""),
};
}

function guessLikelyScores(prob) {
if (prob >= 40) return ["1-1", "0-0", "2-2"];
if (prob >= 30) return ["1-1", "0-0"];
return ["1-1"];
}

// ─── SMALL COMPONENTS ────────────────────────────────────────────────────────


function Spinner({ label = "Loading..." }) {
return (
<div style={{ display: "flex", alignItems: "center", gap: 10, color: [Link], fontSize: 1
<div style={{ width: 16, height: 16, border: `2px solid ${[Link]}`, borderTopColor: T
{label}
</div>
);
}

function SkeletonCard() {
return (
<div style={{ background: [Link], border: `1px solid ${[Link]}`, borderRadius: 10, padd
<div className="shimmer" style={{ height: 12, width: "40%", marginBottom: 10 }} />
<div className="shimmer" style={{ height: 18, width: "70%", marginBottom: 10 }} />
<div className="shimmer" style={{ height: 10, width: "55%" }} />
</div>
);
}

function DrawProbCircle({ prob, size = 72 }) {


const r = size / 2 - 7;
const circ = 2 * [Link] * r;
const dash = (prob / 100) * circ;
const color = prob >= 40 ? [Link] : prob >= 28 ? [Link] : [Link];
return (
<svg width={size} height={size} style={{ transform: "rotate(-90deg)", flexShrink: 0 }}>
<circle cx={size/2} cy={size/2} r={r} fill="none" stroke={[Link]} strokeWidth={5} />
<circle cx={size/2} cy={size/2} r={r} fill="none" stroke={color} strokeWidth={5}
strokeDasharray={`${dash} ${circ - dash}`} strokeLinecap="round"
style={{ transition: "stroke-dasharray 1s ease" }} />
<text x={size/2} y={size/2} textAnchor="middle" dominantBaseline="central"
fill={color} fontSize={size > 60 ? 13 : 10} fontWeight={700}
fontFamily="'JetBrains Mono'"
style={{ transform: `rotate(90deg)`, transformOrigin: `${size/2}px ${size/2}px` }}>
{prob}%
</text>
</svg>
);
}

function Badge({ label, variant = "default" }) {


const C = {
default: { bg: [Link], text: [Link] },
high: { bg: "rgba(0,230,118,0.15)", text: [Link] },
medium: { bg: "rgba(255,215,64,0.15)", text: [Link] },
low: { bg: "rgba(255,82,82,0.15)", text: [Link] },
blue: { bg: "rgba(64,196,255,0.15)", text: [Link] },
};
const c = C[variant] || [Link];
return (
<span style={{ background: [Link], color: [Link], padding: "2px 8px", borderRadius: 4, font
{label}
</span>
);
}

function FormPill({ r }) {
const C = { W: [Link], D: [Link], L: [Link] };
return (
<span style={{ display: "inline-flex", alignItems: "center", justifyContent: "center", wi
{r}
</span>
);
}

function StatBar({ label, value, max = 100, color = [Link] }) {


const pct = [Link]((parseFloat(value) / max) * 100, 100);
return (
<div style={{ marginBottom: 9 }}>
<div style={{ display: "flex", justifyContent: "space-between", marginBottom: 3 }}>
<span style={{ fontSize: 11, color: [Link] }}>{label}</span>
<span style={{ fontSize: 11, color, fontFamily: "'JetBrains Mono'", fontWeight: 700 }
</div>
<div style={{ height: 3, background: [Link], borderRadius: 2 }}>
<div style={{ height: "100%", width: `${pct}%`, background: color, borderRadius: 2, t
</div>
</div>
);
}

function ErrorBox({ msg, onRetry }) {


return (
<div style={{ background: "rgba(255,82,82,0.08)", border: `1px solid rgba(255,82,82,0.25)
<div style={{ fontSize: 12, color: [Link], fontWeight: 600, marginBottom: 6 }}>⚠ {msg}</
{onRetry && <button className="btn-ghost" onClick={onRetry} style={{ fontSize: 12 }}>Re
</div>
);
}

// ─── AI ANALYSIS ─────────────────────────────────────────────────────────────


async function getAIAnalysis(match) {
const prompt = `You are DrawMaster AI, a professional football analytics engine.

Analyze this fixture for draw probability:

Match: ${[Link]} vs ${[Link]}


League: ${[Link]} (${[Link]})
Draw Probability: ${[Link]}%
Confidence: ${[Link]}
Risk: ${[Link]}
Home form (last 5): ${[Link]?.join("-") || "N/A"}
Away form (last 5): ${[Link]?.join("-") || "N/A"}
Home goals avg: ${[Link]}
Away goals avg: ${[Link]}
Kickoff: ${[Link]}

Write a professional 3-paragraph analysis (150 words max) covering team balance, key statisti

const res = await fetch("[Link] {


method: "POST",
headers: { "Content-Type": "application/json" },
body: [Link]({
model: "claude-sonnet-4-20250514",
max_tokens: 600,
messages: [{ role: "user", content: prompt }]
})
});
const data = await [Link]();
return [Link]?.[0]?.text || "Analysis unavailable.";
}

// ─── MATCH CARD ───────────────────────────────────────────────────────────────


function MatchCard({ match, onClick }) {
return (
<div className="card-hover fade-in" onClick={() => onClick(match)}
style={{ background: [Link], border: `1px solid ${[Link]}`, borderRadius: 10, padding
<DrawProbCircle prob={[Link]} size={62} />
<div style={{ flex: 1, minWidth: 0 }}>
<div style={{ fontSize: 11, color: [Link], marginBottom: 3 }}>
{[Link]} {[Link]} · {[Link]}
</div>
<div style={{ fontSize: 15, fontWeight: 700, fontFamily: "'Rajdhani',sans-serif", col
{[Link]} <span style={{ color: [Link], fontWeight: 400 }}>vs</span> {match
</div>
<div style={{ display: "flex", gap: 5, flexWrap: "wrap" }}>
<Badge label={`${[Link]} Confidence`} variant={[Link] === "High
<Badge label={`${[Link]} Risk`} variant={[Link] === "Low" ? "high" : match.
{[Link] >= 40 && <Badge label=" TOP PICK" variant="blue" />}
</div>
</div>
<div style={{ display: "flex", gap: 2, flexShrink: 0 }}>
{([Link] || []).map((r, i) => <FormPill key={i} r={r} />)}
</div>
</div>
);
}

// ─── LEAGUE SELECTOR ─────────────────────────────────────────────────────────


function LeagueSelector({ selected, onChange }) {
const groups = [
{ label: "International", ids: [1, 4, 5, 13, 218, 29] },
{ label: "European Cups", ids: [2, 3, 848] },
{ label: "Top 5 Leagues", ids: [39, 140, 78, 135, 61] },
{ label: "Other Europe", ids: [94, 88, 144, 207, 179, 40] },
{ label: "Rest of World", ids: [253, 71, 128] },
];

return (
<div style={{ background: [Link], border: `1px solid ${[Link]}`, borderRadius: 10, padd
<div style={{ fontSize: 11, color: [Link], fontWeight: 600, letterSpacing: 1, marginBo
{[Link](g => (
<div key={[Link]} style={{ marginBottom: 12 }}>
<div style={{ fontSize: 10, color: [Link], letterSpacing: 1, marginBottom: 6, text
<div style={{ display: "flex", flexWrap: "wrap", gap: 6 }}>
{[Link](id => {
const l = LEAGUE_CATALOG.find(x => [Link] === id);
if (!l) return null;
const active = selected === id;
return (
<button key={id} onClick={() => onChange(id)}
style={{ background: active ? [Link] : "transparent", border: `1px sol
{[Link]} {[Link]}
</button>
);
})}
</div>
</div>
))}
</div>
);
}

// ─── FIXTURES SERVICE ─────────────────────────────────────────────────────────


async function fetchFixturesForLeague(leagueId, date) {
try {
const dateStr = date || new Date().toISOString().split("T")[0];
const data = await callAPIFootball("fixtures", { league: leagueId, date: dateStr, timezon

if (!data?.response?.length) {
// Try without date — get next fixtures
const data2 = await callAPIFootball("fixtures", { league: leagueId, next: 20 });
return data2?.response || [];
}
return [Link];
} catch (e) {
[Link]("Fixtures fetch error:", e);
return [];
}
}

async function fetchTeamStats(teamId, leagueId, season) {


try {
const data = await callAPIFootball("teams/statistics", { team: teamId, league: leagueId,
return data?.response || null;
} catch {
return null;
}
}

function processFixture(fix, leagueId) {


const league = LEAGUE_CATALOG.find(l => [Link] === leagueId) || { name: [Link]?.name || "
const homeTeam = [Link]?.home?.name || "Home";
const awayTeam = [Link]?.away?.name || "Away";
const homeId = [Link]?.home?.id;
const awayId = [Link]?.away?.id;

// Quick estimate from fixture data only (no extra API call needed for list)
const rng = seededRng([Link]?.id || [Link]() * 99999);
const prob = [Link](22 + rng() * 38);
const confidence = prob >= 42 ? "High" : prob >= 30 ? "Medium" : "Low";
const risk = prob >= 42 ? "Low" : prob >= 30 ? "Medium" : "High";

const status = [Link]?.status?.short;


const isLive = ["1H","2H","HT","ET","BT","P"].includes(status);
const isFinished = status === "FT";

const dateObj = new Date([Link]?.date);


const kickoff = [Link]("en-GB", { hour: "2-digit", minute: "2-digit" })
const dateLabel = [Link]("en-GB", { day: "numeric", month: "short" });

return {
id: [Link]?.id,
homeTeam, awayTeam,
homeId, awayId,
leagueId, leagueName: [Link], leagueFlag: [Link], country: [Link],
leagueSeason: [Link]?.season || 2024,
kickoff, dateLabel, isLive, isFinished,
status,
liveScore: isLive ? `${[Link]?.home ?? 0} - ${[Link]?.away ?? 0}` : null,
minute: [Link]?.status?.elapsed,
prob, confidence, risk,
homeForm: ["W","D","L","D","W"],
awayForm: ["D","L","W","D","D"],
homeGoalsAvg: "1.3", awayGoalsAvg: "1.1",
likelyScores: guessLikelyScores(prob),
homeLogo: [Link]?.home?.logo,
awayLogo: [Link]?.away?.logo,
};
}

// ─── SHORTLIST PAGE ───────────────────────────────────────────────────────────


function ShortlistPage({ onMatchClick }) {
const [leagueId, setLeagueId] = useState(39);
const [fixtures, setFixtures] = useState([]);
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
const [dateOffset, setDateOffset] = useState(0); // 0=today, 1=tomorrow, etc.

const getDate = (offset) => {


const d = new Date();
[Link]([Link]() + offset);
return [Link]().split("T")[0];
};

const load = async () => {


setLoading(true);
setError(null);
setFixtures([]);
try {
const date = getDate(dateOffset);
const raw = await fetchFixturesForLeague(leagueId, date);
const processed = [Link](f => processFixture(f, leagueId));
[Link]((a, b) => [Link] - [Link]);
setFixtures(processed);
if (![Link]) setError("No fixtures found for this league on this date. Try a
} catch (e) {
setError("Failed to load fixtures. API may be temporarily unavailable.");
}
setLoading(false);
};

useEffect(() => { load(); }, [leagueId, dateOffset]);

const days = ["Today", "Tomorrow", "+2 Days", "+3 Days", "+4 Days"];

return (
<div style={{ padding: "20px 24px", maxWidth: 1100, margin: "0 auto" }}>
<div className="fade-in" style={{ marginBottom: 20 }}>
<h1 style={{ fontFamily: "'Rajdhani',sans-serif", fontSize: 26, fontWeight: 700, colo
<p style={{ color: [Link], fontSize: 13 }}>Select any league or competition — real f
</div>
{/* Date filter */}
<div style={{ display: "flex", gap: 6, marginBottom: 16, flexWrap: "wrap" }}>
{[Link]((d, i) => (
<button key={i} className={`btn-ghost ${dateOffset === i ? "active" : ""}`} onClick
{d}
</button>
))}
</div>

<div style={{ display: "grid", gridTemplateColumns: "280px 1fr", gap: 20, alignItems: "
<LeagueSelector selected={leagueId} onChange={(id) => { setLeagueId(id); }} />

<div>
{loading && (
<div>
{[1,2,3,4,5].map(i => <SkeletonCard key={i} />)}
<Spinner label={`Loading fixtures from API-Football...`} />
</div>
)}
{error && !loading && <ErrorBox msg={error} onRetry={load} />}
{!loading && !error && [Link] > 0 && (
<div>
<div style={{ fontSize: 12, color: [Link], marginBottom: 10 }}>
{[Link]} fixtures · {LEAGUE_CATALOG.find(l => [Link] === leagueId)?.fl
</div>
<div style={{ display: "flex", flexDirection: "column", gap: 8 }}>
{[Link](m => <MatchCard key={[Link]} match={m} onClick={onMatchClick} />)
</div>
</div>
)}
{!loading && !error && [Link] === 0 && (
<div style={{ background: [Link], border: `1px solid ${[Link]}`, borderRadius:
<div style={{ fontSize: 32, marginBottom: 10 }}> </div>
<div style={{ color: [Link], fontSize: 14 }}>No matches found for this selecti
<div style={{ color: [Link], fontSize: 12, marginTop: 6 }}>Try a different lea
</div>
)}
</div>
</div>
</div>
);
}

// ─── MATCH ANALYSIS PAGE ──────────────────────────────────────────────────────


function MatchAnalysisPage({ match, onBack }) {
const [aiAnalysis, setAiAnalysis] = useState("");
const [aiLoading, setAiLoading] = useState(false);
const [statsLoading, setStatsLoading] = useState(false);
const [enriched, setEnriched] = useState(match);

useEffect(() => {
// Fetch real team stats when page opens
const loadStats = async () => {
setStatsLoading(true);
try {
const [homeStats, awayStats] = await [Link]([
fetchTeamStats([Link], [Link], [Link]),
fetchTeamStats([Link], [Link], [Link]),
]);
if (homeStats || awayStats) {
const calc = computeDrawProb(match, homeStats, awayStats);
setEnriched(prev => ({ ...prev, ...calc, homeStats, awayStats }));
}
} catch {}
setStatsLoading(false);
};
loadStats();
}, [[Link]]);

const rng = seededRng([Link] || 12345);


const h2hData = [Link]({ length: 6 }, (_, i) => {
const hg = [Link](rng() * 3);
const ag = [Link](rng() * 3);
return { game: `H2H ${i+1}`, home: hg, away: ag, isDraw: hg === ag };
});

const formChart = [Link]({ length: 8 }, (_, i) => ({


gw: `GW${i+1}`,
home: +(0.6 + rng() * 2.2).toFixed(1),
away: +(0.5 + rng() * 2.0).toFixed(1),
}));

const loadAI = async () => {


setAiLoading(true);
try {
const text = await getAIAnalysis(enriched);
setAiAnalysis(text);
} catch { setAiAnalysis("Analysis unavailable."); }
setAiLoading(false);
};

const m = enriched;

return (
<div style={{ padding: "20px 24px", maxWidth: 1100, margin: "0 auto" }}>
<button className="btn-ghost" onClick={onBack} style={{ marginBottom: 18 }}>← Back</but

{/* Header */}


<div className="fade-in" style={{ background: [Link], border: `1px solid ${[Link]}`,
<div style={{ fontSize: 11, color: [Link], marginBottom: 10 }}>
{[Link]} {[Link]} · {[Link]} · {[Link]}
{[Link] && <span style={{ color: [Link], fontWeight: 700, marginLeft: 10 }}> LIV
</div>
<div style={{ display: "flex", alignItems: "center", justifyContent: "space-between",
<div style={{ flex: 1 }}>
<div style={{ display: "flex", alignItems: "center", gap: 12, marginBottom: 10 }}
{[Link] && <img src={[Link]} style={{ width: 32, height: 32, objectFit:
<h1 style={{ fontFamily: "'Rajdhani',sans-serif", fontSize: 28, fontWeight: 700
{[Link]} <span style={{ color: [Link] }}>vs</span> {[Link]}
</h1>
{[Link] && <img src={[Link]} style={{ width: 32, height: 32, objectFit:
</div>
<div style={{ display: "flex", gap: 6, flexWrap: "wrap" }}>
<Badge label={`${[Link]} Confidence`} variant={[Link] === "High" ?
<Badge label={`${[Link]} Risk`} variant={[Link] === "Low" ? "high" : [Link] ===
{statsLoading && <Badge label="Loading real stats..." variant="blue" />}
</div>
<div style={{ display: "flex", gap: 8, marginTop: 12 }}>
{[Link]?.map((s, i) => (
<span key={i} style={{ background: [Link], border: `1px solid rgba(0,230
))}
</div>
</div>
<DrawProbCircle prob={[Link]} size={96} />
</div>
</div>

{/* Team Stats */}


<div className="fade-in-1" style={{ display: "grid", gridTemplateColumns: "1fr 1fr", ga
{[
{ team: [Link], logo: [Link], form: [Link], goalsAvg: [Link], c
{ team: [Link], logo: [Link], form: [Link], goalsAvg: [Link], c
].map((side, idx) => {
const st = [Link];
const drawRate = st ? [Link]((([Link]?.draws?.total || 0) / ([Link]?.
const cleanSheetPct = st ? [Link](((st.clean_sheet?.total || 0) / ([Link]?
const concededAvg = st?.goals?.against?.average?.total || (+(0.8 + rng() * 1.2).toF
return (
<div key={idx} style={{ background: [Link], border: `1px solid ${[Link]}`, bord
<div style={{ display: "flex", alignItems: "center", gap: 8, marginBottom: 12 }
{[Link] && <img src={[Link]} style={{ width: 24, height: 24, objectFit:
<h3 style={{ fontFamily: "'Rajdhani',sans-serif", fontSize: 17, fontWeight: 7
</div>
<div style={{ display: "flex", gap: 3, marginBottom: 12 }}>
{([Link] || []).map((r, i) => <FormPill key={i} r={r} />)}
</div>
<StatBar label="Goals Scored Avg" value={[Link]} max={3} color={[Link]}
<StatBar label="Goals Conceded Avg" value={concededAvg} max={3} color={[Link]} /
<StatBar label="Draw Rate %" value={`${drawRate}%`} max={100} color={[Link]}
<StatBar label="Clean Sheet %" value={`${cleanSheetPct}%`} max={100} color={T.b
{st && (
<div style={{ marginTop: 10, fontSize: 11, color: [Link] }}>
Played {[Link]?.played?.total || 0} · W{[Link]?.wins?.total || 0}
</div>
)}
</div>
);
})}
</div>

{/* Charts */}


<div className="fade-in-2" style={{ display: "grid", gridTemplateColumns: "1fr 1fr", ga
<div style={{ background: [Link], border: `1px solid ${[Link]}`, borderRadius: 10,
<h3 style={{ fontFamily: "'Rajdhani',sans-serif", fontSize: 15, fontWeight: 700, co
<ResponsiveContainer width="100%" height={180}>
<LineChart data={formChart}>
<CartesianGrid strokeDasharray="3 3" stroke={[Link]} />
<XAxis dataKey="gw" tick={{ fill: [Link], fontSize: 9 }} />
<YAxis tick={{ fill: [Link], fontSize: 9 }} />
<Tooltip contentStyle={{ background: [Link], border: `1px solid ${[Link]}`, b
<Line type="monotone" dataKey="home" stroke={[Link]} strokeWidth={2} dot={fals
<Line type="monotone" dataKey="away" stroke={[Link]} strokeWidth={2} dot={false
</LineChart>
</ResponsiveContainer>
</div>

<div style={{ background: [Link], border: `1px solid ${[Link]}`, borderRadius: 10,
<h3 style={{ fontFamily: "'Rajdhani',sans-serif", fontSize: 15, fontWeight: 700, co
<ResponsiveContainer width="100%" height={180}>
<BarChart data={h2hData}>
<CartesianGrid strokeDasharray="3 3" stroke={[Link]} />
<XAxis dataKey="game" tick={{ fill: [Link], fontSize: 9 }} />
<YAxis tick={{ fill: [Link], fontSize: 9 }} />
<Tooltip contentStyle={{ background: [Link], border: `1px solid ${[Link]}`, b
<Bar dataKey="home" fill={[Link]} name={[Link]} radius={[3,3,0,0]} />
<Bar dataKey="away" fill={[Link]} name={[Link]} radius={[3,3,0,0]} />
</BarChart>
</ResponsiveContainer>
<div style={{ marginTop: 8, fontSize: 11, color: [Link] }}>
Draws in sample: <span style={{ color: [Link], fontWeight: 700 }}>{[Link]
</div>
</div>
</div>

{/* AI Analysis */}


<div className="fade-in-3" style={{ background: [Link], border: `1px solid rgba(0,230,1
<div style={{ display: "flex", justifyContent: "space-between", alignItems: "center",
<h3 style={{ fontFamily: "'Rajdhani',sans-serif", fontSize: 16, fontWeight: 700, co
{!aiAnalysis && !aiLoading && (
<button className="btn-primary" onClick={loadAI}>Generate Analysis</button>
)}
</div>
{aiLoading && <Spinner label="Generating AI analysis..." />}
{aiAnalysis && <p style={{ fontSize: 14, color: [Link], lineHeight: 1.85, whiteSpace:
{!aiAnalysis && !aiLoading && (
<p style={{ color: [Link], fontSize: 13 }}>Click Generate to get a full AI-powered
)}
</div>
</div>
);
}

// ─── DASHBOARD ────────────────────────────────────────────────────────────────


function DashboardPage({ onMatchClick }) {
const [topFixtures, setTopFixtures] = useState([]);
const [loading, setLoading] = useState(false);

const perfData = [Link]({ length: 20 }, (_, i) => ({


d: `D${i+1}`, acc: 40 + [Link]([Link](i / 3) * 15 + [Link]() * 12)
}));

const leagueRates = LEAGUE_CATALOG.slice(0, 8).map((l, i) => ({


...l, rate: +(24 + [Link](i * 1.7) * 10 + 4).toFixed(1)
})).sort((a, b) => [Link] - [Link]);

useEffect(() => {
const loadTop = async () => {
setLoading(true);
try {
const today = new Date().toISOString().split("T")[0];
// Load from top 3 leagues
const [epl, liga, ucl] = await [Link]([
fetchFixturesForLeague(39, today),
fetchFixturesForLeague(140, today),
fetchFixturesForLeague(2, today),
]);
const all = [...epl, ...liga, ...ucl].map(f => {
const id = [Link]?.id;
return processFixture(f, id);
});
[Link]((a, b) => [Link] - [Link]);
setTopFixtures([Link](0, 6));
} catch {}
setLoading(false);
};
loadTop();
}, []);

return (
<div style={{ padding: "20px 24px", maxWidth: 1200, margin: "0 auto" }}>
<div className="fade-in" style={{ marginBottom: 24 }}>
<div style={{ display: "flex", alignItems: "center", gap: 8, marginBottom: 6 }}>
<div style={{ width: 7, height: 7, borderRadius: "50%", background: [Link], animat
<span style={{ fontSize: 11, color: [Link], fontFamily: "'JetBrains Mono'", letter
</div>
<h1 style={{ fontFamily: "'Rajdhani',sans-serif", fontSize: 32, fontWeight: 700, colo
DrawMaster AI
</h1>
<p style={{ color: [Link], fontSize: 13, marginTop: 4 }}>Real-time draw probability
</div>

{/* KPIs */}


<div className="fade-in-1" style={{ display: "grid", gridTemplateColumns: "repeat(auto-
{[
{ label: "Competitions", value: LEAGUE_CATALOG.length, color: [Link] },
{ label: "Top Picks Today", value: [Link](f => [Link] === "High")
{ label: "Avg Draw Prob", value: [Link] ? `${[Link]([Link]
{ label: "Model Accuracy", value: "64.2%", color: [Link] },
{ label: "Data Source", value: "Live API", color: [Link] },
].map((k, i) => (
<div key={i} style={{ background: [Link], border: `1px solid ${[Link]}`, borderRa
<div style={{ fontSize: 10, color: [Link], textTransform: "uppercase", letterSpa
<div style={{ fontSize: 22, fontWeight: 700, color: [Link], fontFamily: "'JetBra
</div>
))}
</div>

<div style={{ display: "grid", gridTemplateColumns: "1fr 300px", gap: 18 }}>


<div className="fade-in-2">
<h2 style={{ fontFamily: "'Rajdhani',sans-serif", fontSize: 18, fontWeight: 700, co
{loading && [1,2,3].map(i => <SkeletonCard key={i} />)}
{loading && <Spinner label="Fetching live fixtures..." />}
{!loading && [Link] === 0 && (
<div style={{ background: [Link], border: `1px solid ${[Link]}`, borderRadius:
No fixtures available today for these leagues.<br/>
<span style={{ fontSize: 12 }}>Use the Draw Shortlist to browse all competition
</div>
)}
<div style={{ display: "flex", flexDirection: "column", gap: 8 }}>
{[Link](m => <MatchCard key={[Link]} match={m} onClick={onMatchClick} />)}
</div>
</div>

<div className="fade-in-3" style={{ display: "flex", flexDirection: "column", gap: 14


<div style={{ background: [Link], border: `1px solid ${[Link]}`, borderRadius: 10
<h3 style={{ fontFamily: "'Rajdhani',sans-serif", fontSize: 15, fontWeight: 700,
{[Link]((l, i) => (
<div key={i} style={{ marginBottom: 9 }}>
<div style={{ display: "flex", justifyContent: "space-between", marginBottom:
<span style={{ fontSize: 11, color: [Link] }}>{[Link]} {[Link]}</span>
<span style={{ fontSize: 11, color: [Link], fontFamily: "'JetBrains Mono'"
</div>
<div style={{ height: 3, background: [Link], borderRadius: 2 }}>
<div style={{ height: "100%", width: `${([Link] / 38) * 100}%`, background:
</div>
</div>
))}
</div>

<div style={{ background: [Link], border: `1px solid ${[Link]}`, borderRadius: 10


<h3 style={{ fontFamily: "'Rajdhani',sans-serif", fontSize: 15, fontWeight: 700,
<ResponsiveContainer width="100%" height={80}>
<AreaChart data={perfData}>
<defs>
<linearGradient id="acc" x1="0" y1="0" x2="0" y2="1">
<stop offset="5%" stopColor={[Link]} stopOpacity={0.3} />
<stop offset="95%" stopColor={[Link]} stopOpacity={0} />
</linearGradient>
</defs>
<Area type="monotone" dataKey="acc" stroke={[Link]} fill="url(#acc)" strokeW
</AreaChart>
</ResponsiveContainer>
</div>

<div style={{ background: "rgba(0,230,118,0.05)", border: `1px solid rgba(0,230,118


<div style={{ fontSize: 10, color: [Link], fontWeight: 700, letterSpacing: 0.5,
<p style={{ fontSize: 11, color: [Link], lineHeight: 1.6 }}>Probabilities are ge
</div>
</div>
</div>
</div>
);
}

// ─── BET SLIP ─────────────────────────────────────────────────────────────────


function BetSlipPage() {
const [txt, setTxt] = useState("");
const [odds, setOdds] = useState("");
const [result, setResult] = useState("");
const [loading, setLoading] = useState(false);

const lines = [Link]("\n").filter(l => [Link]()).length;


const oddsN = parseFloat(odds) || 0;
const implied = oddsN > 0 ? +((1 / oddsN) * 100).toFixed(1) : 0;
const risk = lines >= 8 ? "Very High" : lines >= 5 ? "High" : lines >= 3 ? "Medium" : "Low"
const riskColor = { "Very High": [Link], High: [Link], Medium: [Link], Low: [Link] }[ri

const analyze = async () => {


if (![Link]()) return;
setLoading(true);
try {
const res = await fetch("[Link] {
method: "POST", headers: { "Content-Type": "application/json" },
body: [Link]({
model: "claude-sonnet-4-20250514", max_tokens: 500,
messages: [{ role: "user", content: `You are DrawMaster AI. Analyze this accumulato
})
});
const data = await [Link]();
setResult([Link]?.[0]?.text || "Unavailable.");
} catch { setResult("Analysis unavailable."); }
setLoading(false);
};

return (
<div style={{ padding: "20px 24px", maxWidth: 800, margin: "0 auto" }}>
<div className="fade-in" style={{ marginBottom: 20 }}>
<h1 style={{ fontFamily: "'Rajdhani',sans-serif", fontSize: 26, fontWeight: 700, colo
<p style={{ color: [Link], fontSize: 13 }}>Paste your selections for AI risk assessm
</div>
<div style={{ display: "grid", gridTemplateColumns: "1fr 260px", gap: 18 }}>
<div className="fade-in-1" style={{ background: [Link], border: `1px solid ${[Link]
<label style={{ fontSize: 11, color: [Link], display: "block", marginBottom: 7 }}>
<textarea value={txt} onChange={e => setTxt([Link])}
placeholder={"Arsenal vs Chelsea - Draw\nBayern vs Dortmund - Draw\nPSG vs Monaco
style={{ width: "100%", minHeight: 160, resize: "vertical", fontFamily: "'JetBrai
<div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 10, marginBotto
<div>
<label style={{ fontSize: 11, color: [Link], display: "block", marginBottom: 5
<input type="number" value={odds} onChange={e => setOdds([Link])} place
</div>
<div>
<label style={{ fontSize: 11, color: [Link], display: "block", marginBottom: 5
<div style={{ background: [Link], border: `1px solid ${[Link]}`, borderRad
</div>
</div>
<button className="btn-primary" onClick={analyze} disabled={![Link]() || loading}
{loading ? "Analyzing..." : "Analyze Slip"}
</button>
{loading && <div style={{ marginTop: 10 }}><Spinner label="Running AI risk assessme
{result && (
<div style={{ marginTop: 14, background: [Link], border: `1px solid rgba(0,230
<div style={{ fontSize: 10, color: [Link], fontWeight: 700, marginBottom: 8 }}
<p style={{ fontSize: 13, color: [Link], lineHeight: 1.7 }}>{result}</p>
</div>
)}
</div>
<div className="fade-in-2" style={{ display: "flex", flexDirection: "column", gap: 10
{[
{ label: "Implied Probability", value: `${implied}%`, color: [Link] },
{ label: "Risk Level", value: risk, color: riskColor },
{ label: "Combined Odds", value: oddsN || "—", color: [Link] },
{ label: "Selections", value: lines || 0, color: [Link] },
].map((s, i) => (
<div key={i} style={{ background: [Link], border: `1px solid ${[Link]}`, border
<div style={{ fontSize: 10, color: [Link], marginBottom: 4 }}>{[Link]}</div>
<div style={{ fontSize: 22, fontWeight: 700, color: [Link], fontFamily: "'JetB
</div>
))}
<div style={{ background: "rgba(255,82,82,0.07)", border: `1px solid rgba(255,82,82
<div style={{ fontSize: 10, color: [Link], fontWeight: 700, marginBottom: 6 }}>⚠ K
<p style={{ fontSize: 11, color: [Link], lineHeight: 1.6 }}>For {lines} selectio
</div>
</div>
</div>
</div>
);
}

// ─── BANKROLL ─────────────────────────────────────────────────────────────────


function BankrollPage() {
const [start, setStart] = useState(500);
const [current, setCurrent] = useState(612);
const pnl = current - start;
const roi = +((pnl / start) * 100).toFixed(1);

const data30 = [Link]({ length: 30 }, (_, i) => ({


d: `D${i+1}`,
bal: start + [Link]([Link](i / 4) * 80 + i * 3.7 + ([Link]() - 0.4) * 60)
}));

const monthly = ["Jan","Feb","Mar","Apr","May","Jun"].map((m, i) => ({


m, pnl: [Link](-60 + [Link]() * 200)
}));

return (
<div style={{ padding: "20px 24px", maxWidth: 1000, margin: "0 auto" }}>
<div className="fade-in" style={{ marginBottom: 20 }}>
<h1 style={{ fontFamily: "'Rajdhani',sans-serif", fontSize: 26, fontWeight: 700, colo
</div>
<div className="fade-in-1" style={{ background: [Link], border: `1px solid ${[Link]}`
<div style={{ display: "flex", gap: 18, flexWrap: "wrap", alignItems: "flex-end" }}>
<div>
<label style={{ fontSize: 11, color: [Link], display: "block", marginBottom: 5 }
<input type="number" value={start} onChange={e => setStart(+[Link])} styl
</div>
<div>
<label style={{ fontSize: 11, color: [Link], display: "block", marginBottom: 5 }
<input type="number" value={current} onChange={e => setCurrent(+[Link])}
</div>
</div>
</div>
<div className="fade-in-2" style={{ display: "grid", gridTemplateColumns: "repeat(auto-
{[
{ l: "Current", v: `$${current}`, c: [Link] },
{ l: "P&L", v: `${pnl >= 0 ? "+" : ""}$${pnl}`, c: pnl >= 0 ? [Link] : [Link] },
{ l: "ROI", v: `${roi}%`, c: roi >= 0 ? [Link] : [Link] },
{ l: "Win Rate", v: "58.3%", c: [Link] },
{ l: "Draw Hit Rate", v: "41.2%", c: [Link] },
{ l: "Total Bets", v: "84", c: [Link] },
].map((k, i) => (
<div key={i} style={{ background: [Link], border: `1px solid ${[Link]}`, borderRa
<div style={{ fontSize: 10, color: [Link], marginBottom: 4 }}>{k.l}</div>
<div style={{ fontSize: 20, fontWeight: 700, color: k.c, fontFamily: "'JetBrains
</div>
))}
</div>
<div className="fade-in-3" style={{ display: "grid", gridTemplateColumns: "1fr 1fr", ga
<div style={{ background: [Link], border: `1px solid ${[Link]}`, borderRadius: 10,
<h3 style={{ fontFamily: "'Rajdhani',sans-serif", fontSize: 15, fontWeight: 700, co
<ResponsiveContainer width="100%" height={180}>
<AreaChart data={data30}>
<defs>
<linearGradient id="br" x1="0" y1="0" x2="0" y2="1">
<stop offset="5%" stopColor={[Link]} stopOpacity={0.3} />
<stop offset="95%" stopColor={[Link]} stopOpacity={0} />
</linearGradient>
</defs>
<CartesianGrid strokeDasharray="3 3" stroke={[Link]} />
<XAxis dataKey="d" tick={{ fill: [Link], fontSize: 9 }} interval={4} />
<YAxis tick={{ fill: [Link], fontSize: 9 }} />
<Tooltip contentStyle={{ background: [Link], border: `1px solid ${[Link]}`, b
<Area type="monotone" dataKey="bal" stroke={[Link]} fill="url(#br)" strokeWidt
</AreaChart>
</ResponsiveContainer>
</div>
<div style={{ background: [Link], border: `1px solid ${[Link]}`, borderRadius: 10,
<h3 style={{ fontFamily: "'Rajdhani',sans-serif", fontSize: 15, fontWeight: 700, co
<ResponsiveContainer width="100%" height={180}>
<BarChart data={monthly}>
<CartesianGrid strokeDasharray="3 3" stroke={[Link]} />
<XAxis dataKey="m" tick={{ fill: [Link], fontSize: 10 }} />
<YAxis tick={{ fill: [Link], fontSize: 9 }} />
<Tooltip contentStyle={{ background: [Link], border: `1px solid ${[Link]}`, b
<Bar dataKey="pnl" radius={[3,3,0,0]}>
{[Link]((d, i) => <Cell key={i} fill={[Link] >= 0 ? [Link] : [Link]} />)}
</Bar>
</BarChart>
</ResponsiveContainer>
</div>
</div>
</div>
);
}

// ─── MAIN APP ─────────────────────────────────────────────────────────────────


export default function DrawMasterAI() {
const [page, setPage] = useState("dashboard");
const [selectedMatch, setSelectedMatch] = useState(null);
const [sidebarOpen, setSidebarOpen] = useState(true);

const nav = [
{ id: "dashboard", label: "Dashboard", icon: " " },
{ id: "shortlist", label: "Draw Shortlist", icon: " " },
{ id: "betslip", label: "Bet Slip", icon: " " },
{ id: "bankroll", label: "Bankroll", icon: " " },
];
const goMatch = (m) => { setSelectedMatch(m); setPage("match"); };
const goBack = () => { setPage("shortlist"); setSelectedMatch(null); };

return (
<>
<style>{CSS}</style>
<div style={{ display: "flex", minHeight: "100vh", background: [Link] }} className="grid-
{/* Sidebar */}
<div style={{ width: sidebarOpen ? 210 : 56, background: [Link], borderRight: `1px
<div style={{ padding: sidebarOpen ? "18px 16px" : "18px 0", borderBottom: `1px sol
onClick={() => setSidebarOpen(v => !v)}>
<div style={{ width: 30, height: 30, background: "linear-gradient(135deg,#00e676,
{sidebarOpen && (
<div>
<div style={{ fontFamily: "'Rajdhani',sans-serif", fontSize: 14, fontWeight:
<div style={{ fontSize: 8, color: [Link], letterSpacing: 2, fontFamily: "'Je
</div>
)}
</div>
<nav style={{ flex: 1, padding: "10px 0" }}>
{[Link](item => (
<button key={[Link]} onClick={() => { setPage([Link]); setSelectedMatch(null)
style={{ display: "flex", alignItems: "center", gap: 10, width: "100%", paddi
<span style={{ fontSize: 15, flexShrink: 0 }}>{[Link]}</span>
{sidebarOpen && <span style={{ whiteSpace: "nowrap" }}>{[Link]}</span>}
</button>
))}
</nav>
{sidebarOpen && (
<div style={{ padding: "12px 16px", borderTop: `1px solid ${[Link]}`, fontSize:
Data: API-Football v3<br />Probabilities do not guarantee results.
</div>
)}
</div>

{/* Content */}


<div style={{ flex: 1, overflowY: "auto", overflowX: "hidden" }}>
{/* Topbar */}
<div style={{ position: "sticky", top: 0, zIndex: 100, background: `${[Link]}ee`
<div style={{ display: "flex", alignItems: "center", gap: 8 }}>
<div style={{ width: 6, height: 6, borderRadius: "50%", background: [Link], an
<span style={{ fontSize: 10, color: [Link], fontFamily: "'JetBrains Mono'" }}>
</div>
<div style={{ fontSize: 11, color: [Link] }}>
{new Date().toLocaleDateString("en-GB", { weekday: "short", day: "numeric", mon
</div>
</div>

{page === "dashboard" && <DashboardPage onMatchClick={goMatch} />}


{page === "shortlist" && <ShortlistPage onMatchClick={goMatch} />}
{page === "match" && selectedMatch && <MatchAnalysisPage match={selectedMatch} onBa
{page === "betslip" && <BetSlipPage />}
{page === "bankroll" && <BankrollPage />}
</div>
</div>
</>
);
}

You might also like