@ -63,7 +63,7 @@ export function PlanDialog(props: {
const save = ( ) = > {
const save = ( ) = > {
if ( saving ) return
if ( saving ) return
if ( f . clientModuleId === '' ) { setError ( 'Pick a subscribed module' ) ; return }
if ( ! editing && f . clientModuleId === '' ) { setError ( 'Pick a subscribed module' ) ; return }
const amount = f . amountRs === '' ? undefined : Number ( f . amountRs )
const amount = f . amountRs === '' ? undefined : Number ( f . amountRs )
if ( amount !== undefined && ( ! Number . isFinite ( amount ) || amount <= 0 ) ) {
if ( amount !== undefined && ( ! Number . isFinite ( amount ) || amount <= 0 ) ) {
setError ( 'Amount must be a positive rupee value (or blank for the price book)' ) ; return
setError ( 'Amount must be a positive rupee value (or blank for the price book)' ) ; return
@ -71,7 +71,10 @@ export function PlanDialog(props: {
setError ( undefined )
setError ( undefined )
setSaving ( true )
setSaving ( true )
const body = {
const body = {
clientModuleId : f.clientModuleId , cadence : f.cadence , nextRun : f.nextRun , policy : f.policy ,
cadence : f.cadence , nextRun : f.nextRun , policy : f.policy ,
// PATCH /recurring/:id cannot re-point a plan at another module, so edit mode
// never sends clientModuleId (the select is disabled to match).
. . . ( editing ? { } : { clientModuleId : f.clientModuleId } ) ,
// Edit mode: blank means "revert to price book" — send an explicit null so it clears.
// Edit mode: blank means "revert to price book" — send an explicit null so it clears.
// Create mode: blank just omits the override, letting the price book resolve at generation time.
// Create mode: blank just omits the override, letting the price book resolve at generation time.
. . . ( editing
. . . ( editing
@ -93,13 +96,13 @@ export function PlanDialog(props: {
footer = {
footer = {
< >
< >
< Button pill onClick = { ( ) = > { if ( ! saving ) props . onClose ( ) } } > Cancel < / Button >
< Button pill onClick = { ( ) = > { if ( ! saving ) props . onClose ( ) } } > Cancel < / Button >
< Button pill tone = "primary" onClick= { save } > { saving ? 'Saving…' : editing ? 'Save changes' : 'New recurring plan' } < / Button >
< Button pill tone = "primary" disabled= { saving } onClick= { save } > { saving ? 'Saving…' : editing ? 'Save changes' : 'New recurring plan' } < / Button >
< / >
< / >
}
}
>
>
< FormGrid >
< FormGrid >
< FormField label = "Module" >
< FormField label = "Module" >
< select className = "wf" autoFocus value = { f . clientModuleId } onChange = { set ( 'clientModuleId' ) } >
< select className = "wf" autoFocus = { ! editing } value = { f . clientModuleId } onChange = { set ( 'clientModuleId' ) } disabled = { editing } >
< option value = "" > Module … < / option >
< option value = "" > Module … < / option >
{ props . options . map ( ( o ) = > < option key = { o . id } value = { o . id } > { o . label } < / option > ) }
{ props . options . map ( ( o ) = > < option key = { o . id } value = { o . id } > { o . label } < / option > ) }
< / select >
< / select >
@ -176,7 +179,7 @@ export function AmcDialog(props: {
footer = {
footer = {
< >
< >
< Button pill onClick = { ( ) = > { if ( ! saving ) props . onClose ( ) } } > Cancel < / Button >
< Button pill onClick = { ( ) = > { if ( ! saving ) props . onClose ( ) } } > Cancel < / Button >
< Button pill tone = "primary" onClick= { save } > { saving ? 'Saving…' : editing ? 'Save changes' : 'New AMC' } < / Button >
< Button pill tone = "primary" disabled= { saving } onClick= { save } > { saving ? 'Saving…' : editing ? 'Save changes' : 'New AMC' } < / Button >
< / >
< / >
}
}
>
>
@ -222,7 +225,11 @@ export function InteractionDialog(props: {
setError ( undefined )
setError ( undefined )
setSaving ( true )
setSaving ( true )
const body = {
const body = {
typeCode : f.typeCode , onDate : f.onDate , notes : f.notes ,
notes : f.notes ,
// PATCH /interactions/:id cannot change type or date, so edit mode never sends
// typeCode/onDate (the fields are disabled to match) — a silently-ignored
// "correction" with a success toast is worse than a locked field.
. . . ( editing ? { } : { typeCode : f.typeCode , onDate : f.onDate } ) ,
// Edit mode: blank means "clear it" — send an explicit null so the server clears the column
// Edit mode: blank means "clear it" — send an explicit null so the server clears the column
// (same semantics as ClientDetail's inline follow-up quick-edit). Create mode omits when blank.
// (same semantics as ClientDetail's inline follow-up quick-edit). Create mode omits when blank.
. . . ( editing
. . . ( editing
@ -247,18 +254,18 @@ export function InteractionDialog(props: {
footer = {
footer = {
< >
< >
< Button pill onClick = { ( ) = > { if ( ! saving ) props . onClose ( ) } } > Cancel < / Button >
< Button pill onClick = { ( ) = > { if ( ! saving ) props . onClose ( ) } } > Cancel < / Button >
< Button pill tone = "primary" onClick= { save } > { saving ? ( editing ? 'Saving…' : 'Logging…' ) : editing ? 'Save changes' : 'Log interaction' } < / Button >
< Button pill tone = "primary" disabled= { saving } onClick= { save } > { saving ? ( editing ? 'Saving…' : 'Logging…' ) : editing ? 'Save changes' : 'Log interaction' } < / Button >
< / >
< / >
}
}
>
>
< FormGrid >
< FormGrid >
< FormField label = "Type" >
< FormField label = "Type" >
< select className = "wf" autoFocus value = { f . typeCode } onChange = { set ( 'typeCode' ) } >
< select className = "wf" autoFocus = { ! editing } value = { f . typeCode } onChange = { set ( 'typeCode' ) } disabled = { editing } >
< option value = "" > Type … < / option >
< option value = "" > Type … < / option >
{ props . types . map ( ( t ) = > < option key = { t . code } value = { t . code } > { t . label } < / option > ) }
{ props . types . map ( ( t ) = > < option key = { t . code } value = { t . code } > { t . label } < / option > ) }
< / select >
< / select >
< / FormField >
< / FormField >
< FormField label = "On" > < input type = "date" className = "wf" value = { f . onDate } onChange = { set ( 'onDate' ) } / > < / FormField >
< FormField label = "On" > < input type = "date" className = "wf" value = { f . onDate } onChange = { set ( 'onDate' ) } disabled = { editing } / > < / FormField >
< FormField label = "Outcome" >
< FormField label = "Outcome" >
< select className = "wf" value = { f . outcome } onChange = { set ( 'outcome' ) } >
< select className = "wf" value = { f . outcome } onChange = { set ( 'outcome' ) } >
< option value = "" > — < / option >
< option value = "" > — < / option >
@ -375,7 +382,7 @@ export function PaymentForm(props: { clientId: string; onDone: () => void }) {
< / Field >
< / Field >
< Field label = "Reference" > < input className = "wf" value = { f . reference } onChange = { set ( 'reference' ) } / > < / Field >
< Field label = "Reference" > < input className = "wf" value = { f . reference } onChange = { set ( 'reference' ) } / > < / Field >
< Field label = "Received on" > < input type = "date" className = "wf" value = { f . receivedOn } onChange = { set ( 'receivedOn' ) } / > < / Field >
< Field label = "Received on" > < input type = "date" className = "wf" value = { f . receivedOn } onChange = { set ( 'receivedOn' ) } / > < / Field >
< Button tone = "primary" onClick= { save } > { saving ? 'Recording…' : 'Record payment' } < / Button >
< Button tone = "primary" disabled= { saving } onClick= { save } > { saving ? 'Recording…' : 'Record payment' } < / Button >
< / div >
< / div >
{ error !== undefined && < Notice tone = "err" > { error } < / Notice > }
{ error !== undefined && < Notice tone = "err" > { error } < / Notice > }
< / div >
< / div >