'use client' import { useEffect, useState } from 'react' import { trpc } from '@/lib/trpc/client' import { Button } from '@/components/ui/button' import { Input } from '@/components/ui/input' import { Label } from '@/components/ui/label' import { Textarea } from '@/components/ui/textarea' import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from '@/components/ui/dialog' import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '@/components/ui/select' import { Loader2 } from 'lucide-react' import { toast } from 'sonner' import type { VisaStatus } from '@prisma/client' const STATUS_OPTIONS: { value: VisaStatus; label: string }[] = [ { value: 'NOT_NEEDED', label: 'Not needed' }, { value: 'REQUESTED', label: 'Requested' }, { value: 'INVITATION_SENT', label: 'Invitation sent' }, { value: 'APPOINTMENT_BOOKED', label: 'Appointment booked' }, { value: 'GRANTED', label: 'Granted' }, { value: 'DENIED', label: 'Denied' }, ] function toDateInputValue(d: Date | null | undefined): string { if (!d) return '' const dt = new Date(d) if (Number.isNaN(dt.getTime())) return '' // YYYY-MM-DD for return dt.toISOString().slice(0, 10) } function fromDateInputValue(s: string): Date | null { if (!s) return null const dt = new Date(s) return Number.isNaN(dt.getTime()) ? null : dt } export type VisaEditTarget = { id: string status: VisaStatus nationality: string | null invitationSentAt: Date | null appointmentAt: Date | null decisionAt: Date | null notes: string | null attendeeName: string projectTitle: string } export function VisaEditDialog({ open, target, programId, onOpenChange, }: { open: boolean target: VisaEditTarget | null programId: string onOpenChange: (next: boolean) => void }) { const utils = trpc.useUtils() const [status, setStatus] = useState('REQUESTED') const [nationality, setNationality] = useState('') const [invitationSent, setInvitationSent] = useState('') const [appointment, setAppointment] = useState('') const [decision, setDecision] = useState('') const [notes, setNotes] = useState('') useEffect(() => { if (target && open) { setStatus(target.status) setNationality(target.nationality ?? '') setInvitationSent(toDateInputValue(target.invitationSentAt)) setAppointment(toDateInputValue(target.appointmentAt)) setDecision(toDateInputValue(target.decisionAt)) setNotes(target.notes ?? '') } }, [target, open]) const mutation = trpc.logistics.updateVisaApplication.useMutation({ onSuccess: () => { toast.success('Visa application updated') utils.logistics.listVisaApplications.invalidate({ programId }) onOpenChange(false) }, onError: (e) => toast.error(e.message), }) const handleSave = () => { if (!target) return mutation.mutate({ id: target.id, status, nationality: nationality.trim() || null, invitationSentAt: fromDateInputValue(invitationSent), appointmentAt: fromDateInputValue(appointment), decisionAt: fromDateInputValue(decision), notes: notes.trim() || null, }) } return ( { if (!mutation.isPending) onOpenChange(next) }} > Update visa application {target ? `${target.attendeeName} · ${target.projectTitle}` : 'Loading…'}
setNationality(e.target.value)} placeholder="Self-declared, optional" />
setInvitationSent(e.target.value)} />
setAppointment(e.target.value)} />
setDecision(e.target.value)} />