@propeller-commerce/propeller-v2-react-ui 0.13.0 → 0.15.0

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/CHANGELOG.md CHANGED
@@ -8,6 +8,70 @@ once it reaches 1.0. Until then (the `0.x` line) the public API may change
8
8
  between minor versions; breaking changes are called out below and in
9
9
  [MIGRATION.md](./MIGRATION.md).
10
10
 
11
+ ## [0.15.0] - 2026-08-06
12
+
13
+ ### Changed
14
+
15
+ - **BREAKING — the stock filter is a toggle plus a quantity, not two
16
+ checkboxes.** `<GridFilters>` now takes `activeAvailability` as a single
17
+ `Availability` (`'all' | 'in-stock'`) rather than an array, gains
18
+ `activeMinStock`, and its `onAvailabilityChange` fires with both the
19
+ selection and the quantity. `<GridToolbar>` takes `availability` as a single
20
+ value plus `minStock`, and its `onAvailabilityFilterRemove` takes no
21
+ argument. `<ProductGrid>` takes `availability` plus `minStock`. The
22
+ out-of-stock bucket has no replacement. See [MIGRATION.md](./MIGRATION.md).
23
+
24
+ Two checkboxes could express "in stock or out of stock" — every product, and
25
+ so a state that looked active but sent no filter. They also could not answer
26
+ what a shopper asks next: not "is it stocked?" but "do you have enough?".
27
+
28
+ The section is now a two-state toggle and, once In stock is chosen, an
29
+ editable quantity with stepper buttons. The value can be typed directly or
30
+ stepped, commits on blur or Enter, and is floored and clamped to a minimum
31
+ of 1 — a lower threshold would match zero-stock products and contradict the
32
+ toggle. Switching back to All products clears it.
33
+
34
+ Requires `propeller-v2-core-ui` >= 0.6.0.
35
+
36
+ - **The toolbar shows one stock chip** instead of one per bucket, carrying the
37
+ quantity when it is above the default.
38
+
39
+ ### Added
40
+
41
+ - Label keys `allProducts`, `atLeast`, `pcs`, `quantityDecrease` and
42
+ `quantityIncrease`. The `outOfStock` key is no longer read.
43
+
44
+ ## [0.14.0] - 2026-08-05
45
+
46
+ ### Added
47
+
48
+ - **`hideHeader` and `flat` on `<OrderList>` and
49
+ `<PurchaseAuthorizationRequests>`** — for embedding a list inside a host's
50
+ own card. `hideHeader` drops the table's column-header row, redundant once
51
+ a card names what it contains and shows three columns. `flat` drops the
52
+ component's own background, border, shadow and rounded corners, which
53
+ otherwise nest a box inside the host's box. On `<OrderList>` the empty
54
+ state honours `flat` too, so a card with no results does not draw a stray
55
+ panel.
56
+
57
+ - **`limit`, `columns`, `columnConfig`, `showActions` and `hideTitle` on
58
+ `<PurchaseAuthorizationRequests>`** — the component rendered a fixed
59
+ five-column table (date, quantity, total, requested by, actions) and its
60
+ own heading, so it could not be reduced to a summary. `columns` selects
61
+ which of those render and in what order, `columnConfig` overrides their
62
+ header labels, `showActions` hides the accept/delete buttons, `hideTitle`
63
+ suppresses the component's own `<h2>` when the host already has one, and
64
+ `limit` caps the list to the most recently modified — mirroring the prop
65
+ `<FavoriteLists>` already carries.
66
+
67
+ ### Notes
68
+
69
+ Every prop above is additive and defaults to current behaviour: an existing
70
+ consumer that passes none of them renders exactly as it did in 0.13.0. In
71
+ particular `<PurchaseAuthorizationRequests>` still lists requests in the
72
+ order the API returned them; the most-recent-first sort applies only when
73
+ `limit` is set, so the rows that survive the slice are the newest.
74
+
11
75
  ## [0.13.0] - 2026-08-05
12
76
 
13
77
  ### Added
package/MIGRATION.md CHANGED
@@ -6,6 +6,69 @@ minor versions — each one is documented here.
6
6
 
7
7
  ---
8
8
 
