162 lines
7.3 KiB
TypeScript
162 lines
7.3 KiB
TypeScript
// components/DirectorForm.tsx
|
|
// Renders a single director's form including Section 69 questions.
|
|
|
|
"use client";
|
|
|
|
import type { DirectorInput, Section69 } from "@/lib/wizard-types";
|
|
|
|
interface Props {
|
|
director: DirectorInput;
|
|
onUpdate: (patch: Partial<DirectorInput>) => void;
|
|
index: number;
|
|
}
|
|
|
|
const S69_QUESTIONS: { key: keyof Section69; label: string }[] = [
|
|
{ key: "q1_probation", label: "Are you a person who has been placed under probation by a court in terms of section 162, or in terms of section 47 of the Close Corporations Act, 1984?" },
|
|
{ key: "q2_court_prohibited", label: "Has a court prohibited you to be a director, or declared you to be delinquent in terms of section 162, or in terms of section 47 of the Close Corporations Act, 1984?" },
|
|
{ key: "q3_unrehabilitated_insolvent", label: "Are you an unrehabilitated insolvent?" },
|
|
{ key: "q4_public_regulation", label: "Are you prohibited in terms of any public regulation to be a director of the company?" },
|
|
{ key: "q5_removed_from_office", label: "Were you removed from an office of trust, on the grounds of misconduct involving dishonesty?" },
|
|
{ key: "q6_convicted_offence", label: "Were you convicted, in the Republic or elsewhere, and imprisoned without the option of a fine, or fined more than the prescribed amount, for theft, fraud, forgery, perjury or an offence?" },
|
|
];
|
|
|
|
function FormField({ label, hint, children }: { label: string; hint?: string; children: React.ReactNode }) {
|
|
return (
|
|
<div className="space-y-1.5">
|
|
<label className="text-sm font-semibold text-fg">{label}</label>
|
|
{children}
|
|
{hint && <p className="text-xs text-muted">{hint}</p>}
|
|
</div>
|
|
);
|
|
}
|
|
|
|
function YesNoButtons({ value, onChange }: { value: boolean | null; onChange: (v: boolean | null) => void }) {
|
|
return (
|
|
<div className="flex gap-2 mt-1">
|
|
{([true, false] as const).map((opt) => (
|
|
<button
|
|
key={String(opt)}
|
|
type="button"
|
|
onClick={() => onChange(value === opt ? null : opt)}
|
|
className={
|
|
"px-4 py-1.5 rounded text-sm font-semibold border transition-colors " +
|
|
(value === opt
|
|
? opt ? "bg-success text-success-on border-transparent" : "bg-danger text-danger-on border-transparent"
|
|
: "bg-surface border-border text-muted hover:text-fg")
|
|
}
|
|
>
|
|
{opt ? "Yes" : "No"}
|
|
</button>
|
|
))}
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export default function DirectorForm({ director: d, onUpdate, index }: Props) {
|
|
const updateS69 = (key: keyof Section69, value: boolean | null) => {
|
|
onUpdate({ section69: { ...d.section69, [key]: value } });
|
|
};
|
|
|
|
return (
|
|
<div className="border border-border rounded-lg overflow-hidden mb-6 last:mb-0">
|
|
<div className="bg-surface-warm border-b border-border px-5 py-3">
|
|
<p className="text-sm font-bold text-fg">Director {index + 1}</p>
|
|
</div>
|
|
<div className="p-5 space-y-5">
|
|
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
|
<FormField label="First names">
|
|
<input
|
|
className="w-full bg-surface border border-border rounded px-3 py-2 text-sm text-fg placeholder-muted focus:outline-none focus:border-accent transition-colors"
|
|
placeholder="e.g. Stephanus Johannes"
|
|
value={d.first_names}
|
|
onChange={(e) => onUpdate({ first_names: e.target.value })}
|
|
/>
|
|
</FormField>
|
|
<FormField label="Surname">
|
|
<input
|
|
className="w-full bg-surface border border-border rounded px-3 py-2 text-sm text-fg placeholder-muted focus:outline-none focus:border-accent transition-colors"
|
|
placeholder="e.g. van der Merwe"
|
|
value={d.surname}
|
|
onChange={(e) => onUpdate({ surname: e.target.value })}
|
|
/>
|
|
</FormField>
|
|
<FormField label="SA ID number">
|
|
<input
|
|
type="tel"
|
|
className="w-full bg-surface border border-border rounded px-3 py-2 text-sm text-fg placeholder-muted focus:outline-none focus:border-accent transition-colors"
|
|
placeholder="13-digit SA ID"
|
|
maxLength={13}
|
|
value={d.id_no}
|
|
onChange={(e) => onUpdate({ id_no: e.target.value })}
|
|
/>
|
|
</FormField>
|
|
<FormField label="Date of birth">
|
|
<input
|
|
type="date"
|
|
className="w-full bg-surface border border-border rounded px-3 py-2 text-sm text-fg focus:outline-none focus:border-accent transition-colors"
|
|
value={d.date_of_birth}
|
|
onChange={(e) => onUpdate({ date_of_birth: e.target.value })}
|
|
/>
|
|
</FormField>
|
|
</div>
|
|
|
|
<FormField label="Residential address">
|
|
<textarea
|
|
rows={2}
|
|
className="w-full bg-surface border border-border rounded px-3 py-2 text-sm text-fg placeholder-muted focus:outline-none focus:border-accent transition-colors resize-none"
|
|
placeholder="Physical residential address"
|
|
value={d.residential_address}
|
|
onChange={(e) => onUpdate({ residential_address: e.target.value })}
|
|
/>
|
|
</FormField>
|
|
|
|
<FormField label="Postal address" hint="Leave blank if same as residential address">
|
|
<textarea
|
|
rows={2}
|
|
className="w-full bg-surface border border-border rounded px-3 py-2 text-sm text-fg placeholder-muted focus:outline-none focus:border-accent transition-colors resize-none"
|
|
placeholder="Postal address"
|
|
value={d.postal_address}
|
|
onChange={(e) => onUpdate({ postal_address: e.target.value })}
|
|
/>
|
|
</FormField>
|
|
|
|
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
|
<FormField label="Cell phone">
|
|
<input
|
|
type="tel"
|
|
className="w-full bg-surface border border-border rounded px-3 py-2 text-sm text-fg placeholder-muted focus:outline-none focus:border-accent transition-colors"
|
|
placeholder="e.g. 0821234567"
|
|
value={d.cell_phone}
|
|
onChange={(e) => onUpdate({ cell_phone: e.target.value })}
|
|
/>
|
|
</FormField>
|
|
<FormField label="Email address">
|
|
<input
|
|
type="email"
|
|
className="w-full bg-surface border border-border rounded px-3 py-2 text-sm text-fg placeholder-muted focus:outline-none focus:border-accent transition-colors"
|
|
placeholder="unique@email.com"
|
|
value={d.email}
|
|
onChange={(e) => onUpdate({ email: e.target.value })}
|
|
/>
|
|
</FormField>
|
|
</div>
|
|
|
|
<div className="border-t border-border pt-5">
|
|
<p className="text-sm font-semibold text-fg mb-4">
|
|
Section 69 — Companies Act 71 of 2008
|
|
</p>
|
|
<div className="space-y-4">
|
|
{S69_QUESTIONS.map((q) => (
|
|
<div key={q.key} className="flex flex-col sm:flex-row sm:items-start sm:gap-4">
|
|
<div className="sm:w-2/3 text-sm text-fg leading-relaxed pt-0.5">{q.label}</div>
|
|
<div className="sm:w-1/3 flex-shrink-0">
|
|
<YesNoButtons value={d.section69[q.key]} onChange={(v) => updateS69(q.key, v)} />
|
|
</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|