@metron-labs/quote-react 0.1.67 → 0.1.69
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.
- package/LICENSE +31 -31
- package/README.md +253 -253
- package/dist/app/QuickQuote.js +3 -1
- package/dist/app/stages/BasketStage.js +2 -11
- package/dist/app/stages/ScheduleResultsStage.js +18 -32
- package/dist/embed/quote.js +6970 -6970
- package/dist/styles.css +6961 -6961
- package/dist/util/exportScheduleExcel.js +3 -21
- package/dist/util/pricing.js +1 -1
- package/dist/util/types.d.ts +2 -13
- package/package.json +53 -53
|
@@ -121,11 +121,6 @@ export function refreshedCartItem(refreshed, existing) {
|
|
|
121
121
|
conversionNotes: existing.conversionNotes,
|
|
122
122
|
};
|
|
123
123
|
}
|
|
124
|
-
function classificationLabel(value) {
|
|
125
|
-
if (!value)
|
|
126
|
-
return "not stated";
|
|
127
|
-
return value.replace(/_/g, " ");
|
|
128
|
-
}
|
|
129
124
|
function ConfChip({ band }) {
|
|
130
125
|
return (_jsx("span", { className: `status-dot status-dot--${band}`, title: band, children: _jsx("span", { className: "status-dot__mark" }) }));
|
|
131
126
|
}
|
|
@@ -285,14 +280,13 @@ function AdjudicationDebugBlock({ result }) {
|
|
|
285
280
|
const details = [
|
|
286
281
|
["Dependent rerank applied", debug.dependent_rerank_applied ? "yes" : "no"],
|
|
287
282
|
["Linked parent selected product", debug.linked_parent_selected_candidate_description || debug.linked_parent_selected_candidate_id || "-"],
|
|
288
|
-
["Dimension reason overridden", debug.dimension_reason_overridden ? "yes" : "no"],
|
|
289
283
|
];
|
|
290
284
|
return (_jsxs("div", { className: "results-detail-block", children: [_jsx("h4", { style: { margin: "0 0 12px" }, children: "Adjudication context" }), _jsx("dl", { className: "results-detail-grid", children: details.map(([label, value]) => (_jsxs(Fragment, { children: [_jsx("dt", { children: label }), _jsx("dd", { children: value })] }, label))) }), debug.rerank_line_item_input ? (_jsxs(_Fragment, { children: [_jsx("h5", { style: { margin: "12px 0 8px" }, children: "Rerank input" }), _jsx("pre", { className: "results-pre", children: JSON.stringify(debug.rerank_line_item_input, null, 2) })] })) : null] }));
|
|
291
285
|
}
|
|
292
|
-
function DetailedDecision({ item, decision, result, showRetrievalDebug, reviewOnly = false, linkedGroupMeta, }) {
|
|
286
|
+
function DetailedDecision({ item, decision, selectedProductId, result, showRetrievalDebug, reviewOnly = false, linkedGroupMeta, }) {
|
|
293
287
|
if (!decision)
|
|
294
288
|
return null;
|
|
295
|
-
const reviewLabel =
|
|
289
|
+
const reviewLabel = selectedProductId == null ? "Needs review:" : "Selected:";
|
|
296
290
|
if (reviewOnly) {
|
|
297
291
|
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;
|
|
298
292
|
}
|
|
@@ -306,7 +300,7 @@ function CandidateBreakdown({ item, candidates, result, decision, unmatchable, s
|
|
|
306
300
|
// Metron Labs' own tooling — only surfaced under the `debug` config's detail mode.
|
|
307
301
|
const showBusinessDetail = internal || detailMode === "detailed";
|
|
308
302
|
const showScoreColumns = debugEnabled && detailMode === "detailed";
|
|
309
|
-
const detailBlock = showBusinessDetail || forceReviewNote ? (_jsx(DetailedDecision, { item: item, decision: decision, result: result, showRetrievalDebug: showScoreColumns, reviewOnly: forceReviewNote && !showBusinessDetail, linkedGroupMeta: linkedGroupMeta })) : null;
|
|
303
|
+
const detailBlock = showBusinessDetail || forceReviewNote ? (_jsx(DetailedDecision, { item: item, decision: decision, selectedProductId: selectedProductId, result: result, showRetrievalDebug: showScoreColumns, reviewOnly: forceReviewNote && !showBusinessDetail, linkedGroupMeta: linkedGroupMeta })) : null;
|
|
310
304
|
if (unmatchable) {
|
|
311
305
|
return (_jsxs(_Fragment, { children: [detailBlock, _jsx("p", { className: "results-empty-hint", children: "Classified as labour/plant or referencing another line item - skipped by design." })] }));
|
|
312
306
|
}
|
|
@@ -391,7 +385,7 @@ export default function ScheduleResultsStage({ scheduleResult, onStartOver, cart
|
|
|
391
385
|
let totalValue = hasPendingReview ? null : getCartSubtotal(Object.values(cart), { wasteFactorEnabled: false, wasteFactorOverride: 0 });
|
|
392
386
|
let needsPricingCount = 0;
|
|
393
387
|
for (const row of rows) {
|
|
394
|
-
if (row.unmatchable ||
|
|
388
|
+
if (row.unmatchable || !row.best)
|
|
395
389
|
continue;
|
|
396
390
|
const cartItem = cart[row.item.line_id];
|
|
397
391
|
if (!cartItem || getPricingBreakdown(cartItem).lineTotal == null)
|
|
@@ -400,7 +394,7 @@ export default function ScheduleResultsStage({ scheduleResult, onStartOver, cart
|
|
|
400
394
|
if (needsPricingCount > 0)
|
|
401
395
|
totalValue = null;
|
|
402
396
|
const totalLabel = formatResultsTotal(totalValue, needsPricingCount);
|
|
403
|
-
const hasBestAlternative = (row) => !row.unmatchable && !row.best &&
|
|
397
|
+
const hasBestAlternative = (row) => !row.unmatchable && !row.best && recommendedCandidates(row.result).length > 0;
|
|
404
398
|
const previewCandidate = (row) => row.best ?? recommendedCandidates(row.result)[0];
|
|
405
399
|
const reviewRequiredRows = rows.filter((row) => !row.unmatchable && !row.best);
|
|
406
400
|
const pendingReviewRows = reviewRequiredRows.filter((row) => !skippedReviewIds.has(row.item.line_id));
|
|
@@ -418,9 +412,8 @@ export default function ScheduleResultsStage({ scheduleResult, onStartOver, cart
|
|
|
418
412
|
const currentPage = Math.min(page, totalPages);
|
|
419
413
|
const pagedRows = visibleRows.slice((currentPage - 1) * PAGE_SIZE, currentPage * PAGE_SIZE);
|
|
420
414
|
const matchedTileRows = pagedRows.filter((row) => !row.unmatchable && row.best);
|
|
421
|
-
const
|
|
422
|
-
const
|
|
423
|
-
const unmatchedTileRows = pagedRows.filter((row) => row.unmatchable || (!row.best && !hasBestAlternative(row)));
|
|
415
|
+
const matchedDisplayRows = pagedRows.filter((row) => !row.unmatchable && row.best);
|
|
416
|
+
const unmatchedTileRows = pagedRows.filter((row) => row.unmatchable || !row.best);
|
|
424
417
|
const activeReviewRow = selectedReviewId ? (rows.find((row) => row.item.line_id === selectedReviewId) ?? null) : null;
|
|
425
418
|
const reviewGateOpen = !internal && !reviewGateComplete && !activeReviewRow && pendingReviewRows.length > 0;
|
|
426
419
|
const sortMenuRef = useRef(null);
|
|
@@ -534,7 +527,7 @@ export default function ScheduleResultsStage({ scheduleResult, onStartOver, cart
|
|
|
534
527
|
else
|
|
535
528
|
closeReview(true);
|
|
536
529
|
};
|
|
537
|
-
const unmatchedSection = unmatchedTileRows.length > 0 ? (_jsxs("section", { className: "results-tile-section results-tile-section--unmatched", "aria-label": "Items
|
|
530
|
+
const unmatchedSection = unmatchedTileRows.length > 0 ? (_jsxs("section", { className: "results-tile-section results-tile-section--unmatched", "aria-label": "Items needing review", children: [_jsxs("div", { className: "results-tile-section__head", children: [_jsx("h3", { children: "Needs review" }), _jsx("p", { children: "We couldn\u2019t confidently match these to a product. Open one to pick from the closest options." })] }), _jsx("div", { className: "results-unmatched-list", children: unmatchedTileRows.map((row) => {
|
|
538
531
|
const { item, qty } = row;
|
|
539
532
|
return (_jsxs("button", { type: "button", className: "results-unmatched-card", onClick: () => openReview(item.line_id), children: [_jsx("span", { className: "results-unmatched-card__main", children: _jsx("span", { className: "results-unmatched-card__title", children: displayLineLabel(item, lineItems) }) }), _jsx("span", { className: "bom-toolbar-btn results-unmatched-card__prompt", children: "Review" })] }, item.line_id));
|
|
540
533
|
}) })] })) : null;
|
|
@@ -565,7 +558,9 @@ export default function ScheduleResultsStage({ scheduleResult, onStartOver, cart
|
|
|
565
558
|
})));
|
|
566
559
|
}
|
|
567
560
|
function toCartItem(row) {
|
|
568
|
-
const candidate = row.best
|
|
561
|
+
const candidate = row.best;
|
|
562
|
+
if (!candidate)
|
|
563
|
+
throw new Error("Cannot add a line item without a selected product.");
|
|
569
564
|
return candidateToCartItem(candidate, {
|
|
570
565
|
lineId: row.item.line_id,
|
|
571
566
|
description: row.item.description_original,
|
|
@@ -590,8 +585,8 @@ export default function ScheduleResultsStage({ scheduleResult, onStartOver, cart
|
|
|
590
585
|
: undefined,
|
|
591
586
|
});
|
|
592
587
|
}
|
|
593
|
-
// All
|
|
594
|
-
//
|
|
588
|
+
// All selected items land in the basket automatically so the common case starts from
|
|
589
|
+
// a complete draft basket. Gated by cartSeeded (lifted
|
|
595
590
|
// to BoQApp) so this fires once per schedule result, not on every remount of this stage.
|
|
596
591
|
useEffect(() => {
|
|
597
592
|
if (cartSeeded)
|
|
@@ -650,8 +645,8 @@ export default function ScheduleResultsStage({ scheduleResult, onStartOver, cart
|
|
|
650
645
|
const cartCount = Object.keys(cart).length;
|
|
651
646
|
const reviewQuery = reviewSearch.trim();
|
|
652
647
|
const llmReviewCandidates = recommendedCandidates(activeReviewRow?.result);
|
|
653
|
-
const hasNoSuitableCandidate = activeReviewRow?.
|
|
654
|
-
const hasAiVerdict = activeReviewRow?.
|
|
648
|
+
const hasNoSuitableCandidate = !!activeReviewRow && !activeReviewRow.best && (activeReviewRow.result?.candidates.length === 0 || activeReviewRow.result?.rerank?.selectedCandidateId === null);
|
|
649
|
+
const hasAiVerdict = activeReviewRow?.result?.rerank != null;
|
|
655
650
|
const activeReviewReason = activeReviewRow?.decision?.reason ?? (hasNoSuitableCandidate ? "No catalogue candidate found. Refine the request or search the catalogue." : null);
|
|
656
651
|
const catalogueSearchCandidates = catalogueSearchResults.map((candidate) => ({
|
|
657
652
|
product_id: candidate.product_id,
|
|
@@ -750,22 +745,13 @@ export default function ScheduleResultsStage({ scheduleResult, onStartOver, cart
|
|
|
750
745
|
}, children: _jsx("span", { children: activeReviewCartMatches ? `Remove from ${customerCollection}` : `Add selected product to ${customerCollection}` }) }))) : null, reviewFlowActive ? (_jsx("button", { type: "button", className: "cta-btn cta-btn-secondary customer-review-skip", onClick: () => skipReviewAndReturnToGate(activeReviewRow.item.line_id), children: "Skip this item" })) : null] })) })] }) })) : null, _jsxs("div", { className: "results-tile-layout", children: [visibleRows.length === 0 ? _jsx("div", { className: "results-empty-card", children: "No line items match the current search/filter." }) : null, matchedDisplayRows.length > 0 ? (_jsx("section", { className: "results-tile-section", "aria-label": "Matched and review items", children: _jsx("div", { className: "results-tile-grid", children: matchedDisplayRows.map((row) => {
|
|
751
746
|
const { item, best, qty } = row;
|
|
752
747
|
const preview = previewCandidate(row);
|
|
753
|
-
|
|
754
|
-
return (_jsxs("article", { className: "results-tile-card", children: [_jsxs("button", { type: "button", className: "results-tile-card__surface", onClick: () => openReview(item.line_id), "aria-label": `Review match for ${displayLineLabel(item, lineItems) || "item"}`, children: [_jsxs("div", { className: "results-tile-card__media", children: [isPartial || hasVisibleLinkedGroup(item) ? (_jsxs("div", { className: "results-tile-card__badges", children: [hasVisibleLinkedGroup(item) ? _jsx(LinkedGroupPill, { meta: linkedGroupMetaById.get(item.linked_group_id) }) : _jsx("span", {}), isPartial ? (_jsx("span", { style: {
|
|
755
|
-
padding: "6px 10px",
|
|
756
|
-
borderRadius: 999,
|
|
757
|
-
background: "#fef3c7",
|
|
758
|
-
color: "#92400e",
|
|
759
|
-
fontSize: 12,
|
|
760
|
-
fontWeight: 700,
|
|
761
|
-
lineHeight: 1,
|
|
762
|
-
}, children: "Partially matched" })) : null] })) : null, _jsx(ProductImage, { className: "fill-img results-tile-card__image", description: preview?.description || item.description_original, photoUrl: preview?.pdp_photo_url })] }), _jsxs("div", { className: "results-tile-card__body", children: [preview ? (_jsx(_Fragment, { children: _jsx("div", { className: "results-tile-card__heading", children: _jsx("div", { className: "results-tile-card__title", children: preview.description }) }) })) : (_jsx("div", { className: "results-empty-hint", children: "No product currently selected for this line item." })), _jsx("div", { className: "results-tile-card__match", children: preview ? (_jsxs(_Fragment, { children: [_jsx("div", { className: "results-tile-card__match-label", children: isPartial ? "↳ partially matched from" : "↳ matched from" }), _jsx("div", { className: "results-tile-card__match-name", children: displayLineLabel(item, lineItems) }), hasVisibleLinkedGroup(item) ? _jsx("div", { className: "results-row-meta", children: linkedGroupSummary(item) }) : null] })) : (_jsx("span", { className: "results-empty-hint", children: "No matched product selected." })) })] }), _jsx("span", { className: "results-tile-card__hover-prompt", "aria-hidden": "true", children: "Click to view options" })] }), _jsxs("div", { className: "results-tile-card__actions", children: [internal && (_jsx("button", { type: "button", className: "bom-toolbar-btn", onClick: () => openReview(item.line_id), children: "Review" })), _jsx("button", { type: "button", className: `bom-toolbar-btn${cart[item.line_id] ? " bom-toolbar-btn--added" : " bom-toolbar-btn--accent"}`, onClick: () => {
|
|
748
|
+
return (_jsxs("article", { className: "results-tile-card", children: [_jsxs("button", { type: "button", className: "results-tile-card__surface", onClick: () => openReview(item.line_id), "aria-label": `Review match for ${displayLineLabel(item, lineItems) || "item"}`, children: [_jsxs("div", { className: "results-tile-card__media", children: [hasVisibleLinkedGroup(item) ? (_jsx("div", { className: "results-tile-card__badges", children: _jsx(LinkedGroupPill, { meta: linkedGroupMetaById.get(item.linked_group_id) }) })) : null, _jsx(ProductImage, { className: "fill-img results-tile-card__image", description: preview?.description || item.description_original, photoUrl: preview?.pdp_photo_url })] }), _jsxs("div", { className: "results-tile-card__body", children: [preview ? (_jsx(_Fragment, { children: _jsx("div", { className: "results-tile-card__heading", children: _jsx("div", { className: "results-tile-card__title", children: preview.description }) }) })) : (_jsx("div", { className: "results-empty-hint", children: "No product currently selected for this line item." })), _jsx("div", { className: "results-tile-card__match", children: preview ? (_jsxs(_Fragment, { children: [_jsx("div", { className: "results-tile-card__match-label", children: "\u21B3 matched from" }), _jsx("div", { className: "results-tile-card__match-name", children: displayLineLabel(item, lineItems) }), hasVisibleLinkedGroup(item) ? _jsx("div", { className: "results-row-meta", children: linkedGroupSummary(item) }) : null] })) : (_jsx("span", { className: "results-empty-hint", children: "No matched product selected." })) })] }), _jsx("span", { className: "results-tile-card__hover-prompt", "aria-hidden": "true", children: "Click to view options" })] }), _jsxs("div", { className: "results-tile-card__actions", children: [internal && (_jsx("button", { type: "button", className: "bom-toolbar-btn", onClick: () => openReview(item.line_id), children: "Review" })), _jsx("button", { type: "button", className: `bom-toolbar-btn${cart[item.line_id] ? " bom-toolbar-btn--added" : " bom-toolbar-btn--accent"}`, onClick: () => {
|
|
763
749
|
if (cart[item.line_id])
|
|
764
750
|
onRemoveFromCart(item.line_id);
|
|
765
751
|
else {
|
|
766
752
|
onAddToCart(toCartItem(row));
|
|
767
753
|
}
|
|
768
|
-
}, disabled: !
|
|
754
|
+
}, disabled: !best, "aria-label": cart[item.line_id]
|
|
769
755
|
? internal
|
|
770
756
|
? "Remove from selection"
|
|
771
757
|
: `Remove from ${customerCollection}`
|
|
@@ -785,7 +771,7 @@ export default function ScheduleResultsStage({ scheduleResult, onStartOver, cart
|
|
|
785
771
|
alignItems: "center",
|
|
786
772
|
gap: 8,
|
|
787
773
|
marginTop: 4,
|
|
788
|
-
}, 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
|
|
774
|
+
}, 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 && (_jsx("div", { className: "results-row-meta", children: decision.selected_candidate_id === best.product_id ? "Automatically selected" : "Selected" }))] })) : (_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) => {
|
|
789
775
|
event.stopPropagation();
|
|
790
776
|
if (cart[item.line_id])
|
|
791
777
|
onRemoveFromCart(item.line_id);
|