fix(audit-wave-9): copy/terminology sweep (copy-auditor)
Address the highest-impact items from the copy-auditor's CRITICAL +
HIGH + MEDIUM bands:
**C2 portal raw-status leak**
- Drop the staff-only `leadCategory` chip from the portal interests
page entirely. Privacy + optics: clients should never see "hot lead"
in their own portal. `eoiStatus` was already wrapped in
`portalSigningLabel`; only the categorical chip remained.
**C3 signing-status label drift**
- Add `src/lib/labels/document-status.ts` as the single source of
truth for the {draft, sent, partially_signed, completed, expired,
cancelled} lifecycle: labels (CRM + portal variants), StatusPill
variant, and the "active / in-flight" set.
- Wire it into interest-eoi-tab, interest-contract-tab,
interest-reservation-tab — they previously redefined identical
STATUS_LABELS / ACTIVE_STATUSES blocks per-file.
**H1 + M3 verbiage codemod**
- `Save Changes` → `Save changes` (sentence case, matches the
surrounding admin/CRM pattern).
- `Saving...` (ASCII three dots) → `Saving…` (Unicode ellipsis).
Matches the project's UTF-8-elsewhere convention and reads
correctly via screen-readers.
**M1 envelope jargon → signing request**
- smart-archive-dialog: "Leave envelope pending" → "Leave signing
request pending"; "Void the signing envelope" → "Cancel the signing
request"; section header updated to match.
- document-detail: "voids the signing envelope" → "cancels the signing
request".
- bulk-archive-wizard: "leave invoices/signing envelopes alone" →
"leave invoices/signing requests alone".
- Documenso admin page intentionally keeps `envelope` (dev/integration
vocabulary).
**M5 Hot Lead casing**
- Normalize `Hot Lead` / `General Interest` / `Specific Qualified` to
sentence case in `constants.ts` LABEL_OVERRIDES and all per-file
lead-category maps so the CRM trend (sentence case) is consistent.
**C1 surface-level rename**
- "Linked prospect (optional)" → "Linked interest (optional)" on the
berth status-change dialog.
- "Deal Documents" tab → "Interest Documents" (URL/route kept as
`/deal-documents` to avoid breaking deep links; rename deferred).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
87
src/lib/labels/document-status.ts
Normal file
87
src/lib/labels/document-status.ts
Normal file
@@ -0,0 +1,87 @@
|
||||
/**
|
||||
* Canonical labels + StatusPill tones for the signing-document lifecycle.
|
||||
*
|
||||
* Six surfaces previously carried divergent label sets (interest-eoi-tab,
|
||||
* interest-contract-tab, interest-reservation-tab, documents-hub,
|
||||
* signing-progress, notification-digest, realtime-toast). A signer would
|
||||
* see "Partially signed", "partially_signed", and "EOI fully signed" for
|
||||
* the same enum state across one session. This module is the single
|
||||
* source of truth — import from here, do not redefine inline.
|
||||
*
|
||||
* If a new lifecycle state arrives in the schema, add it here once.
|
||||
*/
|
||||
|
||||
import type { StatusPillStatus } from '@/components/ui/status-pill';
|
||||
|
||||
export type DocumentStatus =
|
||||
| 'draft'
|
||||
| 'sent'
|
||||
| 'partially_signed'
|
||||
| 'completed'
|
||||
| 'expired'
|
||||
| 'cancelled';
|
||||
|
||||
/**
|
||||
* Human label rendered in CRM UI (staff-facing). Use the portal-specific
|
||||
* mapping in `documentStatusLabelForPortal` when rendering to clients —
|
||||
* "Awaiting signatures" reads fine on the inside; clients want
|
||||
* "Awaiting your signature".
|
||||
*/
|
||||
export const DOCUMENT_STATUS_LABELS: Record<DocumentStatus, string> = {
|
||||
draft: 'Draft',
|
||||
sent: 'Awaiting signatures',
|
||||
partially_signed: 'Partially signed',
|
||||
completed: 'Signed',
|
||||
expired: 'Expired',
|
||||
cancelled: 'Cancelled',
|
||||
};
|
||||
|
||||
/**
|
||||
* Client-portal labels. The portal previously rendered
|
||||
* `eoiStatus.replace(/_/g, ' ')` so a client saw "EOI: partially signed".
|
||||
* Map to action-oriented copy that the client can act on.
|
||||
*/
|
||||
export const DOCUMENT_STATUS_LABELS_PORTAL: Record<DocumentStatus, string> = {
|
||||
draft: 'Pending',
|
||||
sent: 'Awaiting your signature',
|
||||
partially_signed: 'Signed (other parties remaining)',
|
||||
completed: 'Signed',
|
||||
expired: 'Expired',
|
||||
cancelled: 'Cancelled',
|
||||
};
|
||||
|
||||
/**
|
||||
* StatusPill variant per state. Pairs with `<StatusPill status={...}>`
|
||||
* via the shared primitive so the colour palette stays consistent with
|
||||
* non-document status pills (berth/user/etc).
|
||||
*/
|
||||
export const DOCUMENT_STATUS_PILL: Record<DocumentStatus, StatusPillStatus> = {
|
||||
draft: 'draft',
|
||||
sent: 'sent',
|
||||
partially_signed: 'partial',
|
||||
completed: 'completed',
|
||||
expired: 'expired',
|
||||
cancelled: 'cancelled',
|
||||
};
|
||||
|
||||
/**
|
||||
* The "in-flight" set — useful for hero treatment, banners, "we're
|
||||
* waiting on action" UI. completed/expired/cancelled are terminal.
|
||||
*/
|
||||
export const DOCUMENT_STATUS_ACTIVE: ReadonlySet<DocumentStatus> = new Set<DocumentStatus>([
|
||||
'draft',
|
||||
'sent',
|
||||
'partially_signed',
|
||||
]);
|
||||
|
||||
export function documentStatusLabel(status: string): string {
|
||||
return DOCUMENT_STATUS_LABELS[status as DocumentStatus] ?? status;
|
||||
}
|
||||
|
||||
export function documentStatusLabelForPortal(status: string): string {
|
||||
return DOCUMENT_STATUS_LABELS_PORTAL[status as DocumentStatus] ?? status;
|
||||
}
|
||||
|
||||
export function documentStatusPill(status: string): StatusPillStatus {
|
||||
return DOCUMENT_STATUS_PILL[status as DocumentStatus] ?? 'pending';
|
||||
}
|
||||
Reference in New Issue
Block a user