"use client"; // components/EditEntityModal.tsx // Pre-filled edit form for existing director or company records. // Opens from the Edit button on a table row or from the detail page. // PUT/PATCH via /api/pb/records/:id, invalidates list + detail cache. import { useState, useEffect } from "react"; import { useQueryClient } from "@tanstack/react-query"; import { pbPatch, pbList } from "@/lib/api"; interface Director { id: string; surname?: string | null; first_names?: string | null; id_no?: string | null; telephone?: string | null; email?: string | null; postal_address?: string | null; director_type?: string | null; notes?: string | null; } interface Company { id: string; enterprise_no?: string | null; enterprise_name?: string | null; enterprise_type?: string | null; registration_date?: string | null; physical_address?: string | null; postal_address?: string | null; director?: string | null; notes?: string | null; sars_login_username?: string | null; sars_login_password?: string | null; sars_paye_no?: string | null; sars_vat_no?: string | null; sars_tax_number?: string | null; sars_vat_returns_period?: number | null; sars_paye_return_period?: number | null; groups?: string[] | null; } interface GroupOption { id: string; name: string; description?: string | null; } interface Props { entity: "director" | "company"; /** Original record data for pre-filling the form */ record: Director | Company; open: boolean; onClose: () => void; /** Called after a successful save */ onAfterSave?: () => void; } export default function EditEntityModal({ entity, record, open, onClose, onAfterSave }: Props) { const qc = useQueryClient(); const [loading, setLoading] = useState(false); const [error, setError] = useState(null); // Director fields const [surname, setSurname] = useState(""); const [firstNames, setFirstNames] = useState(""); const [idNo, setIdNo] = useState(""); const [telephone, setTelephone] = useState(""); const [email, setEmail] = useState(""); const [postalAddress, setPostalAddress] = useState(""); const [directorType, setDirectorType] = useState(""); const [notes, setNotes] = useState(""); // Company fields const [enterpriseNo, setEnterpriseNo] = useState(""); const [enterpriseName, setEnterpriseName] = useState(""); const [enterpriseType, setEnterpriseType] = useState(""); const [registrationDate, setRegistrationDate] = useState(""); const [physicalAddress, setPhysicalAddress] = useState(""); const [postalAddressCo, setPostalAddressCo] = useState(""); const [notesCo, setNotesCo] = useState(""); // SARS fields const [sarsLoginUsername, setSarsLoginUsername] = useState(""); const [sarsLoginPassword, setSarsLoginPassword] = useState(""); const [sarsPayeNo, setSarsPayeNo] = useState(""); const [sarsVatNo, setSarsVatNo] = useState(""); const [sarsTaxNo, setSarsTaxNo] = useState(""); const [sarsVatReturnsPeriod, setSarsVatReturnsPeriod] = useState(""); const [sarsPayeReturnPeriod, setSarsPayeReturnPeriod] = useState(""); // Group fields const [selectedGroups, setSelectedGroups] = useState([]); const [groupOptions, setGroupOptions] = useState([]); // Populate form when modal opens or record changes useEffect(() => { if (!open) return; setError(null); if (entity === "director") { const d = record as Director; setSurname(d.surname ?? ""); setFirstNames(d.first_names ?? ""); setIdNo(d.id_no ?? ""); setTelephone(d.telephone ?? ""); setEmail(d.email ?? ""); setPostalAddress(d.postal_address ?? ""); setDirectorType(d.director_type ?? ""); setNotes(d.notes ?? ""); } else { const c = record as Company; setEnterpriseNo(c.enterprise_no ?? ""); setEnterpriseName(c.enterprise_name ?? ""); setEnterpriseType(c.enterprise_type ?? ""); setRegistrationDate(c.registration_date ?? ""); setPhysicalAddress(c.physical_address ?? ""); setPostalAddressCo(c.postal_address ?? ""); setNotesCo(c.notes ?? ""); setSarsLoginUsername(c.sars_login_username ?? ""); setSarsLoginPassword(c.sars_login_password ?? ""); setSarsPayeNo(c.sars_paye_no ?? ""); setSarsVatNo(c.sars_vat_no ?? ""); setSarsTaxNo(c.sars_tax_number ?? ""); setSarsVatReturnsPeriod(c.sars_vat_returns_period != null ? String(c.sars_vat_returns_period) : ""); setSarsPayeReturnPeriod(c.sars_paye_return_period != null ? String(c.sars_paye_return_period) : ""); setSelectedGroups(c.groups ?? []); } }, [open, entity, record]); // Fetch group options when modal opens (company entity only) useEffect(() => { if (!open || entity !== "company") return; pbList({ collection: "groups", perPage: 200, sort: "name" }) .then((res) => setGroupOptions(res.items)) .catch(() => {}); }, [open, entity]); if (!open) return null; const isDirector = entity === "director"; const title = isDirector ? `Edit director — ${(record as Director).surname}, ${(record as Director).first_names}` : `Edit company — ${(record as Company).enterprise_name}`; const collection = isDirector ? "ysterbaard_directors" : "ysterbaard_companies"; const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); setError(null); setLoading(true); try { const fields: Record = {}; if (isDirector) { if (!surname.trim() || !firstNames.trim()) { setError("Surname and first names are required."); setLoading(false); return; } fields.surname = surname.trim(); fields.first_names = firstNames.trim(); if (idNo.trim()) fields.id_no = idNo.trim(); if (telephone.trim()) fields.telephone = telephone.trim(); if (email.trim()) fields.email = email.trim(); if (postalAddress.trim()) fields.postal_address = postalAddress.trim(); if (directorType.trim()) fields.director_type = directorType.trim(); if (notes.trim()) fields.notes = notes.trim(); } else { if (!enterpriseNo.trim() || !enterpriseName.trim()) { setError("Enterprise number and name are required."); setLoading(false); return; } fields.enterprise_no = enterpriseNo.trim().toUpperCase(); fields.enterprise_name = enterpriseName.trim().toUpperCase(); if (enterpriseType.trim()) fields.enterprise_type = enterpriseType.trim(); if (registrationDate.trim()) fields.registration_date = registrationDate.trim(); if (physicalAddress.trim()) fields.physical_address = physicalAddress.trim(); if (postalAddressCo.trim()) fields.postal_address = postalAddressCo.trim(); if (notesCo.trim()) fields.notes = notesCo.trim(); if (sarsLoginUsername.trim()) fields.sars_login_username = sarsLoginUsername.trim(); if (sarsLoginPassword.trim()) fields.sars_login_password = sarsLoginPassword.trim(); if (sarsPayeNo.trim()) fields.sars_paye_no = sarsPayeNo.trim(); if (sarsVatNo.trim()) fields.sars_vat_no = sarsVatNo.trim(); if (sarsTaxNo.trim()) fields.sars_tax_number = sarsTaxNo.trim(); // Period fields: store the selected numeric value as string (PocketBase number field accepts string->number conversion) const vatPeriod = sarsVatReturnsPeriod; const payePeriod = sarsPayeReturnPeriod; if (vatPeriod !== "" || (record as Company).sars_vat_returns_period != null) { fields.sars_vat_returns_period = vatPeriod !== "" ? Number(vatPeriod) : 0; } if (payePeriod !== "" || (record as Company).sars_paye_return_period != null) { fields.sars_paye_return_period = payePeriod !== "" ? Number(payePeriod) : 0; } // Groups — always send current selection (empty array is valid to clear) fields.groups = selectedGroups; } await pbPatch({ collection, id: record.id, fields }); // Invalidate both list and detail caches await qc.invalidateQueries({ queryKey: ["pb-list", collection] }); await qc.invalidateQueries({ queryKey: ["director", record.id] }); await qc.invalidateQueries({ queryKey: ["company", record.id] }); onAfterSave?.(); onClose(); } catch (err) { setError(err instanceof Error ? err.message : "Something went wrong. Please try again."); } finally { setLoading(false); } }; return (
{/* Header */}

