Files
gridpilot.gg/apps/website/templates/StewardingTemplate.tsx
2026-01-19 02:14:53 +01:00

147 lines
4.8 KiB
TypeScript

'use client';
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 type { StewardingViewData } from '@/lib/view-data/leagues/StewardingViewData';
import {
SharedBox,
SharedButton,
SharedStack,
SharedText,
SharedCard
} from '@/components/shared/UIComponents';
import { TemplateProps } from '@/lib/contracts/components/ComponentContracts';
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 (
<SharedStack gap={6}>
<StewardingStats
totalPending={viewData.totalPending}
totalResolved={viewData.totalResolved}
totalPenalties={viewData.totalPenalties}
/>
{/* Tab navigation */}
<SharedBox borderBottom borderColor="border-charcoal-outline">
<SharedStack direction="row" gap={4}>
<SharedBox
borderBottom={activeTab === 'pending'}
borderColor={activeTab === 'pending' ? 'border-primary-blue' : undefined}
>
<SharedButton
variant="ghost"
onClick={() => onTabChange('pending')}
rounded={false}
>
<SharedStack direction="row" align="center" gap={2}>
<SharedText weight="medium" color={activeTab === 'pending' ? 'text-primary-blue' : undefined}>Pending Protests</SharedText>
{viewData.totalPending > 0 && (
<SharedBox px={2} py={0.5} fontSize="0.75rem" bg="bg-warning-amber/20" color="text-warning-amber" rounded="full">
{viewData.totalPending}
</SharedBox>
)}
</SharedStack>
</SharedButton>
</SharedBox>
<SharedBox
borderBottom={activeTab === 'history'}
borderColor={activeTab === 'history' ? 'border-primary-blue' : undefined}
>
<SharedButton
variant="ghost"
onClick={() => onTabChange('history')}
rounded={false}
>
<SharedText weight="medium" color={activeTab === 'history' ? 'text-primary-blue' : undefined}>History</SharedText>
</SharedButton>
</SharedBox>
</SharedStack>
</SharedBox>
{/* Content */}
{activeTab === 'pending' ? (
<StewardingQueuePanel
protests={allPendingProtests}
onReview={onReviewProtest}
/>
) : (
<SharedCard>
<SharedBox p={6}>
<PenaltyHistoryList
protests={allResolvedProtests}
races={racesMap}
drivers={driverMap}
/>
</SharedBox>
</SharedCard>
)}
{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) }))}
/>
)}
</SharedStack>
);
}