192 lines
5.5 KiB
TypeScript
192 lines
5.5 KiB
TypeScript
'use client';
|
|
|
|
import React from 'react';
|
|
import { Card } from '@/ui/Card';
|
|
import { Button } from '@/ui/Button';
|
|
import { Heading } from '@/ui/Heading';
|
|
import { Breadcrumbs } from '@/ui/Breadcrumbs';
|
|
import {
|
|
Flag,
|
|
SlidersHorizontal,
|
|
Calendar,
|
|
} from 'lucide-react';
|
|
import { RaceFilterModal } from '@/ui/RaceFilterModal';
|
|
import { Pagination } from '@/ui/Pagination';
|
|
import { Box } from '@/ui/Box';
|
|
import { Stack } from '@/ui/Stack';
|
|
import { Text } from '@/ui/Text';
|
|
import { Container } from '@/ui/Container';
|
|
import { Icon } from '@/ui/Icon';
|
|
import { Surface } from '@/ui/Surface';
|
|
import { Skeleton } from '@/ui/Skeleton';
|
|
import { RaceListItem } from '@/ui/RaceListItemWrapper';
|
|
import type { RacesViewData } from '@/lib/view-data/RacesViewData';
|
|
|
|
export type StatusFilter = 'scheduled' | 'running' | 'completed' | 'cancelled' | 'all';
|
|
|
|
interface RacesAllTemplateProps {
|
|
viewData: RacesViewData;
|
|
races: RacesViewData['races'];
|
|
totalFilteredCount: number;
|
|
isLoading: boolean;
|
|
// Pagination
|
|
currentPage: number;
|
|
totalPages: number;
|
|
itemsPerPage: number;
|
|
onPageChange: (page: number) => void;
|
|
// Filters
|
|
statusFilter: StatusFilter;
|
|
setStatusFilter: (filter: StatusFilter) => void;
|
|
leagueFilter: string;
|
|
setLeagueFilter: (filter: string) => void;
|
|
searchQuery: string;
|
|
setSearchQuery: (query: string) => void;
|
|
// UI State
|
|
showFilters: boolean;
|
|
setShowFilters: (show: boolean) => void;
|
|
showFilterModal: boolean;
|
|
setShowFilterModal: (show: boolean) => void;
|
|
// Actions
|
|
onRaceClick: (raceId: string) => void;
|
|
onLeagueClick: (leagueId: string) => void;
|
|
}
|
|
|
|
export function RacesAllTemplate({
|
|
viewData,
|
|
races,
|
|
totalFilteredCount,
|
|
isLoading,
|
|
currentPage,
|
|
totalPages,
|
|
itemsPerPage,
|
|
onPageChange,
|
|
statusFilter,
|
|
setStatusFilter,
|
|
leagueFilter,
|
|
setLeagueFilter,
|
|
searchQuery,
|
|
setSearchQuery,
|
|
showFilters,
|
|
setShowFilters,
|
|
showFilterModal,
|
|
setShowFilterModal,
|
|
onRaceClick,
|
|
}: RacesAllTemplateProps) {
|
|
const breadcrumbItems = [
|
|
{ label: 'Races', href: '/races' },
|
|
{ label: 'All Races' },
|
|
];
|
|
|
|
if (isLoading) {
|
|
return (
|
|
<Container size="lg" py={8}>
|
|
<Stack gap={6}>
|
|
<Skeleton width="8rem" height="1.5rem" />
|
|
<Skeleton width="12rem" height="2.5rem" />
|
|
<Stack gap={4}>
|
|
{[1, 2, 3, 4, 5].map(i => (
|
|
<Skeleton key={i} width="100%" height="6rem" />
|
|
))}
|
|
</Stack>
|
|
</Stack>
|
|
</Container>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<Container size="lg" py={8}>
|
|
<Stack gap={6}>
|
|
{/* Breadcrumbs */}
|
|
<Breadcrumbs items={breadcrumbItems} />
|
|
|
|
{/* Header */}
|
|
<Stack direction="row" align="center" justify="between" wrap gap={4}>
|
|
<Box>
|
|
<Heading level={1} icon={<Icon icon={Flag} size={6} color="#3b82f6" />}>
|
|
All Races
|
|
</Heading>
|
|
<Text size="sm" color="text-gray-400" block mt={1}>
|
|
{totalFilteredCount} race{totalFilteredCount !== 1 ? 's' : ''} found
|
|
</Text>
|
|
</Box>
|
|
|
|
<Button
|
|
variant="secondary"
|
|
onClick={() => setShowFilters(!showFilters)}
|
|
icon={<Icon icon={SlidersHorizontal} size={4} />}
|
|
>
|
|
Filters
|
|
</Button>
|
|
</Stack>
|
|
|
|
{/* Search & Filters (Simplified for template) */}
|
|
{showFilters && (
|
|
<Card>
|
|
<Stack gap={4}>
|
|
<Text size="sm" color="text-gray-400">
|
|
Use the filter button to open advanced search and filtering options.
|
|
</Text>
|
|
<Box>
|
|
<Button variant="primary" onClick={() => setShowFilterModal(true)}>
|
|
Open Filters
|
|
</Button>
|
|
</Box>
|
|
</Stack>
|
|
</Card>
|
|
)}
|
|
|
|
{/* Race List */}
|
|
{races.length === 0 ? (
|
|
<Card>
|
|
<Stack align="center" py={12} gap={4}>
|
|
<Surface variant="muted" rounded="full" padding={4}>
|
|
<Icon icon={Calendar} size={8} color="#525252" />
|
|
</Surface>
|
|
<Box textAlign="center">
|
|
<Text weight="medium" color="text-white" block mb={1}>No races found</Text>
|
|
<Text size="sm" color="text-gray-500">
|
|
{viewData.races.length === 0
|
|
? 'No races have been scheduled yet'
|
|
: 'Try adjusting your search or filters'}
|
|
</Text>
|
|
</Box>
|
|
</Stack>
|
|
</Card>
|
|
) : (
|
|
<Stack gap={3}>
|
|
{races.map(race => (
|
|
<RaceListItem key={race.id} race={race} onClick={onRaceClick} />
|
|
))}
|
|
</Stack>
|
|
)}
|
|
|
|
{/* Pagination */}
|
|
<Pagination
|
|
currentPage={currentPage}
|
|
totalPages={totalPages}
|
|
totalItems={totalFilteredCount}
|
|
itemsPerPage={itemsPerPage}
|
|
onPageChange={onPageChange}
|
|
/>
|
|
|
|
{/* Filter Modal */}
|
|
<RaceFilterModal
|
|
isOpen={showFilterModal}
|
|
onClose={() => setShowFilterModal(false)}
|
|
statusFilter={statusFilter}
|
|
setStatusFilter={setStatusFilter}
|
|
leagueFilter={leagueFilter}
|
|
setLeagueFilter={setLeagueFilter}
|
|
timeFilter="all"
|
|
setTimeFilter={() => {}}
|
|
searchQuery={searchQuery}
|
|
setSearchQuery={setSearchQuery}
|
|
leagues={viewData.leagues}
|
|
showSearch={true}
|
|
showTimeFilter={false}
|
|
/>
|
|
</Stack>
|
|
</Container>
|
|
);
|
|
}
|