"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; // ─── Structured address fields (added 2026-08-18) ─── residential_address?: string | null; residential_address_line_1?: string | null; residential_address_line_2?: string | null; residential_town_city?: string | null; residential_province?: string | null; residential_postal_code?: string | null; postal_address_line_1?: string | null; postal_address_line_2?: string | null; postal_town_city?: string | null; postal_province?: string | null; postal_postal_code?: string | null; date_of_birth?: 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; company_email?: 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; // ─── Structured address fields (added 2026-08-18) ─── physical_address_line_1?: string | null; physical_address_line_2?: string | null; physical_town_city?: string | null; physical_province?: string | null; physical_postal_code?: string | null; postal_address_line_1?: string | null; postal_address_line_2?: string | null; postal_town_city?: string | null; postal_province?: string | null; postal_postal_code?: string | null; // ─── Company-level fields (added 2026-08-18) ─── financial_year_end_month?: number | null; authorised_shares?: number | null; company_cell_phone?: string | null; public_officer_name?: string | null; company_secretary_name?: string | null; } interface GroupOption { id: string; name: string; description?: string | null; } const SA_PROVINCES = [ "Eastern Cape", "Free State", "Gauteng", "KwaZulu-Natal", "Limpopo", "Mpumalanga", "Northern Cape", "North West", "Western Cape", ]; 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(""); // Director structured address fields (added 2026-08-18) const [dateOfBirth, setDateOfBirth] = useState(""); const [resAddr1, setResAddr1] = useState(""); const [resAddr2, setResAddr2] = useState(""); const [resTown, setResTown] = useState(""); const [resProvince, setResProvince] = useState(""); const [resPostalCode, setResPostalCode] = useState(""); const [postAddr1, setPostAddr1] = useState(""); const [postAddr2, setPostAddr2] = useState(""); const [postTown, setPostTown] = useState(""); const [postProvince, setPostProvince] = useState(""); const [postPostalCode, setPostPostalCode] = 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 [companyEmail, setCompanyEmail] = useState(""); const [notesCo, setNotesCo] = useState(""); // Company structured address fields (added 2026-08-18) const [physAddr1, setPhysAddr1] = useState(""); const [physAddr2, setPhysAddr2] = useState(""); const [physTown, setPhysTown] = useState(""); const [physProvince, setPhysProvince] = useState(""); const [physPostalCode, setPhysPostalCode] = useState(""); const [postCoAddr1, setPostCoAddr1] = useState(""); const [postCoAddr2, setPostCoAddr2] = useState(""); const [postCoTown, setPostCoTown] = useState(""); const [postCoProvince, setPostCoProvince] = useState(""); const [postCoPostalCode, setPostCoPostalCode] = useState(""); // Company-level fields (added 2026-08-18) const [financialYearEndMonth, setFinancialYearEndMonth] = useState(""); const [authorisedShares, setAuthorisedShares] = useState(""); const [companyCellPhone, setCompanyCellPhone] = useState(""); const [publicOfficerName, setPublicOfficerName] = useState(""); const [companySecretaryName, setCompanySecretaryName] = 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 ?? ""); setDateOfBirth(d.date_of_birth ?? ""); setResAddr1(d.residential_address_line_1 ?? ""); setResAddr2(d.residential_address_line_2 ?? ""); setResTown(d.residential_town_city ?? ""); setResProvince(d.residential_province ?? ""); setResPostalCode(d.residential_postal_code ?? ""); setPostAddr1(d.postal_address_line_1 ?? ""); setPostAddr2(d.postal_address_line_2 ?? ""); setPostTown(d.postal_town_city ?? ""); setPostProvince(d.postal_province ?? ""); setPostPostalCode(d.postal_postal_code ?? ""); } 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 ?? ""); setCompanyEmail(c.company_email ?? ""); setNotesCo(c.notes ?? ""); setPhysAddr1(c.physical_address_line_1 ?? ""); setPhysAddr2(c.physical_address_line_2 ?? ""); setPhysTown(c.physical_town_city ?? ""); setPhysProvince(c.physical_province ?? ""); setPhysPostalCode(c.physical_postal_code ?? ""); setPostCoAddr1(c.postal_address_line_1 ?? ""); setPostCoAddr2(c.postal_address_line_2 ?? ""); setPostCoTown(c.postal_town_city ?? ""); setPostCoProvince(c.postal_province ?? ""); setPostCoPostalCode(c.postal_postal_code ?? ""); setFinancialYearEndMonth(c.financial_year_end_month != null ? String(c.financial_year_end_month) : ""); setAuthorisedShares(c.authorised_shares != null ? String(c.authorised_shares) : ""); setCompanyCellPhone(c.company_cell_phone ?? ""); setPublicOfficerName(c.public_officer_name ?? ""); setCompanySecretaryName(c.company_secretary_name ?? ""); 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(); // Structured address fields (added 2026-08-18) if (dateOfBirth.trim()) fields.date_of_birth = dateOfBirth.trim(); if (resAddr1.trim()) fields.residential_address_line_1 = resAddr1.trim(); if (resAddr2.trim()) fields.residential_address_line_2 = resAddr2.trim(); if (resTown.trim()) fields.residential_town_city = resTown.trim(); if (resProvince.trim()) fields.residential_province = resProvince.trim(); if (resPostalCode.trim()) fields.residential_postal_code = resPostalCode.trim(); if (postAddr1.trim()) fields.postal_address_line_1 = postAddr1.trim(); if (postAddr2.trim()) fields.postal_address_line_2 = postAddr2.trim(); if (postTown.trim()) fields.postal_town_city = postTown.trim(); if (postProvince.trim()) fields.postal_province = postProvince.trim(); if (postPostalCode.trim()) fields.postal_postal_code = postPostalCode.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 (companyEmail.trim()) fields.company_email = companyEmail.trim(); if (notesCo.trim()) fields.notes = notesCo.trim(); // Structured address fields (added 2026-08-18) if (physAddr1.trim()) fields.physical_address_line_1 = physAddr1.trim(); if (physAddr2.trim()) fields.physical_address_line_2 = physAddr2.trim(); if (physTown.trim()) fields.physical_town_city = physTown.trim(); if (physProvince.trim()) fields.physical_province = physProvince.trim(); if (physPostalCode.trim()) fields.physical_postal_code = physPostalCode.trim(); if (postCoAddr1.trim()) fields.postal_address_line_1 = postCoAddr1.trim(); if (postCoAddr2.trim()) fields.postal_address_line_2 = postCoAddr2.trim(); if (postCoTown.trim()) fields.postal_town_city = postCoTown.trim(); if (postCoProvince.trim()) fields.postal_province = postCoProvince.trim(); if (postCoPostalCode.trim()) fields.postal_postal_code = postCoPostalCode.trim(); // Company-level fields (added 2026-08-18) if (financialYearEndMonth !== "" || (record as Company).financial_year_end_month != null) { fields.financial_year_end_month = financialYearEndMonth !== "" ? Number(financialYearEndMonth) : 0; } if (authorisedShares !== "" || (record as Company).authorised_shares != null) { fields.authorised_shares = authorisedShares !== "" ? Number(authorisedShares) : 0; } if (companyCellPhone.trim()) fields.company_cell_phone = companyCellPhone.trim(); if (publicOfficerName.trim()) fields.public_officer_name = publicOfficerName.trim(); if (companySecretaryName.trim()) fields.company_secretary_name = companySecretaryName.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 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); } }; const monthNames = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]; 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} />
setDateOfBirth(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" />
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" />