2026-07-30 14:38:05 +00:00
"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.
2026-08-11 16:33:03 +00:00
import { useState , useEffect } from "react" ;
2026-07-30 14:38:05 +00:00
import { useQueryClient } from "@tanstack/react-query" ;
2026-08-11 16:33:03 +00:00
import { pbPatch , pbList } from "@/lib/api" ;
2026-07-30 14:38:05 +00:00
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 ;
2026-08-17 18:08:33 +00:00
company_email? : string | null ;
2026-07-30 14:38:05 +00:00
director? : string | null ;
notes? : string | null ;
2026-08-11 16:33:03 +00:00
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 ;
2026-07-30 14:38:05 +00:00
}
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 < string | null > ( 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 ( "" ) ;
2026-08-17 18:08:33 +00:00
const [ companyEmail , setCompanyEmail ] = useState ( "" ) ;
2026-07-30 14:38:05 +00:00
const [ notesCo , setNotesCo ] = useState ( "" ) ;
2026-08-11 16:33:03 +00:00
// 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 < string [ ] > ( [ ] ) ;
const [ groupOptions , setGroupOptions ] = useState < GroupOption [ ] > ( [ ] ) ;
2026-07-30 14:38:05 +00:00
// 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 ? ? "" ) ;
2026-08-17 18:08:33 +00:00
setCompanyEmail ( c . company_email ? ? "" ) ;
2026-07-30 14:38:05 +00:00
setNotesCo ( c . notes ? ? "" ) ;
2026-08-11 16:33:03 +00:00
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 ? ? [ ] ) ;
2026-07-30 14:38:05 +00:00
}
} , [ open , entity , record ] ) ;
2026-08-11 16:33:03 +00:00
// Fetch group options when modal opens (company entity only)
useEffect ( ( ) = > {
if ( ! open || entity !== "company" ) return ;
pbList < GroupOption > ( { collection : "groups" , perPage : 200 , sort : "name" } )
. then ( ( res ) = > setGroupOptions ( res . items ) )
. catch ( ( ) = > { } ) ;
} , [ open , entity ] ) ;
2026-07-30 14:38:05 +00:00
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 {
2026-08-11 16:33:03 +00:00
const fields : Record < string , string | number | string [ ] > = { } ;
2026-07-30 14:38:05 +00:00
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 ( ) ;
2026-08-17 18:08:33 +00:00
if ( companyEmail . trim ( ) ) fields . company_email = companyEmail . trim ( ) ;
2026-07-30 14:38:05 +00:00
if ( notesCo . trim ( ) ) fields . notes = notesCo . trim ( ) ;
2026-08-11 16:33:03 +00:00
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 ;
2026-07-30 14:38:05 +00:00
}
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 (
< div
className = "fixed inset-0 z-50 flex items-center justify-center bg-black/50 backdrop-blur-sm p-4"
role = "dialog"
aria - modal = "true"
aria - label = { title }
>
< div className = "bg-surface border border-border rounded-xl shadow-2xl w-full max-w-lg flex flex-col max-h-[90vh]" >
{ /* Header */ }
< div className = "px-6 pt-6 pb-4 border-b border-border flex-shrink-0" >
< div className = "flex items-start justify-between" >
< div >
< h2 className = "text-lg font-bold text-fg" > Edit { isDirector ? "director" : "company" } < / h2 >
< p className = "text-sm text-muted mt-0.5" > { title } < / p >
< / div >
< button
onClick = { onClose }
className = "ml-4 text-muted hover:text-fg text-xl leading-none p-1 rounded transition-colors"
aria - label = "Close"
>
×
< / button >
< / div >
< / div >
{ /* Form */ }
< form onSubmit = { handleSubmit } className = "flex-1 overflow-y-auto px-6 py-5 space-y-4" >
{ error && (
< div className = "bg-red-500/10 border border-red-500/30 rounded-lg px-4 py-3 text-sm text-red-400" >
{ error }
< / div >
) }
{ isDirector ? (
< >
< div className = "grid grid-cols-2 gap-4" >
< div >
< label className = "block text-sm font-semibold text-fg mb-1.5" htmlFor = "edit-surname" > Surname < span className = "text-red-400" > * < / span > < / label >
< input id = "edit-surname" type = "text" value = { surname }
onChange = { ( e ) = > 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 / >
< / div >
< div >
< label className = "block text-sm font-semibold text-fg mb-1.5" htmlFor = "edit-firstnames" > First names < span className = "text-red-400" > * < / span > < / label >
< input id = "edit-firstnames" type = "text" value = { firstNames }
onChange = { ( e ) = > 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 / >
< / div >
< / div >
< div >
< label className = "block text-sm font-semibold text-fg mb-1.5" htmlFor = "edit-idno" > SA ID number < span className = "text-xs text-muted font-normal" > ( optional ) < / span > < / label >
2026-07-30 15:53:41 +00:00
< input id = "edit-idno" type = "tel" value = { idNo }
2026-07-30 14:38:05 +00:00
onChange = { ( e ) = > 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 } / >
< / div >
< div className = "grid grid-cols-2 gap-4" >
< div >
< label className = "block text-sm font-semibold text-fg mb-1.5" htmlFor = "edit-tel" > Telephone < span className = "text-xs text-muted font-normal" > ( optional ) < / span > < / label >
< input id = "edit-tel" type = "tel" value = { telephone }
onChange = { ( e ) = > 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" / >
< / div >
< div >
< label className = "block text-sm font-semibold text-fg mb-1.5" htmlFor = "edit-email" > Email < span className = "text-xs text-muted font-normal" > ( optional ) < / span > < / label >
< input id = "edit-email" type = "email" value = { email }
onChange = { ( e ) = > 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" / >
< / div >
< / div >
< div >
< label className = "block text-sm font-semibold text-fg mb-1.5" htmlFor = "edit-postal" > Postal address < span className = "text-xs text-muted font-normal" > ( optional ) < / span > < / label >
< textarea id = "edit-postal" value = { postalAddress } rows = { 2 }
onChange = { ( e ) = > setPostalAddress ( e . target . value ) }
className = "w-full rounded-lg border border-border bg-surface-warm px-3 py-2.5 text-sm text-fg resize-none focus:outline-none focus:border-accent focus:ring-1 focus:ring-accent" / >
< / div >
< div >
< label className = "block text-sm font-semibold text-fg mb-1.5" htmlFor = "edit-type" > Director type < span className = "text-xs text-muted font-normal" > ( optional ) < / span > < / label >
< input id = "edit-type" type = "text" value = { directorType }
onChange = { ( e ) = > setDirectorType ( 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"
placeholder = "e.g. Individual, Corporate" / >
< / div >
< div >
< label className = "block text-sm font-semibold text-fg mb-1.5" htmlFor = "edit-notes" > Notes < span className = "text-xs text-muted font-normal" > ( optional ) < / span > < / label >
< textarea id = "edit-notes" value = { notes } rows = { 2 }
onChange = { ( e ) = > setNotes ( e . target . value ) }
className = "w-full rounded-lg border border-border bg-surface-warm px-3 py-2.5 text-sm text-fg resize-none focus:outline-none focus:border-accent focus:ring-1 focus:ring-accent" / >
< / div >
< / >
) : (
< >
< div className = "grid grid-cols-2 gap-4" >
< div >
< label className = "block text-sm font-semibold text-fg mb-1.5" htmlFor = "edit-eno" > Enterprise No . < span className = "text-red-400" > * < / span > < / label >
< input id = "edit-eno" type = "text" value = { enterpriseNo }
onChange = { ( e ) = > setEnterpriseNo ( e . target . value . toUpperCase ( ) ) }
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"
required / >
< / div >
< div >
< label className = "block text-sm font-semibold text-fg mb-1.5" htmlFor = "edit-etype" > Enterprise type < span className = "text-xs text-muted font-normal" > ( optional ) < / span > < / label >
< input id = "edit-etype" type = "text" value = { enterpriseType }
onChange = { ( e ) = > setEnterpriseType ( 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"
placeholder = "Private Company" / >
< / div >
< / div >
< div >
< label className = "block text-sm font-semibold text-fg mb-1.5" htmlFor = "edit-ename" > Enterprise name < span className = "text-red-400" > * < / span > < / label >
< input id = "edit-ename" type = "text" value = { enterpriseName }
onChange = { ( e ) = > setEnterpriseName ( 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 / >
< / div >
< div >
< label className = "block text-sm font-semibold text-fg mb-1.5" htmlFor = "edit-rdate" > Registration date < span className = "text-xs text-muted font-normal" > ( optional ) < / span > < / label >
< input id = "edit-rdate" type = "date" value = { registrationDate }
onChange = { ( e ) = > setRegistrationDate ( 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" / >
< / div >
< div >
< label className = "block text-sm font-semibold text-fg mb-1.5" htmlFor = "edit-phys" > Physical address < span className = "text-xs text-muted font-normal" > ( optional ) < / span > < / label >
< textarea id = "edit-phys" value = { physicalAddress } rows = { 2 }
onChange = { ( e ) = > setPhysicalAddress ( e . target . value ) }
className = "w-full rounded-lg border border-border bg-surface-warm px-3 py-2.5 text-sm text-fg resize-none focus:outline-none focus:border-accent focus:ring-1 focus:ring-accent" / >
< / div >
< div >
< label className = "block text-sm font-semibold text-fg mb-1.5" htmlFor = "edit-postalco" > Postal address < span className = "text-xs text-muted font-normal" > ( optional ) < / span > < / label >
< textarea id = "edit-postalco" value = { postalAddressCo } rows = { 2 }
onChange = { ( e ) = > setPostalAddressCo ( e . target . value ) }
className = "w-full rounded-lg border border-border bg-surface-warm px-3 py-2.5 text-sm text-fg resize-none focus:outline-none focus:border-accent focus:ring-1 focus:ring-accent" / >
< / div >
2026-08-17 18:08:33 +00:00
< div >
< label className = "block text-sm font-semibold text-fg mb-1.5" htmlFor = "edit-emailco" > Company email < span className = "text-xs text-muted font-normal" > ( optional ) < / span > < / label >
< input id = "edit-emailco" type = "email" value = { companyEmail }
onChange = { ( e ) = > setCompanyEmail ( 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"
placeholder = "company@example.com" / >
< / div >
2026-07-30 14:38:05 +00:00
< div >
< label className = "block text-sm font-semibold text-fg mb-1.5" htmlFor = "edit-notesco" > Notes < span className = "text-xs text-muted font-normal" > ( optional ) < / span > < / label >
< textarea id = "edit-notesco" value = { notesCo } rows = { 2 }
onChange = { ( e ) = > setNotesCo ( e . target . value ) }
className = "w-full rounded-lg border border-border bg-surface-warm px-3 py-2.5 text-sm text-fg resize-none focus:outline-none focus:border-accent focus:ring-1 focus:ring-accent" / >
< / div >
2026-08-11 16:33:03 +00:00
{ /* Group membership */ }
< div >
< label className = "block text-sm font-semibold text-fg mb-1.5" htmlFor = "edit-groups" > Group Membership < span className = "text-xs text-muted font-normal" > ( optional ) < / span > < / label >
< p className = "text-xs text-muted mb-2" > Hold Ctrl ( or Cmd on Mac ) to select multiple groups . < / p >
< select
id = "edit-groups"
multiple
value = { selectedGroups }
onChange = { ( e ) = > {
const opts = Array . from ( e . target . selectedOptions ) . map ( ( o ) = > o . value ) ;
setSelectedGroups ( opts ) ;
} }
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 min-h-[100px]" >
{ groupOptions . length === 0 ? (
< option value = "" disabled > No groups created yet — save and add groups via PocketBase < / option >
) : (
groupOptions . map ( ( g ) = > (
< option key = { g . id } value = { g . id } > { g . name } < / option >
) )
) }
< / select >
< / div >
{ /* SARS credentials */ }
< div className = "border-t border-border pt-4 mt-2" >
< p className = "text-sm font-semibold text-fg mb-3" > SARS eFiling Details < / p >
< div className = "grid grid-cols-2 gap-4" >
< div >
< label className = "block text-sm font-semibold text-fg mb-1.5" htmlFor = "edit-sars-user" > SARS Login Username < span className = "text-xs text-muted font-normal" > ( optional ) < / span > < / label >
< input id = "edit-sars-user" type = "text" value = { sarsLoginUsername }
onChange = { ( e ) = > setSarsLoginUsername ( 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"
placeholder = "eFiling username" / >
< / div >
< div >
< label className = "block text-sm font-semibold text-fg mb-1.5" htmlFor = "edit-sars-pass" > SARS Login Password < span className = "text-xs text-muted font-normal" > ( optional ) < / span > < / label >
< input id = "edit-sars-pass" type = "text" value = { sarsLoginPassword }
onChange = { ( e ) = > setSarsLoginPassword ( 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"
placeholder = "eFiling password" / >
< / div >
< / div >
< div className = "grid grid-cols-2 gap-4 mt-3" >
< div >
< label className = "block text-sm font-semibold text-fg mb-1.5" htmlFor = "edit-sars-paye" > SARS PAYE No . < span className = "text-xs text-muted font-normal" > ( optional ) < / span > < / label >
< input id = "edit-sars-paye" type = "text" value = { sarsPayeNo }
onChange = { ( e ) = > setSarsPayeNo ( e . target . value ) }
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"
placeholder = "e.g. 7020829828" / >
< / div >
< div >
< label className = "block text-sm font-semibold text-fg mb-1.5" htmlFor = "edit-sars-vat" > SARS VAT No . < span className = "text-xs text-muted font-normal" > ( optional ) < / span > < / label >
< input id = "edit-sars-vat" type = "text" value = { sarsVatNo }
onChange = { ( e ) = > setSarsVatNo ( e . target . value ) }
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"
placeholder = "e.g. 4123456789" / >
< / div >
< / div >
< div className = "mt-3" >
< label className = "block text-sm font-semibold text-fg mb-1.5" htmlFor = "edit-sars-tax" > SARS Tax No . < span className = "text-xs text-muted font-normal" > ( optional ) < / span > < / label >
< input id = "edit-sars-tax" type = "text" value = { sarsTaxNo }
onChange = { ( e ) = > setSarsTaxNo ( e . target . value ) }
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"
placeholder = "e.g. 9004615283" / >
< / div >
< div className = "grid grid-cols-2 gap-4 mt-3" >
< div >
< label className = "block text-sm font-semibold text-fg mb-1.5" htmlFor = "edit-sars-vat-period" > SARS VAT Returns Period < / label >
< select id = "edit-sars-vat-period" value = { sarsVatReturnsPeriod }
onChange = { ( e ) = > setSarsVatReturnsPeriod ( 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" >
< option value = "" > — select — < / option >
< option value = "0" > None < / option >
< option value = "1" > Every Month < / option >
< option value = "2" > Even Month < / option >
< option value = "3" > Uneven Months < / option >
< option value = "6" > Bi Annually < / option >
< option value = "12" > Annually < / option >
< / select >
< / div >
< div >
< label className = "block text-sm font-semibold text-fg mb-1.5" htmlFor = "edit-sars-paye-period" > SARS PAYE Returns Period < / label >
< select id = "edit-sars-paye-period" value = { sarsPayeReturnPeriod }
onChange = { ( e ) = > setSarsPayeReturnPeriod ( 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" >
< option value = "" > — select — < / option >
< option value = "0" > None < / option >
< option value = "1" > Every month < / option >
< / select >
< / div >
< / div >
< / div >
2026-07-30 14:38:05 +00:00
< / >
) }
< div className = "pt-2 flex gap-3" >
< button type = "button" onClick = { onClose }
className = "flex-1 px-4 py-2.5 rounded-lg border border-border bg-surface-warm text-sm font-semibold text-fg hover:bg-surface transition-colors" >
Cancel
< / button >
< button type = "submit" disabled = { loading }
className = "flex-1 px-4 py-2.5 rounded-lg bg-accent text-accent-on text-sm font-bold hover:bg-accent-hover transition-colors disabled:opacity-60 disabled:cursor-not-allowed" >
{ loading ? "Saving..." : "Save changes" }
< / button >
< / div >
< / form >
< / div >
< / div >
) ;
}