@propeller-commerce/propeller-v2-react-ui 0.15.7 → 0.15.9

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
@@ -1535,10 +1535,18 @@ interface UseQuickOrderOptions {
1535
1535
  language?: string;
1536
1536
  /** Max typeahead results per row. Defaults to 8. */
1537
1537
  searchLimit?: number;
1538
- /** Image filters forwarded to search + cart queries. */
1538
+ /** Tax zone for price calculation. Defaults to `'NL'`. */
1539
+ taxZone?: string;
1540
+ /** Orderlist (contract) ids to scope the catalogue by. */
1541
+ orderlistIds?: number[];
1542
+ /** Set `false` to ignore `orderlistIds`. Defaults to true when ids are given. */
1543
+ applyOrderlists?: boolean;
1544
+ /** Image filters + the base category the search is scoped to. */
1539
1545
  configuration?: {
1540
1546
  imageSearchFiltersGrid?: MediaImageProductSearchInput;
1541
1547
  imageVariantFiltersSmall?: TransformationsInput;
1548
+ /** Catalog root. Without it the search returns nothing — see `searchProducts`. */
1549
+ baseCategoryId?: number;
1542
1550
  };
1543
1551
  /** Fires when `submit` creates a fresh cart — persist the cart id. */
1544
1552
  onCartCreated?: (cart: Cart) => void;
@@ -1576,10 +1584,16 @@ interface UseQuickOrderReturn {
1576
1584
  *
1577
1585
  * @remarks
1578
1586
  * GraphQL integration: services are built per-call via `createServices(graphqlClient)`.
1579
- * `searchProducts` calls `services.product.getProducts()` (`ProductService`, the
1580
- * `ProductSearch` operation). `submit` resolves a cart with the shared `initCart`
1581
- * flow, then calls `services.cart.bulkUpdateCartItems()` once with every line
1582
- * (`CartItemBulk`). All calls require an authenticated session.
1587
+ * `searchProducts` calls `services.category.getCategory()` over
1588
+ * `configuration.baseCategoryId` — the same path ProductGrid and the SearchBar
1589
+ * preview use. The flat `products` resolver ignores orderlist scoping
1590
+ * server-side, so searching through it returns products outside the user's
1591
+ * catalogue. Without a `baseCategoryId` the search returns nothing rather than
1592
+ * falling back to that resolver.
1593
+ *
1594
+ * `submit` resolves a cart with the shared `initCart` flow, then calls
1595
+ * `services.cart.bulkUpdateCartItems()` once with every line (`CartItemBulk`).
1596
+ * All calls require an authenticated session.
1583
1597
  */
1584
1598
  declare function useQuickOrder(options: UseQuickOrderOptions): UseQuickOrderReturn;
1585
1599
 
@@ -5380,7 +5394,20 @@ interface QuickOrderProps {
5380
5394
  configuration?: {
5381
5395
  imageSearchFiltersGrid?: MediaImageProductSearchInput;
5382
5396
  imageVariantFiltersSmall?: TransformationsInput;
5397
+ /**
5398
+ * Catalog root the code search is scoped to. Required: without it the
5399
+ * typeahead and the upload resolve nothing, since searching outside a
5400
+ * category ignores orderlist scoping and would surface products the user
5401
+ * has no access to.
5402
+ */
5403
+ baseCategoryId?: number;
5383
5404
  };
5405
+ /** Tax zone for price calculation. Defaults to `'NL'`. */
5406
+ taxZone?: string;
5407
+ /** Orderlist (contract) ids to scope the catalogue by. */
5408
+ orderlistIds?: number[];
5409
+ /** Set `false` to ignore `orderlistIds`. Defaults to true when ids are given. */
5410
+ applyOrderlists?: boolean;
5384
5411
  /** Number of blank rows to start with. Defaults to 5. */
5385
5412
  initialRows?: number;
5386
5413
  /** Minimum characters before the typeahead fires. Defaults to 3. */
package/dist/index.d.ts CHANGED
@@ -1535,10 +1535,18 @@ interface UseQuickOrderOptions {
1535
1535
  language?: string;
1536
1536
  /** Max typeahead results per row. Defaults to 8. */
1537
1537
  searchLimit?: number;
1538
- /** Image filters forwarded to search + cart queries. */
1538
+ /** Tax zone for price calculation. Defaults to `'NL'`. */
1539
+ taxZone?: string;
1540
+ /** Orderlist (contract) ids to scope the catalogue by. */
1541
+ orderlistIds?: number[];
1542
+ /** Set `false` to ignore `orderlistIds`. Defaults to true when ids are given. */
1543
+ applyOrderlists?: boolean;
1544
+ /** Image filters + the base category the search is scoped to. */
1539
1545
  configuration?: {
1540
1546
  imageSearchFiltersGrid?: MediaImageProductSearchInput;
1541
1547
  imageVariantFiltersSmall?: TransformationsInput;
1548
+ /** Catalog root. Without it the search returns nothing — see `searchProducts`. */
1549
+ baseCategoryId?: number;
1542
1550
  };
1543
1551
  /** Fires when `submit` creates a fresh cart — persist the cart id. */
1544
1552
  onCartCreated?: (cart: Cart) => void;
@@ -1576,10 +1584,16 @@ interface UseQuickOrderReturn {
1576
1584
  *
1577
1585
  * @remarks
1578
1586
  * GraphQL integration: services are built per-call via `createServices(graphqlClient)`.
1579
- * `searchProducts` calls `services.product.getProducts()` (`ProductService`, the
1580
- * `ProductSearch` operation). `submit` resolves a cart with the shared `initCart`
1581
- * flow, then calls `services.cart.bulkUpdateCartItems()` once with every line
1582
- * (`CartItemBulk`). All calls require an authenticated session.
1587
+ * `searchProducts` calls `services.category.getCategory()` over
1588
+ * `configuration.baseCategoryId` — the same path ProductGrid and the SearchBar
1589
+ * preview use. The flat `products` resolver ignores orderlist scoping
1590
+ * server-side, so searching through it returns products outside the user's
1591
+ * catalogue. Without a `baseCategoryId` the search returns nothing rather than
1592
+ * falling back to that resolver.
1593
+ *
1594
+ * `submit` resolves a cart with the shared `initCart` flow, then calls
1595
+ * `services.cart.bulkUpdateCartItems()` once with every line (`CartItemBulk`).
1596
+ * All calls require an authenticated session.
1583
1597
  */
1584
1598
  declare function useQuickOrder(options: UseQuickOrderOptions): UseQuickOrderReturn;
1585
1599
 
@@ -5380,7 +5394,20 @@ interface QuickOrderProps {
5380
5394
  configuration?: {
5381
5395
  imageSearchFiltersGrid?: MediaImageProductSearchInput;
5382
5396
  imageVariantFiltersSmall?: TransformationsInput;
5397
+ /**
5398
+ * Catalog root the code search is scoped to. Required: without it the
5399
+ * typeahead and the upload resolve nothing, since searching outside a
5400
+ * category ignores orderlist scoping and would surface products the user
5401
+ * has no access to.
5402
+ */
5403
+ baseCategoryId?: number;
5383
5404
  };
5405
+ /** Tax zone for price calculation. Defaults to `'NL'`. */
5406
+ taxZone?: string;
5407
+ /** Orderlist (contract) ids to scope the catalogue by. */
5408
+ orderlistIds?: number[];
5409
+ /** Set `false` to ignore `orderlistIds`. Defaults to true when ids are given. */
5410
+ applyOrderlists?: boolean;
5384
5411
  /** Number of blank rows to start with. Defaults to 5. */
5385
5412
  initialRows?: number;
5386
5413
  /** Minimum characters before the typeahead fires. Defaults to 3. */
package/dist/index.js CHANGED
@@ -2576,21 +2576,33 @@ function useQuickOrder(options) {
2576
2576
  } = options;
2577
2577
  const language = options.language || "NL";
2578
2578
  const searchLimit = options.searchLimit ?? 8;
2579
+ const taxZone = options.taxZone || "NL";
2580
+ const { orderlistIds, applyOrderlists } = options;
2579
2581
  const [submitting, setSubmitting] = useState(false);
2580
2582
  const [error, setError] = useState(null);
2581
2583
  const searchProducts = useCallback(
2582
2584
  async (term) => {
2583
2585
  const trimmed = term.trim();
2584
2586
  if (!trimmed || !graphqlClient) return [];
2587
+ const catId = configuration.baseCategoryId ?? 0;
2588
+ if (!catId) return [];
2585
2589
  try {
2586
- const service = createServices(graphqlClient).product;
2590
+ const service = createServices(graphqlClient).category;
2591
+ const orderlistScope = orderlistIds && orderlistIds.length > 0 ? { applyOrderlists: applyOrderlists !== false, orderlistIds } : { applyOrderlists: false };
2592
+ const userId = user && "contactId" in user ? user.contactId : user && "customerId" in user ? user.customerId : void 0;
2593
+ const contactId = user && "contactId" in user ? user.contactId : void 0;
2594
+ const customerId = user && "customerId" in user ? user.customerId : void 0;
2587
2595
  const input = {
2588
2596
  term: trimmed,
2589
2597
  language,
2590
2598
  page: 1,
2591
2599
  offset: searchLimit,
2592
2600
  statuses: [ProductStatus.A, ProductStatus.P, ProductStatus.T, ProductStatus.S],
2601
+ hidden: false,
2593
2602
  sortInputs: [{ field: ProductSortField.RELEVANCE, order: SortOrder.DESC }],
2603
+ ...companyId && { companyId },
2604
+ ...userId !== void 0 && { userId },
2605
+ ...orderlistScope,
2594
2606
  searchFields: [
2595
2607
  {
2596
2608
  fieldNames: [
@@ -2614,18 +2626,36 @@ function useQuickOrder(options) {
2614
2626
  ]
2615
2627
  };
2616
2628
  const variables = {
2617
- input,
2629
+ categoryId: catId,
2618
2630
  language,
2631
+ categoryProductSearchInput: input,
2632
+ priceCalculateProductInput: {
2633
+ taxZone,
2634
+ ...companyId && { companyId },
2635
+ ...contactId !== void 0 && { contactId },
2636
+ ...customerId !== void 0 && { customerId }
2637
+ },
2638
+ imageSearchFilters: configuration.imageSearchFiltersGrid,
2619
2639
  imageVariantFilters: configuration.imageVariantFiltersSmall
2620
2640
  };
2621
- const result = await service.getProducts(variables);
2622
- const items = result?.items ?? [];
2641
+ const response = await service.getCategory(variables);
2642
+ const items = response?.products?.items ?? [];
2623
2643
  return items.map((it) => toMatch(it, language));
2624
2644
  } catch {
2625
2645
  return [];
2626
2646
  }
2627
2647
  },
2628
- [graphqlClient, language, searchLimit, configuration]
2648
+ [
2649
+ graphqlClient,
2650
+ language,
2651
+ searchLimit,
2652
+ configuration,
2653
+ user,
2654
+ companyId,
2655
+ taxZone,
2656
+ orderlistIds,
2657
+ applyOrderlists
2658
+ ]
2629
2659
  );
2630
2660
  const submit = useCallback(
2631
2661
  async (lines) => {
@@ -14140,6 +14170,9 @@ function QuickOrderInner(props) {
14140
14170
  companyId,
14141
14171
  language,
14142
14172
  configuration,
14173
+ taxZone: props.taxZone,
14174
+ orderlistIds: props.orderlistIds,
14175
+ applyOrderlists: props.applyOrderlists,
14143
14176
  onCartCreated,
14144
14177
  afterAddToCart
14145
14178
  });
@@ -16436,19 +16469,27 @@ function ProductSpecifications(rawProps) {
16436
16469
  (a) => (a.attributeDescription?.group || "") === group
16437
16470
  );
16438
16471
  }
16472
+ function pickLocalized(rows, isUsable) {
16473
+ const list = (rows || []).filter(isUsable);
16474
+ const lang = (props.language || "NL").toUpperCase();
16475
+ return list.find((row) => (row.language || "").toUpperCase() === lang) || list[0];
16476
+ }
16439
16477
  function getAttributeLabel(attr) {
16440
- const lang = props.language || "NL";
16441
- const descs = attr.attributeDescription?.descriptions || [];
16442
- const match = descs.find((d) => d.language === lang);
16478
+ const match = pickLocalized(
16479
+ attr.attributeDescription?.descriptions,
16480
+ (d) => !!d.value
16481
+ );
16443
16482
  return match?.value || attr.attributeDescription?.name || "";
16444
16483
  }
16445
16484
  function getAttributeValue(attr) {
16446
16485
  const v = attr.value;
16447
16486
  if (!v) return "";
16448
- const lang = props.language || "NL";
16449
16487
  if (v.type === AttributeType.TEXT) {
16450
16488
  const tv = v;
16451
- const entry = tv.textValues?.find((row) => row.language === lang);
16489
+ const entry = pickLocalized(
16490
+ tv.textValues,
16491
+ (row) => (row?.values || []).some(Boolean)
16492
+ );
16452
16493
  const vals = (entry?.values || []).filter(Boolean);
16453
16494
  return vals.join(", ");
16454
16495
  }