Files
MyClub/frontend/src/pages/StandingsPage.tsx
T
Tomáš Dvořák 12cba639b9 upload
2025-10-16 13:32:05 +02:00

124 lines
4.4 KiB
TypeScript

import { Box, Button, Heading, HStack, Input, Spinner, Table, Tbody, Td, Th, Thead, Tr, Text, VStack, List, ListItem } from '@chakra-ui/react';
import { useEffect, useMemo, useState } from 'react';
import { useQuery } from '@tanstack/react-query';
import { facrApi } from '../services/facr/facrApi';
import type { ClubInfo, Competition, TableRow, SearchResult } from '../services/facr/types';
import { TeamLogo } from '../components/common/TeamLogo';
type SelectedClub = { clubId: string; clubType: 'football' | 'futsal' };
const STORAGE_KEY = 'facrClub';
const StandingsPage: React.FC = () => {
const [query, setQuery] = useState('');
const [selected, setSelected] = useState<SelectedClub | null>(null);
useEffect(() => {
const saved = localStorage.getItem(STORAGE_KEY);
if (saved) {
try { setSelected(JSON.parse(saved)); } catch {}
}
}, []);
useEffect(() => {
if (selected) localStorage.setItem(STORAGE_KEY, JSON.stringify(selected));
}, [selected]);
const { data: searchData, isFetching: searching } = useQuery({
queryKey: ['facr', 'search', query],
queryFn: () => facrApi.searchClubs(query),
enabled: query.trim().length >= 3,
});
const { data: clubTable, isLoading, isError } = useQuery<ClubInfo>({
queryKey: ['facr', 'clubTable', selected?.clubType, selected?.clubId],
queryFn: () => facrApi.getClubTable(selected!.clubId, selected!.clubType),
enabled: !!selected,
});
const tableRows: TableRow[] = useMemo(() => {
if (!clubTable?.competitions) return [];
// pick first competition that has table.overall
const compWithTable: Competition | undefined = clubTable.competitions.find(c => c.table?.overall?.length) || clubTable.competitions[0];
return compWithTable?.table?.overall || [];
}, [clubTable]);
return (
<VStack align="stretch" spacing={4}>
<Heading size="lg">Tabulka</Heading>
<Box bg="white" p={4} borderWidth="1px" borderRadius="md">
<HStack>
<Input placeholder="Vyhledat klub (min. 3 znaky)" value={query} onChange={(e) => setQuery(e.target.value)} />
<Button onClick={() => setQuery(query.trim())} isLoading={searching}>Hledat</Button>
</HStack>
{searchData?.results?.length ? (
<List spacing={2} mt={3}>
{searchData.results.slice(0, 8).map((r: SearchResult) => (
<ListItem key={`${r.club_type}-${r.club_id}`}>
<Button size="sm" variant="ghost" onClick={() => setSelected({ clubId: r.club_id, clubType: r.club_type })}>
{r.name}
</Button>
</ListItem>
))}
</List>
) : null}
</Box>
{!selected && (
<Text color="gray.500">Vyberte klub pro zobrazení tabulky soutěže.</Text>
)}
{selected && isLoading && <Spinner />}
{selected && isError && <Text color="red.500">Chyba při načítání tabulky</Text>}
{selected && !isLoading && (
<Table bg="white">
<Thead>
<Tr>
<Th>#</Th>
<Th>Tým</Th>
<Th isNumeric>Z</Th>
<Th isNumeric>V</Th>
<Th isNumeric>R</Th>
<Th isNumeric>P</Th>
<Th isNumeric>Skóre</Th>
<Th isNumeric>Body</Th>
</Tr>
</Thead>
<Tbody>
{tableRows.map((row) => (
<Tr key={row.team_id}>
<Td>{row.rank}</Td>
<Td>
<HStack>
<TeamLogo
teamId={row.team_id}
teamName={row.team}
facrLogo={row.team_logo_url}
size="small"
alt={row.team}
objectFit="contain"
/>
<Text>{row.team}</Text>
</HStack>
</Td>
<Td isNumeric>{row.played}</Td>
<Td isNumeric>{row.wins}</Td>
<Td isNumeric>{row.draws}</Td>
<Td isNumeric>{row.losses}</Td>
<Td isNumeric>{row.score}</Td>
<Td isNumeric>{row.points}</Td>
</Tr>
))}
{tableRows.length === 0 && (
<Tr><Td colSpan={8}><Text>Tabulka není dostupná.</Text></Td></Tr>
)}
</Tbody>
</Table>
)}
</VStack>
);
}
export default StandingsPage;