Skip to content

Commit 2c117fd

Browse files
committed
connect matchdetails to backend
1 parent 06f9851 commit 2c117fd

1 file changed

Lines changed: 194 additions & 35 deletions

File tree

  • client/src/components/ui/Matchdetails

client/src/components/ui/Matchdetails/List.tsx

Lines changed: 194 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,206 @@
1+
"use client";
2+
13
import { useEffect, useState } from "react";
24

35
import { MatchDetailsData } from "../Common/types";
46

5-
export type MatchDetailsProps = {
6-
matchData: MatchDetailsData[];
7-
header: string[];
8-
};
7+
export default function MatchDetailsList() {
8+
const BASE_URL = process.env.NEXT_PUBLIC_BACKEND_URL;
9+
10+
const [matchData, setMatchData] = useState<MatchDetailsData[][]>([]);
11+
const [groups, setGroups] = useState<number[]>([]);
12+
const [stages, setStages] = useState<number[]>([]);
13+
const [selectedGroup, setSelectedGroup] = useState<number | null>(null);
14+
const [selectedStage, setSelectedStage] = useState<number | null>(null);
15+
const [loading, setLoading] = useState<boolean>(false);
16+
17+
useEffect(() => {
18+
async function fetchDropdownOptions() {
19+
try {
20+
const [groupRes, stageRes] = await Promise.all([
21+
fetch(`${BASE_URL}/details/groups/`),
22+
fetch(`${BASE_URL}/details/stages/`),
23+
]);
24+
const groupData = await groupRes.json();
25+
const stageData = await stageRes.json();
26+
setGroups(groupData);
27+
setStages(stageData);
28+
if (stageData.length > 0) setSelectedStage(stageData[0]);
29+
} catch (err) {
30+
console.error("Failed to fetch dropdown options", err);
31+
}
32+
}
33+
34+
fetchDropdownOptions();
35+
}, []);
36+
37+
useEffect(() => {
38+
if (!selectedStage) return;
39+
40+
async function fetchMatchDetails() {
41+
setLoading(true);
42+
try {
43+
let url = `${BASE_URL}/details/knockout_stage/${selectedStage}/`;
44+
if (selectedGroup !== null) url += `?group_id=${selectedGroup}`;
45+
46+
const res = await fetch(url);
47+
const data = await res.json();
48+
49+
const transformed = data.map((match: any[]) =>
50+
match.map((item: any) => ({
51+
teamName: item.team_name,
52+
matchId: item.match_id,
53+
matchName: item.match_name,
54+
group: item.group,
55+
stage: item.stage,
56+
honorPoint: item.honor_point,
57+
point: item.point,
58+
completedTime: item.completed_time_second,
59+
p1_postion: item.p1_position,
60+
p2_postion: item.p2_position,
61+
whitePins: item.white_pins,
62+
penaltyPins: item.penalty_pins,
63+
yellowCard: item.yellow_cards,
64+
redCard: item.red_cards,
65+
})),
66+
);
67+
68+
setMatchData(transformed);
69+
} catch (err) {
70+
console.error("Failed to fetch match details", err);
71+
setMatchData([]);
72+
} finally {
73+
setLoading(false);
74+
}
75+
}
76+
77+
fetchMatchDetails();
78+
}, [selectedGroup, selectedStage]);
79+
80+
const header = [
81+
"Team Name",
82+
"White Pins",
83+
"Penalty Pins",
84+
"Yellow Card",
85+
"Red Card",
86+
"P1 Position",
87+
"P2 Position",
88+
"Honor Points",
89+
"Regular Points",
90+
"Completed Time",
91+
];
92+
93+
const sortedMatchData = [...matchData].sort((a, b) => {
94+
const aId = a[0]?.matchId ?? 0;
95+
const bId = b[0]?.matchId ?? 0;
96+
return aId - bId;
97+
});
998

10-
export default function List({ matchData, header }: MatchDetailsProps) {
1199
return (
12100
<div className="w-full overflow-hidden rounded-lg shadow-lg">
13101
<div className="overflow-x-auto">
14-
<table className="min-w-full bg-white">
15-
<thead>
16-
<tr className="title bg-primary text-center font-bold text-white">
17-
{header.map((row, index) => (
18-
<th key={index} className="px-6 py-4 md:text-lg">
19-
{row}
20-
</th>
102+
<div className="flex flex-wrap gap-6 bg-white p-4">
103+
{/* Dropdowns */}
104+
<div className="relative">
105+
<label htmlFor="stageSelect" className="body-sm pr-2 text-xs">
106+
Select Stage (required)
107+
</label>
108+
<select
109+
id="stageSelect"
110+
value={selectedStage ?? ""}
111+
onChange={(e) =>
112+
setSelectedStage(
113+
e.target.value ? parseInt(e.target.value) : null,
114+
)
115+
}
116+
className="body-sm rounded-md border border-gray-300 bg-white px-4 py-2 pt-3 focus:border-primary focus:outline-none focus:ring-2 focus:ring-primary"
117+
>
118+
<option value="">-- Select --</option>
119+
{stages.map((sid) => (
120+
<option key={sid} value={sid}>
121+
Stage {sid}
122+
</option>
123+
))}
124+
</select>
125+
</div>
126+
127+
<div className="relative">
128+
<label htmlFor="groupSelect" className="body-sm pr-2 text-xs">
129+
Select Group (optional)
130+
</label>
131+
<select
132+
id="groupSelect"
133+
value={selectedGroup ?? ""}
134+
onChange={(e) =>
135+
setSelectedGroup(
136+
e.target.value ? parseInt(e.target.value) : null,
137+
)
138+
}
139+
className="body-sm rounded-md border border-gray-300 bg-white px-4 py-2 pt-3 focus:border-primary focus:outline-none focus:ring-2 focus:ring-primary"
140+
>
141+
<option value="">-- None --</option>
142+
{groups.map((gid) => (
143+
<option key={gid} value={gid}>
144+
Group {gid}
145+
</option>
146+
))}
147+
</select>
148+
</div>
149+
</div>
150+
151+
{loading ? (
152+
<p className="py-8 text-center">Loading match details...</p>
153+
) : selectedStage ? (
154+
matchData.length === 0 ? (
155+
<p className="py-6 text-center text-gray-500">
156+
No match data available.
157+
</p>
158+
) : (
159+
<div className="space-y-10 px-4 pb-8 pt-4">
160+
{sortedMatchData.map((match, idx) => (
161+
<div key={idx}>
162+
<h2 className="subtitle mb-4 font-semibold text-primary">
163+
{match[0]?.matchName ?? `Match ${idx + 1}`}
164+
</h2>
165+
<table className="min-w-full bg-white shadow">
166+
<thead>
167+
<tr className="bg-primary text-center text-xs font-bold text-white sm:text-sm md:text-base">
168+
{header.map((col, i) => (
169+
<th key={i} className="whitespace-nowrap px-2 py-2">
170+
{col}
171+
</th>
172+
))}
173+
</tr>
174+
</thead>
175+
<tbody className="body-sm text-center">
176+
{match.map((row, index) => (
177+
<tr
178+
key={index}
179+
className="border-b border-gray-200 bg-green-50 hover:bg-gray-100"
180+
>
181+
<td className="px-4 py-2">{row.teamName}</td>
182+
<td className="px-4 py-2">{row.whitePins}</td>
183+
<td className="px-4 py-2">{row.penaltyPins}</td>
184+
<td className="px-4 py-2">{row.yellowCard}</td>
185+
<td className="px-4 py-2">{row.redCard}</td>
186+
<td className="px-4 py-2">{row.p1_postion}</td>
187+
<td className="px-4 py-2">{row.p2_postion}</td>
188+
<td className="px-4 py-2">{row.honorPoint}</td>
189+
<td className="px-4 py-2">{row.point}</td>
190+
<td className="px-4 py-2">{row.completedTime}</td>
191+
</tr>
192+
))}
193+
</tbody>
194+
</table>
195+
</div>
21196
))}
22-
</tr>
23-
</thead>
24-
<tbody className="body-sm">
25-
{matchData.map((row, index) => (
26-
<tr
27-
key={index}
28-
className={`border-b border-gray-200 bg-green-50 text-center hover:bg-gray-100`}
29-
>
30-
<td className="px-6 py-4">{row.teamName}</td>
31-
<td className="px-6 py-4">{row.opponent}</td>
32-
<td className="px-6 py-4">{row.whitePins}</td>
33-
<td className="px-6 py-4">{row.penaltyPins}</td>
34-
<td className="px-6 py-4">{row.yellowCard}</td>
35-
<td className="px-6 py-4">{row.redCard}</td>
36-
<td className="px-6 py-4">{row.p1_postion}</td>
37-
<td className="px-6 py-4">{row.p2_postion}</td>
38-
<td className="px-6 py-4">{row.honorPoint}</td>
39-
<td className="px-6 py-4">{row.regularPoint}</td>
40-
<td className="px-6 py-4">{row.completedTime}</td>
41-
</tr>
42-
))}
43-
</tbody>
44-
</table>
197+
</div>
198+
)
199+
) : (
200+
<p className="py-8 text-center text-gray-500">
201+
Select a stage to view results
202+
</p>
203+
)}
45204
</div>
46205
</div>
47206
);

0 commit comments

Comments
 (0)