@metron-labs/quote-react 0.1.62 → 0.1.63

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.
@@ -17,5 +17,5 @@ export declare function candidateFromCart(item: CartItem): MatchCandidate;
17
17
  export declare function refreshedCartItem(refreshed: CartItem, existing: CartItem): CartItem;
18
18
  export declare function displayLineLabel(item: LineItem, allItems: LineItem[]): string;
19
19
  export declare function formatResultsTotal(totalValue: number | null, needsPricingCount: number): string | null;
20
- export default function ScheduleResultsStage({ scheduleResult, onStartOver, cart, onAddToCart, onRemoveFromCart, onGoToBasket, cartSeeded, onCartSeeded, reviewGateComplete, onReviewGateComplete, internal }: ResultsStageProps): import("react").JSX.Element;
20
+ export default function ScheduleResultsStage({ scheduleResult, onStartOver, cart, onAddToCart, onRemoveFromCart, onGoToBasket, cartSeeded, onCartSeeded, reviewGateComplete, onReviewGateComplete, internal, }: ResultsStageProps): import("react").JSX.Element;
21
21
  export {};
@@ -198,7 +198,9 @@ function curatedCandidates(candidates, result, selectedProductId) {
198
198
  const recommendedIds = result?.rerank?.recommendedCandidateIds ?? [];
199
199
  if (recommendedIds.length === 0) {
200
200
  const topCandidates = candidates.slice(0, 6);
201
- const pinnedSelected = !topCandidates.some((candidate) => candidate.product_id === selectedProductId) ? candidates.find((candidate) => candidate.product_id === selectedProductId) : undefined;
201
+ const pinnedSelected = !topCandidates.some((candidate) => candidate.product_id === selectedProductId)
202
+ ? candidates.find((candidate) => candidate.product_id === selectedProductId)
203
+ : undefined;
202
204
  return pinnedSelected ? [...topCandidates, pinnedSelected] : topCandidates;
203
205
  }
204
206
  const byId = new Map(candidates.map((candidate) => [candidate.product_id, candidate]));
@@ -326,7 +328,7 @@ function CandidateBreakdown({ item, candidates, result, decision, unmatchable, s
326
328
  }, "aria-label": isCurrent ? `${c.description} selected` : `Use ${c.description}` }), _jsx("span", { className: "switch-toggle-track", "aria-hidden": "true" })] }) })] }, `${c.product_id}-${i}`));
327
329
  }) })] })] }));
328
330
  }