Edit {isDirector ? "director" : "company"}

{title}

{/* Form */}
{error && (
{error}
)} {isDirector ? ( <>
setSurname(e.target.value.toUpperCase())} className="w-full rounded-lg border border-border bg-surface-warm px-3 py-2.5 text-sm text-fg focus:outline-none focus:border-accent focus:ring-1 focus:ring-accent" required />
setFirstNames(e.target.value.toUpperCase())} className="w-full rounded-lg border border-border bg-surface-warm px-3 py-2.5 text-sm text-fg focus:outline-none focus:border-accent focus:ring-1 focus:ring-accent" required />
setIdNo(e.target.value.replace(/\D/g, "").slice(0, 13))} className="w-full rounded-lg border border-border bg-surface-warm px-3 py-2.5 text-sm text-fg font-mono focus:outline-none focus:border-accent focus:ring-1 focus:ring-accent" maxLength={13} />
setTelephone(e.target.value)} className="w-full rounded-lg border border-border bg-surface-warm px-3 py-2.5 text-sm text-fg focus:outline-none focus:border-accent focus:ring-1 focus:ring-accent" />
setEmail(e.target.value)} className="w-full rounded-lg border border-border bg-surface-warm px-3 py-2.5 text-sm text-fg focus:outline-none focus:border-accent focus:ring-1 focus:ring-accent" />