first commit

This commit is contained in:
a.alinaghipour
2026-04-05 15:53:20 +03:30
commit aa9ed69dd2
96 changed files with 7721 additions and 0 deletions

View File

@@ -0,0 +1,138 @@
"use client";
import { useState } from "react";
type Player = { id: string; name: string; position: string };
type StatRow = {
playerId: string;
goals: number;
assists: number;
yellowCards: number;
redCards: number;
minutesPlayed: number;
cleanSheet: boolean;
};
export default function StatsForm({ match }: { match: any }) {
const allPlayers: Player[] = [
...match.homeTeam.players,
...match.awayTeam.players,
];
const initStats = (): Record<string, StatRow> => {
const map: Record<string, StatRow> = {};
for (const p of allPlayers) {
const existing = match.playerStats.find((s: any) => s.playerId === p.id);
map[p.id] = existing ?? {
playerId: p.id,
goals: 0,
assists: 0,
yellowCards: 0,
redCards: 0,
minutesPlayed: 0,
cleanSheet: false,
};
}
return map;
};
const [stats, setStats] = useState<Record<string, StatRow>>(initStats);
const [loading, setLoading] = useState(false);
const [saved, setSaved] = useState(false);
function update(playerId: string, field: keyof StatRow, value: any) {
setStats((prev) => ({ ...prev, [playerId]: { ...prev[playerId], [field]: value } }));
}
async function handleSave() {
setLoading(true);
const payload = Object.values(stats).filter((s) => s.minutesPlayed > 0);
await fetch(`/api/matches/${match.id}/stats`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(payload),
});
setSaved(true);
setLoading(false);
setTimeout(() => setSaved(false), 3000);
}
const renderTeam = (players: Player[], teamName: string) => (
<div className="mb-8">
<h3 className="font-bold text-lg mb-3 text-green-800">{teamName}</h3>
<div className="bg-white rounded-2xl shadow overflow-hidden">
<table className="w-full text-sm">
<thead className="bg-gray-100 text-gray-600">
<tr>
<th className="text-right px-4 py-3">بازیکن</th>
<th className="px-3 py-3">دقیقه</th>
<th className="px-3 py-3">گل</th>
<th className="px-3 py-3">پاس گل</th>
<th className="px-3 py-3">زرد</th>
<th className="px-3 py-3">قرمز</th>
<th className="px-3 py-3">کلینشیت</th>
</tr>
</thead>
<tbody>
{players.map((p) => {
const s = stats[p.id];
if (!s) return null;
return (
<tr key={p.id} className="border-t hover:bg-gray-50">
<td className="px-4 py-2">
<div className="font-medium">{p.name}</div>
<div className="text-xs text-gray-400">{p.position}</div>
</td>
{(["minutesPlayed", "goals", "assists", "yellowCards", "redCards"] as const).map((field) => (
<td key={field} className="px-2 py-2 text-center">
<input
type="number"
min="0"
max={field === "minutesPlayed" ? 120 : 10}
value={s[field] as number}
onChange={(e) => update(p.id, field, parseInt(e.target.value) || 0)}
className="w-14 border rounded-lg px-2 py-1 text-center focus:outline-none focus:ring-2 focus:ring-green-400"
/>
</td>
))}
<td className="px-2 py-2 text-center">
<input
type="checkbox"
checked={s.cleanSheet}
onChange={(e) => update(p.id, "cleanSheet", e.target.checked)}
className="w-4 h-4 accent-green-600"
/>
</td>
</tr>
);
})}
</tbody>
</table>
</div>
</div>
);
return (
<div>
<div className="bg-green-50 border border-green-200 rounded-2xl p-4 mb-6 text-center">
<span className="font-bold text-lg">{match.homeTeam.name}</span>
<span className="mx-4 text-gray-400">vs</span>
<span className="font-bold text-lg">{match.awayTeam.name}</span>
</div>
{renderTeam(match.homeTeam.players, match.homeTeam.name)}
{renderTeam(match.awayTeam.players, match.awayTeam.name)}
<div className="flex items-center gap-4">
<button
onClick={handleSave}
disabled={loading}
className="bg-green-700 text-white px-8 py-3 rounded-xl font-bold hover:bg-green-800 transition disabled:opacity-50"
>
{loading ? "در حال ذخیره..." : "ذخیره آمار و محاسبه امتیازات"}
</button>
{saved && <span className="text-green-600 font-medium"> ذخیره شد</span>}
</div>
</div>
);
}