"use client"; // components/UploadDocumentModal.tsx // Shared upload modal for director and company documents. // Has an inline "+ New Type" flow — no need to leave PB to add a type. import { useState, useEffect, useRef } from "react"; import { useQueryClient } from "@tanstack/react-query"; import { fetchDocumentTypes, createDocumentType, uploadDirectorDocument, uploadCompanyDocument, type DocType, } from "@/lib/api"; interface Props { context: "director" | "company"; entityId: string; open: boolean; onClose: () => void; onUploaded: () => void; } export default function UploadDocumentModal({ context, entityId, open, onClose, onUploaded, }: Props) { const qc = useQueryClient(); const overlayRef = useRef(null); const [docTypes, setDocTypes] = useState([]); const [selectedTypeId, setSelectedTypeId] = useState(""); const [notes, setNotes] = useState(""); const [file, setFile] = useState(null); const [loading, setLoading] = useState(false); const [error, setError] = useState(null); // New type creation state const [showNewType, setShowNewType] = useState(false); const [newTypeName, setNewTypeName] = useState(""); const [newTypeDesc, setNewTypeDesc] = useState(""); const [creatingType, setCreatingType] = useState(false); // Load document types whenever modal opens useEffect(() => { if (!open) return; fetchDocumentTypes(context) .then((r) => setDocTypes(r.items)) .catch(() => setDocTypes([])); }, [open, context]); // Reset form on open useEffect(() => { if (open) { setSelectedTypeId(""); setNotes(""); setFile(null); setError(null); setShowNewType(false); setNewTypeName(""); setNewTypeDesc(""); } }, [open]); if (!open) return null; const handleOverlayClick = (e: React.MouseEvent) => { if (e.target === overlayRef.current) onClose(); }; const handleCreateType = async (e: React.FormEvent) => { e.preventDefault(); if (!newTypeName.trim()) return; setCreatingType(true); setError(null); try { const created = await createDocumentType({ name: newTypeName.trim(), context, description: newTypeDesc.trim() || undefined, }); setDocTypes((prev) => [...prev, created]); setSelectedTypeId(created.id); setShowNewType(false); setNewTypeName(""); setNewTypeDesc(""); } catch (err) { setError(err instanceof Error ? err.message : "Failed to create type"); } finally { setCreatingType(false); } }; const handleFileChange = (e: React.ChangeEvent) => { const f = e.target.files?.[0] ?? null; if (f) { const allowed = ["application/pdf", "image/jpeg", "image/jpg"]; if (!allowed.includes(f.type)) { setError("Only PDF and JPEG files are allowed"); e.target.value = ""; return; } if (f.size > 10 * 1024 * 1024) { setError("File must be smaller than 10MB"); e.target.value = ""; return; } setFile(f); setError(null); } }; const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); if (!selectedTypeId) { setError("Please select a document type"); return; } if (!file) { setError("Please select a file to upload"); return; } setLoading(true); setError(null); const formData = new FormData(); formData.append(context === "director" ? "director_id" : "company_id", entityId); formData.append("document_type_id", selectedTypeId); formData.append("notes", notes); formData.append("file", file); formData.append("original_filename", file.name); try { if (context === "director") { await uploadDirectorDocument(formData); } else { await uploadCompanyDocument(formData); } await qc.invalidateQueries({ queryKey: ["documents", context, entityId] }); onUploaded(); onClose(); } catch (err) { setError(err instanceof Error ? err.message : "Upload failed. Please try again."); } finally { setLoading(false); } }; return (
{/* Header */}

Upload document

PDF or JPEG, max 10MB

{error && (
{error}
)} {/* Document type */}
{showNewType ? ( /* Inline new type form */

New type

setNewTypeName(e.target.value)} placeholder="e.g. SA ID, Tax Clearance" className="w-full rounded border border-border bg-surface-warm px-3 py-2 text-sm text-fg placeholder:text-muted focus:outline-none focus:border-accent" required /> setNewTypeDesc(e.target.value)} placeholder="Description (optional)" className="w-full rounded border border-border bg-surface-warm px-3 py-2 text-sm text-fg placeholder:text-muted focus:outline-none focus:border-accent" />
) : (
)}
{/* File */}
{file && (

{file.name} ({(file.size / 1024 / 1024).toFixed(2)} MB)

)}
{/* Notes */}