9
+ ## `GridFilters` / `GridToolbar`: stock filter is a toggle plus a quantity
10
+
11
+ **When:** `0.15.0`.
12
+
13
+ The two stock checkboxes (In stock / Out of stock) are now a two-state toggle
14
+ plus an editable quantity — "in stock, at least N pcs". The out-of-stock
15
+ bucket has no replacement.
16
+
17
+ Two checkboxes could express "in stock or out of stock", which is every
18
+ product and so had to collapse to no filter — a state that looked active and
19
+ did nothing. They also could not express a quantity.
20
+
21
+ **`GridFilters`**
22
+
23
+ ```tsx
24
+ // before
25
+ <GridFilters
26
+ activeAvailability={['in-stock']} // Availability[]
27
+ onAvailabilityChange={(sel) => setAvailability(sel)}
28
+ />
29
+
30
+ // after
31
+ <GridFilters
32
+ activeAvailability={'in-stock'} // Availability ('all' | 'in-stock')
33
+ activeMinStock={5} // new, optional; undefined = 1
34
+ onAvailabilityChange={(sel, minStock) => { setAvailability(sel); setMinStock(minStock); }}
35
+ />
36
+ ```
37
+
38
+ **`GridToolbar`**
39
+
40
+ ```tsx
41
+ // before
42
+ <GridToolbar
43
+ availability={['in-stock']} // Availability[]
44
+ onAvailabilityFilterRemove={(value) => remove(value)}
45
+ />
46
+
47
+ // after
48
+ <GridToolbar
49
+ availability={'in-stock'} // Availability
50
+ minStock={5} // new, optional
51
+ onAvailabilityFilterRemove={() => reset()} // no argument — one chip
52
+ />
53
+ ```
54
+
55
+ **`ProductGrid`** takes `availability?: Availability` and `minStock?: number`
56
+ in place of `availability?: Availability[]`.
57
+
58
+ **Steps**
59
+
60
+ 1. Upgrade `@propeller-commerce/propeller-v2-core-ui` to `^0.6.0`, where
61
+ `Availability` becomes `'all' | 'in-stock'` and `buildInventoryFilter`
62
+ takes `(selection, minQuantity?)`.
63
+ 2. Replace array state with a single value plus a quantity number.
64
+ 3. Drop any out-of-stock option from your own UI and URL handling.
65
+ 4. If you serialise the selection into a URL, decide how to carry the
66
+ quantity. The boilerplates use `?availability=in-stock` for the default
67
+ and `?availability=in-stock:5` for a raised quantity, omitting the
68
+ parameter entirely for "all products".
69
+ 5. Add labels for the new keys: `allProducts`, `atLeast`, `pcs`,
70
+ `quantityDecrease`, `quantityIncrease`. Remove `outOfStock`.
71
+
9
72
  ## `Menu`: optional pre-fetched `tree` prop (additive)
10
73
 
11
74
  **When:** during `0.1.0` stabilization (pre-publish).
package/dist/index.cjs CHANGED
@@ -2262,7 +2262,8 @@ function useProductSearch(options) {
2262
2262
  JSON.stringify(options.textFilters ?? []),
2263
2263
  options.priceFilterMin ?? "",
2264
2264
  options.priceFilterMax ?? "",
2265
- JSON.stringify(options.availability ?? [])
2265
+ options.availability ?? "",
2266
+ options.minStock ?? ""
2266
2267
  ].join("|");
2267
2268
  if (inflightFetches2.has(inflightKey)) {
2268
2269
  fetchIdRef.current--;
@@ -2304,7 +2305,7 @@ function useProductSearch(options) {
2304
2305
  }
2305
2306
  ] : [];
2306
2307
  const priceFilter = options.priceFilterMin !== void 0 || options.priceFilterMax !== void 0 ? { from: options.priceFilterMin ?? 0, to: options.priceFilterMax ?? 999999 } : void 0;
2307
- const inventoryFilter = propellerV2CoreUi.buildInventoryFilter(options.availability);
2308
+ const inventoryFilter = propellerV2CoreUi.buildInventoryFilter(options.availability, options.minStock);
2308
2309
  const userId = options.user && "contactId" in options.user ? options.user.contactId : options.user && "customerId" in options.user ? options.user.customerId : void 0;
2309
2310
  const contactId = options.user && "contactId" in options.user ? options.user.contactId : void 0;
2310
2311
  const customerId = options.user && "customerId" in options.user ? options.user.customerId : void 0;
