import React, { useState, useEffect, useRef } from 'react' import Modal from '../shared/Modal' import { Calendar, Camera, X } from 'lucide-react' import { tripsApi } from '../../api/client' import { useToast } from '../shared/Toast' import { useTranslation } from '../../i18n' import { CustomDatePicker } from '../shared/CustomDateTimePicker' export default function TripFormModal({ isOpen, onClose, onSave, trip, onCoverUpdate }) { const isEditing = !!trip const fileRef = useRef(null) const toast = useToast() const { t } = useTranslation() const [formData, setFormData] = useState({ title: '', description: '', start_date: '', end_date: '', }) const [error, setError] = useState('') const [isLoading, setIsLoading] = useState(false) const [coverPreview, setCoverPreview] = useState(null) const [uploadingCover, setUploadingCover] = useState(false) useEffect(() => { if (trip) { setFormData({ title: trip.title || '', description: trip.description || '', start_date: trip.start_date || '', end_date: trip.end_date || '', }) setCoverPreview(trip.cover_image || null) } else { setFormData({ title: '', description: '', start_date: '', end_date: '' }) setCoverPreview(null) } setError('') }, [trip, isOpen]) const handleSubmit = async (e) => { e.preventDefault() setError('') if (!formData.title.trim()) { setError(t('dashboard.titleRequired')); return } if (formData.start_date && formData.end_date && new Date(formData.end_date) < new Date(formData.start_date)) { setError(t('dashboard.endDateError')); return } setIsLoading(true) try { await onSave({ title: formData.title.trim(), description: formData.description.trim() || null, start_date: formData.start_date || null, end_date: formData.end_date || null, }) onClose() } catch (err) { setError(err.message || t('places.saveError')) } finally { setIsLoading(false) } } const handleCoverChange = async (e) => { const file = e.target.files?.[0] if (!file || !trip?.id) return setUploadingCover(true) try { const fd = new FormData() fd.append('cover', file) const data = await tripsApi.uploadCover(trip.id, fd) setCoverPreview(data.cover_image) onCoverUpdate?.(trip.id, data.cover_image) toast.success(t('dashboard.coverSaved')) } catch { toast.error(t('dashboard.coverUploadError')) } finally { setUploadingCover(false) e.target.value = '' } } const handleRemoveCover = async () => { if (!trip?.id) return try { await tripsApi.update(trip.id, { cover_image: null }) setCoverPreview(null) onCoverUpdate?.(trip.id, null) } catch { toast.error(t('dashboard.coverRemoveError')) } } const update = (field, value) => setFormData(prev => ({ ...prev, [field]: value })) const inputCls = "w-full px-3 py-2.5 border border-slate-200 rounded-lg text-slate-900 placeholder-slate-400 focus:outline-none focus:ring-2 focus:ring-slate-300 focus:border-transparent text-sm" return ( } >
{error && (
{error}
)} {/* Cover image — only for existing trips */} {isEditing && (
{coverPreview ? (
) : ( )}
)}
update('title', e.target.value)} required placeholder={t('dashboard.tripTitlePlaceholder')} className={inputCls} />