diff --git a/src/app/[locale]/admin/clubs/[club_id]/competitions/[competition_id]/CompetitionDetailComponent.tsx b/src/app/[locale]/admin/clubs/[club_id]/competitions/[competition_id]/CompetitionDetailComponent.tsx index 0f4ee3a..7fcc406 100644 --- a/src/app/[locale]/admin/clubs/[club_id]/competitions/[competition_id]/CompetitionDetailComponent.tsx +++ b/src/app/[locale]/admin/clubs/[club_id]/competitions/[competition_id]/CompetitionDetailComponent.tsx @@ -16,6 +16,8 @@ import { Settings, Trophy, ListOrdered, + FileText, + CalendarClock, } from 'lucide-react'; import useTranslation from '@/src/hooks/useTranslation'; import Card from '@/src/components/cards/Card'; @@ -31,7 +33,10 @@ import OverviewTab from './tabs/OverviewTab'; import RegistrationsTab from './tabs/RegistrationsTab'; import ParticipantsTab from './tabs/ParticipantsTab'; import FixturesTab from './tabs/FixturesTab'; +import SchedulingTab from './tabs/SchedulingTab'; +import ResultsTab from './tabs/ResultsTab'; import StandingsTab from './tabs/StandingsTab'; +import SaveAsTemplateModal from './SaveAsTemplateModal'; import type { CompetitionStatus } from '@/src/types/competition'; interface CompetitionDetailComponentProps { @@ -39,13 +44,15 @@ interface CompetitionDetailComponentProps { competitionId: number; } -type TabKey = 'overview' | 'registrations' | 'participants' | 'fixtures' | 'standings'; +type TabKey = 'overview' | 'registrations' | 'participants' | 'fixtures' | 'scheduling' | 'results' | 'standings'; const tabs: { key: TabKey; label: string; icon: React.ComponentType<{ className?: string }> }[] = [ { key: 'overview', label: 'Overview', icon: Eye }, { key: 'registrations', label: 'Registrations', icon: Users }, { key: 'participants', label: 'Participants', icon: Trophy }, { key: 'fixtures', label: 'Fixtures', icon: Calendar }, + { key: 'scheduling', label: 'Scheduling', icon: CalendarClock }, + { key: 'results', label: 'Results', icon: CheckCircle }, { key: 'standings', label: 'Standings', icon: ListOrdered }, ]; @@ -157,6 +164,7 @@ export default function CompetitionDetailComponent({ }: CompetitionDetailComponentProps) { const { locale } = useTranslation(); const [activeTab, setActiveTab] = useState('overview'); + const [showSaveAsTemplateModal, setShowSaveAsTemplateModal] = useState(false); const { data: competition, isLoading, error } = useCompetition(competitionId); @@ -218,7 +226,16 @@ export default function CompetitionDetailComponent({

{competition.description}

)} - +
+ + +
{/* Quick Stats */} @@ -310,14 +327,31 @@ export default function CompetitionDetailComponent({ )} {activeTab === 'participants' && ( - + s.groups ?? []) ?? []} + /> )} {activeTab === 'fixtures' && ( )} + {activeTab === 'scheduling' && ( + + )} + {activeTab === 'results' && ( + + )} {activeTab === 'standings' && ( )} + + {/* Save as Template Modal */} + setShowSaveAsTemplateModal(false)} + competitionId={competitionId} + defaultName={competition.title} + /> ); } diff --git a/src/app/[locale]/admin/clubs/[club_id]/competitions/[competition_id]/SaveAsTemplateModal.tsx b/src/app/[locale]/admin/clubs/[club_id]/competitions/[competition_id]/SaveAsTemplateModal.tsx new file mode 100644 index 0000000..1e10a47 --- /dev/null +++ b/src/app/[locale]/admin/clubs/[club_id]/competitions/[competition_id]/SaveAsTemplateModal.tsx @@ -0,0 +1,143 @@ +'use client'; + +import React, { useState } from 'react'; +import { X, Loader2, FileText } from 'lucide-react'; +import { useSaveAsTemplate } from '@/src/hooks/mutations/useCompetitionMutations'; + +interface SaveAsTemplateModalProps { + isOpen: boolean; + onClose: () => void; + competitionId: number; + defaultName: string; +} + +export default function SaveAsTemplateModal({ + isOpen, + onClose, + competitionId, + defaultName, +}: SaveAsTemplateModalProps) { + const [name, setName] = useState(defaultName + ' Template'); + const [description, setDescription] = useState(''); + const saveAsTemplateMutation = useSaveAsTemplate(competitionId); + + if (!isOpen) return null; + + const handleSubmit = async (e: React.FormEvent) => { + e.preventDefault(); + + if (!name.trim()) return; + + try { + await saveAsTemplateMutation.mutateAsync({ + name: name.trim(), + description: description.trim() || undefined, + }); + onClose(); + } catch { + // Error is handled by the mutation + } + }; + + return ( +
+ {/* Backdrop */} +
+ + {/* Modal */} +
+ {/* Header */} +
+
+
+ +
+
+

Save as Template

+

Create a reusable template from this competition

+
+
+ +
+ + {/* Form */} +
+
+
+ + setName(e.target.value)} + placeholder="e.g., Weekly Padel Tournament" + className="w-full px-4 py-2 border border-slate-300 rounded-xl focus:ring-2 focus:ring-purple-500 focus:border-purple-500 outline-none transition-all" + required + /> +
+ +
+ +