@@ -2405,6 +2406,7 @@ function useProductSearch(options) {
2405
2406
  options.priceFilterMin,
2406
2407
  options.priceFilterMax,
2407
2408
  options.availability,
2409
+ options.minStock,
2408
2410
  options.sortField,
2409
2411
  options.sortOrder,
2410
2412
  options.companyId,
@@ -2444,7 +2446,7 @@ function useProductSearch(options) {
2444
2446
  const userId = options.user && "contactId" in options.user ? options.user.contactId : options.user && "customerId" in options.user ? options.user.customerId : void 0;
2445
2447
  const contactId = options.user && "contactId" in options.user ? options.user.contactId : void 0;
2446
2448
  const customerId = options.user && "customerId" in options.user ? options.user.customerId : void 0;
2447
- const inventoryFilter = propellerV2CoreUi.buildInventoryFilter(options.availability);
2449
+ const inventoryFilter = propellerV2CoreUi.buildInventoryFilter(options.availability, options.minStock);
2448
2450
  const categoryProductSearchInput = {
2449
2451
  language,
2450
2452
  page: 1,
@@ -2537,6 +2539,7 @@ function useProductSearch(options) {
2537
2539
  options.priceFilterMin,
2538
2540
  options.priceFilterMax,
2539
2541
  options.availability,
2542
+ options.minStock,
2540
2543
  options.sortField,
2541
2544
  options.sortOrder,
2542
2545
  pageSize,
@@ -9060,6 +9063,7 @@ function ProductGrid(rawProps) {
9060
9063
  priceFilterMin: props.priceFilterMin,
9061
9064
  priceFilterMax: props.priceFilterMax,
9062
9065
  availability: props.availability,
9066
+ minStock: props.minStock,
9063
9067
  sortField: props.sortField,
9064
9068
  sortOrder: props.sortOrder,
9065
9069
  pageSize: props.pageSize,
@@ -9363,7 +9367,13 @@ function GridFilters(rawProps) {
9363
9367
  const [appliedMin, setAppliedMin] = React6.useState(() => void 0);
9364
9368
  const [appliedMax, setAppliedMax] = React6.useState(() => void 0);
9365
9369
  const [availability, setAvailability] = React6.useState(
9366
- () => [...props.activeAvailability || []]
9370
+ () => props.activeAvailability || "all"
9371
+ );
9372
+ const [minStock, setMinStock] = React6.useState(
9373
+ () => props.activeMinStock ?? propellerV2CoreUi.MIN_STOCK_THRESHOLD
9374
+ );
9375
+ const [minStockInput, setMinStockInput] = React6.useState(
9376
+ () => String(props.activeMinStock ?? propellerV2CoreUi.MIN_STOCK_THRESHOLD)
9367
9377
  );
9368
9378
  function showPriceFilter() {
9369
9379
  const mode = props.portalMode || "open";
@@ -9418,13 +9428,28 @@ function GridFilters(rawProps) {
9418
9428
  props.onFilterChange(filter, value);
9419
9429
  if (props.getSelectedFilters) props.getSelectedFilters();
9420
9430
  }
9421
- function handleAvailabilityToggle(value, checked) {
9422
- const next = checked ? [...availability, value] : availability.filter((v) => v !== value);
9423
- setAvailability(next);
9431
+ function handleAvailabilityChange(value) {
9432
+ const nextMinStock = value === "all" ? propellerV2CoreUi.MIN_STOCK_THRESHOLD : minStock;
9433
+ setAvailability(value);
9434
+ setMinStock(nextMinStock);
9435
+ setMinStockInput(String(nextMinStock));
9436
+ setIsPending(true);
9437
+ if (props.onAvailabilityChange) props.onAvailabilityChange(value, nextMinStock);
9438
+ if (props.getSelectedFilters) props.getSelectedFilters();
9439
+ }
9440
+ function handleMinStockChange(value) {
9441
+ const n = Math.max(Math.floor(value) || propellerV2CoreUi.MIN_STOCK_THRESHOLD, propellerV2CoreUi.MIN_STOCK_THRESHOLD);
9442
+ setMinStock(n);
9443
+ setMinStockInput(String(n));
9444
+ if (n === minStock) return;
9424
9445
  setIsPending(true);
9425
- if (props.onAvailabilityChange) props.onAvailabilityChange(next);
9446
+ if (props.onAvailabilityChange) props.onAvailabilityChange(availability, n);
9426
9447
  if (props.getSelectedFilters) props.getSelectedFilters();
9427
9448
  }
9449
+ function commitMinStockInput() {
9450
+ const parsed = parseInt(minStockInput, 10);
9451
+ handleMinStockChange(isNaN(parsed) ? propellerV2CoreUi.MIN_STOCK_THRESHOLD : parsed);
9452
+ }
9428
9453
  function handleMinChange(value) {
9429
9454
  const n = value > currentMax ? currentMax : value;
9430
9455
  setCurrentMin(n);
@@ -9498,7 +9523,9 @@ function GridFilters(rawProps) {
9498
9523
  setCurrentMin(props.priceMin || 0);
9499
9524
  setCurrentMax(props.priceMax || 9999);
9500
9525
  setExpandedFilters({});
9501
- setAvailability([]);
9526
+ setAvailability("all");
9527
+ setMinStock(propellerV2CoreUi.MIN_STOCK_THRESHOLD);
9528
+ setMinStockInput(String(propellerV2CoreUi.MIN_STOCK_THRESHOLD));
9502
9529
  }, [props.clearSignal, props.priceMin, props.priceMax]);
9503
9530
  React6.useEffect(() => {
9504
9531
  if (!props.activeTextFilters) return;
@@ -9506,8 +9533,10 @@ function GridFilters(rawProps) {
9506
9533
  }, [props.activeTextFilters]);
9507
9534
  React6.useEffect(() => {
9508
9535
  if (!props.activeAvailability) return;
9509
- setAvailability([...props.activeAvailability]);
9510
- }, [props.activeAvailability]);
9536
+ setAvailability(props.activeAvailability);
9537
+ setMinStock(props.activeMinStock ?? propellerV2CoreUi.MIN_STOCK_THRESHOLD);
9538
+ setMinStockInput(String(props.activeMinStock ?? propellerV2CoreUi.MIN_STOCK_THRESHOLD));
9539
+ }, [props.activeAvailability, props.activeMinStock]);
9511
9540
  React6.useEffect(() => {
9512
9541
  if (props.activePriceMin === void 0 && props.activePriceMax === void 0) {
9513
9542
  setCurrentMin(props.priceMin || 0);
@@ -9610,34 +9639,76 @@ function GridFilters(rawProps) {
9610
9639
  showAvailability() ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
9611
9640
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "propeller-grid-filters__availability space-y-3", children: [
9612
9641
  /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "propeller-grid-filters__availability-title text-xs font-semibold uppercase tracking-wide text-muted-foreground", children: propellerV2CoreUi.getLabel(props.labels, "availability", "Availability") }),
9613
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "propeller-grid-filters__availability-options space-y-1.5", children: [
9614
- /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "propeller-grid-filters__option flex items-center gap-2 cursor-pointer group", children: [
9642
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "propeller-grid-filters__availability-toggle inline-flex h-8 w-full rounded-control border border-input overflow-hidden", children: [
9643
+ /* @__PURE__ */ jsxRuntime.jsx(
9644
+ "button",
9645
+ {
9646
+ type: "button",
9647
+ className: `propeller-grid-filters__availability-option flex-1 text-xs font-medium transition-colors ${availability === "all" ? "bg-secondary text-secondary-foreground" : "bg-transparent text-muted-foreground hover:text-foreground"}`,
9648
+ "aria-pressed": availability === "all",
9649
+ disabled: !!props.isLoading,
9650
+ onClick: () => handleAvailabilityChange("all"),
9651
+ children: propellerV2CoreUi.getLabel(props.labels, "allProducts", "All products")
9652
+ }
9653
+ ),
9654
+ /* @__PURE__ */ jsxRuntime.jsx(
9655
+ "button",
9656
+ {
9657
+ type: "button",
9658
+ className: `propeller-grid-filters__availability-option flex-1 text-xs font-medium transition-colors ${availability === "in-stock" ? "bg-secondary text-secondary-foreground" : "bg-transparent text-muted-foreground hover:text-foreground"}`,
9659
+ "aria-pressed": availability === "in-stock",
9660
+ disabled: !!props.isLoading,
9661
+ onClick: () => handleAvailabilityChange("in-stock"),
9662
+ children: propellerV2CoreUi.getLabel(props.labels, "inStock", "In stock")
9663
+ }
9664
+ )
9665
+ ] }),
9666
+ availability === "in-stock" ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "propeller-grid-filters__availability-quantity flex items-center gap-2 text-sm text-muted-foreground", children: [
9667
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: propellerV2CoreUi.getLabel(props.labels, "atLeast", "at least") }),
9668
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "propeller-grid-filters__availability-stepper inline-flex items-center h-8 rounded-control border border-input bg-card overflow-hidden focus-within:ring-1 focus-within:ring-secondary", children: [
9615
9669
  /* @__PURE__ */ jsxRuntime.jsx(
9616
- "input",
9670
+ "button",
9617
9671
  {
9618
- type: "checkbox",
9619
- className: "propeller-grid-filters__checkbox h-4 w-4 rounded border-input text-secondary focus:ring-secondary cursor-pointer flex-shrink-0",
9620
- checked: availability.includes("in-stock"),
9621
- disabled: !!props.isLoading,
9622
- onChange: (e) => handleAvailabilityToggle("in-stock", e.target.checked)
9672
+ type: "button",
9673
+ className: "propeller-grid-filters__quantity-decrease h-full w-8 flex items-center justify-center text-muted-foreground disabled:opacity-40 disabled:cursor-not-allowed hover:bg-accent hover:text-foreground transition-colors",
9674
+ "aria-label": propellerV2CoreUi.getLabel(props.labels, "quantityDecrease", "Decrease quantity"),
9675
+ disabled: !!props.isLoading || minStock <= propellerV2CoreUi.MIN_STOCK_THRESHOLD,
9676
+ onClick: () => handleMinStockChange(minStock - 1),
9677
+ children: "\u2212"
9623
9678
  }
9624
9679
  ),
9625
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "propeller-grid-filters__option-label flex-1 text-sm text-muted-foreground leading-none select-none group-hover:text-foreground", children: propellerV2CoreUi.getLabel(props.labels, "inStock", "In stock") })
9626
- ] }),
9627
- /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "propeller-grid-filters__option flex items-center gap-2 cursor-pointer group", children: [
9628
9680
  /* @__PURE__ */ jsxRuntime.jsx(
9629
9681
  "input",
9630
9682
  {
9631
- type: "checkbox",
9632
- className: "propeller-grid-filters__checkbox h-4 w-4 rounded border-input text-secondary focus:ring-secondary cursor-pointer flex-shrink-0",
9633
- checked: availability.includes("out-of-stock"),
9683
+ type: "number",
9684
+ inputMode: "numeric",
9685
+ className: "propeller-grid-filters__availability-quantity-input w-10 h-full px-0 text-center font-medium text-foreground bg-transparent border-0 focus:outline-none focus:ring-0 [appearance:textfield] [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none",
9686
+ "aria-label": propellerV2CoreUi.getLabel(props.labels, "atLeast", "at least"),
9687
+ min: propellerV2CoreUi.MIN_STOCK_THRESHOLD,
9688
+ step: 1,
9689
+ value: minStockInput,
9634
9690
  disabled: !!props.isLoading,
9635
- onChange: (e) => handleAvailabilityToggle("out-of-stock", e.target.checked)
9691
+ onChange: (e) => setMinStockInput(e.target.value),
9692
+ onBlur: () => commitMinStockInput(),
9693
+ onKeyDown: (e) => {
9694
+ if (e.key === "Enter") e.target.blur();
9695
+ }
9636
9696
  }
9637
9697
  ),
9638
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "propeller-grid-filters__option-label flex-1 text-sm text-muted-foreground leading-none select-none group-hover:text-foreground", children: propellerV2CoreUi.getLabel(props.labels, "outOfStock", "Out of stock") })
9639
- ] })
9640
- ] })
9698
+ /* @__PURE__ */ jsxRuntime.jsx(
9699
+ "button",
9700
+ {
9701
+ type: "button",
9702
+ className: "propeller-grid-filters__quantity-increase h-full w-8 flex items-center justify-center text-muted-foreground disabled:opacity-40 disabled:cursor-not-allowed hover:bg-accent hover:text-foreground transition-colors",
9703
+ "aria-label": propellerV2CoreUi.getLabel(props.labels, "quantityIncrease", "Increase quantity"),
9704
+ disabled: !!props.isLoading,
9705
+ onClick: () => handleMinStockChange(minStock + 1),
9706
+ children: "+"
9707
+ }
9708
+ )
9709
+ ] }),
9710
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: propellerV2CoreUi.getLabel(props.labels, "pcs", "pcs") })
9711
+ ] }) : null
9641
9712
  ] }),
