import { useState, useEffect } from 'react'; import { useForm } from 'react-hook-form'; import { zodResolver } from '@hookform/resolvers/zod'; import * as z from 'zod'; import { entitySchemas } from '@/lib/entityValidationSchemas'; import { validateSubmissionHandler } from '@/lib/entityFormValidation'; import { getErrorMessage } from '@/lib/errorHandler'; import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { Textarea } from '@/components/ui/textarea'; import { Label } from '@/components/ui/label'; import { EntityMultiImageUploader, ImageAssignments } from '@/components/upload/EntityMultiImageUploader'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; import { DatePicker } from '@/components/ui/date-picker'; import { FlexibleDateInput, type DatePrecision } from '@/components/ui/flexible-date-input'; import { SlugField } from '@/components/ui/slug-field'; import { toast } from '@/hooks/use-toast'; import { handleError } from '@/lib/errorHandler'; import { MapPin, Save, X, Plus } from 'lucide-react'; import { toDateOnly } from '@/lib/dateUtils'; import { Badge } from '@/components/ui/badge'; import { Combobox } from '@/components/ui/combobox'; import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from '@/components/ui/dialog'; import { useOperators, usePropertyOwners } from '@/hooks/useAutocompleteData'; import { useUserRole } from '@/hooks/useUserRole'; import { useAuth } from '@/hooks/useAuth'; import type { TempCompanyData } from '@/types/company'; import { LocationSearch } from './LocationSearch'; import { OperatorForm } from './OperatorForm'; import { PropertyOwnerForm } from './PropertyOwnerForm'; const parkSchema = z.object({ name: z.string().min(1, 'Park name is required'), slug: z.string().min(1, 'Slug is required'), // Auto-generated, validated on submit description: z.string().optional(), park_type: z.string().min(1, 'Park type is required'), status: z.string().min(1, 'Status is required'), opening_date: z.string().optional(), opening_date_precision: z.enum(['day', 'month', 'year']).optional(), closing_date: z.string().optional(), closing_date_precision: z.enum(['day', 'month', 'year']).optional(), location: z.object({ name: z.string(), city: z.string().optional(), state_province: z.string().optional(), country: z.string(), postal_code: z.string().optional(), latitude: z.number(), longitude: z.number(), timezone: z.string().optional(), display_name: z.string(), }).optional(), location_id: z.string().uuid().optional(), website_url: z.string().url().optional().or(z.literal('')), phone: z.string().optional(), email: z.string().email().optional().or(z.literal('')), operator_id: z.string().uuid().optional(), property_owner_id: z.string().uuid().optional(), images: z.object({ uploaded: z.array(z.object({ url: z.string(), cloudflare_id: z.string().optional(), file: z.any().optional(), isLocal: z.boolean().optional(), caption: z.string().optional(), })), banner_assignment: z.number().nullable().optional(), card_assignment: z.number().nullable().optional(), }).optional() }); type ParkFormData = z.infer; interface ParkFormProps { onSubmit: (data: ParkFormData & { operator_id?: string; property_owner_id?: string; _compositeSubmission?: any; }) => Promise; onCancel?: () => void; initialData?: Partial; isEditing?: boolean; } const parkTypes = [ 'Theme Park', 'Amusement Park', 'Water Park', 'Family Entertainment Center', 'Adventure Park', 'Safari Park', 'Carnival', 'Fair' ]; const statusOptions = [ 'Operating', 'Closed Temporarily', 'Closed Permanently', 'Under Construction', 'Planned', 'Abandoned' ]; // Status mappings const STATUS_DISPLAY_TO_DB: Record = { 'Operating': 'operating', 'Closed Temporarily': 'closed_temporarily', 'Closed Permanently': 'closed_permanently', 'Under Construction': 'under_construction', 'Planned': 'planned', 'Abandoned': 'abandoned' }; const STATUS_DB_TO_DISPLAY: Record = { 'operating': 'Operating', 'closed_temporarily': 'Closed Temporarily', 'closed_permanently': 'Closed Permanently', 'under_construction': 'Under Construction', 'planned': 'Planned', 'abandoned': 'Abandoned' }; export function ParkForm({ onSubmit, onCancel, initialData, isEditing = false }: ParkFormProps) { const { isModerator } = useUserRole(); // Validate that onSubmit uses submission helpers (dev mode only) useEffect(() => { validateSubmissionHandler(onSubmit, 'park'); }, [onSubmit]); const { user } = useAuth(); // Operator state const [selectedOperatorId, setSelectedOperatorId] = useState(initialData?.operator_id || ''); const [tempNewOperator, setTempNewOperator] = useState(null); const [isOperatorModalOpen, setIsOperatorModalOpen] = useState(false); // Property Owner state const [selectedPropertyOwnerId, setSelectedPropertyOwnerId] = useState(initialData?.property_owner_id || ''); const [tempNewPropertyOwner, setTempNewPropertyOwner] = useState(null); const [isPropertyOwnerModalOpen, setIsPropertyOwnerModalOpen] = useState(false); // Fetch data const { operators, loading: operatorsLoading } = useOperators(); const { propertyOwners, loading: ownersLoading } = usePropertyOwners(); const { register, handleSubmit, setValue, watch, formState: { errors } } = useForm({ resolver: zodResolver(entitySchemas.park), defaultValues: { name: initialData?.name || '', slug: initialData?.slug || '', description: initialData?.description || '', park_type: initialData?.park_type || '', status: initialData?.status || 'operating' as const, // Store DB value opening_date: initialData?.opening_date || '', closing_date: initialData?.closing_date || '', location_id: initialData?.location_id || undefined, website_url: initialData?.website_url || '', phone: initialData?.phone || '', email: initialData?.email || '', operator_id: initialData?.operator_id || undefined, property_owner_id: initialData?.property_owner_id || undefined, images: { uploaded: [] } } }); const handleFormSubmit = async (data: ParkFormData) => { try { // Build composite submission if new entities were created const submissionContent: any = { park: data, }; // Add new operator if created if (tempNewOperator) { submissionContent.new_operator = tempNewOperator; submissionContent.park.operator_id = null; } // Add new property owner if created if (tempNewPropertyOwner) { submissionContent.new_property_owner = tempNewPropertyOwner; submissionContent.park.property_owner_id = null; } await onSubmit({ ...data, operator_id: tempNewOperator ? undefined : (selectedOperatorId || undefined), property_owner_id: tempNewPropertyOwner ? undefined : (selectedPropertyOwnerId || undefined), _compositeSubmission: (tempNewOperator || tempNewPropertyOwner) ? submissionContent : undefined }); toast({ title: isEditing ? "Park Updated" : "Park Created", description: isEditing ? "The park information has been updated successfully." : "The new park has been created successfully." }); } catch (error: unknown) { const errorMessage = getErrorMessage(error); handleError(error, { action: isEditing ? 'Update Park' : 'Create Park', userId: user?.id, metadata: { parkName: data.name, hasLocation: !!data.location_id, hasNewOperator: !!tempNewOperator, hasNewOwner: !!tempNewPropertyOwner } }); } }; return ( {isEditing ? 'Edit Park' : 'Create New Park'}
{/* Basic Information */}
{errors.name && (

{errors.name.message}

)}
setValue('slug', slug)} isModerator={isModerator()} />
{/* Description */}