|
|
|
|
@ -346,6 +346,7 @@ export function ClientDetail() {
|
|
|
|
|
name={moduleName(cm.moduleId)}
|
|
|
|
|
refreshToken={milestonesVersion}
|
|
|
|
|
payments={ledger.data?.payments ?? []}
|
|
|
|
|
docs={ledger.data?.documents ?? []}
|
|
|
|
|
onTickPayment={(key, label) => { setLinkError(undefined); setPaymentPicker({ clientModuleId: cm.id, key, label }) }}
|
|
|
|
|
onTickCreds={(key, label) => { setCredsError(undefined); setCredsDialog({ cm, key, label }) }}
|
|
|
|
|
onTickDocument={(key, label) => { setDocLinkError(undefined); setDocPicker({ clientModuleId: cm.id, key, label }) }}
|
|
|
|
|
@ -1428,7 +1429,10 @@ function SecretField(props: { cm: ClientModule; field: FieldDef; managerial: boo
|
|
|
|
|
* 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
|
|
|
|
|
* 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
|
|
|
|
|
* 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
|
|
|
|
|
@ -1438,7 +1442,10 @@ function SecretField(props: { cm: ClientModule; field: FieldDef; managerial: boo
|
|
|
|
|
*/
|
|
|
|
|
function StatusLine(props: {
|
|
|
|
|
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[]
|
|
|
|
|
docs: Doc[]
|
|
|
|
|
onTickPayment: (key: string, label: string) => void
|
|
|
|
|
onTickCreds: (key: string, label: string) => void
|
|
|
|
|
onTickDocument: (key: string, label: string) => void
|
|
|
|
|
@ -1548,20 +1555,33 @@ function StatusLine(props: {
|
|
|
|
|
<span className="nm">{m.label}</span>
|
|
|
|
|
<span className="dt">{m.done ? (m.doneOn ?? '—') : m.key === currentKey ? 'now' : '—'}</span>
|
|
|
|
|
{/* The linked payment/document itself — otherwise a done payment/quotation
|
|
|
|
|
step shows only a date, with no evidence the link actually landed. */}
|
|
|
|
|
{m.done && m.documentId !== null && (
|
|
|
|
|
step shows only a date, with no evidence the link actually landed. The
|
|
|
|
|
reference wraps inside the node (it used to be ellipsised to one 104px
|
|
|
|
|
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
|
|
|
|
|
type="button" className="ref" title="Open the linked document"
|
|
|
|
|
type="button" className="ref" title={detail} aria-label={detail}
|
|
|
|
|
onClick={() => props.onOpenDocument(m.documentId!)}
|
|
|
|
|
>
|
|
|
|
|
view document →
|
|
|
|
|
{d === undefined ? 'view document' : d.docNo ?? `${docLabel(d)} (draft)`}
|
|
|
|
|
</button>
|
|
|
|
|
)}
|
|
|
|
|
)
|
|
|
|
|
})()}
|
|
|
|
|
{m.done && m.paymentId !== null && (() => {
|
|
|
|
|
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 (
|
|
|
|
|
<button
|
|
|
|
|
type="button" className="ref" title="The linked payment — open Payments & plans"
|
|
|
|
|
type="button" className="ref" title={detail} aria-label={detail}
|
|
|
|
|
onClick={() => props.onOpenPayments()}
|
|
|
|
|
>
|
|
|
|
|
{p !== undefined ? `${p.receivedOn} · ${inr(p.amountPaise)}` : 'payment linked'}
|
|
|
|
|
|