9642
9713
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "propeller-grid-filters__divider h-px bg-border-subtle" })
9643
9714
  ] }) : null,
@@ -9817,7 +9888,6 @@ var DEFAULT_LABELS = {
9817
9888
  perPage: " per page",
9818
9889
  price: "Price",
9819
9890
  inStock: "In stock",
9820
- outOfStock: "Out of stock",
9821
9891
  switchToList: "Switch to list view",
9822
9892
  switchToGrid: "Switch to grid view"
9823
9893
  };
@@ -9846,7 +9916,7 @@ function GridToolbar(rawProps) {
9846
9916
  const text = props.activeTextFilters || {};
9847
9917
  const hasText = Object.keys(text).some((k) => (text[k] || []).length > 0);
9848
9918
  const hasPrice = props.priceFilterMin !== void 0 || props.priceFilterMax !== void 0;
9849
- const hasAvailability = (props.availability || []).length > 0;
9919
+ const hasAvailability = props.availability === "in-stock";
9850
9920
  return hasText || hasPrice || hasAvailability;
9851
9921
  }
9852
9922
  function getActiveFilterBadges() {
@@ -9865,8 +9935,10 @@ function GridToolbar(rawProps) {
9865
9935
  function isPriceSortDisabled() {
9866
9936
  return propellerV2CoreUi.isContentHidden(props.portalMode, props.user);
9867
9937
  }
9868
- function getAvailabilityLabel(value) {
9869
- return value === "in-stock" ? getLabel56("inStock") : getLabel56("outOfStock");
9938
+ function getAvailabilityLabel() {
9939
+ const qty = props.minStock;
9940
+ if (qty !== void 0 && qty > propellerV2CoreUi.MIN_STOCK_THRESHOLD) return `${getLabel56("inStock")}: ${qty}+`;
9941
+ return getLabel56("inStock");
9870
9942
  }
9871
9943
  function handleSortFieldChange(field) {
9872
9944
  setCurrentSortField(field);
@@ -10041,20 +10113,19 @@ function GridToolbar(rawProps) {
10041
10113
  ]
10042
10114
  }
10043
10115
  ) : null,
10044
- (props.availability || []).map((value) => /* @__PURE__ */ jsxRuntime.jsxs(
10116
+ props.availability === "in-stock" ? /* @__PURE__ */ jsxRuntime.jsxs(
10045
10117
  "span",
10046
10118
  {
10047
10119
  className: "propeller-grid-toolbar__filter-badge propeller-grid-toolbar__filter-badge--availability inline-flex items-center gap-1 cursor-pointer px-2.5 py-0.5 rounded-full text-xs font-semibold border border-input bg-background hover:bg-primary hover:text-primary-foreground hover:border-primary transition-colors",
10048
10120
  onClick: (event) => {
10049
- if (props.onAvailabilityFilterRemove) props.onAvailabilityFilterRemove(value);
10121
+ if (props.onAvailabilityFilterRemove) props.onAvailabilityFilterRemove();
10050
10122
  },
10051
10123
  children: [
10052
- getAvailabilityLabel(value),
10124
+ getAvailabilityLabel(),
10053
10125
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "propeller-grid-toolbar__filter-badge-remove", children: "\xD7" })
10054
10126
  ]
10055
- },
10056
- value
10057
- )),
10127
+ }
10128
+ ) : null,
10058
10129
  getActiveFilterBadges()?.map((badge) => /* @__PURE__ */ jsxRuntime.jsxs(
10059
10130
  "span",
10060
10131
  {
@@ -13906,9 +13977,9 @@ function OrderList(rawProps) {
13906
13977
  )
13907
13978
  ] })