329
- export default function ScheduleResultsStage({ scheduleResult, onStartOver, cart, onAddToCart, onRemoveFromCart, onGoToBasket, cartSeeded, onCartSeeded, reviewGateComplete, onReviewGateComplete, internal = false }) {
331
+ export default function ScheduleResultsStage({ scheduleResult, onStartOver, cart, onAddToCart, onRemoveFromCart, onGoToBasket, cartSeeded, onCartSeeded, reviewGateComplete, onReviewGateComplete, internal = false, }) {
330
332
  const qzaQuoteRequest = !internal && getBoqClientId() === "QZA6-MRA4";
331
333
  const customerCollection = qzaQuoteRequest ? "quote" : "basket";
332
334
  const { results, lineItems, parseReport, timings } = scheduleResult;
@@ -368,7 +370,10 @@ export default function ScheduleResultsStage({ scheduleResult, onStartOver, cart
368
370
  const pick = pickOverrides[item.line_id];
369
371
  const automaticMatch = resolveBest(result, pick);
370
372
  const savedCartMatch = cart[item.line_id];
371
- const matched = pick === NO_SELECTION ? undefined : (pickOverrideCandidates[item.line_id] ?? (savedCartMatch && savedCartMatch.productId !== automaticMatch?.product_id ? candidateFromCart(savedCartMatch) : automaticMatch));
373
+ const matched = pick === NO_SELECTION
374
+ ? undefined
375
+ : (pickOverrideCandidates[item.line_id] ??
376
+ (savedCartMatch && savedCartMatch.productId !== automaticMatch?.product_id ? candidateFromCart(savedCartMatch) : automaticMatch));
372
377
  const best = unmatchable ? undefined : matched;
373
378
  const qty = item.qty ?? 0;
374
379
  return {
@@ -671,7 +676,9 @@ export default function ScheduleResultsStage({ scheduleResult, onStartOver, cart
671
676
  }));
672
677
  const reviewCandidates = reviewQuery ? catalogueSearchCandidates : llmReviewCandidates;
673
678
  const savedSearchCandidate = activeReviewRow ? savedSearchCandidates[activeReviewRow.item.line_id] : undefined;
674
- const reviewDisplayCandidates = !reviewQuery && savedSearchCandidate && !reviewCandidates.some((candidate) => candidate.product_id === savedSearchCandidate.product_id) ? [...reviewCandidates, savedSearchCandidate] : reviewCandidates;
679
+ const reviewDisplayCandidates = !reviewQuery && savedSearchCandidate && !reviewCandidates.some((candidate) => candidate.product_id === savedSearchCandidate.product_id)
680
+ ? [...reviewCandidates, savedSearchCandidate]
681
+ : reviewCandidates;
675
682
  const reviewOptionCandidates = (() => {
676
683
  const topCandidates = reviewDisplayCandidates.slice(0, reviewQuery ? 12 : 6);
677
684
  if (reviewQuery || !savedSearchCandidate || topCandidates.some((candidate) => candidate.product_id === savedSearchCandidate.product_id))
@@ -680,22 +687,22 @@ export default function ScheduleResultsStage({ scheduleResult, onStartOver, cart
680
687
  })();
681
688
  const activeReviewCartMatches = !!activeReviewRow?.best && cart[activeReviewRow.item.line_id]?.productId === activeReviewRow.best.product_id;
682
689
  const activeReviewHasPendingUpdate = !!activeReviewRow?.best && !!cart[activeReviewRow.item.line_id] && !activeReviewCartMatches;
683
- 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: totalLabel ?? "Review quantities" }), " 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, disabled: cartCount === 0, "aria-label": qzaQuoteRequest ? "View quote" : "View basket", children: [_jsxs("span", { children: [_jsx("small", { children: qzaQuoteRequest ? "View Quote" : "View Basket" }), totalLabel != null && _jsx("strong", { children: totalLabel })] }), _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: {
684
- display: "flex",
685
- gap: 8,
686
- flexWrap: "wrap",
687
- alignItems: "center",
688
- }, 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) => {
689
- const active = sortConfig === opt.dir;
690
- return (_jsxs("button", { type: "button", className: `sort-menu-item${active ? " is-active" : ""}`, onClick: () => {
691
- setSortConfig(active ? null : opt.dir);
692
- sortMenuRef.current?.removeAttribute("open");
693
- }, children: [_jsx("span", { className: "sort-menu-item__check", children: active ? "✓" : "" }), opt.label] }, opt.dir));
694
- }) })] })] })] })) })), 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: {
690
+ 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: totalLabel ?? "Review quantities" }), " 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, disabled: cartCount === 0, "aria-label": qzaQuoteRequest ? "View quote" : "View basket", children: [_jsxs("span", { children: [_jsx("small", { children: qzaQuoteRequest ? "View Quote" : "View Basket" }), totalLabel != null && _jsx("strong", { children: totalLabel })] }), _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 && (_jsx("div", { className: "results-summary", style: { marginBottom: 0 }, children: _jsxs("div", { style: {
691
+ display: "flex",
692
+ gap: 8,
693
+ flexWrap: "wrap",
694
+ alignItems: "center",
695
+ }, 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) => {
696
+ const active = sortConfig === opt.dir;
697
+ return (_jsxs("button", { type: "button", className: `sort-menu-item${active ? " is-active" : ""}`, onClick: () => {
698
+ setSortConfig(active ? null : opt.dir);
699
+ sortMenuRef.current?.removeAttribute("open");
700
+ }, children: [_jsx("span", { className: "sort-menu-item__check", children: active ? "✓" : "" }), opt.label] }, opt.dir));
701
+ }) })] })] }) })) })), 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: {
695
702
  display: "flex",
696
703
  gap: 8,
697
704
  flexWrap: "wrap",
698
- }, 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: {
705
+ }, 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: {
699
706
  display: "flex",
700
707
  alignItems: "center",
701
708
  gap: 8,
@@ -708,7 +715,19 @@ export default function ScheduleResultsStage({ scheduleResult, onStartOver, cart
708
715
  saveSearchCandidate(activeReviewRow.item.line_id, activeReviewRow.best);
709
716
  onAddToCart(toCartItem(activeReviewRow));
710
717
  }
711
- }, disabled: !activeReviewRow.best, "aria-label": cart[activeReviewRow.item.line_id] ? (internal ? "Remove from selection" : `Remove from ${customerCollection}`) : internal ? "Add to selection" : `Add to ${customerCollection}`, children: cart[activeReviewRow.item.line_id] ? "✓ Added" : internal ? "+ Add to selection" : `Add to ${customerCollection}` }) })] })] }), catalogueSearchLoading ? _jsx("div", { className: "results-empty-card", children: "Searching catalogue\u2026" }) : null, !catalogueSearchLoading && catalogueSearchError ? _jsx("div", { className: "results-empty-card", children: catalogueSearchError }) : null, !catalogueSearchLoading && !catalogueSearchError && reviewQuery && reviewCandidates.length === 0 ? (_jsx("div", { className: "results-empty-card", children: "No candidate products match this database search." })) : !catalogueSearchLoading && !catalogueSearchError ? (_jsx(CandidateBreakdown, { item: activeReviewRow.item, candidates: reviewCandidates, result: activeReviewRow.result, decision: activeReviewRow.decision, unmatchable: activeReviewRow.unmatchable, selectedProductId: activeReviewRow.best?.product_id ?? null, detailMode: detailMode, linkedGroupMeta: hasVisibleLinkedGroup(activeReviewRow.item) ? linkedGroupMetaById.get(activeReviewRow.item.linked_group_id) : undefined, onPick: (candidate) => handlePickProduct(activeReviewRow.item.line_id, candidate), onClear: () => clearPickedProduct(activeReviewRow.item.line_id), showAll: internal || debugEnabled || reviewQuery.length > 0, internal: internal, debugEnabled: debugEnabled, forceReviewNote: true })) : null] })) : (_jsxs(_Fragment, { children: [_jsxs("section", { className: "customer-review-request", children: [_jsx("span", { className: "customer-review-eyebrow", children: "Original request" }), _jsx("strong", { children: displayLineLabel(activeReviewRow.item, lineItems) || "Original request" })] }), activeReviewReason ? (_jsxs("section", { className: "customer-review-ai", children: [_jsx("strong", { children: hasNoSuitableCandidate ? "No automatic match:" : "AI review:" }), " ", activeReviewReason] })) : null, _jsxs("section", { className: "customer-review-options", children: [_jsx("div", { className: "customer-review-options__head", children: _jsxs("div", { children: [_jsx("h2", { children: hasNoSuitableCandidate ? (llmReviewCandidates.length > 0 ? "Choose a product" : "No suitable product found") : hasAiVerdict ? "Choose a product" : "We couldn't review this item" }), _jsx("p", { children: hasNoSuitableCandidate
718
+ }, disabled: !activeReviewRow.best, "aria-label": cart[activeReviewRow.item.line_id]
719
+ ? internal
720
+ ? "Remove from selection"
721
+ : `Remove from ${customerCollection}`
722
+ : internal
723
+ ? "Add to selection"
724
+ : `Add to ${customerCollection}`, children: cart[activeReviewRow.item.line_id] ? "✓ Added" : internal ? "+ Add to selection" : `Add to ${customerCollection}` }) })] })] }), catalogueSearchLoading ? _jsx("div", { className: "results-empty-card", children: "Searching catalogue\u2026" }) : null, !catalogueSearchLoading && catalogueSearchError ? _jsx("div", { className: "results-empty-card", children: catalogueSearchError }) : null, !catalogueSearchLoading && !catalogueSearchError && reviewQuery && reviewCandidates.length === 0 ? (_jsx("div", { className: "results-empty-card", children: "No candidate products match this database search." })) : !catalogueSearchLoading && !catalogueSearchError ? (_jsx(CandidateBreakdown, { item: activeReviewRow.item, candidates: reviewCandidates, result: activeReviewRow.result, decision: activeReviewRow.decision, unmatchable: activeReviewRow.unmatchable, selectedProductId: activeReviewRow.best?.product_id ?? null, detailMode: detailMode, linkedGroupMeta: hasVisibleLinkedGroup(activeReviewRow.item) ? linkedGroupMetaById.get(activeReviewRow.item.linked_group_id) : undefined, onPick: (candidate) => handlePickProduct(activeReviewRow.item.line_id, candidate), onClear: () => clearPickedProduct(activeReviewRow.item.line_id), showAll: internal || debugEnabled || reviewQuery.length > 0, internal: internal, debugEnabled: debugEnabled, forceReviewNote: true })) : null] })) : (_jsxs(_Fragment, { children: [_jsxs("section", { className: "customer-review-request", children: [_jsx("span", { className: "customer-review-eyebrow", children: "Original request" }), _jsx("strong", { children: displayLineLabel(activeReviewRow.item, lineItems) || "Original request" })] }), activeReviewReason ? (_jsxs("section", { className: "customer-review-ai", children: [_jsx("strong", { children: hasNoSuitableCandidate ? "No automatic match:" : "AI review:" }), " ", activeReviewReason] })) : null, _jsxs("section", { className: "customer-review-options", children: [_jsx("div", { className: "customer-review-options__head", children: _jsxs("div", { children: [_jsx("h2", { children: hasNoSuitableCandidate
725
+ ? llmReviewCandidates.length > 0
726
+ ? "Choose a product"
727
+ : "No suitable product found"
728
+ : hasAiVerdict
729
+ ? "Choose a product"
730
+ : "We couldn't review this item" }), _jsx("p", { children: hasNoSuitableCandidate
712
731
  ? llmReviewCandidates.length > 0
713
732
  ? "No product was selected automatically. Review these related options before adding one."
714
733
  : "Search the catalogue to choose an alternative."
@@ -717,7 +736,7 @@ export default function ScheduleResultsStage({ scheduleResult, onStartOver, cart
717
736
  : "Search the catalogue to choose a product." })] }) }), !reviewQuery && reviewDisplayCandidates.length > 0 ? (_jsx("div", { className: "customer-review-option-grid", children: reviewOptionCandidates.map((candidate) => {
718
737
  const selected = candidate.product_id === activeReviewRow.best?.product_id;
719
738
  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));
720
- }) })) : 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) => {
739
+ }) })) : 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) => {
721
740
  const selected = candidate.product_id === activeReviewRow.best?.product_id;
722
741
  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));
