import { useState } from 'react'; import { useForm } from 'react-hook-form'; import { zodResolver } from '@hookform/resolvers/zod'; import * as z from 'zod'; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from '@/components/ui/dialog'; import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger, } from '@/components/ui/alert-dialog'; import { Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage, } from '@/components/ui/form'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '@/components/ui/select'; import { Input } from '@/components/ui/input'; import { Textarea } from '@/components/ui/textarea'; import { Button } from '@/components/ui/button'; import { DatePicker } from '@/components/ui/date-picker'; import { Loader2, Trash } from 'lucide-react'; import { useAuth } from '@/hooks/useAuth'; import { useToast } from '@/hooks/use-toast'; import { submitTimelineEvent, submitTimelineEventUpdate, deleteTimelineEvent } from '@/lib/entitySubmissionHelpers'; import { getErrorMessage } from '@/lib/errorHandler'; import type { EntityType, TimelineEventFormData, } from '@/types/timeline'; // Validation schema const timelineEventSchema = z.object({ event_type: z.enum([ 'name_change', 'operator_change', 'owner_change', 'location_change', 'status_change', 'opening', 'closure', 'reopening', 'renovation', 'expansion', 'acquisition', 'milestone', 'other', ]), event_date: z.date({ message: 'Event date is required', }), event_date_precision: z.enum(['day', 'month', 'year']).default('day'), title: z.string().min(1, 'Title is required').max(200, 'Title is too long'), description: z.string().max(1000, 'Description is too long').optional(), // Conditional fields from_value: z.string().max(200).optional(), to_value: z.string().max(200).optional(), from_entity_id: z.string().uuid().optional(), to_entity_id: z.string().uuid().optional(), from_location_id: z.string().uuid().optional(), to_location_id: z.string().uuid().optional(), is_public: z.boolean().default(true), }); interface TimelineEventEditorDialogProps { open: boolean; onOpenChange: (open: boolean) => void; entityType: EntityType; entityId: string; entityName: string; existingEvent?: any; onSuccess?: () => void; } export function TimelineEventEditorDialog({ open, onOpenChange, entityType, entityId, entityName, existingEvent, onSuccess, }: TimelineEventEditorDialogProps) { const { user } = useAuth(); const { toast } = useToast(); const [isSubmitting, setIsSubmitting] = useState(false); const [showDeleteConfirm, setShowDeleteConfirm] = useState(false); const [isDeleting, setIsDeleting] = useState(false); const isEditing = !!existingEvent; const dialogTitle = isEditing ? 'Edit Timeline Event' : 'Add Timeline Event'; const submitButtonText = isEditing ? 'Update Event' : 'Submit for Review'; const form = useForm({ resolver: zodResolver(timelineEventSchema), defaultValues: existingEvent ? { event_type: existingEvent.event_type, event_date: new Date(existingEvent.event_date), event_date_precision: existingEvent.event_date_precision, title: existingEvent.title, description: existingEvent.description || '', from_value: existingEvent.from_value || '', to_value: existingEvent.to_value || '', from_entity_id: existingEvent.from_entity_id || '', to_entity_id: existingEvent.to_entity_id || '', from_location_id: existingEvent.from_location_id || '', to_location_id: existingEvent.to_location_id || '', } : { event_type: 'milestone', event_date: new Date(), event_date_precision: 'day', title: '', description: '', }, }); const selectedEventType = form.watch('event_type'); const onSubmit = async (data: TimelineEventFormData) => { if (!user) { toast({ title: 'Authentication required', description: 'You must be logged in to submit timeline events.', variant: 'destructive', }); return; } setIsSubmitting(true); try { if (isEditing) { await submitTimelineEventUpdate(existingEvent.id, data, user.id); toast({ title: 'Timeline event update submitted', description: 'Your update has been submitted for moderator review.', }); } else { await submitTimelineEvent(entityType, entityId, data, user.id); toast({ title: 'Timeline event submitted', description: 'Your timeline event has been submitted for moderator review.', }); } form.reset(); onOpenChange(false); onSuccess?.(); } catch (error) { console.error('Failed to submit timeline event:', error); toast({ title: 'Submission failed', description: error instanceof Error ? error.message : 'Failed to submit timeline event', variant: 'destructive', }); } finally { setIsSubmitting(false); } }; const handleDelete = async () => { if (!existingEvent || !user) return; setIsDeleting(true); try { await deleteTimelineEvent(existingEvent.id, user.id); toast({ title: 'Event deleted', description: 'Your timeline event has been deleted successfully.', }); onSuccess?.(); onOpenChange(false); setShowDeleteConfirm(false); form.reset(); } catch (error) { const errorMsg = getErrorMessage(error); console.error('Delete error:', errorMsg); toast({ title: 'Failed to delete event', description: errorMsg, variant: 'destructive', }); } finally { setIsDeleting(false); } }; // Event type configurations for conditional field rendering const showFromTo = [ 'name_change', 'operator_change', 'owner_change', 'status_change', ].includes(selectedEventType); return ( {dialogTitle} Add a historical milestone or event for {entityName}. All submissions go through moderator review.
( Event Type )} /> ( Event Title A brief, descriptive title for this event )} />
( Event Date )} /> ( Date Precision )} />
{showFromTo && (
( From )} /> ( To )} />
)} ( Description (Optional)