13908
13979
  ] }) : null,
13909
- !loading || orders.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: orders.length > 0 ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "propeller-order-list__results bg-card rounded-container shadow overflow-hidden", children: [
13980
+ !loading || orders.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: orders.length > 0 ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `propeller-order-list__results${props.flat ? "" : " bg-card rounded-container shadow"} overflow-hidden`, children: [
13910
13981
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "overflow-x-auto", children: /* @__PURE__ */ jsxRuntime.jsxs("table", { className: "propeller-order-list__table min-w-full divide-y divide-border", children: [
13911
- /* @__PURE__ */ jsxRuntime.jsx("thead", { className: "propeller-order-list__thead bg-surface-hover", children: /* @__PURE__ */ jsxRuntime.jsx("tr", { children: columns?.map((col) => /* @__PURE__ */ jsxRuntime.jsx(
13982
+ !props.hideHeader ? /* @__PURE__ */ jsxRuntime.jsx("thead", { className: "propeller-order-list__thead bg-surface-hover", children: /* @__PURE__ */ jsxRuntime.jsx("tr", { children: columns?.map((col) => /* @__PURE__ */ jsxRuntime.jsx(
13912
13983
  "th",
13913
13984
  {
13914
13985
  "data-column": col,
@@ -13916,7 +13987,7 @@ function OrderList(rawProps) {
13916
13987
  children: getColumnLabel(col)
13917
13988
  },
13918
13989
  col
13919
- )) }) }),
13990
+ )) }) }) : null,
13920
13991
  /* @__PURE__ */ jsxRuntime.jsx("tbody", { className: "propeller-order-list__tbody bg-card divide-y divide-border", children: orders?.map((order) => /* @__PURE__ */ jsxRuntime.jsx(
13921
13992
  "tr",
13922
13993
  {
@@ -14023,7 +14094,7 @@ function OrderList(rawProps) {
14023
14094
  ) })
14024
14095
  ] })
14025
14096
  ] }) : null
14026
- ] }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "propeller-order-list__empty bg-card rounded-container shadow p-8 text-center", children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-muted-foreground mb-4", children: propellerV2CoreUi.getLabel(props.labels, "noOrders", "No orders found.") }) }) }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "propeller-order-list__loading p-8 text-center text-muted-foreground", children: propellerV2CoreUi.getLabel(props.labels, "loading", "Loading orders...") })
14097
+ ] }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: `propeller-order-list__empty${props.flat ? "" : " bg-card rounded-container shadow"} p-8 text-center`, children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-muted-foreground mb-4", children: propellerV2CoreUi.getLabel(props.labels, "noOrders", "No orders found.") }) }) }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "propeller-order-list__loading p-8 text-center text-muted-foreground", children: propellerV2CoreUi.getLabel(props.labels, "loading", "Loading orders...") })
14027
14098
  ] });
