145 lines
4.7 KiB
TypeScript
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>
|
|
);
|
|
}
|