website refactor
This commit is contained in:
@@ -0,0 +1,224 @@
|
||||
'use client';
|
||||
|
||||
import { useState } from 'react';
|
||||
import { useParams } from 'next/navigation';
|
||||
import { PageWrapper } from '@/components/shared/state/PageWrapper';
|
||||
import { LeagueAdminScheduleTemplate } from '@/templates/LeagueAdminScheduleTemplate';
|
||||
import {
|
||||
useLeagueAdminStatus,
|
||||
useLeagueSeasons,
|
||||
useLeagueAdminSchedule
|
||||
} from "@/hooks/league/useLeagueScheduleAdminPageData";
|
||||
import { useEffectiveDriverId } from "@/hooks/useEffectiveDriverId";
|
||||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { useInject } from '@/lib/di/hooks/useInject';
|
||||
import { LEAGUE_SERVICE_TOKEN } from '@/lib/di/tokens';
|
||||
import { Box } from '@/ui/Box';
|
||||
import { Stack } from '@/ui/Stack';
|
||||
import { Text } from '@/ui/Text';
|
||||
import { Card } from '@/ui/Card';
|
||||
import { Heading } from '@/ui/Heading';
|
||||
|
||||
export function LeagueAdminSchedulePageClient() {
|
||||
const params = useParams();
|
||||
const leagueId = params.id as string;
|
||||
const currentDriverId = useEffectiveDriverId() || '';
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
const leagueService = useInject(LEAGUE_SERVICE_TOKEN);
|
||||
|
||||
// Form state
|
||||
const [seasonId, setSeasonId] = useState<string>('');
|
||||
const [track, setTrack] = useState('');
|
||||
const [car, setCar] = useState('');
|
||||
const [scheduledAtIso, setScheduledAtIso] = useState('');
|
||||
const [editingRaceId, setEditingRaceId] = useState<string | null>(null);
|
||||
|
||||
// Check admin status using domain hook
|
||||
const { data: isAdmin, isLoading: isAdminLoading } = useLeagueAdminStatus(leagueId, currentDriverId);
|
||||
|
||||
// Load seasons using domain hook
|
||||
const { data: seasonsData, isLoading: seasonsLoading } = useLeagueSeasons(leagueId, !!isAdmin);
|
||||
|
||||
// Auto-select season
|
||||
const selectedSeasonId = seasonId || (seasonsData && seasonsData.length > 0
|
||||
? (seasonsData.find((s) => s.status === 'active') ?? seasonsData[0])?.seasonId
|
||||
: '');
|
||||
|
||||
// Load schedule using domain hook
|
||||
const { data: schedule, isLoading: scheduleLoading } = useLeagueAdminSchedule(leagueId, selectedSeasonId, !!isAdmin);
|
||||
|
||||
// Mutations
|
||||
const publishMutation = useMutation({
|
||||
mutationFn: async () => {
|
||||
if (!schedule || !selectedSeasonId) return null;
|
||||
return schedule.published
|
||||
? await leagueService.unpublishAdminSchedule(leagueId, selectedSeasonId)
|
||||
: await leagueService.publishAdminSchedule(leagueId, selectedSeasonId);
|
||||
},
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['adminSchedule', leagueId, selectedSeasonId] });
|
||||
},
|
||||
});
|
||||
|
||||
const saveMutation = useMutation({
|
||||
mutationFn: async () => {
|
||||
if (!selectedSeasonId || !scheduledAtIso) return null;
|
||||
|
||||
if (!editingRaceId) {
|
||||
return await leagueService.createAdminScheduleRace(leagueId, selectedSeasonId, {
|
||||
track,
|
||||
car,
|
||||
scheduledAtIso,
|
||||
});
|
||||
} else {
|
||||
return await leagueService.updateAdminScheduleRace(leagueId, selectedSeasonId, editingRaceId, {
|
||||
...(track ? { track } : {}),
|
||||
...(car ? { car } : {}),
|
||||
...(scheduledAtIso ? { scheduledAtIso } : {}),
|
||||
});
|
||||
}
|
||||
},
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['adminSchedule', leagueId, selectedSeasonId] });
|
||||
// Reset form
|
||||
setTrack('');
|
||||
setCar('');
|
||||
setScheduledAtIso('');
|
||||
setEditingRaceId(null);
|
||||
},
|
||||
});
|
||||
|
||||
const deleteMutation = useMutation({
|
||||
mutationFn: async (raceId: string) => {
|
||||
return await leagueService.deleteAdminScheduleRace(leagueId, selectedSeasonId, raceId);
|
||||
},
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['adminSchedule', leagueId, selectedSeasonId] });
|
||||
},
|
||||
});
|
||||
|
||||
// Derived states
|
||||
const isLoading = isAdminLoading || seasonsLoading || scheduleLoading;
|
||||
const isPublishing = publishMutation.isPending;
|
||||
const isSaving = saveMutation.isPending;
|
||||
const isDeleting = deleteMutation.variables || null;
|
||||
|
||||
// Handlers
|
||||
const handleSeasonChange = (newSeasonId: string) => {
|
||||
setSeasonId(newSeasonId);
|
||||
setEditingRaceId(null);
|
||||
setTrack('');
|
||||
setCar('');
|
||||
setScheduledAtIso('');
|
||||
};
|
||||
|
||||
const handlePublishToggle = () => {
|
||||
publishMutation.mutate();
|
||||
};
|
||||
|
||||
const handleAddOrSave = () => {
|
||||
if (!scheduledAtIso) return;
|
||||
saveMutation.mutate();
|
||||
};
|
||||
|
||||
const handleEdit = (raceId: string) => {
|
||||
if (!schedule) return;
|
||||
const race = schedule.races.find((r) => r.id === raceId);
|
||||
if (!race) return;
|
||||
|
||||
setEditingRaceId(raceId);
|
||||
setTrack('');
|
||||
setCar('');
|
||||
setScheduledAtIso(race.scheduledAt.toISOString());
|
||||
};
|
||||
|
||||
const handleDelete = (raceId: string) => {
|
||||
const confirmed = window.confirm('Delete this race?');
|
||||
if (!confirmed) return;
|
||||
deleteMutation.mutate(raceId);
|
||||
};
|
||||
|
||||
const handleCancelEdit = () => {
|
||||
setEditingRaceId(null);
|
||||
setTrack('');
|
||||
setCar('');
|
||||
setScheduledAtIso('');
|
||||
};
|
||||
|
||||
// Prepare template data
|
||||
const templateData = schedule && seasonsData && selectedSeasonId
|
||||
? {
|
||||
published: schedule.published,
|
||||
races: schedule.races.map(r => ({
|
||||
id: r.id,
|
||||
name: r.name,
|
||||
track: r.track || '',
|
||||
car: r.car || '',
|
||||
scheduledAt: r.scheduledAt.toISOString(),
|
||||
})),
|
||||
seasons: seasonsData.map(s => ({
|
||||
seasonId: s.seasonId,
|
||||
name: s.name,
|
||||
})),
|
||||
seasonId: selectedSeasonId,
|
||||
}
|
||||
: undefined;
|
||||
|
||||
// Render admin access required if not admin
|
||||
if (!isLoading && !isAdmin) {
|
||||
return (
|
||||
<Stack gap={6}>
|
||||
<Card>
|
||||
<Box p={6} textAlign="center">
|
||||
<Heading level={3}>Admin Access Required</Heading>
|
||||
<Box mt={2}>
|
||||
<Text size="sm" color="text-gray-400">Only league admins can manage the schedule.</Text>
|
||||
</Box>
|
||||
</Box>
|
||||
</Card>
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
|
||||
// Template component that wraps the actual template with all props
|
||||
const TemplateWrapper = ({ data }: { data: typeof templateData }) => {
|
||||
if (!data) return null;
|
||||
|
||||
return (
|
||||
<LeagueAdminScheduleTemplate
|
||||
viewData={data}
|
||||
onSeasonChange={handleSeasonChange}
|
||||
onPublishToggle={handlePublishToggle}
|
||||
onAddOrSave={handleAddOrSave}
|
||||
onEdit={handleEdit}
|
||||
onDelete={handleDelete}
|
||||
onCancelEdit={handleCancelEdit}
|
||||
track={track}
|
||||
car={car}
|
||||
scheduledAtIso={scheduledAtIso}
|
||||
editingRaceId={editingRaceId}
|
||||
isPublishing={isPublishing}
|
||||
isSaving={isSaving}
|
||||
isDeleting={isDeleting}
|
||||
setTrack={setTrack}
|
||||
setCar={setCar}
|
||||
setScheduledAtIso={setScheduledAtIso}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<PageWrapper
|
||||
data={templateData}
|
||||
isLoading={isLoading}
|
||||
error={null}
|
||||
Template={TemplateWrapper}
|
||||
loading={{ variant: 'full-screen', message: 'Loading schedule admin...' }}
|
||||
empty={{
|
||||
title: 'No schedule data available',
|
||||
description: 'Unable to load schedule administration data',
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user