@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/dist/index.d.cts CHANGED
@@ -1396,11 +1396,13 @@ interface UseProductSearchOptions {
1396
1396
  /** Upper price bound filter. */
1397
1397
  priceFilterMax?: number;
1398
1398
  /**
1399
- * Stock buckets to filter by. Empty, unset, or both buckets sends no stock
1400
- * filter. Filtering happens server-side, so `itemsFound` and the page count
1399
+ * Stock selection to filter by. `'all'` or unset sends no stock filter.
1400
+ * Filtering happens server-side, so `itemsFound` and the page count
1401
1401
  * describe the filtered set.
1402
1402
  */
1403
- availability?: Availability[];
1403
+ availability?: Availability;
1404
+ /** Minimum stock quantity for the `'in-stock'` selection. */
1405
+ minStock?: number;
1404
1406
  /** Sort field; overrides the internal sort state when set. */
1405
1407
  sortField?: string;
1406
1408
  /** Sort direction (`'ASC'` / `'DESC'`); overrides internal state when set. */
@@ -4635,12 +4637,14 @@ interface GridFiltersProps {
4635
4637
  */
4636
4638
  showAvailabilityFilter?: boolean;
4637
4639
  /**
4638
- * Currently active availability buckets (URL-driven). Seeds the checkboxes
4639
- * on the first render so a restored filtered URL renders them ticked.
4640
+ * Currently active availability selection (URL-driven). Seeds the toggle
4641
+ * on the first render so a restored filtered URL renders it correctly.
4640
4642
  */
4641
- activeAvailability?: Availability[];
4642
- /** Called whenever an availability checkbox is toggled. */
4643
- onAvailabilityChange?: (sel: Availability[]) => void;
4643
+ activeAvailability?: Availability;
4644
+ /** Currently active minimum stock quantity (URL-driven). Undefined means the minimum. */
4645
+ activeMinStock?: number;
4646
+ /** Called on every toggle or stepper change with both values. */
4647
+ onAvailabilityChange?: (sel: Availability, minStock: number) => void;
4644
4648
  /**
4645
4649
  * When true, all checkboxes and price inputs are disabled.
4646
4650
  * Wire to ProductGrid's `onLoadingChange` to block rapid re-clicks while a fetch is in flight.
@@ -4826,15 +4830,14 @@ interface GridToolbarProps {
4826
4830
  */
4827
4831
  onPriceFilterRemove?: () => void;
4828
4832
  /**
4829
- * Currently active availability (stock) filter selections.
4830
- * Renders one removable chip per selected bucket.
4833
+ * Currently active availability (stock) selection.
4834
+ * Renders a single removable chip when set to `'in-stock'`.
4831
4835
  */
4832
- availability?: Availability[];
4833
- /**
4834
- * Called when an availability filter badge × is clicked.
4835
- * Receives the specific bucket to remove.
4836
- */
4837
- onAvailabilityFilterRemove?: (value: Availability) => void;
4836
+ availability?: Availability;
4837
+ /** Currently active minimum stock quantity, shown on the chip above the default. */
4838
+ minStock?: number;
4839
+ /** Called when the availability filter badge × is clicked. */
4840
+ onAvailabilityFilterRemove?: () => void;
4838
4841
  /**
4839
4842
  * Called when "Clear All" is clicked.
4840
4843
  */
@@ -5278,6 +5281,10 @@ interface OrderListProps {
5278
5281
  showCompanyOrders?: boolean;
5279
5282
  /** Hide pagination controls. Defaults to false. */
5280
5283
  hidePagination?: boolean;
5284
+ /** Hide the column header row. Defaults to false. */
5285
+ hideHeader?: boolean;
5286
+ /** Drop the results container's card chrome (background/border/shadow). Defaults to false. */
5287
+ flat?: boolean;
5281
5288
  /** Filter orders by channel IDs */
5282
5289
  channelIds?: number[];
5283
5290
  /** Format price */
@@ -6229,10 +6236,12 @@ interface ProductGridProps {
6229
6236
  /** * Active price range lower bound from the FiltersSidebar `onPriceChange`. * Triggers a re-fetch when changed. */ priceFilterMin?: number;
6230
6237
  /** * Active price range upper bound from the FiltersSidebar `onPriceChange`. * Triggers a re-fetch when changed. */ priceFilterMax?: number;
6231
6238
  /**
6232
- * Active stock buckets from the filters sidebar. Triggers a re-fetch when
6233
- * changed. Empty or both buckets means no stock filter.
6239
+ * Active stock selection from the filters sidebar. Triggers a re-fetch when
6240
+ * changed. `'all'` or undefined means no stock filter.
6234
6241
  */
6235
- availability?: Availability[];
6242
+ availability?: Availability;
6243
+ /** Minimum stock quantity for the `'in-stock'` selection. Defaults to the minimum threshold. */
6244
+ minStock?: number;
6236
6245
  /** * Called when sort state changes internally (for syncing a sibling toolbar). */ onSortChange?: (field: string, order: string) => void;
6237
6246
  /** * Called after each internal data fetch with the min/max price of the * current product set — use to populate a price range slider in the parent. */ onPriceBoundsChange?: (min: number, max: number) => void;
6238
6247
  /** * Called after each fetch with the total number of products found — * use to display a result count in the parent toolbar. */ onItemsFoundChange?: (count: number) => void;
@@ -7048,6 +7057,20 @@ interface PurchaseAuthorizationRequestsProps {
7048
7057
  user?: Contact | Customer;
7049
7058
  /** The companyId of the current selected company. Resolved from PropellerProvider when omitted. */
7050
7059
  companyId?: number;
7060
+ /** Limit the number of requests shown (e.g. 3 = last 3 modified). undefined = show all */
7061
+ limit?: number;
7062
+ /** Columns to display, in order. Keys: 'date' | 'quantity' | 'total' | 'requestedBy' | 'action'. Defaults to all five. */
7063
+ columns?: string[];
7064
+ /** Label mapping for columns */
7065
+ columnConfig?: Record<string, string>;
7066
+ /** Show the actions column and its buttons. Defaults to true. */
7067
+ showActions?: boolean;
7068
+ /** Hide the column header row. Defaults to false. */
7069
+ hideHeader?: boolean;
7070
+ /** Drop the results container's card chrome (background/border/shadow). Defaults to false. */
7071
+ flat?: boolean;
7072
+ /** Hide the component's own title. Defaults to false. */
7073
+ hideTitle?: boolean;
7051
7074
  /**
7052
7075
  * Override: fires instead of the default CartService.acceptPurchaseAuthorizationRequest() call.
7053
7076
  * Receives the cartId string.
package/dist/index.d.ts CHANGED
@@ -1396,11 +1396,13 @@ interface UseProductSearchOptions {
1396
1396
  /** Upper price bound filter. */
1397
1397
  priceFilterMax?: number;
1398
1398
  /**
1399
- * Stock buckets to filter by. Empty, unset, or both buckets sends no stock
1400
- * filter. Filtering happens server-side, so `itemsFound` and the page count
1399
+ * Stock selection to filter by. `'all'` or unset sends no stock filter.
1400
+ * Filtering happens server-side, so `itemsFound` and the page count
1401
1401
  * describe the filtered set.
1402
1402
  */
1403
- availability?: Availability[];
1403
+ availability?: Availability;
1404
+ /** Minimum stock quantity for the `'in-stock'` selection. */
1405
+ minStock?: number;
1404
1406
  /** Sort field; overrides the internal sort state when set. */
1405
1407
  sortField?: string;
1406
1408
  /** Sort direction (`'ASC'` / `'DESC'`); overrides internal state when set. */
@@ -4635,12 +4637,14 @@ interface GridFiltersProps {
4635
4637
  */
4636
4638
  showAvailabilityFilter?: boolean;
4637
4639
  /**
4638
- * Currently active availability buckets (URL-driven). Seeds the checkboxes
4639
- * on the first render so a restored filtered URL renders them ticked.
4640
+ * Currently active availability selection (URL-driven). Seeds the toggle
4641
+ * on the first render so a restored filtered URL renders it correctly.
4640
4642
  */
4641
- activeAvailability?: Availability[];
4642
- /** Called whenever an availability checkbox is toggled. */
4643
- onAvailabilityChange?: (sel: Availability[]) => void;
4643
+ activeAvailability?: Availability;
4644
+ /** Currently active minimum stock quantity (URL-driven). Undefined means the minimum. */
4645
+ activeMinStock?: number;
4646
+ /** Called on every toggle or stepper change with both values. */
4647
+ onAvailabilityChange?: (sel: Availability, minStock: number) => void;
4644
4648
  /**
4645
4649
  * When true, all checkboxes and price inputs are disabled.
4646
4650
  * Wire to ProductGrid's `onLoadingChange` to block rapid re-clicks while a fetch is in flight.
@@ -4826,15 +4830,14 @@ interface GridToolbarProps {
4826
4830
  */
4827
4831
  onPriceFilterRemove?: () => void;
4828
4832
  /**
4829
- * Currently active availability (stock) filter selections.
4830
- * Renders one removable chip per selected bucket.
4833
+ * Currently active availability (stock) selection.
4834
+ * Renders a single removable chip when set to `'in-stock'`.
4831
4835
  */
4832
- availability?: Availability[];
4833
- /**
4834
- * Called when an availability filter badge × is clicked.
4835
- * Receives the specific bucket to remove.
4836
- */
4837
- onAvailabilityFilterRemove?: (value: Availability) => void;
4836
+ availability?: Availability;
4837
+ /** Currently active minimum stock quantity, shown on the chip above the default. */
4838
+ minStock?: number;
4839
+ /** Called when the availability filter badge × is clicked. */
4840
+ onAvailabilityFilterRemove?: () => void;
4838
4841
  /**
4839
4842
  * Called when "Clear All" is clicked.
4840
4843
  */
@@ -5278,6 +5281,10 @@ interface OrderListProps {
5278
5281
  showCompanyOrders?: boolean;
5279
5282
  /** Hide pagination controls. Defaults to false. */
5280
5283
  hidePagination?: boolean;
5284
+ /** Hide the column header row. Defaults to false. */
5285
+ hideHeader?: boolean;
5286
+ /** Drop the results container's card chrome (background/border/shadow). Defaults to false. */
5287
+ flat?: boolean;
5281
5288
  /** Filter orders by channel IDs */
5282
5289
  channelIds?: number[];
5283
5290
  /** Format price */
@@ -6229,10 +6236,12 @@ interface ProductGridProps {
6229
6236
  /** * Active price range lower bound from the FiltersSidebar `onPriceChange`. * Triggers a re-fetch when changed. */ priceFilterMin?: number;
6230
6237
  /** * Active price range upper bound from the FiltersSidebar `onPriceChange`. * Triggers a re-fetch when changed. */ priceFilterMax?: number;
6231
6238
  /**
6232
- * Active stock buckets from the filters sidebar. Triggers a re-fetch when
6233
- * changed. Empty or both buckets means no stock filter.
6239
+ * Active stock selection from the filters sidebar. Triggers a re-fetch when
6240
+ * changed. `'all'` or undefined means no stock filter.
6234
6241
  */
6235
- availability?: Availability[];
6242
+ availability?: Availability;
6243
+ /** Minimum stock quantity for the `'in-stock'` selection. Defaults to the minimum threshold. */
6244
+ minStock?: number;
6236
6245
  /** * Called when sort state changes internally (for syncing a sibling toolbar). */ onSortChange?: (field: string, order: string) => void;
6237
6246
  /** * Called after each internal data fetch with the min/max price of the * current product set — use to populate a price range slider in the parent. */ onPriceBoundsChange?: (min: number, max: number) => void;
6238
6247
  /** * Called after each fetch with the total number of products found — * use to display a result count in the parent toolbar. */ onItemsFoundChange?: (count: number) => void;
@@ -7048,6 +7057,20 @@ interface PurchaseAuthorizationRequestsProps {
7048
7057
  user?: Contact | Customer;
7049
7058
  /** The companyId of the current selected company. Resolved from PropellerProvider when omitted. */
7050
7059
  companyId?: number;
7060
+ /** Limit the number of requests shown (e.g. 3 = last 3 modified). undefined = show all */
7061
+ limit?: number;
7062
+ /** Columns to display, in order. Keys: 'date' | 'quantity' | 'total' | 'requestedBy' | 'action'. Defaults to all five. */
7063
+ columns?: string[];
7064
+ /** Label mapping for columns */
7065
+ columnConfig?: Record<string, string>;
7066
+ /** Show the actions column and its buttons. Defaults to true. */
7067
+ showActions?: boolean;
7068
+ /** Hide the column header row. Defaults to false. */
7069
+ hideHeader?: boolean;
7070
+ /** Drop the results container's card chrome (background/border/shadow). Defaults to false. */
7071
+ flat?: boolean;
7072
+ /** Hide the component's own title. Defaults to false. */
7073
+ hideTitle?: boolean;
7051
7074
  /**
7052
7075
  * Override: fires instead of the default CartService.acceptPurchaseAuthorizationRequest() call.
7053
7076
  * Receives the cartId string.
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  "use client";
2
- import { getLabel, getLocalizedValue, formatPrice, getClusterSku, getClusterImageUrl, isContentHidden, getProductSku, getProductImageUrl, createServices, err, ok, formatSurcharge, deriveUserMode, isContact, isCustomer, getAddresses, attributeNameMatches, getAttributeDisplayName, filterProductsBySelections, extractAttributeValues, buildInventoryFilter, getLanguageString, collectAttributeValues, getCountryName } from '@propeller-commerce/propeller-v2-core-ui';
2
+ import { getLabel, getLocalizedValue, formatPrice, getClusterSku, getClusterImageUrl, isContentHidden, getProductSku, getProductImageUrl, createServices, err, ok, formatSurcharge, deriveUserMode, isContact, isCustomer, getAddresses, attributeNameMatches, getAttributeDisplayName, filterProductsBySelections, extractAttributeValues, buildInventoryFilter, MIN_STOCK_THRESHOLD, getLanguageString, collectAttributeValues, getCountryName } from '@propeller-commerce/propeller-v2-core-ui';
3
3
  export * from '@propeller-commerce/propeller-v2-core-ui';
4
4
  import * as React6 from 'react';
5
5
  import { createContext, useState, useRef, useMemo, useCallback, useContext, useEffect } from 'react';
@@ -2242,7 +2242,8 @@ function useProductSearch(options) {
2242
2242
  JSON.stringify(options.textFilters ?? []),
2243
2243
  options.priceFilterMin ?? "",
2244
2244
  options.priceFilterMax ?? "",
2245
- JSON.stringify(options.availability ?? [])
2245
+ options.availability ?? "",
2246
+ options.minStock ?? ""
2246
2247
  ].join("|");
2247
2248
  if (inflightFetches2.has(inflightKey)) {
2248
2249
  fetchIdRef.current--;
@@ -2284,7 +2285,7 @@ function useProductSearch(options) {
2284
2285
  }
2285
2286
  ] : [];
2286
2287
  const priceFilter = options.priceFilterMin !== void 0 || options.priceFilterMax !== void 0 ? { from: options.priceFilterMin ?? 0, to: options.priceFilterMax ?? 999999 } : void 0;
2287
- const inventoryFilter = buildInventoryFilter(options.availability);
2288
+ const inventoryFilter = buildInventoryFilter(options.availability, options.minStock);
2288
2289
  const userId = options.user && "contactId" in options.user ? options.user.contactId : options.user && "customerId" in options.user ? options.user.customerId : void 0;
2289
2290
  const contactId = options.user && "contactId" in options.user ? options.user.contactId : void 0;
2290
2291
  const customerId = options.user && "customerId" in options.user ? options.user.customerId : void 0;
@@ -2385,6 +2386,7 @@ function useProductSearch(options) {
2385
2386
  options.priceFilterMin,
2386
2387
  options.priceFilterMax,
2387
2388
  options.availability,
2389
+ options.minStock,
2388
2390
  options.sortField,
2389
2391
  options.sortOrder,
2390
2392
  options.companyId,
@@ -2424,7 +2426,7 @@ function useProductSearch(options) {
2424
2426
  const userId = options.user && "contactId" in options.user ? options.user.contactId : options.user && "customerId" in options.user ? options.user.customerId : void 0;
2425
2427
  const contactId = options.user && "contactId" in options.user ? options.user.contactId : void 0;
2426
2428
  const customerId = options.user && "customerId" in options.user ? options.user.customerId : void 0;
2427
- const inventoryFilter = buildInventoryFilter(options.availability);
2429
+ const inventoryFilter = buildInventoryFilter(options.availability, options.minStock);
2428
2430
  const categoryProductSearchInput = {
2429
2431
  language,
2430
2432
  page: 1,
@@ -2517,6 +2519,7 @@ function useProductSearch(options) {
2517
2519
  options.priceFilterMin,
2518
2520
  options.priceFilterMax,
2519
2521
  options.availability,
2522
+ options.minStock,
2520
2523
  options.sortField,
2521
2524
  options.sortOrder,
2522
2525
  pageSize,
@@ -9040,6 +9043,7 @@ function ProductGrid(rawProps) {
9040
9043
  priceFilterMin: props.priceFilterMin,
9041
9044
  priceFilterMax: props.priceFilterMax,
9042
9045
  availability: props.availability,
9046
+ minStock: props.minStock,
9043
9047
  sortField: props.sortField,
9044
9048
  sortOrder: props.sortOrder,
9045
9049
  pageSize: props.pageSize,
@@ -9343,7 +9347,13 @@ function GridFilters(rawProps) {
9343
9347
  const [appliedMin, setAppliedMin] = useState(() => void 0);
9344
9348
  const [appliedMax, setAppliedMax] = useState(() => void 0);
9345
9349
  const [availability, setAvailability] = useState(
9346
- () => [...props.activeAvailability || []]
9350
+ () => props.activeAvailability || "all"
9351
+ );
9352
+ const [minStock, setMinStock] = useState(
9353
+ () => props.activeMinStock ?? MIN_STOCK_THRESHOLD
9354
+ );
9355
+ const [minStockInput, setMinStockInput] = useState(
9356
+ () => String(props.activeMinStock ?? MIN_STOCK_THRESHOLD)
9347
9357
  );
9348
9358
  function showPriceFilter() {
9349
9359
  const mode = props.portalMode || "open";
@@ -9398,13 +9408,28 @@ function GridFilters(rawProps) {
9398
9408
  props.onFilterChange(filter, value);
9399
9409
  if (props.getSelectedFilters) props.getSelectedFilters();
9400
9410
  }
9401
- function handleAvailabilityToggle(value, checked) {
9402
- const next = checked ? [...availability, value] : availability.filter((v) => v !== value);
9403
- setAvailability(next);
9411
+ function handleAvailabilityChange(value) {
9412
+ const nextMinStock = value === "all" ? MIN_STOCK_THRESHOLD : minStock;
9413
+ setAvailability(value);
9414
+ setMinStock(nextMinStock);
9415
+ setMinStockInput(String(nextMinStock));
9416
+ setIsPending(true);
9417
+ if (props.onAvailabilityChange) props.onAvailabilityChange(value, nextMinStock);
9418
+ if (props.getSelectedFilters) props.getSelectedFilters();
9419
+ }
9420
+ function handleMinStockChange(value) {
9421
+ const n = Math.max(Math.floor(value) || MIN_STOCK_THRESHOLD, MIN_STOCK_THRESHOLD);
9422
+ setMinStock(n);
9423
+ setMinStockInput(String(n));
9424
+ if (n === minStock) return;
9404
9425
  setIsPending(true);
9405
- if (props.onAvailabilityChange) props.onAvailabilityChange(next);
9426
+ if (props.onAvailabilityChange) props.onAvailabilityChange(availability, n);
9406
9427
  if (props.getSelectedFilters) props.getSelectedFilters();
9407
9428
  }
9429
+ function commitMinStockInput() {
9430
+ const parsed = parseInt(minStockInput, 10);
9431
+ handleMinStockChange(isNaN(parsed) ? MIN_STOCK_THRESHOLD : parsed);
9432
+ }
9408
9433
  function handleMinChange(value) {
9409
9434
  const n = value > currentMax ? currentMax : value;
9410
9435
  setCurrentMin(n);
@@ -9478,7 +9503,9 @@ function GridFilters(rawProps) {
9478
9503
  setCurrentMin(props.priceMin || 0);
9479
9504
  setCurrentMax(props.priceMax || 9999);
9480
9505
  setExpandedFilters({});
9481
- setAvailability([]);
9506
+ setAvailability("all");
9507
+ setMinStock(MIN_STOCK_THRESHOLD);
9508
+ setMinStockInput(String(MIN_STOCK_THRESHOLD));
9482
9509
  }, [props.clearSignal, props.priceMin, props.priceMax]);
9483
9510
  useEffect(() => {
9484
9511
  if (!props.activeTextFilters) return;
@@ -9486,8 +9513,10 @@ function GridFilters(rawProps) {
9486
9513
  }, [props.activeTextFilters]);
9487
9514
  useEffect(() => {
9488
9515
  if (!props.activeAvailability) return;
9489
- setAvailability([...props.activeAvailability]);
9490
- }, [props.activeAvailability]);
9516
+ setAvailability(props.activeAvailability);
9517
+ setMinStock(props.activeMinStock ?? MIN_STOCK_THRESHOLD);
9518
+ setMinStockInput(String(props.activeMinStock ?? MIN_STOCK_THRESHOLD));
9519
+ }, [props.activeAvailability, props.activeMinStock]);
9491
9520
  useEffect(() => {
9492
9521
  if (props.activePriceMin === void 0 && props.activePriceMax === void 0) {
9493
9522
  setCurrentMin(props.priceMin || 0);
@@ -9590,34 +9619,76 @@ function GridFilters(rawProps) {
9590
9619
  showAvailability() ? /* @__PURE__ */ jsxs(Fragment, { children: [
9591
9620
  /* @__PURE__ */ jsxs("div", { className: "propeller-grid-filters__availability space-y-3", children: [
9592
9621
  /* @__PURE__ */ jsx("h3", { className: "propeller-grid-filters__availability-title text-xs font-semibold uppercase tracking-wide text-muted-foreground", children: getLabel(props.labels, "availability", "Availability") }),
9593
- /* @__PURE__ */ jsxs("div", { className: "propeller-grid-filters__availability-options space-y-1.5", children: [
9594
- /* @__PURE__ */ jsxs("label", { className: "propeller-grid-filters__option flex items-center gap-2 cursor-pointer group", children: [
9622
+ /* @__PURE__ */ jsxs("div", { className: "propeller-grid-filters__availability-toggle inline-flex h-8 w-full rounded-control border border-input overflow-hidden", children: [
9623
+ /* @__PURE__ */ jsx(
9624
+ "button",
9625
+ {
9626
+ type: "button",
9627
+ 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"}`,
9628
+ "aria-pressed": availability === "all",
9629
+ disabled: !!props.isLoading,
9630
+ onClick: () => handleAvailabilityChange("all"),
9631
+ children: getLabel(props.labels, "allProducts", "All products")
9632
+ }
9633
+ ),
9634
+ /* @__PURE__ */ jsx(
9635
+ "button",
9636
+ {
9637
+ type: "button",
9638
+ 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"}`,
9639
+ "aria-pressed": availability === "in-stock",
9640
+ disabled: !!props.isLoading,
9641
+ onClick: () => handleAvailabilityChange("in-stock"),
9642
+ children: getLabel(props.labels, "inStock", "In stock")
9643
+ }
9644
+ )
9645
+ ] }),
9646
+ availability === "in-stock" ? /* @__PURE__ */ jsxs("div", { className: "propeller-grid-filters__availability-quantity flex items-center gap-2 text-sm text-muted-foreground", children: [
9647
+ /* @__PURE__ */ jsx("span", { children: getLabel(props.labels, "atLeast", "at least") }),
9648
+ /* @__PURE__ */ 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: [
9595
9649
  /* @__PURE__ */ jsx(
9596
- "input",
9650
+ "button",
9597
9651
  {
9598
- type: "checkbox",
9599
- className: "propeller-grid-filters__checkbox h-4 w-4 rounded border-input text-secondary focus:ring-secondary cursor-pointer flex-shrink-0",
9600
- checked: availability.includes("in-stock"),
9601
- disabled: !!props.isLoading,
9602
- onChange: (e) => handleAvailabilityToggle("in-stock", e.target.checked)
9652
+ type: "button",
9653
+ 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",
9654
+ "aria-label": getLabel(props.labels, "quantityDecrease", "Decrease quantity"),
9655
+ disabled: !!props.isLoading || minStock <= MIN_STOCK_THRESHOLD,
9656
+ onClick: () => handleMinStockChange(minStock - 1),
9657
+ children: "\u2212"
9603
9658
  }
9604
9659
  ),
9605
- /* @__PURE__ */ jsx("span", { className: "propeller-grid-filters__option-label flex-1 text-sm text-muted-foreground leading-none select-none group-hover:text-foreground", children: getLabel(props.labels, "inStock", "In stock") })
9606
- ] }),
9607
- /* @__PURE__ */ jsxs("label", { className: "propeller-grid-filters__option flex items-center gap-2 cursor-pointer group", children: [
9608
9660
  /* @__PURE__ */ jsx(
9609
9661
  "input",
9610
9662
  {
9611
- type: "checkbox",
9612
- className: "propeller-grid-filters__checkbox h-4 w-4 rounded border-input text-secondary focus:ring-secondary cursor-pointer flex-shrink-0",
9613
- checked: availability.includes("out-of-stock"),
9663
+ type: "number",
9664
+ inputMode: "numeric",
9665
+ 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",
9666
+ "aria-label": getLabel(props.labels, "atLeast", "at least"),
9667
+ min: MIN_STOCK_THRESHOLD,
9668
+ step: 1,
9669
+ value: minStockInput,
9614
9670
  disabled: !!props.isLoading,
9615
- onChange: (e) => handleAvailabilityToggle("out-of-stock", e.target.checked)
9671
+ onChange: (e) => setMinStockInput(e.target.value),
9672
+ onBlur: () => commitMinStockInput(),
9673
+ onKeyDown: (e) => {
9674
+ if (e.key === "Enter") e.target.blur();
9675
+ }
9616
9676
  }
9617
9677
  ),
9618
- /* @__PURE__ */ jsx("span", { className: "propeller-grid-filters__option-label flex-1 text-sm text-muted-foreground leading-none select-none group-hover:text-foreground", children: getLabel(props.labels, "outOfStock", "Out of stock") })
9619
- ] })
9620
- ] })
9678
+ /* @__PURE__ */ jsx(
9679
+ "button",
9680
+ {
9681
+ type: "button",
9682
+ 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",
9683
+ "aria-label": getLabel(props.labels, "quantityIncrease", "Increase quantity"),
9684
+ disabled: !!props.isLoading,
9685
+ onClick: () => handleMinStockChange(minStock + 1),
9686
+ children: "+"
9687
+ }
9688
+ )
9689
+ ] }),
9690
+ /* @__PURE__ */ jsx("span", { children: getLabel(props.labels, "pcs", "pcs") })
9691
+ ] }) : null
9621
9692
  ] }),
9622
9693
  /* @__PURE__ */ jsx("div", { className: "propeller-grid-filters__divider h-px bg-border-subtle" })
9623
9694
  ] }) : null,
@@ -9797,7 +9868,6 @@ var DEFAULT_LABELS = {
9797
9868
  perPage: " per page",
9798
9869
  price: "Price",
9799
9870
  inStock: "In stock",
9800
- outOfStock: "Out of stock",
9801
9871
  switchToList: "Switch to list view",
9802
9872
  switchToGrid: "Switch to grid view"
9803
9873
  };
@@ -9826,7 +9896,7 @@ function GridToolbar(rawProps) {
9826
9896
  const text = props.activeTextFilters || {};
9827
9897
  const hasText = Object.keys(text).some((k) => (text[k] || []).length > 0);
9828
9898
  const hasPrice = props.priceFilterMin !== void 0 || props.priceFilterMax !== void 0;
9829
- const hasAvailability = (props.availability || []).length > 0;
9899
+ const hasAvailability = props.availability === "in-stock";
9830
9900
  return hasText || hasPrice || hasAvailability;
9831
9901
  }
9832
9902
  function getActiveFilterBadges() {
@@ -9845,8 +9915,10 @@ function GridToolbar(rawProps) {
9845
9915
  function isPriceSortDisabled() {
9846
9916
  return isContentHidden(props.portalMode, props.user);
9847
9917
  }
9848
- function getAvailabilityLabel(value) {
9849
- return value === "in-stock" ? getLabel56("inStock") : getLabel56("outOfStock");
9918
+ function getAvailabilityLabel() {
9919
+ const qty = props.minStock;
9920
+ if (qty !== void 0 && qty > MIN_STOCK_THRESHOLD) return `${getLabel56("inStock")}: ${qty}+`;
9921
+ return getLabel56("inStock");
9850
9922
  }
9851
9923
  function handleSortFieldChange(field) {
9852
9924
  setCurrentSortField(field);
@@ -10021,20 +10093,19 @@ function GridToolbar(rawProps) {
10021
10093
  ]
10022
10094
  }
10023
10095
  ) : null,
10024
- (props.availability || []).map((value) => /* @__PURE__ */ jsxs(
10096
+ props.availability === "in-stock" ? /* @__PURE__ */ jsxs(
10025
10097
  "span",
10026
10098
  {
10027
10099
  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",
10028
10100
  onClick: (event) => {
10029
- if (props.onAvailabilityFilterRemove) props.onAvailabilityFilterRemove(value);
10101
+ if (props.onAvailabilityFilterRemove) props.onAvailabilityFilterRemove();
10030
10102
  },
10031
10103
  children: [
10032
- getAvailabilityLabel(value),
10104
+ getAvailabilityLabel(),
10033
10105
  /* @__PURE__ */ jsx("span", { className: "propeller-grid-toolbar__filter-badge-remove", children: "\xD7" })
10034
10106
  ]
10035
- },
10036
- value
10037
- )),
10107
+ }
10108
+ ) : null,
10038
10109
  getActiveFilterBadges()?.map((badge) => /* @__PURE__ */ jsxs(
10039
10110
  "span",
10040
10111
  {
@@ -13886,9 +13957,9 @@ function OrderList(rawProps) {
13886
13957
  )
13887
13958
  ] })
13888
13959
  ] }) : null,
13889
- !loading || orders.length > 0 ? /* @__PURE__ */ jsx(Fragment, { children: orders.length > 0 ? /* @__PURE__ */ jsxs("div", { className: "propeller-order-list__results bg-card rounded-container shadow overflow-hidden", children: [
13960
+ !loading || orders.length > 0 ? /* @__PURE__ */ jsx(Fragment, { children: orders.length > 0 ? /* @__PURE__ */ jsxs("div", { className: `propeller-order-list__results${props.flat ? "" : " bg-card rounded-container shadow"} overflow-hidden`, children: [
13890
13961
  /* @__PURE__ */ jsx("div", { className: "overflow-x-auto", children: /* @__PURE__ */ jsxs("table", { className: "propeller-order-list__table min-w-full divide-y divide-border", children: [
13891
- /* @__PURE__ */ jsx("thead", { className: "propeller-order-list__thead bg-surface-hover", children: /* @__PURE__ */ jsx("tr", { children: columns?.map((col) => /* @__PURE__ */ jsx(
13962
+ !props.hideHeader ? /* @__PURE__ */ jsx("thead", { className: "propeller-order-list__thead bg-surface-hover", children: /* @__PURE__ */ jsx("tr", { children: columns?.map((col) => /* @__PURE__ */ jsx(
13892
13963
  "th",
13893
13964
  {
13894
13965
  "data-column": col,
@@ -13896,7 +13967,7 @@ function OrderList(rawProps) {
13896
13967
  children: getColumnLabel(col)
13897
13968
  },
13898
13969
  col
13899
- )) }) }),
13970
+ )) }) }) : null,
13900
13971
  /* @__PURE__ */ jsx("tbody", { className: "propeller-order-list__tbody bg-card divide-y divide-border", children: orders?.map((order) => /* @__PURE__ */ jsx(
13901
13972
  "tr",
13902
13973
  {
@@ -14003,7 +14074,7 @@ function OrderList(rawProps) {
14003
14074
  ) })
14004
14075
  ] })
14005
14076
  ] }) : null
14006
- ] }) : /* @__PURE__ */ jsx("div", { className: "propeller-order-list__empty bg-card rounded-container shadow p-8 text-center", children: /* @__PURE__ */ jsx("p", { className: "text-muted-foreground mb-4", children: getLabel(props.labels, "noOrders", "No orders found.") }) }) }) : /* @__PURE__ */ jsx("div", { className: "propeller-order-list__loading p-8 text-center text-muted-foreground", children: getLabel(props.labels, "loading", "Loading orders...") })
14077
+ ] }) : /* @__PURE__ */ jsx("div", { className: `propeller-order-list__empty${props.flat ? "" : " bg-card rounded-container shadow"} p-8 text-center`, children: /* @__PURE__ */ jsx("p", { className: "text-muted-foreground mb-4", children: getLabel(props.labels, "noOrders", "No orders found.") }) }) }) : /* @__PURE__ */ jsx("div", { className: "propeller-order-list__loading p-8 text-center text-muted-foreground", children: getLabel(props.labels, "loading", "Loading orders...") })
14007
14078
  ] });
14008
14079
  }
14009
14080
  var OrderList_default = OrderList;
@@ -17170,6 +17241,10 @@ function PurchaseAuthorizationConfigurator(rawProps) {
17170
17241
  var PurchaseAuthorizationConfigurator_default = PurchaseAuthorizationConfigurator;
17171
17242
  function PurchaseAuthorizationRequests(rawProps) {
17172
17243
  const props = useInfraProps(rawProps);
17244
+ const showActions = props.showActions !== false;
17245
+ const columns = (props.columns || ["date", "quantity", "total", "requestedBy", "action"]).filter(
17246
+ (col) => showActions || col !== "action"
17247
+ );
17173
17248
  const {
17174
17249
  carts,
17175
17250
  loading,
@@ -17203,6 +17278,17 @@ function PurchaseAuthorizationRequests(rawProps) {
17203
17278
  await handleDeleteRequest();
17204
17279
  setShowDeleteConfirm(false);
17205
17280
  };
17281
+ const displayedCarts = useMemo(() => {
17282
+ if (props.limit && props.limit > 0) {
17283
+ const sorted = [...carts].sort((a, b) => {
17284
+ const dateA = new Date(a.lastModifiedAt || "").getTime();
17285
+ const dateB = new Date(b.lastModifiedAt || "").getTime();
17286
+ return dateB - dateA;
17287
+ });
17288
+ return sorted.slice(0, props.limit);
17289
+ }
17290
+ return carts;
17291
+ }, [carts, props.limit]);
17206
17292
  function formatDate(dateStr) {
17207
17293
  if (props.formatDate) return props.formatDate(dateStr);
17208
17294
  if (!dateStr) return "-";
@@ -17216,6 +17302,18 @@ function PurchaseAuthorizationRequests(rawProps) {
17216
17302
  if (props.formatPrice) return props.formatPrice(price);
17217
17303
  return formatPrice(price, { symbol: props.currency ?? "\u20AC" });
17218
17304
  }
17305
+ const columnLabelKeys = {
17306
+ date: ["colDate", "Date"],
17307
+ quantity: ["colQuantity", "Quantity"],
17308
+ total: ["colTotal", "Total"],
17309
+ requestedBy: ["colRequestedBy", "Requested by"],
17310
+ action: ["colActions", "Actions"]
17311
+ };
17312
+ function getColumnLabel(col) {
17313
+ if (props.columnConfig?.[col]) return props.columnConfig[col];
17314
+ const [key, fallback] = columnLabelKeys[col] || [col, col];
17315
+ return getLabel(props.labels, key, fallback);
17316
+ }
17219
17317
  function getProductName5(item) {
17220
17318
  const lang = props.language || "NL";
17221
17319
  const fromNames = getLanguageString(item?.product?.names, lang, "");
@@ -17225,27 +17323,21 @@ function PurchaseAuthorizationRequests(rawProps) {
17225
17323
  return item?.product?.sku || "";
17226
17324
  }
17227
17325
  return /* @__PURE__ */ jsx("div", { className: `propeller-purchase-authorization-requests ${props.className || ""}`, children: isAuthManager ? /* @__PURE__ */ jsxs("div", { className: "propeller-purchase-authorization-requests__content space-y-4", children: [
17228
- /* @__PURE__ */ jsx("h2", { className: "propeller-purchase-authorization-requests__title text-xl font-semibold", children: getLabel(props.labels, "title", "Authorization Requests") }),
17326
+ !props.hideTitle ? /* @__PURE__ */ jsx("h2", { className: "propeller-purchase-authorization-requests__title text-xl font-semibold", children: getLabel(props.labels, "title", "Authorization Requests") }) : null,
17229
17327
  loading ? /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center py-12", children: /* @__PURE__ */ jsx("div", { className: "w-8 h-8 border-4 border-primary border-t-transparent rounded-full animate-spin" }) }) : null,
17230
17328
  !loading ? /* @__PURE__ */ jsxs(Fragment, { children: [
17231
17329
  carts.length === 0 ? /* @__PURE__ */ jsx("div", { className: "text-center py-12 text-muted-foreground", children: getLabel(props.labels, "empty", "No pending authorization requests") }) : null,
17232
- carts.length > 0 ? /* @__PURE__ */ jsx("div", { className: "overflow-x-auto rounded-lg border border-border bg-card shadow-sm", children: /* @__PURE__ */ jsxs("table", { className: "w-full text-sm", children: [
17233
- /* @__PURE__ */ jsx("thead", { className: "bg-muted/50 border-b border-border", children: /* @__PURE__ */ jsxs("tr", { children: [
17234
- /* @__PURE__ */ jsx("th", { className: "text-left px-4 py-3 font-medium text-muted-foreground", children: getLabel(props.labels, "colDate", "Date") }),
17235
- /* @__PURE__ */ jsx("th", { className: "text-left px-4 py-3 font-medium text-muted-foreground", children: getLabel(props.labels, "colQuantity", "Quantity") }),
17236
- /* @__PURE__ */ jsx("th", { className: "text-left px-4 py-3 font-medium text-muted-foreground", children: getLabel(props.labels, "colTotal", "Total") }),
17237
- /* @__PURE__ */ jsx("th", { className: "text-left px-4 py-3 font-medium text-muted-foreground", children: getLabel(props.labels, "colRequestedBy", "Requested by") }),
17238
- /* @__PURE__ */ jsx("th", { className: "text-left px-4 py-3 font-medium text-muted-foreground", children: getLabel(props.labels, "colActions", "Actions") })
17239
- ] }) }),
17240
- /* @__PURE__ */ jsx("tbody", { className: "divide-y divide-border", children: carts.map((cart, index) => /* @__PURE__ */ jsxs("tr", { className: "hover:bg-muted/30 transition-colors", children: [
17241
- /* @__PURE__ */ jsx("td", { className: "px-4 py-3 text-muted-foreground", children: formatDate(cart.lastModifiedAt ?? "") }),
17242
- /* @__PURE__ */ jsx("td", { className: "px-4 py-3", children: getTotalQuantity(cart) }),
17243
- /* @__PURE__ */ jsx("td", { className: "px-4 py-3 font-medium", children: formatPrice17(cart.total?.totalNet ?? 0) }),
17244
- /* @__PURE__ */ jsxs("td", { className: "px-4 py-3", children: [
17330
+ carts.length > 0 ? /* @__PURE__ */ jsx("div", { className: `propeller-purchase-authorization-requests__results overflow-x-auto${props.flat ? "" : " rounded-lg border border-border bg-card shadow-sm"}`, children: /* @__PURE__ */ jsxs("table", { className: "w-full text-sm", children: [
17331
+ !props.hideHeader ? /* @__PURE__ */ jsx("thead", { className: "bg-muted/50 border-b border-border", children: /* @__PURE__ */ jsx("tr", { children: columns.map((col) => /* @__PURE__ */ jsx("th", { className: "text-left px-4 py-3 font-medium text-muted-foreground", children: getColumnLabel(col) }, col)) }) }) : null,
17332
+ /* @__PURE__ */ jsx("tbody", { className: "divide-y divide-border", children: displayedCarts.map((cart, index) => /* @__PURE__ */ jsx("tr", { className: "hover:bg-muted/30 transition-colors", children: columns.map((col) => /* @__PURE__ */ jsxs("td", { className: `px-4 py-3${col === "date" ? " text-muted-foreground" : ""}${col === "total" ? " font-medium" : ""}`, children: [
17333
+ col === "date" ? formatDate(cart.lastModifiedAt ?? "") : null,
17334
+ col === "quantity" ? getTotalQuantity(cart) : null,
17335
+ col === "total" ? formatPrice17(cart.total?.totalNet ?? 0) : null,
17336
+ col === "requestedBy" ? /* @__PURE__ */ jsxs(Fragment, { children: [
17245
17337
  /* @__PURE__ */ jsx("div", { className: "font-medium", children: getContactName(cart.contact) }),
17246
17338
  /* @__PURE__ */ jsx("div", { className: "text-xs text-muted-foreground mt-0.5", children: cart.contact?.email })
17247
- ] }),
17248
- /* @__PURE__ */ jsx("td", { className: "px-4 py-3", children: /* @__PURE__ */ jsx(
17339
+ ] }) : null,
17340
+ col === "action" ? /* @__PURE__ */ jsx(
17249
17341
  "button",
17250
17342
  {
17251
17343
  type: "button",
@@ -17253,8 +17345,8 @@ function PurchaseAuthorizationRequests(rawProps) {
17253
17345
  onClick: () => handleViewCart(cart),
17254
17346
  children: getLabel(props.labels, "view", "View")
17255
17347
  }
17256
- ) })
17257
- ] }, index)) })
17348
+ ) : null
17349
+ ] }, col)) }, index)) })
17258
17350
  ] }) }) : null
17259
17351
  ] }) : null,
17260
17352
  selectedCart ? /* @__PURE__ */ jsxs("div", { className: "propeller-purchase-authorization-requests__modal fixed inset-0 z-50 flex items-center justify-center px-4", children: [