723
742
  }) })) : null] }), activeReviewRow.best ? (activeReviewHasPendingUpdate ? (_jsxs("div", { style: { display: "grid", gap: 8 }, children: [_jsx("button", { type: "button", className: "cta-btn customer-review-add", onClick: () => {
@@ -746,7 +765,13 @@ export default function ScheduleResultsStage({ scheduleResult, onStartOver, cart
746
765
  else {
747
766
  onAddToCart(toCartItem(row));
748
767
  }
749
- }, disabled: !preview, "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));
768
+ }, disabled: !preview, "aria-label": cart[item.line_id]
769
+ ? internal
770
+ ? "Remove from selection"
771
+ : `Remove from ${customerCollection}`
772
+ : internal
773
+ ? "Add to selection"
774
+ : `Add to ${customerCollection}`, children: cart[item.line_id] ? "✓ Added" : internal ? "+ Add" : `Add to ${customerCollection}` })] })] }, item.line_id));
750
775
  }) }) })) : null, unmatchedSection] })] })) : (_jsxs(_Fragment, { children: [hoveredRowBounds && (_jsx("div", { className: "results-table__hover-overlay", style: hoveredRowBounds, "aria-hidden": "true", children: "Click to view options" })), _jsx("div", { className: "bom-table-wrap", children: _jsxs("table", { className: "bom-table results-table", "aria-label": "Matched line items", children: [_jsxs("colgroup", { children: [_jsx("col", { className: "col-item" }), _jsx("col", { style: { width: "220px" } }), _jsx("col", { style: { width: "100px" } }), detailMode === "simple" && _jsx("col", { style: { width: "110px" } })] }), _jsx("thead", { children: _jsxs("tr", { className: "bom-col-header", children: [_jsx("th", { style: { textAlign: "left" }, children: "Description" }), _jsx("th", { style: { textAlign: "center" }, children: "Product Matched" }), _jsx("th", { style: { textAlign: "center" }, children: "Price" }), detailMode === "simple" && _jsx("th", { style: { textAlign: "center" }, children: internal ? "Selection" : qzaQuoteRequest ? "Quote" : "Basket" })] }) }), _jsxs("tbody", { children: [visibleRows.length === 0 && (_jsx("tr", { children: _jsx("td", { colSpan: detailMode === "simple" ? 4 : 3, className: "results-empty-hint", style: { padding: "16px 8px" }, children: "No line items match the current search/filter." }) })), matchedDisplayRows.map((row) => {
751
776
  const { item, result, decision, best } = row;
752
777
  return (_jsxs("tr", { className: "bom-row results-table__review-row", onClick: () => openReview(item.line_id), onMouseEnter: (event) => {
@@ -767,7 +792,13 @@ export default function ScheduleResultsStage({ scheduleResult, onStartOver, cart
767
792
  else {
768
793
  onAddToCart(toCartItem(row));
769
794
  }
770
- }, "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));
795
+ }, "aria-label": cart[item.line_id]
796
+ ? internal
797
+ ? "Remove from selection"
798
+ : `Remove from ${customerCollection}`
799
+ : internal
800
+ ? "Add to selection"
801
+ : `Add to ${customerCollection}`, children: cart[item.line_id] ? "✓ Added" : internal ? "+ Add" : `Add to ${customerCollection}` }) }))] }, item.line_id));
771
802
  })] })] }) }), 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: {
772
803
  flex: "0 1 30%",
773
804
  gap: 10,
@@ -272,13 +272,13 @@ export default function EstimatorResults({ toolId, requirements, ready, onBack,
272
272
  const options = pickerResults.length > 0 ? pickerResults : row.candidates;
273
273
  return (_jsxs("div", { className: "estimator-products__picker", children: [_jsx("input", { type: "text", className: "results-search-input", value: pickerSearch, autoFocus: true, placeholder: "Search products in catalogue...", onChange: (event) => setPickerSearch(event.target.value), "aria-label": `Search a product for ${row.requirement.label}` }), _jsxs("div", { className: "estimator-products__options", children: [options.map((candidate) => (_jsxs("button", { type: "button", className: `estimator-products__option${candidate.product_id === row.chosen?.product_id ? " is-selected" : ""}`, onClick: () => chooseCandidate(row.requirement.key, candidate), children: [_jsx("span", { children: candidate.description }), _jsxs("span", { className: "results-row-meta", children: [candidate.product_id, candidate.price != null && ` · ${fmtCurrency(candidate.price)}`] })] }, candidate.product_id))), options.length === 0 && _jsx("p", { className: "results-empty-hint", children: "No matching products." })] })] }));
274
274
  };
275
- return (_jsxs("section", { className: "estimator-products results-tile-section", "aria-label": "Matched products", children: [!loading && (_jsxs("div", { className: "estimator-products__head", children: [_jsxs("div", { className: "results-tile-section__head", children: [_jsx("h3", { children: "Matched Products" }), _jsx("p", { children: "Products matched to your estimate, check before adding to your basket." })] }), !reviewRow && (_jsxs("div", { className: "results-summary estimator-products__toolbar", children: [needsPricingCount > 0 && (_jsxs("span", { className: "summary-chip summary-chip--neutral", children: [_jsx("strong", { children: needsPricingCount }), " need pricing"] })), _jsxs("div", { className: "estimator-products__controls", children: [_jsx("input", { type: "text", className: "results-search-input", placeholder: "Search description...", value: search, onChange: (event) => setSearch(event.target.value), "aria-label": "Search matched products" }), _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" })] }) })] }), _jsxs("details", { ref: sortMenuRef, style: { position: "relative" }, children: [_jsx("summary", { className: "bom-toolbar-btn sort-menu-summary", "aria-label": "Sort materials", style: { fontSize: 16 }, children: "\u21C5" }), _jsx("div", { className: "sort-menu-panel", children: SORT_OPTIONS.map((option) => {
276
- const active = sortConfig === option.dir;
277
- return (_jsxs("button", { type: "button", className: `sort-menu-item${active ? " is-active" : ""}`, onClick: () => {
278
- setSortConfig(active ? null : option.dir);
279
- sortMenuRef.current?.removeAttribute("open");
280
- }, children: [_jsx("span", { className: "sort-menu-item__check", children: active ? "✓" : "" }), option.label] }, option.dir));
281
- }) })] })] })] }))] })), reviewRow && (_jsxs("div", { className: "results-review-page", 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: [_jsx("div", { className: "results-review-searchbar", children: _jsx("input", { type: "text", className: "results-search-input", placeholder: "Search products in catalogue...", value: reviewSearch, onChange: (event) => setReviewSearch(event.target.value), "aria-label": `Search a product for ${reviewRow.requirement.label}` }) }), reviewRow.chosen && (_jsx("div", { className: "results-candidate-actions", children: _jsx("button", { type: "button", className: "bom-toolbar-btn", onClick: () => clearChosen(reviewRow.requirement.key), 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(reviewRow.chosen?.description || reviewRow.requirement.label, reviewRow.chosen?.product_id, reviewRow.chosen?.pdp_photo_url), alt: "" }) }), _jsxs("div", { className: "results-review-page__summary", children: [_jsx("h2", { children: reviewRow.requirement.label }), _jsxs("p", { className: "results-review-page__meta", children: [fmtQty(reviewRow.requirement.qty), " ", renderDisplayUnit(reviewRow.requirement.unit, reviewRow.requirement.qty)] }), reviewRow.chosen ? (_jsxs(_Fragment, { children: [_jsx("div", { className: "results-review-page__product", children: reviewRow.chosen.description }), _jsxs("div", { className: "results-row-meta", children: [reviewRow.chosen.product_id, reviewRow.chosen.price != null ? ` · ${fmtPrice(reviewRow.chosen.price, reviewRow.chosen.price_basis)}` : ""] })] })) : (_jsx("div", { className: "results-empty-hint", children: "No product currently selected for this line." })), _jsx("div", { className: "results-review-page__actions", children: _jsx("button", { type: "button", className: `bom-toolbar-btn${cart?.cart[lineIdFor(reviewRow.requirement.key)] ? " bom-toolbar-btn--added" : " bom-toolbar-btn--accent"}`, onClick: () => toggleInCart(reviewRow), disabled: !reviewRow.chosen || !cart, children: cart?.cart[lineIdFor(reviewRow.requirement.key)] ? "✓ Added" : "+ Add to basket" }) })] })] }), reviewCandidates.length === 0 ? (_jsx("p", { className: "results-empty-hint", children: "No matching products." })) : (_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" }), _jsx("th", { "aria-label": "Actions" })] }) }), _jsx("tbody", { children: reviewCandidates.map((candidate) => {
275
+ return (_jsxs("section", { className: "estimator-products results-tile-section", "aria-label": "Matched products", children: [!loading && (_jsxs("div", { className: "estimator-products__head", children: [_jsxs("div", { className: "results-tile-section__head", children: [_jsx("h3", { children: "Matched Products" }), _jsx("p", { children: "Products matched to your estimate, check before adding to your basket." })] }), !reviewRow && (_jsx("div", { className: "results-summary estimator-products__toolbar", children: _jsxs("div", { className: "estimator-products__controls", children: [_jsx("input", { type: "text", className: "results-search-input", placeholder: "Search description...", value: search, onChange: (event) => setSearch(event.target.value), "aria-label": "Search matched products" }), _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" })] }) })] }), _jsxs("details", { ref: sortMenuRef, style: { position: "relative" }, children: [_jsx("summary", { className: "bom-toolbar-btn sort-menu-summary", "aria-label": "Sort materials", style: { fontSize: 16 }, children: "\u21C5" }), _jsx("div", { className: "sort-menu-panel", children: SORT_OPTIONS.map((option) => {
276
+ const active = sortConfig === option.dir;
277
+ return (_jsxs("button", { type: "button", className: `sort-menu-item${active ? " is-active" : ""}`, onClick: () => {
278
+ setSortConfig(active ? null : option.dir);
279
+ sortMenuRef.current?.removeAttribute("open");
280
+ }, children: [_jsx("span", { className: "sort-menu-item__check", children: active ? "✓" : "" }), option.label] }, option.dir));
281
+ }) })] })] }) }))] })), reviewRow && (_jsxs("div", { className: "results-review-page", 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: [_jsx("div", { className: "results-review-searchbar", children: _jsx("input", { type: "text", className: "results-search-input", placeholder: "Search products in catalogue...", value: reviewSearch, onChange: (event) => setReviewSearch(event.target.value), "aria-label": `Search a product for ${reviewRow.requirement.label}` }) }), reviewRow.chosen && (_jsx("div", { className: "results-candidate-actions", children: _jsx("button", { type: "button", className: "bom-toolbar-btn", onClick: () => clearChosen(reviewRow.requirement.key), 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(reviewRow.chosen?.description || reviewRow.requirement.label, reviewRow.chosen?.product_id, reviewRow.chosen?.pdp_photo_url), alt: "" }) }), _jsxs("div", { className: "results-review-page__summary", children: [_jsx("h2", { children: reviewRow.requirement.label }), _jsxs("p", { className: "results-review-page__meta", children: [fmtQty(reviewRow.requirement.qty), " ", renderDisplayUnit(reviewRow.requirement.unit, reviewRow.requirement.qty)] }), reviewRow.chosen ? (_jsxs(_Fragment, { children: [_jsx("div", { className: "results-review-page__product", children: reviewRow.chosen.description }), _jsxs("div", { className: "results-row-meta", children: [reviewRow.chosen.product_id, reviewRow.chosen.price != null ? ` · ${fmtPrice(reviewRow.chosen.price, reviewRow.chosen.price_basis)}` : ""] })] })) : (_jsx("div", { className: "results-empty-hint", children: "No product currently selected for this line." })), _jsx("div", { className: "results-review-page__actions", children: _jsx("button", { type: "button", className: `bom-toolbar-btn${cart?.cart[lineIdFor(reviewRow.requirement.key)] ? " bom-toolbar-btn--added" : " bom-toolbar-btn--accent"}`, onClick: () => toggleInCart(reviewRow), disabled: !reviewRow.chosen || !cart, children: cart?.cart[lineIdFor(reviewRow.requirement.key)] ? "✓ Added" : "+ Add to basket" }) })] })] }), reviewCandidates.length === 0 ? (_jsx("p", { className: "results-empty-hint", children: "No matching products." })) : (_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" }), _jsx("th", { "aria-label": "Actions" })] }) }), _jsx("tbody", { children: reviewCandidates.map((candidate) => {
282
282
  const isCurrent = candidate.product_id === reviewRow.chosen?.product_id;
283
283
  return (_jsxs("tr", { className: isCurrent ? "score-breakdown-row--best" : "", children: [_jsxs("td", { children: [_jsx("div", { children: candidate.description }), _jsx("div", { className: "results-row-meta", children: candidate.product_id })] }), _jsx("td", { children: _jsx("span", { className: "unit-badge", children: fmtMeasurements(candidate.measurements_mm) }) }), _jsx("td", { children: candidate.price != null ? fmtPrice(candidate.price, candidate.price_basis) : "-" }), _jsx("td", { children: _jsxs("label", { className: "switch-toggle", title: isCurrent ? "Currently selected" : "Use this candidate", children: [_jsx("input", { type: "checkbox", checked: isCurrent, onChange: () => {
284
284
  if (isCurrent)