14028
14099
  }
14029
14100
  var OrderList_default = OrderList;
@@ -17190,6 +17261,10 @@ function PurchaseAuthorizationConfigurator(rawProps) {
17190
17261
  var PurchaseAuthorizationConfigurator_default = PurchaseAuthorizationConfigurator;
17191
17262
  function PurchaseAuthorizationRequests(rawProps) {
17192
17263
  const props = useInfraProps(rawProps);
17264
+ const showActions = props.showActions !== false;
17265
+ const columns = (props.columns || ["date", "quantity", "total", "requestedBy", "action"]).filter(
17266
+ (col) => showActions || col !== "action"
17267
+ );
17193
17268
  const {
17194
17269
  carts,
17195
17270
  loading,
@@ -17223,6 +17298,17 @@ function PurchaseAuthorizationRequests(rawProps) {
17223
17298
  await handleDeleteRequest();
17224
17299
  setShowDeleteConfirm(false);
17225
17300
  };
17301
+ const displayedCarts = React6.useMemo(() => {
17302
+ if (props.limit && props.limit > 0) {
17303
+ const sorted = [...carts].sort((a, b) => {
17304
+ const dateA = new Date(a.lastModifiedAt || "").getTime();
17305
+ const dateB = new Date(b.lastModifiedAt || "").getTime();
17306
+ return dateB - dateA;
17307
+ });
17308
+ return sorted.slice(0, props.limit);
17309
+ }
17310
+ return carts;
17311
+ }, [carts, props.limit]);
17226
17312
  function formatDate(dateStr) {
17227
17313
  if (props.formatDate) return props.formatDate(dateStr);
17228
17314
  if (!dateStr) return "-";
@@ -17236,6 +17322,18 @@ function PurchaseAuthorizationRequests(rawProps) {
17236
17322
  if (props.formatPrice) return props.formatPrice(price);
17237
17323
  return propellerV2CoreUi.formatPrice(price, { symbol: props.currency ?? "\u20AC" });
17238
17324
  }
17325
+ const columnLabelKeys = {
17326
+ date: ["colDate", "Date"],
17327
+ quantity: ["colQuantity", "Quantity"],
17328
+ total: ["colTotal", "Total"],
17329
+ requestedBy: ["colRequestedBy", "Requested by"],
17330
+ action: ["colActions", "Actions"]
17331
+ };
17332
+ function getColumnLabel(col) {
17333
+ if (props.columnConfig?.[col]) return props.columnConfig[col];
17334
+ const [key, fallback] = columnLabelKeys[col] || [col, col];
17335
+ return propellerV2CoreUi.getLabel(props.labels, key, fallback);
17336
+ }
17239
17337
  function getProductName5(item) {
17240
17338
  const lang = props.language || "NL";
17241
17339
  const fromNames = propellerV2CoreUi.getLanguageString(item?.product?.names, lang, "");
@@ -17245,27 +17343,21 @@ function PurchaseAuthorizationRequests(rawProps) {
17245
17343
  return item?.product?.sku || "";
17246
17344
  }
17247
17345
  return /* @__PURE__ */ jsxRuntime.jsx("div", { className: `propeller-purchase-authorization-requests ${props.className || ""}`, children: isAuthManager ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "propeller-purchase-authorization-requests__content space-y-4", children: [
17248
- /* @__PURE__ */ jsxRuntime.jsx("h2", { className: "propeller-purchase-authorization-requests__title text-xl font-semibold", children: propellerV2CoreUi.getLabel(props.labels, "title", "Authorization Requests") }),
17346
+ !props.hideTitle ? /* @__PURE__ */ jsxRuntime.jsx("h2", { className: "propeller-purchase-authorization-requests__title text-xl font-semibold", children: propellerV2CoreUi.getLabel(props.labels, "title", "Authorization Requests") }) : null,
17249
17347
  loading ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-center py-12", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-8 h-8 border-4 border-primary border-t-transparent rounded-full animate-spin" }) }) : null,
17250
17348
  !loading ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
17251
17349
  carts.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-center py-12 text-muted-foreground", children: propellerV2CoreUi.getLabel(props.labels, "empty", "No pending authorization requests") }) : null,
17252
- carts.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "overflow-x-auto rounded-lg border border-border bg-card shadow-sm", children: /* @__PURE__ */ jsxRuntime.jsxs("table", { className: "w-full text-sm", children: [
17253
- /* @__PURE__ */ jsxRuntime.jsx("thead", { className: "bg-muted/50 border-b border-border", children: /* @__PURE__ */ jsxRuntime.jsxs("tr", { children: [
17254
- /* @__PURE__ */ jsxRuntime.jsx("th", { className: "text-left px-4 py-3 font-medium text-muted-foreground", children: propellerV2CoreUi.getLabel(props.labels, "colDate", "Date") }),
17255
- /* @__PURE__ */ jsxRuntime.jsx("th", { className: "text-left px-4 py-3 font-medium text-muted-foreground", children: propellerV2CoreUi.getLabel(props.labels, "colQuantity", "Quantity") }),
17256
- /* @__PURE__ */ jsxRuntime.jsx("th", { className: "text-left px-4 py-3 font-medium text-muted-foreground", children: propellerV2CoreUi.getLabel(props.labels, "colTotal", "Total") }),
17257
- /* @__PURE__ */ jsxRuntime.jsx("th", { className: "text-left px-4 py-3 font-medium text-muted-foreground", children: propellerV2CoreUi.getLabel(props.labels, "colRequestedBy", "Requested by") }),
17258
- /* @__PURE__ */ jsxRuntime.jsx("th", { className: "text-left px-4 py-3 font-medium text-muted-foreground", children: propellerV2CoreUi.getLabel(props.labels, "colActions", "Actions") })
17259
- ] }) }),
17260
- /* @__PURE__ */ jsxRuntime.jsx("tbody", { className: "divide-y divide-border", children: carts.map((cart, index) => /* @__PURE__ */ jsxRuntime.jsxs("tr", { className: "hover:bg-muted/30 transition-colors", children: [
17261
- /* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-3 text-muted-foreground", children: formatDate(cart.lastModifiedAt ?? "") }),
17262
- /* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-3", children: getTotalQuantity(cart) }),
17263
- /* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-3 font-medium", children: formatPrice17(cart.total?.totalNet ?? 0) }),
17264
- /* @__PURE__ */ jsxRuntime.jsxs("td", { className: "px-4 py-3", children: [
17350
+ carts.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: `propeller-purchase-authorization-requests__results overflow-x-auto${props.flat ? "" : " rounded-lg border border-border bg-card shadow-sm"}`, children: /* @__PURE__ */ jsxRuntime.jsxs("table", { className: "w-full text-sm", children: [
17351
+ !props.hideHeader ? /* @__PURE__ */ jsxRuntime.jsx("thead", { className: "bg-muted/50 border-b border-border", children: /* @__PURE__ */ jsxRuntime.jsx("tr", { children: columns.map((col) => /* @__PURE__ */ jsxRuntime.jsx("th", { className: "text-left px-4 py-3 font-medium text-muted-foreground", children: getColumnLabel(col) }, col)) }) }) : null,
17352
+ /* @__PURE__ */ jsxRuntime.jsx("tbody", { className: "divide-y divide-border", children: displayedCarts.map((cart, index) => /* @__PURE__ */ jsxRuntime.jsx("tr", { className: "hover:bg-muted/30 transition-colors", children: columns.map((col) => /* @__PURE__ */ jsxRuntime.jsxs("td", { className: `px-4 py-3${col === "date" ? " text-muted-foreground" : ""}${col === "total" ? " font-medium" : ""}`, children: [
17353
+ col === "date" ? formatDate(cart.lastModifiedAt ?? "") : null,
17354
+ col === "quantity" ? getTotalQuantity(cart) : null,
17355
+ col === "total" ? formatPrice17(cart.total?.totalNet ?? 0) : null,
17356
+ col === "requestedBy" ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
17265
17357
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "font-medium", children: getContactName(cart.contact) }),
17266
17358
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs text-muted-foreground mt-0.5", children: cart.contact?.email })
17267
- ] }),
17268
- /* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-3", children: /* @__PURE__ */ jsxRuntime.jsx(
17359
+ ] }) : null,
17360
+ col === "action" ? /* @__PURE__ */ jsxRuntime.jsx(
17269
17361
  "button",
17270
17362
  {
17271
17363
  type: "button",
@@ -17273,8 +17365,8 @@ function PurchaseAuthorizationRequests(rawProps) {
17273
17365
  onClick: () => handleViewCart(cart),
17274
17366
  children: propellerV2CoreUi.getLabel(props.labels, "view", "View")
17275
17367
  }
17276
- ) })
17277
- ] }, index)) })
17368
+ ) : null
17369
+ ] }, col)) }, index)) })
17278
17370
  ] }) }) : null
17279
17371
  ] }) : null,
17280
17372
  selectedCart ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "propeller-purchase-authorization-requests__modal fixed inset-0 z-50 flex items-center justify-center px-4", children: [