import React, { useState, useEffect, useRef } from 'react' import Modal from '../shared/Modal' import CustomSelect from '../shared/CustomSelect' import { Plane, Hotel, Utensils, Train, Car, Ship, Ticket, FileText, Users, Paperclip, X, ExternalLink } from 'lucide-react' import { useToast } from '../shared/Toast' import { useTranslation } from '../../i18n' import { CustomDateTimePicker } from '../shared/CustomDateTimePicker' const TYPE_OPTIONS = [ { value: 'flight', labelKey: 'reservations.type.flight', Icon: Plane }, { value: 'hotel', labelKey: 'reservations.type.hotel', Icon: Hotel }, { value: 'restaurant', labelKey: 'reservations.type.restaurant', Icon: Utensils }, { value: 'train', labelKey: 'reservations.type.train', Icon: Train }, { value: 'car', labelKey: 'reservations.type.car', Icon: Car }, { value: 'cruise', labelKey: 'reservations.type.cruise', Icon: Ship }, { value: 'event', labelKey: 'reservations.type.event', Icon: Ticket }, { value: 'tour', labelKey: 'reservations.type.tour', Icon: Users }, { value: 'other', labelKey: 'reservations.type.other', Icon: FileText }, ] export function ReservationModal({ isOpen, onClose, onSave, reservation, days, places, selectedDayId, files = [], onFileUpload, onFileDelete }) { const toast = useToast() const { t } = useTranslation() const fileInputRef = useRef(null) const [form, setForm] = useState({ title: '', type: 'other', status: 'pending', reservation_time: '', location: '', confirmation_number: '', notes: '', day_id: '', place_id: '', }) const [isSaving, setIsSaving] = useState(false) const [uploadingFile, setUploadingFile] = useState(false) const [pendingFiles, setPendingFiles] = useState([]) // for new reservations useEffect(() => { if (reservation) { setForm({ title: reservation.title || '', type: reservation.type || 'other', status: reservation.status || 'pending', reservation_time: reservation.reservation_time ? reservation.reservation_time.slice(0, 16) : '', location: reservation.location || '', confirmation_number: reservation.confirmation_number || '', notes: reservation.notes || '', day_id: reservation.day_id || '', place_id: reservation.place_id || '', }) } else { setForm({ title: '', type: 'other', status: 'pending', reservation_time: '', location: '', confirmation_number: '', notes: '', day_id: selectedDayId || '', place_id: '', }) setPendingFiles([]) } }, [reservation, isOpen, selectedDayId]) const set = (field, value) => setForm(prev => ({ ...prev, [field]: value })) const handleSubmit = async (e) => { e.preventDefault() if (!form.title.trim()) return setIsSaving(true) try { const saved = await onSave({ ...form, day_id: form.day_id || null, place_id: form.place_id || null, }) // Upload pending files for newly created reservations if (!reservation?.id && saved?.id && pendingFiles.length > 0) { for (const file of pendingFiles) { const fd = new FormData() fd.append('file', file) fd.append('reservation_id', saved.id) fd.append('description', form.title) await onFileUpload(fd) } } } finally { setIsSaving(false) } } const handleFileChange = async (e) => { const file = e.target.files?.[0] if (!file) return if (reservation?.id) { // Existing reservation โ€” upload immediately setUploadingFile(true) try { const fd = new FormData() fd.append('file', file) fd.append('reservation_id', reservation.id) fd.append('description', reservation.title) await onFileUpload(fd) toast.success(t('reservations.toast.fileUploaded')) } catch { toast.error(t('reservations.toast.uploadError')) } finally { setUploadingFile(false) e.target.value = '' } } else { // New reservation โ€” stage locally setPendingFiles(prev => [...prev, file]) e.target.value = '' } } const attachedFiles = reservation?.id ? files.filter(f => f.reservation_id === reservation.id) : [] const inputStyle = { width: '100%', border: '1px solid var(--border-primary)', borderRadius: 10, padding: '8px 14px', fontSize: 13, fontFamily: 'inherit', outline: 'none', boxSizing: 'border-box', color: 'var(--text-primary)', background: 'var(--bg-input)', } const labelStyle = { display: 'block', fontSize: 12, fontWeight: 600, color: 'var(--text-secondary)', marginBottom: 5 } return (
{/* Type selector */}
{TYPE_OPTIONS.map(({ value, labelKey, Icon }) => ( ))}
{/* Title */}
set('title', e.target.value)} required placeholder={t('reservations.titlePlaceholder')} style={inputStyle} />
{/* Date/Time + Status */}
set('reservation_time', v)} />
set('status', value)} options={[ { value: 'pending', label: t('reservations.pending') }, { value: 'confirmed', label: t('reservations.confirmed') }, ]} size="sm" />
{/* Location */}
set('location', e.target.value)} placeholder={t('reservations.locationPlaceholder')} style={inputStyle} />
{/* Confirmation number */}
set('confirmation_number', e.target.value)} placeholder={t('reservations.confirmationPlaceholder')} style={inputStyle} />
{/* Linked day + place */}
set('day_id', value)} placeholder={t('reservations.noDay')} options={[ { value: '', label: t('reservations.noDay') }, ...(days || []).map(day => ({ value: day.id, label: `${t('reservations.day')} ${day.day_number}${day.date ? ` ยท ${formatDate(day.date)}` : ''}`, })), ]} size="sm" />
set('place_id', value)} placeholder={t('reservations.noPlace')} options={[ { value: '', label: t('reservations.noPlace') }, ...(places || []).map(place => ({ value: place.id, label: place.name, })), ]} searchable size="sm" />
{/* Notes */}