PageSourceSearch

https://smrtbld.ai/js/utils/tender-status.js

js smrtbld.ai collected 2026-10-05 15:09:09 UTC 6,078 bytes, 82 lines download raw bytes

1// ============================================================================
2// Tender state iconography — Stage-8 V5 (Dan's ruling, 2026-07-09).
3// THE canonical map: every tenders-module status gets a PAIRED icon + badge
4// class + label, defined ONCE. The calendar formula: color to FIND, icon+text
5// to CONFIRM — badges render icon+text so the eye scans shape before words,
6// and colorblind users lose the shortcut but never the meaning.
7//
8// Consumers spread the entry into their row objects:
9//     const s = tenderStatus('bidShortlisted');
10//     row.statusLabel = s.label; row.statusClass = s.cls; row.statusIcon = s.icon;
11// Templates render:  <span class="badge-st {{:statusClass}}">
12//                        {{if statusIcon}}<i data-lucide="{{:statusIcon}}"></i>{{/if}}{{:statusLabel}}
13//                    </span>
14// Badge svg sizing lives on the .badge-st family in tailwind.css.
15// Do NOT hand-roll status→class maps in page modules — extend THIS map.
16// ============================================================================
17
18export const TENDER_STATUS = {
19    // Tender lifecycle (list cards + the dashboard's derived status)
20    active:    { label: 'Active',          icon: 'gavel',          cls: 'badge-st-success' },
21    open:      { label: 'Open',            icon: 'gavel',          cls: 'badge-st-info' },
22    draft:     { label: 'Draft',           icon: 'pencil',         cls: 'badge-st-secondary' },
23    review:    { label: 'Under Review',    icon: 'hourglass',      cls: 'badge-st-warning' },
24    awarded:   { label: 'Awarded',         icon: 'trophy',         cls: 'badge-st-success' },
25    closed:    { label: 'Closed',          icon: 'flag',           cls: 'badge-st-secondary' },
26    archived:  { label: 'Archived',        icon: 'archive',        cls: 'badge-st-error' },
27
28    // Bid lifecycle (admin labels = the shipped E6 wording; portal re-words via its own register)
29    bidReceived:    { label: 'Received',    icon: 'inbox',          cls: 'badge-st-secondary' },
30    bidUnderReview: { label: 'Under Review',icon: 'hourglass',      cls: 'badge-st-warning' },
31    bidShortlisted: { label: 'Shortlisted', icon: 'star',           cls: 'badge-st-info' },
32    bidWon:         { label: 'Won',         icon: 'trophy',         cls: 'badge-st-success' },  // E6 — set only via the Award action
33    bidLost:        { label: 'Lost',        icon: 'x',              cls: 'badge-st-secondary' },// E6 — muted, not an error: simply out
34    assembling:     { label: 'Assembling',  icon: 'hammer',         cls: 'badge-st-secondary' },
35    late:           { label: 'Late',        icon: 'clock',          cls: 'badge-st-error' },
36
37    // Clarifications
38    tcOpen:     { label: 'Open',            icon: 'message-circle', cls: 'badge-st-warning' },
39    tcAnswered: { label: 'Answered',        icon: 'check-circle-2', cls: 'badge-st-success' },
40    tcAddendum: { label: 'Addendum Issued', icon: 'file-plus',      cls: 'badge-st-info' },
41
42    // Invites / confirm answers (roster + invites tab share these)
43    invConfirmed: { label: 'Confirmed', icon: 'check',       cls: 'badge-st-success' },
44    invDeclined:  { label: 'Declined',  icon: 'x',           cls: 'badge-st-error' },
45    invMaybe:     { label: 'Maybe',     icon: 'help-circle', cls: 'badge-st-warning' },
46    invSent:      { label: 'Sent',      icon: 'mail',        cls: 'badge-st-info' },
47    invPending:   { label: 'Pending',   icon: 'clock',       cls: 'badge-st-secondary' },
48    invBounced:   { label: 'Bounced',   icon: 'mail-x',      cls: 'badge-st-error' },
49
50    // Portal register (Stage-8 sweep) — the bidder-facing wording EXACTLY as shipped
51    // (labels/colors unchanged; V5 adds the icon channel). Consumed by portal-format.js
52    // + portal-tender-detail.js — the portal hand-rolled maps are dead.
53    pInvited:        { label: 'Invited',         icon: 'mail',            cls: 'badge-st-warning' },
54    pBidding:        { label: 'Bidding',         icon: 'hammer',          cls: 'badge-st-info' },
55    pSubmitted:      { label: 'Submitted',       icon: 'send',            cls: 'badge-st-info' },
56    pDeclined:       { label: 'Declined',        icon: 'x',               cls: 'badge-st-secondary' },
57    pAwarded:        { label: 'Awarded',         icon: 'trophy',          cls: 'badge-st-success' },
58    pUnsuccessful:   { label: 'Unsuccessful',    icon: 'x',               cls: 'badge-st-secondary' },
59    pBidInProgress:  { label: 'Bid in progress', icon: 'hammer',          cls: 'badge-st-warning' },
60    pBidSubmitted:   { label: 'Bid submitted',   icon: 'send',            cls: 'badge-st-success' },
61    pShortlisted:    { label: 'Shortlisted',     icon: 'star',            cls: 'badge-st-info' },
62    pBidReceived:    { label: 'Received',        icon: 'inbox',           cls: 'badge-st-success' },
63    pBidUnderReview: { label: 'Under review',    icon: 'hourglass',       cls: 'badge-st-warning' },
64    pConfirmYes:     { label: 'Bidding',         icon: 'check',           cls: 'badge-st-success' },
65    pConfirmMaybe:   { label: 'Maybe',           icon: 'help-circle',     cls: 'badge-st-warning' },
66    pConfirmNo:      { label: 'Not bidding',     icon: 'x',               cls: 'badge-st-secondary' },
67    pConfirmNone:    { label: 'Not answered',    icon: 'clock',           cls: 'badge-st-info' },
68    pTcAwaiting:     { label: 'Awaiting answer', icon: 'message-circle',  cls: 'badge-st-warning' },
69    pTcAnswered:     { label: 'Answered',        icon: 'check-circle-2',  cls: 'badge-st-success' },
70    pTcAddendum:     { label: 'Addendum issued', icon: 'file-plus',       cls: 'badge-st-info' },
71};
72
73// Lookup with a safe neutral fallback (unknown key renders as a plain gray badge).
74export function tenderStatus(key) {
75    return TENDER_STATUS[key] || { label: String(key ?? '—'), icon: null, cls: 'badge-st-secondary' };
76}
77
78// Convenience: the three template fields in one spread-ready object.
79export function statusFields(key) {
80    const s = tenderStatus(key);
81    return { statusLabel: s.label, statusClass: s.cls, statusIcon: s.icon };
82}

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.