"use client"; import { useState } from "react"; interface AnnualReturn { id: string; ar_year: number; ar_month: string; is_filed: boolean; date_filed: string; amount_paid: number; ar_non_compliance_date: string; source: string; } interface TaxReturn { id: string; company: string; return_type: "IRP6" | "IncomeTax"; period: string; date_filed: string; amount_paid: number; } interface Props { companyId: string; companyName: string; initialRecords: AnnualReturn[]; irp6Records: TaxReturn[]; incomeTaxRecords: TaxReturn[]; } const MONTH_ORDER = [ "JANUARY", "FEBRUARY", "MARCH", "APRIL", "MAY", "JUNE", "JULY", "AUGUST", "SEPTEMBER", "OCTOBER", "NOVEMBER", "DECEMBER", ]; function sortRecords(records: AnnualReturn[]) { return [...records].sort((a, b) => { if (b.ar_year !== a.ar_year) return b.ar_year - a.ar_year; return MONTH_ORDER.indexOf(a.ar_month) - MONTH_ORDER.indexOf(b.ar_month); }); } function filedBadge(filed: boolean) { return filed ? ( Filed ) : ( Outstanding ); } function formatAmount(amount: number) { const abs = Math.abs(amount); return abs > 0 ? `R ${abs.toLocaleString()}` : "—"; } function formatDate(dateStr: string) { if (!dateStr) return "—"; const d = new Date(dateStr + "T00:00:00"); return d.toLocaleDateString("en-ZA", { year: "numeric", month: "short", day: "numeric" }); } function getNextSubmissionDate(latestYear: number | undefined) { if (latestYear) { const dueYear = latestYear + 1; return `31 January ${dueYear}`; } const now = new Date(); return `31 January ${now.getFullYear()}`; } // ── SARS Returns Section ──────────────────────────────────────────────────────── function formatPeriod(period: string, returnType: string) { if (returnType === "IRP6") { if (period.length === 6) { const year = period.slice(0, 4); const num = period.slice(4); return `${num === "1" ? "1st" : "2nd"} period ${year}`; } return period; } return period; // Income Tax: just the year } function SARSReturnsSection({ irp6Records, incomeTaxRecords }: { irp6Records: TaxReturn[]; incomeTaxRecords: TaxReturn[] }) { if (irp6Records.length === 0 && incomeTaxRecords.length === 0) { return (

No filings recorded yet

Click "Record New Filing" to add an IRP6 or Income Tax submission.

); } const latestIRP6 = [...irp6Records].sort((a, b) => b.period.localeCompare(a.period))[0]; const latestIncomeTax = [...incomeTaxRecords].sort((a, b) => b.period.localeCompare(a.period))[0]; return (
{/* IRP6 */}
IRP6 — Provisional Tax {latestIRP6 && ( · Latest: {formatPeriod(latestIRP6.period, "IRP6")} )}
{irp6Records.slice(0, 5).map((ret) => ( ))} {irp6Records.length === 0 && ( )}
Period Date Filed Amount
{formatPeriod(ret.period, "IRP6")} {formatDate(ret.date_filed)} {formatAmount(ret.amount_paid)}
No IRP6 filings.
{/* Income Tax */}
Income Tax {latestIncomeTax && ( · Latest: {latestIncomeTax.period} year of assessment )}
{incomeTaxRecords.slice(0, 5).map((ret) => ( ))} {incomeTaxRecords.length === 0 && ( )}
Year Date Filed Amount
{ret.period} {formatDate(ret.date_filed)} {formatAmount(ret.amount_paid)}
No Income Tax filings.
); } // ── New Filing Modal ────────────────────────────────────────────────────────── function NewFilingModal({ companyId, onClose, onSuccess }: { companyId: string; onClose: () => void; onSuccess: () => void }) { const [returnType, setReturnType] = useState<"IRP6" | "IncomeTax">("IRP6"); const [period, setPeriod] = useState(""); const [dateFiled, setDateFiled] = useState(""); const [amountPaid, setAmountPaid] = useState(""); const [saving, setSaving] = useState(false); const [error, setError] = useState(""); function handleSubmit(e: React.FormEvent) { e.preventDefault(); if (!period.trim() || !dateFiled) { setError("Period and date filed are required."); return; } setSaving(true); setError(""); const fields: Record = { company: companyId, return_type: returnType, period: period.trim(), date_filed: dateFiled, amount_paid: amountPaid ? parseFloat(amountPaid) : 0, }; fetch("/api/pb/records/create", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ collection: "ysterbaard_sars_irp6_income_tax", fields }), }) .then((r) => r.json()) .then((data) => { if (data.error) throw new Error(data.error); onSuccess(); }) .catch((err: Error) => { setError(err.message || "Failed to save. Please try again."); setSaving(false); }); } return (
e.target === e.currentTarget && onClose()}>

