'use client'; import { useState } from 'react'; import { useRouter } from 'next/navigation'; import { useQuery, useMutation } from '@tanstack/react-query'; import { useForm, useFieldArray } from 'react-hook-form'; import { zodResolver } from '@hookform/resolvers/zod'; import { z } from 'zod'; import { transmittalService } from '@/lib/services/transmittal.service'; import { correspondenceService } from '@/lib/services/correspondence.service'; import { projectService } from '@/lib/services/project.service'; import { organizationService } from '@/lib/services/organization.service'; import { CreateTransmittalDto } from '@/types/dto/transmittal/transmittal.dto'; // UI Components import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { Textarea } from '@/components/ui/textarea'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from '@/components/ui/form'; import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList } from '@/components/ui/command'; import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover'; import { Check, ChevronsUpDown, Trash2, Plus, Loader2 } from 'lucide-react'; import { toast } from 'sonner'; import { cn } from '@/lib/utils'; // Schema for items const itemSchema = z.object({ itemType: z.enum(['DRAWING', 'RFA', 'CORRESPONDENCE']), itemId: z.coerce.number().min(1, 'Document ID is required'), description: z.string().optional(), // Virtual fields for UI display documentNumber: z.string().optional(), }); // Main form schema const formSchema = z.object({ projectId: z.string().min(1, 'Project is required'), // ADR-019: UUID recipientOrganizationId: z.string().min(1, 'Recipient is required'), // ADR-019: UUID correspondenceId: z.string().min(1, 'Correspondence is required'), // ADR-019: UUID string subject: z.string().min(1, 'Subject is required'), purpose: z.enum(['FOR_APPROVAL', 'FOR_INFORMATION', 'FOR_REVIEW', 'OTHER']), remarks: z.string().optional(), items: z.array(itemSchema).min(1, 'At least one item is required'), }); type FormData = z.infer; export function TransmittalForm() { const router = useRouter(); const [docOpen, setDocOpen] = useState(false); const form = useForm({ resolver: zodResolver(formSchema) as any, // eslint-disable-line @typescript-eslint/no-explicit-any -- zod 4 + @hookform/resolvers compat defaultValues: { projectId: '', recipientOrganizationId: '', correspondenceId: '', subject: '', purpose: 'FOR_APPROVAL', remarks: '', items: [{ itemType: 'DRAWING', itemId: 0, description: '' }], }, }); const { fields, append, remove } = useFieldArray({ control: form.control, name: 'items', }); // ADR-019: Fetch projects and organizations for UUID-based selectors const { data: projectsData, isLoading: isLoadingProjects } = useQuery({ queryKey: ['projects-dropdown'], queryFn: () => projectService.getAll(), }); const projectsList = projectsData?.data || projectsData || []; const { data: orgsData, isLoading: isLoadingOrgs } = useQuery({ queryKey: ['organizations-dropdown'], queryFn: () => organizationService.getAll(), }); const orgsList = orgsData?.data || orgsData || []; // Fetch correspondences (for header linkage) const { data: correspondences } = useQuery({ queryKey: ['correspondences-dropdown'], queryFn: () => correspondenceService.getAll({ limit: 50 }), }); const createMutation = useMutation({ mutationFn: (data: CreateTransmittalDto) => transmittalService.create(data), onSuccess: (result) => { toast.success('Transmittal created successfully'); // ADR-019: Navigate using UUID from correspondence router.push(`/transmittals/${result.correspondence?.uuid || result.uuid}`); }, onError: () => { toast.error('Failed to create transmittal'); }, }); const onSubmit = (data: FormData) => { // ADR-019: All IDs are now UUID strings from the form const cleanPayload: CreateTransmittalDto = { projectId: data.projectId, recipientOrganizationId: data.recipientOrganizationId, correspondenceId: data.correspondenceId, subject: data.subject, purpose: data.purpose as string, remarks: data.remarks, items: data.items.map((item) => ({ itemType: item.itemType, itemId: item.itemId, description: item.description, })), }; createMutation.mutate(cleanPayload); }; const selectedDocId = form.watch('correspondenceId'); const correspondenceList = correspondences?.data || []; const selectedDoc = correspondenceList.find((c: { uuid: string }) => c.uuid === selectedDocId); return (
{/* Main Info */} Transmittal Details {/* ADR-019: Project & Recipient Organization selectors */}
( Project )} /> ( Recipient Organization )} />
{/* Linked Correspondence (Ref No) */} ( Reference Document No document found. {correspondenceList.map((doc: { uuid: string; correspondenceNumber?: string }) => ( { form.setValue('correspondenceId', doc.uuid); setDocOpen(false); }} > {doc.correspondenceNumber || doc.uuid} ))} )} /> {/* Purpose */} ( Purpose )} />
{/* Subject */} ( Subject )} /> {/* Remarks */} ( Remarks (Optional)