Files
gridpilot.gg/apps/website/templates/StewardingTemplate.tsx
2026-01-26 17:56:11 +01:00

145 lines
4.7 KiB
TypeScript

import { PenaltyHistoryList } from '@/components/leagues/PenaltyHistoryList';
import { QuickPenaltyModal } from '@/components/leagues/QuickPenaltyModal';
import { ReviewProtestModal } from '@/components/leagues/ReviewProtestModal';
import { StewardingQueuePanel } from '@/components/leagues/StewardingQueuePanel';
import { StewardingStats } from '@/components/leagues/StewardingStats';
import { PenaltyFAB } from '@/components/races/PenaltyFAB';
import { TemplateProps } from '@/lib/contracts/components/ComponentContracts';
import type { StewardingViewData } from '@/lib/view-data/StewardingViewData';
import { Box } from '@/ui/Box';
import { Button } from '@/ui/Button';
import { Card } from '@/ui/Card';
import { Stack } from '@/ui/Stack';
import { Text } from '@/ui/Text';
interface StewardingTemplateProps extends TemplateProps<StewardingViewData> {
activeTab: 'pending' | 'history';
onTabChange: (tab: 'pending' | 'history') => void;
selectedProtest: any;
onReviewProtest: (id: string) => void;
onCloseProtestModal: () => void;
onAcceptProtest: (protestId: string, penaltyType: string, penaltyValue: number, stewardNotes: string) => Promise<void>;
onRejectProtest: (protestId: string, stewardNotes: string) => Promise<void>;
showQuickPenaltyModal: boolean;
setShowQuickPenaltyModal: (show: boolean) => void;
allPendingProtests: any[];
allResolvedProtests: any[];
racesMap: any;
driverMap: any;
currentDriverId: string;
}
export function StewardingTemplate({
viewData,
activeTab,
onTabChange,
selectedProtest,
onReviewProtest,
onCloseProtestModal,
onAcceptProtest,
onRejectProtest,
showQuickPenaltyModal,
setShowQuickPenaltyModal,
allPendingProtests,
allResolvedProtests,
racesMap,
driverMap,
currentDriverId,
}: StewardingTemplateProps) {
return (
<Stack gap={6}>
<StewardingStats
totalPending={viewData.totalPending}
totalResolved={viewData.totalResolved}
totalPenalties={viewData.totalPenalties}
/>
{/* Tab navigation */}
<Box borderBottom borderColor="border-charcoal-outline">
<Stack direction="row" gap={4}>
<Box
borderBottom={activeTab === 'pending'}
borderColor={activeTab === 'pending' ? 'border-primary-blue' : undefined}
>
<Button
variant="ghost"
onClick={() => onTabChange('pending')}
rounded={false}
>
<Stack direction="row" align="center" gap={2}>
<Text weight="medium" color={activeTab === 'pending' ? 'text-primary-blue' : undefined}>Pending Protests</Text>
{viewData.totalPending > 0 && (
<Box px={2} py={0.5} fontSize="0.75rem" bg="bg-warning-amber/20" color="text-warning-amber" rounded="full">
{viewData.totalPending}
</Box>
)}
</Stack>
</Button>
</Box>
<Box
borderBottom={activeTab === 'history'}
borderColor={activeTab === 'history' ? 'border-primary-blue' : undefined}
>
<Button
variant="ghost"
onClick={() => onTabChange('history')}
rounded={false}
>
<Text weight="medium" color={activeTab === 'history' ? 'text-primary-blue' : undefined}>History</Text>
</Button>
</Box>
</Stack>
</Box>
{/* Content */}
{activeTab === 'pending' ? (
<StewardingQueuePanel
protests={allPendingProtests}
onReview={onReviewProtest}
/>
) : (
<Card>
<Box p={6}>
<PenaltyHistoryList
protests={allResolvedProtests}
races={racesMap}
drivers={driverMap}
/>
</Box>
</Card>
)}
{activeTab === 'history' && (
<PenaltyFAB onClick={() => setShowQuickPenaltyModal(true)} />
)}
{selectedProtest && (
<ReviewProtestModal
protest={selectedProtest}
onClose={onCloseProtestModal}
onAccept={onAcceptProtest}
onReject={onRejectProtest}
/>
)}
{showQuickPenaltyModal && (
<QuickPenaltyModal
drivers={viewData.drivers.map(d => ({
id: d.id,
name: d.name,
iracingId: '',
country: '',
joinedAt: '',
avatarUrl: null,
}) as any)}
onClose={() => setShowQuickPenaltyModal(false)}
adminId={currentDriverId || ''}
races={viewData.races.map(r => ({ id: r.id, track: r.track, scheduledAt: new Date(r.scheduledAt) }))}
/>
)}
</Stack>
);
}