Record SARS Filing

{/* Return type */}
{(["IRP6", "IncomeTax"] as const).map((t) => ( ))}
{/* Period */}
setPeriod(e.target.value)} placeholder={returnType === "IRP6" ? "e.g. 202602" : "e.g. 2023"} className="w-full px-4 py-2.5 rounded-md border border-border bg-background text-fg text-sm placeholder-muted focus:outline-none focus:border-indigo-500 focus:ring-1 focus:ring-indigo-500" required />

{returnType === "IRP6" ? "Year + 1 or 2 (e.g. 202602 = 2nd period 2026)" : "Year of assessment (e.g. 2023)"}

{/* Date filed */}
setDateFiled(e.target.value)} className="w-full px-4 py-2.5 rounded-md border border-border bg-background text-fg text-sm focus:outline-none focus:border-indigo-500 focus:ring-1 focus:ring-indigo-500" required />
{/* Amount paid */}
setAmountPaid(e.target.value)} placeholder="0.00" step="0.01" min="0" className="w-full px-4 py-2.5 rounded-md border border-border bg-background text-fg text-sm placeholder-muted focus:outline-none focus:border-indigo-500 focus:ring-1 focus:ring-indigo-500" />
{error && (
{error}
)}
); } // ── Main Component ──────────────────────────────────────────────────────────── export default function ComplianceSnapshot({ companyId, companyName, initialRecords, irp6Records, incomeTaxRecords }: Props) { const [showFilingModal, setShowFilingModal] = useState(false); const records = sortRecords(initialRecords); const filedRecords = records.filter((r) => r.is_filed); const lastThree = filedRecords.slice(0, 3); const latestYear = filedRecords[0]?.ar_year; const nonCompliant = records.find((r) => !r.is_filed && Boolean(r.ar_non_compliance_date)); return ( <>

Compliance snapshot

{/* ── 1. BizPortal ── */}

BizPortal — CIPC Annual Returns

From ysterbaard_annual_returns

{records.length === 0 ? (

No annual return records found for {companyName}.

) : (

Last 3 submissions

{lastThree.length > 0 ? lastThree.map((ret) => ( )) : ( )}
Year Month Date Filed Amount Paid Status
{ret.ar_year} {ret.ar_month.toLowerCase()} {formatDate(ret.date_filed)} {formatAmount(ret.amount_paid)} {filedBadge(ret.is_filed)}
No filed submissions yet.

Next submission date

{getNextSubmissionDate(latestYear)}

{nonCompliant ? (() => { const d = new Date(nonCompliant.ar_non_compliance_date + "T00:00:00"); const now = new Date(); const months = (now.getFullYear() - d.getFullYear()) * 12 + (now.getMonth() - d.getMonth()); const overdueLabel = months <= 0 ? "< 1 month overdue" : `${months} month${months !== 1 ? "s" : ""} overdue`; return (

Non-compliance date

{formatDate(nonCompliant.ar_non_compliance_date)}

{overdueLabel}

); })() : (

Non-compliance date

—

)}
)}
{/* ── 2. SARS ── */}

SARS

IRP6 · Income Tax

{showFilingModal && ( setShowFilingModal(false)} onSuccess={() => { setShowFilingModal(false); window.location.reload(); }} /> )} ); }