@metron-labs/quote-react 0.1.14 โ†’ 0.1.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -41,6 +41,7 @@ export default function BasketStage({ cart, onUpdateQty, onUpdateSellUnits, onRe
41
41
  const items = Object.values(cart);
42
42
  const [reference, setReference] = useState("");
43
43
  const [quoteRequestSent, setQuoteRequestSent] = useState(false);
44
+ const [quoteRequestSending, setQuoteRequestSending] = useState(false);
44
45
  const [quoteContactError, setQuoteContactError] = useState("");
45
46
  const [qtyDrafts, setQtyDrafts] = useState({});
46
47
  const [sellUnitsDrafts, setSellUnitsDrafts] = useState({});
@@ -59,7 +60,26 @@ export default function BasketStage({ cart, onUpdateQty, onUpdateSellUnits, onRe
59
60
  void fetch(apiUrl("/api/catalogue/resolve-conversions"), {
60
61
  method: "POST",
61
62
  headers: { "Content-Type": "application/json", ...clientHeaders() },
62
- body: JSON.stringify({ lines: unresolved.map((item) => ({ line_id: item.lineId, product_id: item.productId, requested_description: item.requestedDescription ?? item.description, requested_qty: item.qty, requested_uom: item.unit, selected_description: item.description, selected_uoi: item.uoi, selected_uoi_count: item.uoiCount, selected_conversion: { sales_uom_normalised: item.salesUomNormalised, conversion_type: item.conversionType, sales_unit_size: item.salesUnitSize, sales_unit_size_uom: item.salesUnitSizeUom, coverage_qty: item.coverageQty, coverage_uom: item.coverageUom } })) }),
63
+ body: JSON.stringify({
64
+ lines: unresolved.map((item) => ({
65
+ line_id: item.lineId,
66
+ product_id: item.productId,
67
+ requested_description: item.requestedDescription ?? item.description,
68
+ requested_qty: item.qty,
69
+ requested_uom: item.unit,
70
+ selected_description: item.description,
71
+ selected_uoi: item.uoi,
72
+ selected_uoi_count: item.uoiCount,
73
+ selected_conversion: {
74
+ sales_uom_normalised: item.salesUomNormalised,
75
+ conversion_type: item.conversionType,
76
+ sales_unit_size: item.salesUnitSize,
77
+ sales_unit_size_uom: item.salesUnitSizeUom,
78
+ coverage_qty: item.coverageQty,
79
+ coverage_uom: item.coverageUom,
80
+ },
81
+ })),
82
+ }),
63
83
  })
64
84
  .then((response) => (response.ok ? readJson(response) : null))
65
85
  .then((payload) => {
@@ -120,13 +140,44 @@ export default function BasketStage({ cart, onUpdateQty, onUpdateSellUnits, onRe
120
140
  onUpdateSellUnits(lineId, Math.max(0, current + delta));
121
141
  clearSellUnitsDraft(lineId);
122
142
  }
123
- function submitQuoteRequest() {
124
- if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(reference.trim())) {
143
+ // Sends the basket to the merchant as a quote request (POST /v1/quote-requests). Success only
144
+ // shows once the API confirms the email went out; otherwise the customer is asked to retry.
145
+ async function submitQuoteRequest() {
146
+ const email = reference.trim();
147
+ if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) {
125
148
  setQuoteContactError("Enter a valid email address so we can send your better price.");
126
149
  return;
127
150
  }
128
151
  setQuoteContactError("");
129
- setQuoteRequestSent(true);
152
+ setQuoteRequestSending(true);
153
+ try {
154
+ const res = await fetch(apiUrl("/api/quote-requests"), {
155
+ method: "POST",
156
+ headers: { "Content-Type": "application/json", ...clientHeaders() },
157
+ body: JSON.stringify({
158
+ email,
159
+ // The quantity the basket shows to order: sale units where it could work them out,
160
+ // otherwise what the customer asked for.
161
+ items: pricedItems.map(({ item, pricing }) => {
162
+ const quantity = pricing.requiredSellUnits ?? pricing.requestedAmount;
163
+ const unit = pricing.requiredSellUnits != null ? pricing.sellUnit : pricing.requestedUnit;
164
+ return { product_id: item.productId, description: item.description, quantity, unit: unitDisplayText(unit, quantity) };
165
+ }),
166
+ }),
167
+ });
168
+ if (!res.ok) {
169
+ const payload = await readJson(res);
170
+ setQuoteContactError(res.status === 429 ? "You've sent a few requests already. Please try again in a few minutes." : (payload?.message ?? "Your request couldn't be sent. Please try again."));
171
+ return;
172
+ }
173
+ setQuoteRequestSent(true);
174
+ }
175
+ catch {
176
+ setQuoteContactError("Your request couldn't be sent. Check your connection and try again.");
177
+ }
178
+ finally {
179
+ setQuoteRequestSending(false);
180
+ }
130
181
  }
131
182
  const pricedItems = items.map((item) => ({
132
183
  item,
@@ -141,17 +192,35 @@ export default function BasketStage({ cart, onUpdateQty, onUpdateSellUnits, onRe
141
192
  const totalPages = Math.max(1, Math.ceil(pricedItems.length / PAGE_SIZE));
142
193
  const currentPage = Math.min(page, totalPages);
143
194
  const pagedItems = pricedItems.slice((currentPage - 1) * PAGE_SIZE, currentPage * PAGE_SIZE);
144
- return (_jsx("div", { className: `wizard-step entry-stage${qzaBasketLayout ? " basket-layout--qza6-mra4" : ""}`, children: _jsxs("div", { className: `quick-order-card${internal ? "" : " quick-order-card--customer"}`, children: [_jsxs("div", { className: `quick-order-hero${internal ? "" : " quick-order-hero--customer"}`, children: [internal && _jsx("div", { className: "quick-order-eyebrow", children: "Construction Services" }), _jsxs("div", { className: "basket-hero-copy", children: [qzaBasketLayout && _jsxs("button", { type: "button", className: "cta-btn cta-btn-secondary basket-hero-back", onClick: onBack, children: [_jsx(BackArrow, {}), _jsx("span", { children: "Back to results" })] }), _jsxs("div", { className: "quick-order-hero-title-row", children: [_jsx("h1", { children: internal ? "Your Selection" : qzaBasketLayout ? "Request a better price" : "Your Basket" }), internal && (_jsxs("span", { className: "summary-chip summary-chip--scope", children: [_jsx("strong", { children: items.length }), " ", items.length === 1 ? "item" : "items"] }))] }), _jsx("p", { children: internal ? "Review the items you've added before exporting them for review." : qzaBasketLayout ? "Check your quantities, then request a better price." : "Review your quantities and order summary before you buy." })] })] }), _jsx("div", { className: "quick-order-panel", style: { paddingTop: 16 }, children: items.length === 0 ? (_jsxs("div", { className: "quick-order-history-empty", children: [_jsx("div", { className: "basket-empty-icon", "aria-hidden": "true", children: internal ? "๐Ÿ“‹" : "๐Ÿงบ" }), _jsx("p", { children: internal ? "Your selection is empty." : qzaBasketLayout ? "Your quote request is empty." : "Your basket is empty." }), _jsx("p", { className: "basket-empty-hint", children: qzaBasketLayout ? "Go back to your results and add items for your quote." : "Go back to your results and add quoted items." }), _jsx("div", { className: "btn-row", style: { marginTop: 20, justifyContent: "center" }, children: _jsx("button", { className: "cta-btn", style: { width: "auto", maxWidth: 280 }, onClick: onBack, "aria-label": "Back to results", children: _jsx("span", { children: "Back to Results" }) }) })] })) : (_jsxs(_Fragment, { children: [_jsxs("div", { className: "basket-layout", children: [_jsxs("div", { className: "basket-main", children: [_jsx("div", { className: "basket-list", "aria-label": internal ? "Selection items" : qzaBasketLayout ? "Quote request items" : "Basket items", children: pagedItems.map(({ item, pricing }) => {
195
+ return (_jsx("div", { className: `wizard-step entry-stage${qzaBasketLayout ? " basket-layout--qza6-mra4" : ""}`, children: _jsxs("div", { className: `quick-order-card${internal ? "" : " quick-order-card--customer"}`, children: [_jsxs("div", { className: `quick-order-hero${internal ? "" : " quick-order-hero--customer"}`, children: [internal && _jsx("div", { className: "quick-order-eyebrow", children: "Construction Services" }), _jsxs("div", { className: "basket-hero-copy", children: [qzaBasketLayout && (_jsxs("button", { type: "button", className: "cta-btn cta-btn-secondary basket-hero-back", onClick: onBack, children: [_jsx(BackArrow, {}), _jsx("span", { children: "Back to results" })] })), _jsxs("div", { className: "quick-order-hero-title-row", children: [_jsx("h1", { children: internal ? "Your Selection" : qzaBasketLayout ? "Request a quote" : "Your Basket" }), internal && (_jsxs("span", { className: "summary-chip summary-chip--scope", children: [_jsx("strong", { children: items.length }), " ", items.length === 1 ? "item" : "items"] }))] }), _jsx("p", { children: internal
196
+ ? "Review the items you've added before exporting them for review."
197
+ : qzaBasketLayout
198
+ ? "Check your items & quantities below, and we'll do our best to beat list prices."
199
+ : "Review your quantities and order summary before you buy." })] })] }), _jsx("div", { className: "quick-order-panel", style: { paddingTop: 16 }, children: items.length === 0 ? (_jsxs("div", { className: "quick-order-history-empty", children: [_jsx("div", { className: "basket-empty-icon", "aria-hidden": "true", children: internal ? "๐Ÿ“‹" : "๐Ÿงบ" }), _jsx("p", { children: internal ? "Your selection is empty." : qzaBasketLayout ? "Your quote request is empty." : "Your basket is empty." }), _jsx("p", { className: "basket-empty-hint", children: qzaBasketLayout ? "Go back to your results and add items for your quote." : "Go back to your results and add quoted items." }), _jsx("div", { className: "btn-row", style: { marginTop: 20, justifyContent: "center" }, children: _jsx("button", { className: "cta-btn", style: { width: "auto", maxWidth: 280 }, onClick: onBack, "aria-label": "Back to results", children: _jsx("span", { children: "Back to Results" }) }) })] })) : (_jsxs(_Fragment, { children: [_jsxs("div", { className: "basket-layout", children: [_jsxs("div", { className: "basket-main", children: [_jsx("div", { className: "basket-list", "aria-label": internal ? "Selection items" : qzaBasketLayout ? "Quote request items" : "Basket items", children: pagedItems.map(({ item, pricing }) => {
145
200
  const requestedQtyValue = qtyDrafts[item.lineId] ?? String(pricing.requestedAmount);
146
201
  const requestedLocked = pricing.requestedUnit === pricing.sellUnit || pricing.costingMode === "review";
147
202
  const rawDiffersFromOrder = pricing.requiredSellUnits == null || pricing.requestedAmount !== pricing.requiredSellUnits || pricing.requestedUnit !== pricing.sellUnit;
148
- return (_jsxs("article", { className: "basket-card", children: [_jsxs("div", { className: "basket-card-top", children: [_jsx("img", { className: "basket-card-thumb", src: productImageSrc(item.description, item.productId, item.pdpPhotoUrl), alt: "", width: 48, height: 48 }), _jsxs("div", { className: "basket-card-info", children: [_jsx("div", { className: "bom-component-name", children: item.description }), rawDiffersFromOrder && pricing.costingMode !== "review" && (_jsxs("button", { type: "button", className: "basket-calc-toggle", onClick: () => setCalcOpen((prev) => ({ ...prev, [item.lineId]: !prev[item.lineId] })), "aria-expanded": !!calcOpen[item.lineId], children: ["How we calculated this", _jsx("span", { className: `basket-calc-toggle-chevron${calcOpen[item.lineId] ? " basket-calc-toggle-chevron--open" : ""}`, children: _jsx(ChevronIcon, {}) })] }))] }), _jsx("div", { className: "basket-card-actions", children: _jsx("button", { type: "button", className: "mf-remove-small-btn basket-card-remove", onClick: () => onRemove(item.lineId), "aria-label": `Remove ${item.description}`, children: _jsx(TrashIcon, {}) }) })] }), internal && (_jsxs("div", { className: "results-detail-block basket-internal-detail", children: [_jsxs("dl", { className: "results-detail-grid", children: [_jsxs("div", { children: [_jsx("dt", { children: "Conversion type" }), _jsx("dd", { children: item.conversionType ?? "-" })] }), _jsxs("div", { children: [_jsx("dt", { children: "Conversion confidence" }), _jsx("dd", { children: item.conversionConfidence ?? "-" })] }), _jsxs("div", { children: [_jsx("dt", { children: "Sales unit" }), _jsx("dd", { children: item.salesUnitSize != null ? (_jsxs(_Fragment, { children: [item.salesUnitSize, " ", renderDisplayUnit(item.salesUnitSizeUom, item.salesUnitSize)] })) : ("-") })] }), _jsxs("div", { children: [_jsx("dt", { children: "Coverage" }), _jsx("dd", { children: item.coverageQty != null ? (_jsxs(_Fragment, { children: [item.coverageQty, " ", renderDisplayUnit(item.coverageUom, item.coverageQty)] })) : ("-") })] }), _jsxs("div", { children: [_jsx("dt", { children: "Waste factor" }), _jsx("dd", { children: item.wasteFactorDefault ?? "-" })] }), _jsxs("div", { children: [_jsx("dt", { children: "Rounding rule" }), _jsx("dd", { children: item.roundingRule ?? "-" })] })] }), item.conversionNotes && _jsx("p", { className: "results-rerank-note", children: item.conversionNotes })] })), pricing.costingMode === "review" ? (_jsxs("p", { className: "basket-calc-text basket-calc-text--review", children: [_jsx("strong", { children: "Quantity needs confirmation." }), " ", reviewMessage(pricing)] })) : rawDiffersFromOrder && calcOpen[item.lineId] ? (_jsx("p", { className: "basket-calc-text", children: orderSummary(item, pricing) })) : null, _jsxs("div", { className: "basket-card-stats", children: [_jsxs("div", { className: "basket-stat", children: [_jsx("span", { className: "basket-stat-label", children: "Requested qty" }), _jsxs("div", { className: "basket-stat-value", children: [_jsxs("div", { className: "basket-qty-field", children: [_jsx("input", { className: "bom-qty-edit", type: "number", inputMode: "decimal", min: "0", placeholder: "-", value: requestedQtyValue, disabled: requestedLocked, onChange: (e) => setQtyDrafts((prev) => ({ ...prev, [item.lineId]: e.target.value })), onBlur: (e) => commitRequestedQty(item.lineId, e.target.value), onKeyDown: (e) => {
203
+ return (_jsxs("article", { className: "basket-card", children: [_jsxs("div", { className: "basket-card-top", children: [_jsx("img", { className: "basket-card-thumb", src: productImageSrc(item.description, item.productId, item.pdpPhotoUrl), alt: "", width: 48, height: 48 }), _jsxs("div", { className: "basket-card-info", children: [_jsx("div", { className: "bom-component-name", children: item.description }), rawDiffersFromOrder && pricing.costingMode !== "review" && (_jsxs("button", { type: "button", className: "basket-calc-toggle", onClick: () => setCalcOpen((prev) => ({
204
+ ...prev,
205
+ [item.lineId]: !prev[item.lineId],
206
+ })), "aria-expanded": !!calcOpen[item.lineId], children: ["How we calculated this", _jsx("span", { className: `basket-calc-toggle-chevron${calcOpen[item.lineId] ? " basket-calc-toggle-chevron--open" : ""}`, children: _jsx(ChevronIcon, {}) })] }))] }), _jsx("div", { className: "basket-card-actions", children: _jsx("button", { type: "button", className: "mf-remove-small-btn basket-card-remove", onClick: () => onRemove(item.lineId), "aria-label": `Remove ${item.description}`, children: _jsx(TrashIcon, {}) }) })] }), internal && (_jsxs("div", { className: "results-detail-block basket-internal-detail", children: [_jsxs("dl", { className: "results-detail-grid", children: [_jsxs("div", { children: [_jsx("dt", { children: "Conversion type" }), _jsx("dd", { children: item.conversionType ?? "-" })] }), _jsxs("div", { children: [_jsx("dt", { children: "Conversion confidence" }), _jsx("dd", { children: item.conversionConfidence ?? "-" })] }), _jsxs("div", { children: [_jsx("dt", { children: "Sales unit" }), _jsx("dd", { children: item.salesUnitSize != null ? (_jsxs(_Fragment, { children: [item.salesUnitSize, " ", renderDisplayUnit(item.salesUnitSizeUom, item.salesUnitSize)] })) : ("-") })] }), _jsxs("div", { children: [_jsx("dt", { children: "Coverage" }), _jsx("dd", { children: item.coverageQty != null ? (_jsxs(_Fragment, { children: [item.coverageQty, " ", renderDisplayUnit(item.coverageUom, item.coverageQty)] })) : ("-") })] }), _jsxs("div", { children: [_jsx("dt", { children: "Waste factor" }), _jsx("dd", { children: item.wasteFactorDefault ?? "-" })] }), _jsxs("div", { children: [_jsx("dt", { children: "Rounding rule" }), _jsx("dd", { children: item.roundingRule ?? "-" })] })] }), item.conversionNotes && _jsx("p", { className: "results-rerank-note", children: item.conversionNotes })] })), pricing.costingMode === "review" ? (_jsxs("p", { className: "basket-calc-text basket-calc-text--review", children: [_jsx("strong", { children: "Quantity needs confirmation." }), " ", reviewMessage(pricing)] })) : rawDiffersFromOrder && calcOpen[item.lineId] ? (_jsx("p", { className: "basket-calc-text", children: orderSummary(item, pricing) })) : null, _jsxs("div", { className: "basket-card-stats", children: [_jsxs("div", { className: "basket-stat", children: [_jsx("span", { className: "basket-stat-label", children: "Requested qty" }), _jsxs("div", { className: "basket-stat-value", children: [_jsxs("div", { className: "basket-qty-field", children: [_jsx("input", { className: "bom-qty-edit", type: "number", inputMode: "decimal", min: "0", placeholder: "-", value: requestedQtyValue, disabled: requestedLocked, onChange: (e) => setQtyDrafts((prev) => ({
207
+ ...prev,
208
+ [item.lineId]: e.target.value,
209
+ })), onBlur: (e) => commitRequestedQty(item.lineId, e.target.value), onKeyDown: (e) => {
149
210
  if (e.key === "Enter")
150
211
  e.target.blur();
151
- }, "aria-label": `${item.description} requested quantity` }), _jsxs("div", { className: "basket-qty-arrows", children: [_jsx("button", { type: "button", className: "basket-qty-arrow", disabled: requestedLocked, onClick: () => stepRequestedQty(item.lineId, parseFloat(requestedQtyValue) || 0, 1), "aria-label": `Increase ${item.description} quantity`, children: _jsx(ChevronIcon, {}) }), _jsx("button", { type: "button", className: "basket-qty-arrow basket-qty-arrow--down", disabled: requestedLocked, onClick: () => stepRequestedQty(item.lineId, parseFloat(requestedQtyValue) || 0, -1), "aria-label": `Decrease ${item.description} quantity`, children: _jsx(ChevronIcon, {}) })] })] }), _jsx("span", { className: "basket-metric-unit", children: renderDisplayUnit(pricing.requestedUnit, parseFloat(requestedQtyValue) || 0) })] })] }), _jsxs("div", { className: "basket-stat basket-stat--right", children: [_jsx("span", { className: "basket-stat-label", children: "Order qty" }), _jsxs("div", { className: "basket-stat-value", children: [_jsxs("div", { className: "basket-qty-field", children: [_jsx("input", { className: "bom-qty-edit", type: "number", inputMode: "decimal", min: "0", placeholder: "-", value: sellUnitsDrafts[item.lineId] ?? String(pricing.requiredSellUnits ?? ""), onChange: (e) => setSellUnitsDrafts((prev) => ({ ...prev, [item.lineId]: e.target.value })), onBlur: (e) => commitSellUnits(item.lineId, e.target.value), onKeyDown: (e) => {
212
+ }, "aria-label": `${item.description} requested quantity` }), _jsxs("div", { className: "basket-qty-arrows", children: [_jsx("button", { type: "button", className: "basket-qty-arrow", disabled: requestedLocked, onClick: () => stepRequestedQty(item.lineId, parseFloat(requestedQtyValue) || 0, 1), "aria-label": `Increase ${item.description} quantity`, children: _jsx(ChevronIcon, {}) }), _jsx("button", { type: "button", className: "basket-qty-arrow basket-qty-arrow--down", disabled: requestedLocked, onClick: () => stepRequestedQty(item.lineId, parseFloat(requestedQtyValue) || 0, -1), "aria-label": `Decrease ${item.description} quantity`, children: _jsx(ChevronIcon, {}) })] })] }), _jsx("span", { className: "basket-metric-unit", children: renderDisplayUnit(pricing.requestedUnit, parseFloat(requestedQtyValue) || 0) })] })] }), _jsxs("div", { className: "basket-stat basket-stat--right", children: [_jsx("span", { className: "basket-stat-label", children: "Order qty" }), _jsxs("div", { className: "basket-stat-value", children: [_jsxs("div", { className: "basket-qty-field", children: [_jsx("input", { className: "bom-qty-edit", type: "number", inputMode: "decimal", min: "0", placeholder: "-", value: sellUnitsDrafts[item.lineId] ?? String(pricing.requiredSellUnits ?? ""), onChange: (e) => setSellUnitsDrafts((prev) => ({
213
+ ...prev,
214
+ [item.lineId]: e.target.value,
215
+ })), onBlur: (e) => commitSellUnits(item.lineId, e.target.value), onKeyDown: (e) => {
152
216
  if (e.key === "Enter")
153
217
  e.target.blur();
154
218
  }, "aria-label": `${item.description} order quantity` }), _jsxs("div", { className: "basket-qty-arrows", children: [_jsx("button", { type: "button", className: "basket-qty-arrow", onClick: () => stepSellUnits(item.lineId, parseFloat(sellUnitsDrafts[item.lineId] ?? String(pricing.requiredSellUnits ?? "0")) || 0, 1), "aria-label": `Increase ${item.description} order quantity`, children: _jsx(ChevronIcon, {}) }), _jsx("button", { type: "button", className: "basket-qty-arrow basket-qty-arrow--down", onClick: () => stepSellUnits(item.lineId, parseFloat(sellUnitsDrafts[item.lineId] ?? String(pricing.requiredSellUnits ?? "0")) || 0, -1), "aria-label": `Decrease ${item.description} order quantity`, children: _jsx(ChevronIcon, {}) })] })] }), _jsx("span", { className: "basket-metric-unit", children: renderDisplayUnit(pricing.sellUnit, parseFloat(sellUnitsDrafts[item.lineId] ?? String(pricing.requiredSellUnits ?? "0")) || 0) })] })] }), _jsxs("div", { className: "basket-stat basket-stat--total", children: [_jsx("span", { className: "basket-stat-label", children: "Total" }), _jsxs("div", { className: "basket-stat-value", children: [_jsx("strong", { children: pricing.lineTotal != null ? fmtCurrency(pricing.lineTotal) : "-" }), pricing.lineTotal != null && _jsx("span", { className: "basket-metric-unit", children: "ex. VAT" })] })] })] })] }, item.lineId));
155
- }) }), totalPages > 1 && (_jsxs("div", { className: "results-pagination", children: [_jsxs("span", { className: "results-pagination-count", children: ["Showing ", (currentPage - 1) * PAGE_SIZE + 1, "\u2013", Math.min(currentPage * PAGE_SIZE, pricedItems.length), " of ", pricedItems.length] }), _jsxs("div", { className: "results-pagination-controls", children: [_jsx("button", { type: "button", className: "bom-toolbar-btn", onClick: () => setPage(currentPage - 1), disabled: currentPage === 1, children: "Previous" }), _jsxs("span", { className: "results-pagination-page", children: ["Page ", currentPage, " of ", totalPages] }), _jsx("button", { type: "button", className: "bom-toolbar-btn", onClick: () => setPage(currentPage + 1), disabled: currentPage === totalPages, children: "Next" })] })] }))] }), _jsxs("aside", { className: "basket-sidebar", children: [_jsx("div", { className: "basket-sidebar-title", children: qzaBasketLayout ? "Quote request summary" : "Order summary" }), _jsxs("div", { className: "basket-sidebar-row", children: [_jsx("span", { children: qzaBasketLayout ? "Standard price (ex. VAT)" : "Subtotal (ex. VAT)" }), _jsx("span", { children: fmtCurrency(subtotal) })] }), _jsxs("div", { className: "basket-sidebar-row", children: [_jsx("span", { children: qzaBasketLayout ? "VAT (20%)" : "VAT (20%)" }), _jsx("span", { children: fmtCurrency(vat) })] }), _jsxs("div", { className: "basket-sidebar-row basket-sidebar-row--total", children: [_jsx("span", { children: qzaBasketLayout ? "Standard price (inc. VAT)" : "Total" }), _jsx("span", { children: fmtCurrency(total) })] }), !qzaBasketLayout && _jsx("div", { className: "basket-summary-waste", children: _jsxs("div", { className: "basket-waste-control", children: [_jsxs("label", { className: "basket-global-waste", children: [_jsx("input", { type: "checkbox", checked: wasteEnabled, onChange: (e) => setWasteEnabled(e.target.checked) }), _jsx("span", { children: "Add waste factor" })] }), _jsxs("label", { className: "basket-global-waste-percent", children: [_jsx("input", { type: "number", inputMode: "decimal", min: "0", step: "0.1", value: wastePercent, onChange: (e) => setWastePercent(e.target.value), disabled: !wasteEnabled, "aria-label": "Waste factor percent" }), _jsx("span", { children: "%" })] })] }) }), _jsx("label", { htmlFor: `${uid}-basket-reference`, className: "basket-sidebar-label", children: qzaBasketLayout ? "Email for your better price" : "Your reference (optional)" }), _jsx("input", { id: `${uid}-basket-reference`, type: qzaBasketLayout ? "email" : "text", className: "basket-sidebar-input", value: reference, onChange: (e) => { setReference(e.target.value); if (qzaBasketLayout)
156
- setQuoteContactError(""); }, placeholder: qzaBasketLayout ? "you@example.com" : "PO number or job reference" }), qzaBasketLayout && quoteContactError && _jsx("p", { className: "basket-quote-request-error", role: "alert", children: quoteContactError }), qzaBasketLayout ? (quoteRequestSent ? (_jsxs("div", { className: "basket-quote-request-success", role: "status", children: [_jsx("strong", { children: "Better price requested" }), _jsx("span", { children: "We'll use this email address to prepare your better price." })] })) : (_jsx("button", { type: "button", className: "cta-btn", onClick: submitQuoteRequest, children: _jsx("span", { children: "Get a better price" }) }))) : (_jsx("button", { className: "cta-btn", onClick: () => void exportBasketExcel(items), "aria-label": internal ? "Download selection" : "Download basket", children: _jsx("span", { children: internal ? "Download Quote" : "Buy Now" }) })), _jsxs("p", { className: "basket-sidebar-disclaimer", children: [_jsx("span", { "aria-hidden": "true", children: "\u26A0\uFE0F" }), qzaBasketLayout ? "This is a quote request, not an order. We'll confirm your better price, availability and delivery before you approve." : "Prices and availability are estimates and should be confirmed before procurement."] })] })] }), _jsx("div", { className: "btn-row results-actions", children: _jsxs("button", { className: "cta-btn cta-btn-secondary", style: { flex: "0 1 30%", gap: 10, justifyContent: "center" }, onClick: onBack, "aria-label": "Back to results", children: [_jsx(BackArrow, {}), _jsx("span", { children: "Back to results" })] }) })] })) })] }) }));
219
+ }) }), totalPages > 1 && (_jsxs("div", { className: "results-pagination", children: [_jsxs("span", { className: "results-pagination-count", children: ["Showing ", (currentPage - 1) * PAGE_SIZE + 1, "\u2013", Math.min(currentPage * PAGE_SIZE, pricedItems.length), " of ", pricedItems.length] }), _jsxs("div", { className: "results-pagination-controls", children: [_jsx("button", { type: "button", className: "bom-toolbar-btn", onClick: () => setPage(currentPage - 1), disabled: currentPage === 1, children: "Previous" }), _jsxs("span", { className: "results-pagination-page", children: ["Page ", currentPage, " of ", totalPages] }), _jsx("button", { type: "button", className: "bom-toolbar-btn", onClick: () => setPage(currentPage + 1), disabled: currentPage === totalPages, children: "Next" })] })] }))] }), _jsxs("aside", { className: "basket-sidebar", children: [_jsx("div", { className: "basket-sidebar-title", children: qzaBasketLayout ? "Quote request summary" : "Order summary" }), _jsxs("div", { className: "basket-sidebar-row", children: [_jsx("span", { children: qzaBasketLayout ? "List price (ex. VAT)" : "Subtotal (ex. VAT)" }), _jsx("span", { children: fmtCurrency(subtotal) })] }), _jsxs("div", { className: "basket-sidebar-row", children: [_jsx("span", { children: qzaBasketLayout ? "VAT (20%)" : "VAT (20%)" }), _jsx("span", { children: fmtCurrency(vat) })] }), _jsxs("div", { className: "basket-sidebar-row basket-sidebar-row--total", children: [_jsx("span", { children: qzaBasketLayout ? "List price (inc. VAT)" : "Total" }), _jsx("span", { children: fmtCurrency(total) })] }), !qzaBasketLayout && (_jsx("div", { className: "basket-summary-waste", children: _jsxs("div", { className: "basket-waste-control", children: [_jsxs("label", { className: "basket-global-waste", children: [_jsx("input", { type: "checkbox", checked: wasteEnabled, onChange: (e) => setWasteEnabled(e.target.checked) }), _jsx("span", { children: "Add waste factor" })] }), _jsxs("label", { className: "basket-global-waste-percent", children: [_jsx("input", { type: "number", inputMode: "decimal", min: "0", step: "0.1", value: wastePercent, onChange: (e) => setWastePercent(e.target.value), disabled: !wasteEnabled, "aria-label": "Waste factor percent" }), _jsx("span", { children: "%" })] })] }) })), _jsx("label", { htmlFor: `${uid}-basket-reference`, className: "basket-sidebar-label", children: qzaBasketLayout ? "Enter email for your sharper quote" : "Your reference (optional)" }), _jsx("input", { id: `${uid}-basket-reference`, type: qzaBasketLayout ? "email" : "text", className: "basket-sidebar-input", value: reference, onChange: (e) => {
220
+ setReference(e.target.value);
221
+ if (qzaBasketLayout)
222
+ setQuoteContactError("");
223
+ }, placeholder: qzaBasketLayout ? "you@example.com" : "PO number or job reference" }), qzaBasketLayout && quoteContactError && (_jsx("p", { className: "basket-quote-request-error", role: "alert", children: quoteContactError })), qzaBasketLayout ? (quoteRequestSent ? (_jsxs("div", { className: "basket-quote-request-success", role: "status", children: [_jsx("strong", { children: "Better price requested" }), _jsx("span", { children: "We'll use this email address to prepare your better price." })] })) : (_jsx("button", { type: "button", className: "cta-btn", onClick: () => void submitQuoteRequest(), disabled: quoteRequestSending, "aria-busy": quoteRequestSending, children: _jsx("span", { children: quoteRequestSending ? "Sendingโ€ฆ" : "Request our best quote" }) }))) : (_jsx("button", { className: "cta-btn", onClick: () => void exportBasketExcel(items), "aria-label": internal ? "Download selection" : "Download basket", children: _jsx("span", { children: internal ? "Download Quote" : "Buy Now" }) })), _jsxs("p", { className: "basket-sidebar-disclaimer", children: [_jsx("span", { "aria-hidden": "true", children: "\u26A0\uFE0F" }), qzaBasketLayout
224
+ ? "This is a quote request, not an order. We'll confirm our best price, availability and delivery before you approve."
225
+ : "Prices and availability are estimates and should be confirmed before procurement."] })] })] }), _jsx("div", { className: "btn-row results-actions", children: _jsxs("button", { className: "cta-btn cta-btn-secondary", style: { flex: "0 1 30%", gap: 10, justifyContent: "center" }, onClick: onBack, "aria-label": "Back to results", children: [_jsx(BackArrow, {}), _jsx("span", { children: "Back to results" })] }) })] })) })] }) }));
157
226
  }
@@ -14,5 +14,5 @@ interface ResultsStageProps {
14
14
  }
15
15
  export declare function candidateFromCart(item: CartItem): MatchCandidate;
16
16
  export declare function displayLineLabel(item: LineItem, allItems: LineItem[]): string;
17
- export default function ScheduleResultsStage({ scheduleResult, onStartOver, cart, onAddToCart, onRemoveFromCart, onGoToBasket, cartSeeded, onCartSeeded, reviewGateComplete, onReviewGateComplete, internal, }: ResultsStageProps): import("react").JSX.Element;
17
+ export default function ScheduleResultsStage({ scheduleResult, onStartOver, cart, onAddToCart, onRemoveFromCart, onGoToBasket, cartSeeded, onCartSeeded, reviewGateComplete, onReviewGateComplete, internal }: ResultsStageProps): import("react").JSX.Element;
18
18
  export {};
@@ -115,12 +115,8 @@ function fmtTextList(values) {
115
115
  return items.length > 0 ? items.join(", ") : "-";
116
116
  }
117
117
  export function displayLineLabel(item, allItems) {
118
- const siblings = allItems.filter((candidate) => candidate.source_line_id === item.source_line_id && candidate.description_original === item.description_original);
119
- const description = item.customer_display_label?.trim() || item.procurement_intent?.trim() || item.description_original || "";
120
- if (siblings.length <= 1 || !item.procurement_intent || description === item.procurement_intent) {
121
- return description || "(no description)";
122
- }
123
- return `${description} -> ${item.procurement_intent}`;
118
+ void allItems;
119
+ return item.customer_display_label?.trim() || item.description_original || "(no description)";
124
120
  }
125
121
  const LINK_GROUP_BUBBLE_STYLES = [
126
122
  { background: "#fff7ed", borderColor: "#fdba74", color: "#9a3412" },
@@ -164,9 +160,7 @@ function curatedCandidates(candidates, result, selectedProductId) {
164
160
  const recommendedIds = result?.rerank?.recommendedCandidateIds ?? [];
165
161
  if (recommendedIds.length === 0) {
166
162
  const top5 = candidates.slice(0, 5);
167
- const pinnedSelected = !top5.some((candidate) => candidate.product_id === selectedProductId)
168
- ? candidates.find((candidate) => candidate.product_id === selectedProductId)
169
- : undefined;
163
+ const pinnedSelected = !top5.some((candidate) => candidate.product_id === selectedProductId) ? candidates.find((candidate) => candidate.product_id === selectedProductId) : undefined;
170
164
  return pinnedSelected ? [...top5, pinnedSelected] : top5;
171
165
  }
172
166
  const byId = new Map(candidates.map((candidate) => [candidate.product_id, candidate]));
@@ -258,9 +252,7 @@ function AdjudicationDebugBlock({ result }) {
258
252
  function DetailedDecision({ item, decision, result, showRetrievalDebug, reviewOnly = false, linkedGroupMeta, }) {
259
253
  if (!decision)
260
254
  return null;
261
- const reviewLabel = decision.technical_classification === "no_suitable_candidate"
262
- ? "Exact match not found:"
263
- : `AI review (${decision.confidence ?? "confidence not stated"}):`;
255
+ const reviewLabel = decision.technical_classification === "no_suitable_candidate" ? "Exact match not found:" : `AI review (${decision.confidence ?? "confidence not stated"}):`;
264
256
  if (reviewOnly) {
265
257
  return decision.reason ? (_jsxs("div", { className: "results-detail-block", children: [_jsxs("p", { className: `basket-calc-text basket-calc-text--review`, children: [_jsx("strong", { children: reviewLabel }), "\u00A0", decision.reason] }), hasVisibleLinkedGroup(item) ? (_jsxs("p", { className: "results-row-meta", style: { marginTop: 8 }, children: ["Linked context: ", linkedGroupMeta ? `Link ${linkedGroupMeta.token} - ` : "", linkedGroupSummary(item)] })) : null] })) : null;
266
258
  }
@@ -284,7 +276,11 @@ function CandidateBreakdown({ item, candidates, result, decision, unmatchable, s
284
276
  const shown = showAll || internal || detailMode === "detailed" ? candidates : curatedCandidates(candidates, result, selectedProductId);
285
277
  return (_jsxs(_Fragment, { children: [detailBlock, _jsxs("table", { className: "score-breakdown-table", children: [_jsx("thead", { children: _jsxs("tr", { children: [_jsx("th", { children: "Product" }), _jsx("th", { children: "Dims (mm)" }), _jsx("th", { children: "Price" }), showScoreColumns && (_jsxs(_Fragment, { children: [_jsx("th", { children: "dimension" }), _jsx("th", { children: "grade" }), _jsx("th", { children: "brand" }), _jsx("th", { children: "fuzzy" }), _jsx("th", { children: "bm25" }), _jsx("th", { children: "overall" })] })), _jsx("th", { "aria-label": "Actions" })] }) }), _jsx("tbody", { children: shown.map((c, i) => {
286
278
  const isCurrent = c.product_id === selectedProductId;
287
- return (_jsxs("tr", { className: isCurrent ? "score-breakdown-row--best" : "", children: [_jsxs("td", { children: [_jsx("div", { children: c.description }), _jsx("div", { className: "results-row-meta", children: c.product_id })] }), _jsx("td", { children: _jsx("span", { className: "unit-badge", children: fmtMeasurements(c.measurements_mm ?? c.debug?.candidate.measurements_mm) }) }), _jsx("td", { children: fmtPrice(c.price, c.price_basis) }), showScoreColumns && (_jsxs(_Fragment, { children: [_jsx("td", { children: (c.scores?.dimension ?? 0).toFixed(2) }), _jsx("td", { children: (c.scores?.grade ?? 0).toFixed(2) }), _jsx("td", { children: (c.scores?.brand ?? 0).toFixed(2) }), _jsx("td", { children: (c.scores?.fuzzy ?? 0).toFixed(2) }), _jsx("td", { children: (c.scores?.bm25 ?? 0).toFixed(2) }), _jsx("td", { children: _jsxs("div", { style: { display: "inline-flex", alignItems: "center", gap: 6 }, children: [_jsx(ConfChip, { band: bandFor(c.scores?.overall) }), _jsx("span", { className: "results-overall-cell", children: (c.scores?.overall ?? 0).toFixed(2) })] }) })] })), _jsx("td", { children: _jsxs("label", { className: "switch-toggle", title: isCurrent ? "Currently selected" : "Use this candidate", children: [_jsx("input", { type: "checkbox", checked: isCurrent, onChange: () => {
279
+ return (_jsxs("tr", { className: isCurrent ? "score-breakdown-row--best" : "", children: [_jsxs("td", { children: [_jsx("div", { children: c.description }), _jsx("div", { className: "results-row-meta", children: c.product_id })] }), _jsx("td", { children: _jsx("span", { className: "unit-badge", children: fmtMeasurements(c.measurements_mm ?? c.debug?.candidate.measurements_mm) }) }), _jsx("td", { children: fmtPrice(c.price, c.price_basis) }), showScoreColumns && (_jsxs(_Fragment, { children: [_jsx("td", { children: (c.scores?.dimension ?? 0).toFixed(2) }), _jsx("td", { children: (c.scores?.grade ?? 0).toFixed(2) }), _jsx("td", { children: (c.scores?.brand ?? 0).toFixed(2) }), _jsx("td", { children: (c.scores?.fuzzy ?? 0).toFixed(2) }), _jsx("td", { children: (c.scores?.bm25 ?? 0).toFixed(2) }), _jsx("td", { children: _jsxs("div", { style: {
280
+ display: "inline-flex",
281
+ alignItems: "center",
282
+ gap: 6,
283
+ }, children: [_jsx(ConfChip, { band: bandFor(c.scores?.overall) }), _jsx("span", { className: "results-overall-cell", children: (c.scores?.overall ?? 0).toFixed(2) })] }) })] })), _jsx("td", { children: _jsxs("label", { className: "switch-toggle", title: isCurrent ? "Currently selected" : "Use this candidate", children: [_jsx("input", { type: "checkbox", checked: isCurrent, onChange: () => {
288
284
  if (isCurrent)
289
285
  onClear?.();
290
286
  else
@@ -292,7 +288,7 @@ function CandidateBreakdown({ item, candidates, result, decision, unmatchable, s
292
288
  }, "aria-label": isCurrent ? `${c.description} selected` : `Use ${c.description}` }), _jsx("span", { className: "switch-toggle-track", "aria-hidden": "true" })] }) })] }, `${c.product_id}-${i}`));
293
289
  }) })] })] }));
294
290
  }
295
- export default function ScheduleResultsStage({ scheduleResult, onStartOver, cart, onAddToCart, onRemoveFromCart, onGoToBasket, cartSeeded, onCartSeeded, reviewGateComplete, onReviewGateComplete, internal = false, }) {
291
+ export default function ScheduleResultsStage({ scheduleResult, onStartOver, cart, onAddToCart, onRemoveFromCart, onGoToBasket, cartSeeded, onCartSeeded, reviewGateComplete, onReviewGateComplete, internal = false }) {
296
292
  const qzaQuoteRequest = !internal && getBoqClientId() === "QZA6-MRA4";
297
293
  const customerCollection = qzaQuoteRequest ? "quote" : "basket";
298
294
  const { results, lineItems, parseReport, timings } = scheduleResult;
@@ -341,7 +337,15 @@ export default function ScheduleResultsStage({ scheduleResult, onStartOver, cart
341
337
  const matched = pick === NO_SELECTION ? undefined : (pickOverrideCandidates[item.line_id] ?? (savedCartMatch && savedCartMatch.productId !== automaticMatch?.product_id ? candidateFromCart(savedCartMatch) : automaticMatch));
342
338
  const best = unmatchable ? undefined : matched;
343
339
  const qty = item.qty ?? 0;
344
- return { item, result, decision, unmatchable, best, qty, band: bandFor(best?.scores?.overall) };
340
+ return {
341
+ item,
342
+ result,
343
+ decision,
344
+ unmatchable,
345
+ best,
346
+ qty,
347
+ band: bandFor(best?.scores?.overall),
348
+ };
345
349
  });
346
350
  let totalValue = 0;
347
351
  let needsPricingCount = 0;
@@ -384,7 +388,12 @@ export default function ScheduleResultsStage({ scheduleResult, onStartOver, cart
384
388
  const { top, left, width, height } = row.getBoundingClientRect();
385
389
  const actionCell = row.querySelector(".bom-toolbar-btn")?.closest("td");
386
390
  const actionLeft = actionCell?.getBoundingClientRect().left;
387
- setHoveredRowBounds({ top, left, width: actionLeft ? actionLeft - left : width, height });
391
+ setHoveredRowBounds({
392
+ top,
393
+ left,
394
+ width: actionLeft ? actionLeft - left : width,
395
+ height,
396
+ });
388
397
  };
389
398
  useEffect(() => {
390
399
  window.addEventListener("scroll", updateHoveredRowBounds, true);
@@ -413,8 +422,14 @@ export default function ScheduleResultsStage({ scheduleResult, onStartOver, cart
413
422
  return;
414
423
  const saved = cart[selectedReviewId];
415
424
  if (saved) {
416
- setPickOverrides((prev) => ({ ...prev, [selectedReviewId]: saved.productId }));
417
- setPickOverrideCandidates((prev) => ({ ...prev, [selectedReviewId]: candidateFromCart(saved) }));
425
+ setPickOverrides((prev) => ({
426
+ ...prev,
427
+ [selectedReviewId]: saved.productId,
428
+ }));
429
+ setPickOverrideCandidates((prev) => ({
430
+ ...prev,
431
+ [selectedReviewId]: candidateFromCart(saved),
432
+ }));
418
433
  return;
419
434
  }
420
435
  setPickOverrides((prev) => {
@@ -492,7 +507,14 @@ export default function ScheduleResultsStage({ scheduleResult, onStartOver, cart
492
507
  }
493
508
  };
494
509
  function handleExport() {
495
- void exportScheduleExcel(rows.map(({ item, best, qty, band, unmatchable, decision }) => ({ item, best, qty, band, unmatchable, decision })));
510
+ void exportScheduleExcel(rows.map(({ item, best, qty, band, unmatchable, decision }) => ({
511
+ item,
512
+ best,
513
+ qty,
514
+ band,
515
+ unmatchable,
516
+ decision,
517
+ })));
496
518
  }
497
519
  function toCartItem(row) {
498
520
  const candidate = row.best ?? recommendedCandidates(row.result)[0];
@@ -525,7 +547,11 @@ export default function ScheduleResultsStage({ scheduleResult, onStartOver, cart
525
547
  if (!existing)
526
548
  continue;
527
549
  const refreshed = toCartItem(row);
528
- onAddToCart({ ...refreshed, qty: existing.qty, sellUnitsOverride: existing.sellUnitsOverride ?? null });
550
+ onAddToCart({
551
+ ...refreshed,
552
+ qty: existing.qty,
553
+ sellUnitsOverride: existing.sellUnitsOverride ?? null,
554
+ });
529
555
  }
530
556
  // eslint-disable-next-line react-hooks/exhaustive-deps
531
557
  }, [scheduleResult]);
@@ -588,14 +614,19 @@ export default function ScheduleResultsStage({ scheduleResult, onStartOver, cart
588
614
  pdp_photo_url: candidate.pdp_photo_url ?? null,
589
615
  conversion: candidate.conversion,
590
616
  measurements_mm: candidate.measurements_mm ?? [],
591
- scores: { dimension: 0, grade: 0, brand: 0, fuzzy: 0, bm25: 0, overall: 0 },
617
+ scores: {
618
+ dimension: 0,
619
+ grade: 0,
620
+ brand: 0,
621
+ fuzzy: 0,
622
+ bm25: 0,
623
+ overall: 0,
624
+ },
592
625
  method: "catalogue_search",
593
626
  }));
594
627
  const reviewCandidates = reviewQuery ? catalogueSearchCandidates : llmReviewCandidates;
595
628
  const savedSearchCandidate = activeReviewRow ? savedSearchCandidates[activeReviewRow.item.line_id] : undefined;
596
- const reviewDisplayCandidates = !reviewQuery && savedSearchCandidate && !reviewCandidates.some((candidate) => candidate.product_id === savedSearchCandidate.product_id)
597
- ? [...reviewCandidates, savedSearchCandidate]
598
- : reviewCandidates;
629
+ const reviewDisplayCandidates = !reviewQuery && savedSearchCandidate && !reviewCandidates.some((candidate) => candidate.product_id === savedSearchCandidate.product_id) ? [...reviewCandidates, savedSearchCandidate] : reviewCandidates;
599
630
  const reviewOptionCandidates = (() => {
600
631
  const topCandidates = reviewDisplayCandidates.slice(0, reviewQuery ? 12 : 3);
601
632
  if (reviewQuery || !savedSearchCandidate || topCandidates.some((candidate) => candidate.product_id === savedSearchCandidate.product_id))
@@ -604,13 +635,27 @@ export default function ScheduleResultsStage({ scheduleResult, onStartOver, cart
604
635
  })();
605
636
  const activeReviewCartMatches = !!activeReviewRow?.best && cart[activeReviewRow.item.line_id]?.productId === activeReviewRow.best.product_id;
606
637
  const activeReviewHasPendingUpdate = !!activeReviewRow?.best && !!cart[activeReviewRow.item.line_id] && !activeReviewCartMatches;
607
- return (_jsxs("div", { className: "wizard-step entry-stage", children: [_jsxs("div", { className: `quick-order-card${internal ? "" : " quick-order-card--customer"}`, children: [_jsx("div", { className: `quick-order-hero${internal ? "" : " quick-order-hero--customer"}`, children: internal ? (_jsxs(_Fragment, { children: [_jsx("div", { className: "quick-order-eyebrow", children: "Construction Services" }), _jsxs("div", { className: "quick-order-hero-title-row", children: [_jsx("h1", { children: "Your Results" }), _jsxs("span", { className: "summary-chip summary-chip--scope", children: [_jsx("strong", { children: fmtCurrency(totalValue) }), " Est. total"] })] }), _jsx("p", { children: "Each line item from your schedule matched against your catalogue, ranked by confidence." })] })) : (_jsxs(_Fragment, { children: [_jsxs("div", { children: [_jsx("h1", { children: "Review your matched products" }), _jsxs("p", { children: ["Check you're happy with these items, then click ", qzaQuoteRequest ? "View Quote" : "View Basket", " to continue."] })] }), _jsxs("button", { type: "button", className: "results-total-action", onClick: onGoToBasket, "aria-label": qzaQuoteRequest ? "View quote" : "View basket", children: [_jsxs("span", { children: [_jsx("small", { children: qzaQuoteRequest ? "View Quote" : "View Basket" }), _jsx("strong", { children: fmtCurrency(totalValue) })] }), _jsx("span", { className: "arrow", children: _jsx(ForwardArrow, {}) })] })] })) }), _jsxs("div", { className: "quick-order-panel", style: { paddingTop: 16 }, children: [debugEnabled && (_jsx("div", { className: "results-summary", style: { marginBottom: 12 }, children: _jsx("button", { type: "button", className: "bom-toolbar-btn", "aria-pressed": showTimings, onClick: () => setShowTimings((value) => !value), children: showTimings ? "Hide timings" : "Show timings" }) })), debugEnabled && showTimings && _jsx(TimingBreakdown, { ...timings }), !qzaQuoteRequest && _jsx("div", { className: "results-toolbar-row", children: !activeReviewRow && (_jsxs("div", { className: "results-summary", style: { marginBottom: 0 }, children: [needsPricingCount > 0 && (_jsxs("span", { className: "summary-chip summary-chip--neutral", children: [_jsx("strong", { children: needsPricingCount }), " need pricing"] })), _jsxs("div", { style: { display: "flex", gap: 8, flexWrap: "wrap", alignItems: "center" }, children: [_jsx("input", { type: "text", className: "results-search-input", placeholder: "Search description...", value: search, onChange: (e) => setSearch(e.target.value), "aria-label": "Search line items" }), !internal && (_jsxs("div", { className: "results-view-toggle", "aria-label": "Results view", children: [_jsx("button", { type: "button", className: `results-view-toggle__btn${viewMode === "tile" ? " is-active" : ""}`, "aria-pressed": viewMode === "tile", "aria-label": "Tile view", title: "Tile view", onClick: () => setViewMode("tile"), children: _jsxs("svg", { width: "18", height: "12", viewBox: "0 0 15 10", fill: "currentColor", children: [_jsx("rect", { x: "0.5", y: "0.5", width: "4", height: "4" }), _jsx("rect", { x: "5.5", y: "0.5", width: "4", height: "4" }), _jsx("rect", { x: "10.5", y: "0.5", width: "4", height: "4" }), _jsx("rect", { x: "0.5", y: "5.5", width: "4", height: "4" }), _jsx("rect", { x: "5.5", y: "5.5", width: "4", height: "4" }), _jsx("rect", { x: "10.5", y: "5.5", width: "4", height: "4" })] }) }), _jsx("button", { type: "button", className: `results-view-toggle__btn${viewMode === "list" ? " is-active" : ""}`, "aria-pressed": viewMode === "list", "aria-label": "List view", title: "List view", onClick: () => setViewMode("list"), children: _jsxs("svg", { width: "17", height: "17", viewBox: "0 0 15 15", fill: "none", stroke: "currentColor", strokeWidth: "1.8", strokeLinecap: "round", children: [_jsx("line", { x1: "0.5", y1: "2.5", x2: "14.5", y2: "2.5" }), _jsx("line", { x1: "0.5", y1: "7.5", x2: "14.5", y2: "7.5" }), _jsx("line", { x1: "0.5", y1: "12.5", x2: "14.5", y2: "12.5" })] }) })] })), debugEnabled && (_jsx("button", { type: "button", className: "bom-toolbar-btn", onClick: () => setDetailMode((mode) => (mode === "simple" ? "detailed" : "simple")), children: detailMode === "detailed" ? "Hide detailed view" : "Show detailed view" })), _jsxs("details", { ref: sortMenuRef, style: { position: "relative" }, children: [_jsx("summary", { className: "bom-toolbar-btn sort-menu-summary", "aria-label": "Sort line items", style: { fontSize: 16 }, children: "\u21C5" }), _jsx("div", { className: "sort-menu-panel", children: SORT_OPTIONS.map((opt) => {
638
+ return (_jsxs("div", { className: "wizard-step entry-stage", children: [_jsxs("div", { className: `quick-order-card${internal ? "" : " quick-order-card--customer"}`, children: [_jsx("div", { className: `quick-order-hero${internal ? "" : " quick-order-hero--customer"}`, children: internal ? (_jsxs(_Fragment, { children: [_jsx("div", { className: "quick-order-eyebrow", children: "Construction Services" }), _jsxs("div", { className: "quick-order-hero-title-row", children: [_jsx("h1", { children: "Your Results" }), _jsxs("span", { className: "summary-chip summary-chip--scope", children: [_jsx("strong", { children: fmtCurrency(totalValue) }), " Est. total"] })] }), _jsx("p", { children: "Each line item from your schedule matched against your catalogue, ranked by confidence." })] })) : (_jsxs(_Fragment, { children: [_jsxs("div", { children: [_jsx("h1", { children: "Review your matched products" }), _jsxs("p", { children: ["Check you're happy with these items, then click ", qzaQuoteRequest ? "View Quote" : "View Basket", " to continue."] })] }), _jsxs("button", { type: "button", className: "results-total-action", onClick: onGoToBasket, "aria-label": qzaQuoteRequest ? "View quote" : "View basket", children: [_jsxs("span", { children: [_jsx("small", { children: qzaQuoteRequest ? "View Quote" : "View Basket" }), _jsx("strong", { children: fmtCurrency(totalValue) })] }), _jsx("span", { className: "arrow", children: _jsx(ForwardArrow, {}) })] })] })) }), _jsxs("div", { className: "quick-order-panel", style: { paddingTop: 16 }, children: [debugEnabled && (_jsx("div", { className: "results-summary", style: { marginBottom: 12 }, children: _jsx("button", { type: "button", className: "bom-toolbar-btn", "aria-pressed": showTimings, onClick: () => setShowTimings((value) => !value), children: showTimings ? "Hide timings" : "Show timings" }) })), debugEnabled && showTimings && _jsx(TimingBreakdown, { ...timings }), !qzaQuoteRequest && (_jsx("div", { className: "results-toolbar-row", children: !activeReviewRow && (_jsxs("div", { className: "results-summary", style: { marginBottom: 0 }, children: [needsPricingCount > 0 && (_jsxs("span", { className: "summary-chip summary-chip--neutral", children: [_jsx("strong", { children: needsPricingCount }), " need pricing"] })), _jsxs("div", { style: {
639
+ display: "flex",
640
+ gap: 8,
641
+ flexWrap: "wrap",
642
+ alignItems: "center",
643
+ }, children: [_jsx("input", { type: "text", className: "results-search-input", placeholder: "Search description...", value: search, onChange: (e) => setSearch(e.target.value), "aria-label": "Search line items" }), !internal && (_jsxs("div", { className: "results-view-toggle", "aria-label": "Results view", children: [_jsx("button", { type: "button", className: `results-view-toggle__btn${viewMode === "tile" ? " is-active" : ""}`, "aria-pressed": viewMode === "tile", "aria-label": "Tile view", title: "Tile view", onClick: () => setViewMode("tile"), children: _jsxs("svg", { width: "18", height: "12", viewBox: "0 0 15 10", fill: "currentColor", children: [_jsx("rect", { x: "0.5", y: "0.5", width: "4", height: "4" }), _jsx("rect", { x: "5.5", y: "0.5", width: "4", height: "4" }), _jsx("rect", { x: "10.5", y: "0.5", width: "4", height: "4" }), _jsx("rect", { x: "0.5", y: "5.5", width: "4", height: "4" }), _jsx("rect", { x: "5.5", y: "5.5", width: "4", height: "4" }), _jsx("rect", { x: "10.5", y: "5.5", width: "4", height: "4" })] }) }), _jsx("button", { type: "button", className: `results-view-toggle__btn${viewMode === "list" ? " is-active" : ""}`, "aria-pressed": viewMode === "list", "aria-label": "List view", title: "List view", onClick: () => setViewMode("list"), children: _jsxs("svg", { width: "17", height: "17", viewBox: "0 0 15 15", fill: "none", stroke: "currentColor", strokeWidth: "1.8", strokeLinecap: "round", children: [_jsx("line", { x1: "0.5", y1: "2.5", x2: "14.5", y2: "2.5" }), _jsx("line", { x1: "0.5", y1: "7.5", x2: "14.5", y2: "7.5" }), _jsx("line", { x1: "0.5", y1: "12.5", x2: "14.5", y2: "12.5" })] }) })] })), debugEnabled && (_jsx("button", { type: "button", className: "bom-toolbar-btn", onClick: () => setDetailMode((mode) => (mode === "simple" ? "detailed" : "simple")), children: detailMode === "detailed" ? "Hide detailed view" : "Show detailed view" })), _jsxs("details", { ref: sortMenuRef, style: { position: "relative" }, children: [_jsx("summary", { className: "bom-toolbar-btn sort-menu-summary", "aria-label": "Sort line items", style: { fontSize: 16 }, children: "\u21C5" }), _jsx("div", { className: "sort-menu-panel", children: SORT_OPTIONS.map((opt) => {
608
644
  const active = sortConfig === opt.dir;
609
645
  return (_jsxs("button", { type: "button", className: `sort-menu-item${active ? " is-active" : ""}`, onClick: () => {
610
646
  setSortConfig(active ? null : opt.dir);
611
647
  sortMenuRef.current?.removeAttribute("open");
612
648
  }, children: [_jsx("span", { className: "sort-menu-item__check", children: active ? "โœ“" : "" }), opt.label] }, opt.dir));
613
- }) })] })] })] })) }), viewMode === "tile" || activeReviewRow ? (_jsxs(_Fragment, { children: [activeReviewRow ? (_jsx("div", { className: "modal-backdrop quick-order-modal-backdrop", role: "dialog", "aria-modal": "true", "aria-label": "Product options", onClick: () => closeReview(), children: _jsxs("section", { className: "quick-order-workflow-modal results-review-modal", onClick: (event) => event.stopPropagation(), children: [_jsx("button", { type: "button", className: "quick-order-workflow-close results-review-modal__close", onClick: () => closeReview(), "aria-label": "Close product options", children: _jsx(CloseIcon, {}) }), _jsx("div", { className: "results-review-page", children: internal ? (_jsxs(_Fragment, { children: [_jsxs("div", { className: "results-review-page__top", children: [_jsxs("button", { type: "button", className: "bom-toolbar-btn bom-toolbar-btn--accent", onClick: () => closeReview(), children: [_jsx(BackArrow, {}), "Back to results"] }), _jsxs("div", { style: { display: "flex", gap: 8, flexWrap: "wrap" }, children: [debugEnabled && (_jsx("button", { type: "button", className: "bom-toolbar-btn", onClick: () => setDetailMode((mode) => (mode === "simple" ? "detailed" : "simple")), children: detailMode === "detailed" ? "Hide detailed info" : "Show detailed info" })), _jsx("div", { className: "results-review-searchbar", children: _jsx("input", { type: "text", className: "results-search-input", placeholder: "Search products in catalogue...", value: reviewSearch, onChange: (e) => setReviewSearch(e.target.value), "aria-label": "Search database candidates" }) }), _jsx("div", { className: "results-candidate-actions", children: _jsx("button", { type: "button", className: "bom-toolbar-btn", onClick: () => clearPickedProduct(activeReviewRow.item.line_id), children: "Clear selected product" }) })] })] }), _jsxs("div", { className: "results-review-page__hero", children: [_jsx("div", { className: "results-review-page__image-wrap", children: _jsx("img", { className: "fill-img results-review-page__image", src: productImageSrc(previewCandidate(activeReviewRow)?.description || activeReviewRow.item.description_original, previewCandidate(activeReviewRow)?.product_id, previewCandidate(activeReviewRow)?.pdp_photo_url), alt: "" }) }), _jsxs("div", { className: "results-review-page__summary", children: [_jsx("h2", { children: displayLineLabel(activeReviewRow.item, lineItems) }), _jsxs("p", { className: "results-review-page__meta", children: [fmtQty(activeReviewRow.qty), " ", renderDisplayUnit(activeReviewRow.item.unit, activeReviewRow.qty)] }), activeReviewRow.best ? (_jsxs(_Fragment, { children: [_jsx("div", { className: "results-review-page__product", children: activeReviewRow.best.description }), activeReviewRow.best.price != null ? _jsx("div", { className: "results-row-meta", children: fmtPrice(activeReviewRow.best.price, activeReviewRow.best.price_basis) }) : null] })) : previewCandidate(activeReviewRow) ? (_jsxs(_Fragment, { children: [_jsx("div", { className: "results-review-page__product", children: previewCandidate(activeReviewRow)?.description }), previewCandidate(activeReviewRow)?.price != null ? _jsx("div", { className: "results-row-meta", children: fmtPrice(previewCandidate(activeReviewRow)?.price ?? null, previewCandidate(activeReviewRow)?.price_basis ?? null) }) : null, _jsx("div", { className: "results-row-meta", children: "Best reviewed alternative - not yet selected" })] })) : (_jsx("div", { className: "results-empty-hint", children: "No product currently selected for this line item." })), hasVisibleLinkedGroup(activeReviewRow.item) ? (_jsxs("div", { style: { display: "flex", alignItems: "center", gap: 8, marginTop: 8 }, children: [_jsx(LinkedGroupPill, { meta: linkedGroupMetaById.get(activeReviewRow.item.linked_group_id) }), _jsx("div", { className: "results-row-meta", style: { marginTop: 0 }, children: linkedGroupSummary(activeReviewRow.item) })] })) : null, _jsx("div", { className: "results-review-page__actions", children: _jsx("button", { type: "button", className: `bom-toolbar-btn${cart[activeReviewRow.item.line_id] ? " bom-toolbar-btn--added" : " bom-toolbar-btn--accent"}`, onClick: () => {
649
+ }) })] })] })] })) })), viewMode === "tile" || activeReviewRow ? (_jsxs(_Fragment, { children: [activeReviewRow ? (_jsx("div", { className: "modal-backdrop quick-order-modal-backdrop", role: "dialog", "aria-modal": "true", "aria-label": "Product options", onClick: () => closeReview(), children: _jsxs("section", { className: "quick-order-workflow-modal results-review-modal", onClick: (event) => event.stopPropagation(), children: [_jsx("button", { type: "button", className: "quick-order-workflow-close results-review-modal__close", onClick: () => closeReview(), "aria-label": "Close product options", children: _jsx(CloseIcon, {}) }), _jsx("div", { className: "results-review-page", children: internal ? (_jsxs(_Fragment, { children: [_jsxs("div", { className: "results-review-page__top", children: [_jsxs("button", { type: "button", className: "bom-toolbar-btn bom-toolbar-btn--accent", onClick: () => closeReview(), children: [_jsx(BackArrow, {}), "Back to results"] }), _jsxs("div", { style: {
650
+ display: "flex",
651
+ gap: 8,
652
+ flexWrap: "wrap",
653
+ }, children: [debugEnabled && (_jsx("button", { type: "button", className: "bom-toolbar-btn", onClick: () => setDetailMode((mode) => (mode === "simple" ? "detailed" : "simple")), children: detailMode === "detailed" ? "Hide detailed info" : "Show detailed info" })), _jsx("div", { className: "results-review-searchbar", children: _jsx("input", { type: "text", className: "results-search-input", placeholder: "Search products in catalogue...", value: reviewSearch, onChange: (e) => setReviewSearch(e.target.value), "aria-label": "Search database candidates" }) }), _jsx("div", { className: "results-candidate-actions", children: _jsx("button", { type: "button", className: "bom-toolbar-btn", onClick: () => clearPickedProduct(activeReviewRow.item.line_id), children: "Clear selected product" }) })] })] }), _jsxs("div", { className: "results-review-page__hero", children: [_jsx("div", { className: "results-review-page__image-wrap", children: _jsx("img", { className: "fill-img results-review-page__image", src: productImageSrc(previewCandidate(activeReviewRow)?.description || activeReviewRow.item.description_original, previewCandidate(activeReviewRow)?.product_id, previewCandidate(activeReviewRow)?.pdp_photo_url), alt: "" }) }), _jsxs("div", { className: "results-review-page__summary", children: [_jsx("h2", { children: displayLineLabel(activeReviewRow.item, lineItems) }), _jsxs("p", { className: "results-review-page__meta", children: [fmtQty(activeReviewRow.qty), " ", renderDisplayUnit(activeReviewRow.item.unit, activeReviewRow.qty)] }), activeReviewRow.best ? (_jsxs(_Fragment, { children: [_jsx("div", { className: "results-review-page__product", children: activeReviewRow.best.description }), activeReviewRow.best.price != null ? _jsx("div", { className: "results-row-meta", children: fmtPrice(activeReviewRow.best.price, activeReviewRow.best.price_basis) }) : null] })) : previewCandidate(activeReviewRow) ? (_jsxs(_Fragment, { children: [_jsx("div", { className: "results-review-page__product", children: previewCandidate(activeReviewRow)?.description }), previewCandidate(activeReviewRow)?.price != null ? (_jsx("div", { className: "results-row-meta", children: fmtPrice(previewCandidate(activeReviewRow)?.price ?? null, previewCandidate(activeReviewRow)?.price_basis ?? null) })) : null, _jsx("div", { className: "results-row-meta", children: "Best reviewed alternative - not yet selected" })] })) : (_jsx("div", { className: "results-empty-hint", children: "No product currently selected for this line item." })), hasVisibleLinkedGroup(activeReviewRow.item) ? (_jsxs("div", { style: {
654
+ display: "flex",
655
+ alignItems: "center",
656
+ gap: 8,
657
+ marginTop: 8,
658
+ }, children: [_jsx(LinkedGroupPill, { meta: linkedGroupMetaById.get(activeReviewRow.item.linked_group_id) }), _jsx("div", { className: "results-row-meta", style: { marginTop: 0 }, children: linkedGroupSummary(activeReviewRow.item) })] })) : null, _jsx("div", { className: "results-review-page__actions", children: _jsx("button", { type: "button", className: `bom-toolbar-btn${cart[activeReviewRow.item.line_id] ? " bom-toolbar-btn--added" : " bom-toolbar-btn--accent"}`, onClick: () => {
614
659
  if (cart[activeReviewRow.item.line_id])
615
660
  onRemoveFromCart(activeReviewRow.item.line_id);
616
661
  else {
@@ -627,7 +672,7 @@ export default function ScheduleResultsStage({ scheduleResult, onStartOver, cart
627
672
  : "Search the catalogue to choose a product." })] }) }), !reviewQuery && reviewDisplayCandidates.length > 0 ? (_jsx("div", { className: "customer-review-option-grid", children: reviewOptionCandidates.map((candidate) => {
628
673
  const selected = candidate.product_id === activeReviewRow.best?.product_id;
629
674
  return (_jsxs("button", { type: "button", className: `customer-review-option${selected ? " is-selected" : ""}`, onClick: () => handlePickProduct(activeReviewRow.item.line_id, candidate), "aria-pressed": selected, children: [_jsx("img", { className: "customer-review-option__image", src: productImageSrc(candidate.description, candidate.product_id, candidate.pdp_photo_url), alt: "", width: 64, height: 64 }), _jsx("span", { className: "customer-review-option__copy", children: _jsx("strong", { children: candidate.description }) }), _jsx("span", { className: "customer-review-option__price", children: candidate.price != null ? `ยฃ${fmtPrice(candidate.price, candidate.price_basis)}` : "-" }), _jsx("span", { className: "customer-review-option__state", children: selected ? "Selected" : "Choose" })] }, candidate.product_id));
630
- }) })) : null, reviewDisplayCandidates.length > 0 && _jsx("div", { className: "customer-review-divider", children: _jsx("span", { children: "or" }) }), _jsxs("label", { className: "customer-review-search", children: [_jsx("span", { children: "Search our full catalogue" }), _jsx("input", { type: "text", className: "results-search-input", placeholder: "Search products...", value: reviewSearch, onChange: (e) => setReviewSearch(e.target.value), "aria-label": "Search catalogue" })] }), reviewQuery && catalogueSearchLoading ? _jsx("div", { className: "results-empty-card", children: "Searching catalogue\u2026" }) : null, reviewQuery && !catalogueSearchLoading && catalogueSearchError ? _jsx("div", { className: "results-empty-card", children: catalogueSearchError }) : null, reviewQuery && !catalogueSearchLoading && !catalogueSearchError && reviewDisplayCandidates.length === 0 ? (_jsx("div", { className: "results-empty-card", children: "No products match this search." })) : null, reviewQuery && !catalogueSearchLoading && !catalogueSearchError && reviewDisplayCandidates.length > 0 ? (_jsx("div", { className: "customer-review-option-grid", children: reviewOptionCandidates.map((candidate) => {
675
+ }) })) : null, reviewDisplayCandidates.length > 0 && (_jsx("div", { className: "customer-review-divider", children: _jsx("span", { children: "or" }) })), _jsxs("label", { className: "customer-review-search", children: [_jsx("span", { children: "Search our full catalogue" }), _jsx("input", { type: "text", className: "results-search-input", placeholder: "Search products...", value: reviewSearch, onChange: (e) => setReviewSearch(e.target.value), "aria-label": "Search catalogue" })] }), reviewQuery && catalogueSearchLoading ? _jsx("div", { className: "results-empty-card", children: "Searching catalogue\u2026" }) : null, reviewQuery && !catalogueSearchLoading && catalogueSearchError ? _jsx("div", { className: "results-empty-card", children: catalogueSearchError }) : null, reviewQuery && !catalogueSearchLoading && !catalogueSearchError && reviewDisplayCandidates.length === 0 ? _jsx("div", { className: "results-empty-card", children: "No products match this search." }) : null, reviewQuery && !catalogueSearchLoading && !catalogueSearchError && reviewDisplayCandidates.length > 0 ? (_jsx("div", { className: "customer-review-option-grid", children: reviewOptionCandidates.map((candidate) => {
631
676
  const selected = candidate.product_id === activeReviewRow.best?.product_id;
632
677
  return (_jsxs("button", { type: "button", className: `customer-review-option${selected ? " is-selected" : ""}`, onClick: () => handlePickProduct(activeReviewRow.item.line_id, candidate), "aria-pressed": selected, children: [_jsx("img", { className: "customer-review-option__image", src: productImageSrc(candidate.description, candidate.product_id, candidate.pdp_photo_url), alt: "", width: 64, height: 64 }), _jsx("span", { className: "customer-review-option__copy", children: _jsx("strong", { children: candidate.description }) }), _jsx("span", { className: "customer-review-option__price", children: candidate.price != null ? `ยฃ${fmtPrice(candidate.price, candidate.price_basis)}` : "-" }), _jsx("span", { className: "customer-review-option__state", children: selected ? "Selected" : "Choose" })] }, candidate.product_id));
633
678
  }) })) : null] }), activeReviewRow.best ? (activeReviewHasPendingUpdate ? (_jsxs("div", { style: { display: "grid", gap: 8 }, children: [_jsx("button", { type: "button", className: "cta-btn customer-review-add", onClick: () => {
@@ -665,7 +710,12 @@ export default function ScheduleResultsStage({ scheduleResult, onStartOver, cart
665
710
  }, onMouseLeave: () => {
666
711
  hoveredRowRef.current = null;
667
712
  setHoveredRowBounds(null);
668
- }, children: [_jsxs("td", { children: [_jsx("div", { className: "bom-component-name", children: displayLineLabel(item, lineItems) }), hasVisibleLinkedGroup(item) ? (_jsxs("div", { style: { display: "flex", alignItems: "center", gap: 8, marginTop: 4 }, children: [_jsx(LinkedGroupPill, { meta: linkedGroupMetaById.get(item.linked_group_id) }), _jsx("div", { className: "results-row-meta", style: { marginTop: 0 }, children: linkedGroupSummary(item) })] })) : null] }), _jsx("td", { children: best ? (_jsxs("div", { children: [_jsx("div", { className: "results-match-cell-text", title: best.description, children: best.description }), detailMode === "detailed" && decision?.technical_classification && (_jsxs("div", { className: "results-row-meta", children: [classificationLabel(decision.technical_classification), decision.approval_required ? " - approval required" : ""] }))] })) : (_jsx("span", { className: "results-empty-hint" })) }), _jsx("td", { style: { textAlign: "center" }, children: best?.price != null ? fmtPrice(best.price, best.price_basis) : "-" }), detailMode === "simple" && (_jsx("td", { style: { textAlign: "center" }, children: _jsx("button", { type: "button", className: `bom-toolbar-btn${cart[item.line_id] ? " bom-toolbar-btn--added" : " bom-toolbar-btn--accent"}`, style: { width: 84, justifyContent: "center" }, onClick: (event) => {
713
+ }, children: [_jsxs("td", { children: [_jsx("div", { className: "bom-component-name", children: displayLineLabel(item, lineItems) }), hasVisibleLinkedGroup(item) ? (_jsxs("div", { style: {
714
+ display: "flex",
715
+ alignItems: "center",
716
+ gap: 8,
717
+ marginTop: 4,
718
+ }, children: [_jsx(LinkedGroupPill, { meta: linkedGroupMetaById.get(item.linked_group_id) }), _jsx("div", { className: "results-row-meta", style: { marginTop: 0 }, children: linkedGroupSummary(item) })] })) : null] }), _jsx("td", { children: best ? (_jsxs("div", { children: [_jsx("div", { className: "results-match-cell-text", title: best.description, children: best.description }), detailMode === "detailed" && decision?.technical_classification && (_jsxs("div", { className: "results-row-meta", children: [classificationLabel(decision.technical_classification), decision.approval_required ? " - approval required" : ""] }))] })) : (_jsx("span", { className: "results-empty-hint" })) }), _jsx("td", { style: { textAlign: "center" }, children: best?.price != null ? fmtPrice(best.price, best.price_basis) : "-" }), detailMode === "simple" && (_jsx("td", { style: { textAlign: "center" }, children: _jsx("button", { type: "button", className: `bom-toolbar-btn${cart[item.line_id] ? " bom-toolbar-btn--added" : " bom-toolbar-btn--accent"}`, style: { width: 84, justifyContent: "center" }, onClick: (event) => {
669
719
  event.stopPropagation();
670
720
  if (cart[item.line_id])
671
721
  onRemoveFromCart(item.line_id);
@@ -673,10 +723,17 @@ export default function ScheduleResultsStage({ scheduleResult, onStartOver, cart
673
723
  onAddToCart(toCartItem(row));
674
724
  }
675
725
  }, "aria-label": cart[item.line_id] ? (internal ? "Remove from selection" : `Remove from ${customerCollection}`) : internal ? "Add to selection" : `Add to ${customerCollection}`, children: cart[item.line_id] ? "โœ“ Added" : internal ? "+ Add" : `Add to ${customerCollection}` }) }))] }, item.line_id));
676
- })] })] }) }), unmatchedSection] })), !activeReviewRow && totalPages > 1 && (_jsxs("div", { className: "results-pagination", children: [_jsxs("span", { className: "results-pagination-count", children: ["Showing ", (currentPage - 1) * PAGE_SIZE + 1, "\u2013", Math.min(currentPage * PAGE_SIZE, visibleRows.length), " of ", visibleRows.length] }), _jsxs("div", { className: "results-pagination-controls", children: [_jsx("button", { type: "button", className: "bom-toolbar-btn", onClick: () => setPage(currentPage - 1), disabled: currentPage === 1, children: "Previous" }), _jsxs("span", { className: "results-pagination-page", children: ["Page ", currentPage, " of ", totalPages] }), _jsx("button", { type: "button", className: "bom-toolbar-btn", onClick: () => setPage(currentPage + 1), disabled: currentPage === totalPages, children: "Next" })] })] })), (parseReport.itemCount != null || parseReport.headingCount != null || parseReport.skippedCount != null) && (_jsxs("div", { className: "results-summary", style: { marginTop: 16 }, children: [parseReport.itemCount != null && (_jsxs("span", { className: "summary-chip", children: [_jsx("strong", { children: parseReport.itemCount }), " items parsed"] })), parseReport.headingCount != null && (_jsxs("span", { className: "summary-chip", children: [_jsx("strong", { children: parseReport.headingCount }), " headings"] })), parseReport.skippedCount != null && (_jsxs("span", { className: "summary-chip", children: [_jsx("strong", { children: parseReport.skippedCount }), " rows skipped"] }))] })), _jsxs("div", { className: "disclaimer-box", children: [_jsx("span", { className: "disclaimer-icon", children: "\u26A0\uFE0F" }), _jsx("p", { className: "disclaimer-text", children: "These matches are generated automatically and should be reviewed before purchase." })] }), !activeReviewRow && (_jsxs("div", { className: "btn-row results-actions", children: [_jsxs("button", { className: "cta-btn cta-btn-secondary", style: { flex: cartCount > 0 ? "0 1 30%" : "0 1 30%", gap: 10, justifyContent: "center" }, onClick: () => setConfirmStartOver(true), "aria-label": "Start over", children: [_jsx(RefreshIcon, {}), _jsx("span", { children: "Start Over" })] }), cartCount > 0 && (_jsxs("button", { className: "cta-btn", style: { flex: "0 1 70%" }, onClick: onGoToBasket, "aria-label": internal ? "View selection" : qzaQuoteRequest ? "View quote" : "View basket", children: [_jsxs("span", { children: [internal ? "View Selection" : qzaQuoteRequest ? "View Quote" : "View Basket", " (", cartCount, ")"] }), _jsx("span", { className: "arrow", children: _jsx(ForwardArrow, {}) })] }))] }))] })] }), reviewGateOpen && (_jsx("div", { className: "modal-backdrop quick-order-modal-backdrop review-gate-modal-backdrop", role: "dialog", "aria-modal": "true", "aria-labelledby": "review-gate-title", children: _jsxs("section", { className: "quick-order-workflow-modal review-gate-modal", children: [_jsxs("div", { className: "review-gate-modal__header", children: [_jsx("h2", { id: "review-gate-title", children: "Choose products for these items" }), _jsx("p", { children: "We couldn\u2019t find a clear match for these items, so we need your help. Select an option from the suggestions, search the catalogue, or leave the item out." })] }), _jsx("div", { className: "review-gate-list", children: pendingReviewRows.map((row) => {
726
+ })] })] }) }), unmatchedSection] })), !activeReviewRow && totalPages > 1 && (_jsxs("div", { className: "results-pagination", children: [_jsxs("span", { className: "results-pagination-count", children: ["Showing ", (currentPage - 1) * PAGE_SIZE + 1, "\u2013", Math.min(currentPage * PAGE_SIZE, visibleRows.length), " of ", visibleRows.length] }), _jsxs("div", { className: "results-pagination-controls", children: [_jsx("button", { type: "button", className: "bom-toolbar-btn", onClick: () => setPage(currentPage - 1), disabled: currentPage === 1, children: "Previous" }), _jsxs("span", { className: "results-pagination-page", children: ["Page ", currentPage, " of ", totalPages] }), _jsx("button", { type: "button", className: "bom-toolbar-btn", onClick: () => setPage(currentPage + 1), disabled: currentPage === totalPages, children: "Next" })] })] })), (parseReport.itemCount != null || parseReport.headingCount != null || parseReport.skippedCount != null) && (_jsxs("div", { className: "results-summary", style: { marginTop: 16 }, children: [parseReport.itemCount != null && (_jsxs("span", { className: "summary-chip", children: [_jsx("strong", { children: parseReport.itemCount }), " items parsed"] })), parseReport.headingCount != null && (_jsxs("span", { className: "summary-chip", children: [_jsx("strong", { children: parseReport.headingCount }), " headings"] })), parseReport.skippedCount != null && (_jsxs("span", { className: "summary-chip", children: [_jsx("strong", { children: parseReport.skippedCount }), " rows skipped"] }))] })), _jsxs("div", { className: "disclaimer-box", children: [_jsx("span", { className: "disclaimer-icon", children: "\u26A0\uFE0F" }), _jsx("p", { className: "disclaimer-text", children: "These matches are generated automatically and should be reviewed before purchase." })] }), !activeReviewRow && (_jsxs("div", { className: "btn-row results-actions", children: [_jsxs("button", { className: "cta-btn cta-btn-secondary", style: {
727
+ flex: cartCount > 0 ? "0 1 30%" : "0 1 30%",
728
+ gap: 10,
729
+ justifyContent: "center",
730
+ }, onClick: () => setConfirmStartOver(true), "aria-label": "Start over", children: [_jsx(RefreshIcon, {}), _jsx("span", { children: "Start Over" })] }), cartCount > 0 && (_jsxs("button", { className: "cta-btn", style: { flex: "0 1 70%" }, onClick: onGoToBasket, "aria-label": internal ? "View selection" : qzaQuoteRequest ? "View quote" : "View basket", children: [_jsxs("span", { children: [internal ? "View Selection" : qzaQuoteRequest ? "View Quote" : "View Basket", " (", cartCount, ")"] }), _jsx("span", { className: "arrow", children: _jsx(ForwardArrow, {}) })] }))] }))] })] }), reviewGateOpen && (_jsx("div", { className: "modal-backdrop quick-order-modal-backdrop review-gate-modal-backdrop", role: "dialog", "aria-modal": "true", "aria-labelledby": "review-gate-title", children: _jsxs("section", { className: "quick-order-workflow-modal review-gate-modal", children: [_jsxs("div", { className: "review-gate-modal__header", children: [_jsx("h2", { id: "review-gate-title", children: "Choose products for these items" }), _jsx("p", { children: "We couldn\u2019t find a clear match for these items, so we need your help. Select an option from the suggestions, search the catalogue, or leave the item out." })] }), _jsx("div", { className: "review-gate-list", children: pendingReviewRows.map((row) => {
677
731
  const reviewed = reviewedReviewIds.has(row.item.line_id);
678
732
  const partial = hasBestAlternative(row);
679
- return (_jsx("div", { className: `review-gate-item${reviewed ? " is-reviewed" : ""}`, children: _jsxs("button", { type: "button", className: "review-gate-item__review", onClick: () => { setReviewFlowActive(true); openReview(row.item.line_id); }, children: [_jsxs("span", { className: "review-gate-item__copy", children: [_jsx("strong", { children: displayLineLabel(row.item, lineItems) }), _jsx("span", { children: row.decision?.reason || (partial ? "A close alternative is available but needs confirmation." : "No product has been selected for this item yet.") })] }), _jsx("span", { className: "review-gate-item__action", children: reviewed ? "Choice made" : "Choose a product" })] }) }, row.item.line_id));
733
+ return (_jsx("div", { className: `review-gate-item${reviewed ? " is-reviewed" : ""}`, children: _jsxs("button", { type: "button", className: "review-gate-item__review", onClick: () => {
734
+ setReviewFlowActive(true);
735
+ openReview(row.item.line_id);
736
+ }, children: [_jsxs("span", { className: "review-gate-item__copy", children: [_jsx("strong", { children: displayLineLabel(row.item, lineItems) }), _jsx("span", { children: row.decision?.reason || (partial ? "A close alternative is available but needs confirmation." : "No product has been selected for this item yet.") })] }), _jsx("span", { className: "review-gate-item__action", children: reviewed ? "Choice made" : "Choose a product" })] }) }, row.item.line_id));
680
737
  }) }), _jsx("button", { type: "button", className: "review-gate-skip", onClick: skipAllReviews, children: "Skip all" }), skippedReviewRows.length > 0 ? (_jsxs("div", { className: "review-gate-skipped", children: [_jsx("strong", { children: "Skipped" }), skippedReviewRows.map((row) => (_jsxs("button", { type: "button", className: "review-gate-item is-skipped", onClick: () => {
681
738
  setSkippedReviewIds((ids) => {
682
739
  const next = new Set(ids);