@ -345,6 +345,7 @@ export function ClientDetail() {
name = { module Name ( cm . module Id ) }
name = { module Name ( cm . module Id ) }
refreshToken = { milestonesVersion }
refreshToken = { milestonesVersion }
payments = { ledger . data ? . payments ? ? [ ] }
payments = { ledger . data ? . payments ? ? [ ] }
docs = { ledger . data ? . documents ? ? [ ] }
onTickPayment = { ( key , label ) = > { setLinkError ( undefined ) ; setPaymentPicker ( { clientModuleId : cm.id , key , label } ) } }
onTickPayment = { ( key , label ) = > { setLinkError ( undefined ) ; setPaymentPicker ( { clientModuleId : cm.id , key , label } ) } }
onTickCreds = { ( key , label ) = > { setCredsError ( undefined ) ; setCredsDialog ( { cm , key , label } ) } }
onTickCreds = { ( key , label ) = > { setCredsError ( undefined ) ; setCredsDialog ( { cm , key , label } ) } }
onTickDocument = { ( key , label ) = > { setDocLinkError ( undefined ) ; setDocPicker ( { clientModuleId : cm.id , key , label } ) } }
onTickDocument = { ( key , label ) = > { setDocLinkError ( undefined ) ; setDocPicker ( { clientModuleId : cm.id , key , label } ) } }
@ -1427,7 +1428,10 @@ function SecretField(props: { cm: ClientModule; field: FieldDef; managerial: boo
* Un - ticking any of them toggles directly ( the server clears the link ) .
* Un - ticking any of them toggles directly ( the server clears the link ) .
* A done step carrying ` paymentId ` / ` documentId ` also renders a small reference under its
* A done step carrying ` paymentId ` / ` documentId ` also renders a small reference under its
* date ( ` onOpenDocument ` / ` onOpenPayments ` ) — otherwise a linked step looks identical to a
* date ( ` onOpenDocument ` / ` onOpenPayments ` ) — otherwise a linked step looks identical to a
* bare - toggled one .
* bare - toggled one . That reference is resolved against the client ' s ledger ( ` payments ` /
* ` docs ` ) so it reads as the real date + amount / document number , wraps to a second line
* inside the node rather than being ellipsised , and carries the full detail in its
* tooltip + accessible name .
* "+ Add step" appends a project - specific milestone . Every change is one audited POST
* "+ Add step" appends a project - specific milestone . Every change is one audited POST
* that returns the fresh list ; ` refreshToken ` lets the parent force a refetch after a
* that returns the fresh list ; ` refreshToken ` lets the parent force a refetch after a
* link lands from outside this component . ` onChanged ` additionally reloads the parent ' s
* link lands from outside this component . ` onChanged ` additionally reloads the parent ' s
@ -1437,7 +1441,10 @@ function SecretField(props: { cm: ClientModule; field: FieldDef; managerial: boo
* /
* /
function StatusLine ( props : {
function StatusLine ( props : {
clientModuleId : string ; name : string ; refreshToken : number
clientModuleId : string ; name : string ; refreshToken : number
/** The client's ledger — used to render the linked payment / document by its real
* date + amount ( and to fill the reference ' s tooltip ) , not a generic "linked" label . * /
payments : Payment [ ]
payments : Payment [ ]
docs : Doc [ ]
onTickPayment : ( key : string , label : string ) = > void
onTickPayment : ( key : string , label : string ) = > void
onTickCreds : ( key : string , label : string ) = > void
onTickCreds : ( key : string , label : string ) = > void
onTickDocument : ( key : string , label : string ) = > void
onTickDocument : ( key : string , label : string ) = > void
@ -1547,20 +1554,33 @@ function StatusLine(props: {
< span className = "nm" > { m . label } < / span >
< span className = "nm" > { m . label } < / span >
< span className = "dt" > { m . done ? ( m . doneOn ? ? '—' ) : m . key === currentKey ? 'now' : '—' } < / span >
< span className = "dt" > { m . done ? ( m . doneOn ? ? '—' ) : m . key === currentKey ? 'now' : '—' } < / span >
{ / * T h e l i n k e d p a y m e n t / d o c u m e n t i t s e l f — o t h e r w i s e a d o n e p a y m e n t / q u o t a t i o n
{ / * T h e l i n k e d p a y m e n t / d o c u m e n t i t s e l f — o t h e r w i s e a d o n e p a y m e n t / q u o t a t i o n
step shows only a date , with no evidence the link actually landed . * / }
step shows only a date , with no evidence the link actually landed . The
{ m . done && m . documentId !== null && (
reference wraps inside the node ( it used to be ellipsised to one 104 px
line , which cut the amount — the one thing it exists to show ) , and the
tooltip / accessible name carries the full detail rather than static text . * / }
{ m . done && m . documentId !== null && ( ( ) = > {
const d = props . docs . find ( ( x ) = > x . id === m . documentId )
const detail = d === undefined
? 'Linked document — open it'
: ` ${ docLabel ( d ) } ${ d . docNo ? ? '(draft)' } · ${ d . docDate } · ${ inr ( d . payablePaise ) } — open it `
return (
< button
< button
type = "button" className = "ref" title = "Open the linked document"
type = "button" className = "ref" title = { detail } aria - label = { detail }
onClick = { ( ) = > props . onOpenDocument ( m . documentId ! ) }
onClick = { ( ) = > props . onOpenDocument ( m . documentId ! ) }
>
>
view document →
{ d === undefined ? 'view document' : d . docNo ? ? ` ${ docLabel ( d ) } (draft) ` }
< / button >
< / button >
) }
)
} ) ( ) }
{ m . done && m . paymentId !== null && ( ( ) = > {
{ m . done && m . paymentId !== null && ( ( ) = > {
const p = props . payments . find ( ( x ) = > x . id === m . paymentId )
const p = props . payments . find ( ( x ) = > x . id === m . paymentId )
const detail = p === undefined
? 'Linked payment — open Payments & plans'
: ` Payment ${ p . receivedOn } · ${ inr ( p . amountPaise ) } `
+ ` ${ p . reference !== '' ? ` · ${ p . reference } ` : '' } — open Payments & plans `
return (
return (
< button
< button
type = "button" className = "ref" title = "The linked payment — open Payments & plans"
type = "button" className = "ref" title = { detail } aria - label = { detail }
onClick = { ( ) = > props . onOpenPayments ( ) }
onClick = { ( ) = > props . onOpenPayments ( ) }
>
>
{ p !== undefined ? ` ${ p . receivedOn } · ${ inr ( p . amountPaise ) } ` : 'payment linked' }
{ p !== undefined ? ` ${ p . receivedOn } · ${ inr ( p . amountPaise ) } ` : 'payment linked' }