import { Button } from '@/components/ui/button'; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from '@/components/ui/dialog'; import { Field, FieldError, FieldLabel } from '@/components/ui/field'; import { Input } from '@/components/ui/input'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '@/components/ui/select'; import { ApiClientError, apiClient } from '@/lib/api-client'; import { zodResolver } from '@hookform/resolvers/zod'; import { type Court, type CreateCourtInput, createCourtSchema } from '@repo/api-contract'; import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; import { useEffect, useMemo, useState } from 'react'; import { Controller, useFieldArray, useForm } from 'react-hook-form'; import { DAY_OPTIONS } from '../lib/court.constants'; import { createDefaultCourtValues } from '../lib/court.utils'; type CourtFormSectionProps = { complexId: string | null; editingCourt: Court | null; initialDraft: CreateCourtInput | null; onCancelEdit: () => void; }; export function CourtFormSection({ complexId, editingCourt, initialDraft, onCancelEdit, }: CourtFormSectionProps) { const queryClient = useQueryClient(); const [formError, setFormError] = useState(null); const [isWeekModalOpen, setIsWeekModalOpen] = useState(false); const [weekDefaultStartTime, setWeekDefaultStartTime] = useState('08:00'); const [weekDefaultEndTime, setWeekDefaultEndTime] = useState('22:00'); const [weekModalError, setWeekModalError] = useState(null); const sportsQuery = useQuery({ queryKey: ['sports'], queryFn: () => apiClient.sports.list(), }); const form = useForm({ resolver: zodResolver(createCourtSchema), mode: 'onBlur', defaultValues: createDefaultCourtValues(), }); const availabilityFieldArray = useFieldArray({ control: form.control, name: 'availability', }); const saveMutation = useMutation({ mutationFn: async (payload: CreateCourtInput) => { if (editingCourt) { return apiClient.courts.update(editingCourt.id, payload); } if (!complexId) { throw new ApiClientError('No se pudo resolver el complejo para guardar la cancha.'); } return apiClient.courts.create(complexId, payload); }, onSuccess: () => { void queryClient.invalidateQueries({ queryKey: ['courts', complexId], }); setFormError(null); if (editingCourt) { onCancelEdit(); } form.reset(createDefaultCourtValues()); }, onError: (error) => { const message = error instanceof ApiClientError ? error.message : 'No se pudo guardar la cancha. Intenta nuevamente.'; setFormError(message); }, }); const activeSports = useMemo( () => (sportsQuery.data ?? []).filter((sport) => sport.isActive), [sportsQuery.data] ); const onSubmit = async (values: CreateCourtInput) => { setFormError(null); await saveMutation.mutateAsync(values); }; useEffect(() => { if (editingCourt) { form.reset({ name: editingCourt.name, sportId: editingCourt.sportId, slotDurationMinutes: editingCourt.slotDurationMinutes, basePrice: editingCourt.basePrice, availability: editingCourt.availability.map((slot) => ({ dayOfWeek: slot.dayOfWeek, startTime: slot.startTime, endTime: slot.endTime, })), }); return; } if (initialDraft) { form.reset(initialDraft); return; } form.reset(createDefaultCourtValues()); }, [editingCourt, form, initialDraft]); const title = editingCourt ? 'Editar cancha' : 'Nueva cancha'; const buttonText = editingCourt ? 'Guardar cambios' : 'Agregar cancha'; return (

{title}

Configura nombre, deporte, duración, precio base y horarios. El backend ya contempla precios por franja horaria para la siguiente etapa.

{ void onSubmit(values); })} > Nombre o descripción
Deporte ( )} /> Duración por turno (min) Precio base

Rangos horarios

Define uno o más rangos por día.

{availabilityFieldArray.fields.map((field, index) => (
Día ( )} /> Desde Hasta
))}
{formError &&

{formError}

}
{editingCourt && ( )}
{ setIsWeekModalOpen(nextOpen); if (!nextOpen) { setWeekModalError(null); } }} > Horario por defecto Ingresa el horario para completar los días faltantes de la semana.
Desde { setWeekDefaultStartTime(event.target.value); setWeekModalError(null); }} /> Hasta { setWeekDefaultEndTime(event.target.value); setWeekModalError(null); }} />
{weekModalError &&

{weekModalError}

}
); }