@propeller-commerce/propeller-v2-react-ui 0.16.0 → 0.19.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.js CHANGED
@@ -1,10 +1,12 @@
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, MIN_STOCK_THRESHOLD, getNettedBonusItems, getLanguageString, collectAttributeValues, getCountryName } from '@propeller-commerce/propeller-v2-core-ui';
2
+ import { getLabel, getLocalizedValue, formatPrice, localeForLanguage, getClusterSku, getClusterImageUrl, isContentHidden, getProductSku, getProductImageUrl, createServices, err, ok, formatSurcharge, deriveUserMode, isContact, isCustomer, getAddresses, attributeNameMatches, getAttributeDisplayName, filterProductsBySelections, extractAttributeValues, buildInventoryFilter, MIN_STOCK_THRESHOLD, getNettedBonusItems, 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
- import { createContext, useState, useRef, useMemo, useCallback, useContext, useEffect } from 'react';
5
+ import { createContext, useState, useRef, useCallback, useMemo, useContext, useEffect } from 'react';
6
6
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
7
7
  import { ProductStatus, ProductSortField, SortOrder, PurchaseRole, CrossupsellType, CartStatus, CartAddressType, Gender, YesNo, AddressType, MagicTokenService, PaymentStatuses, OrderSearchFields, OrderItemClass, ProductSearchableField, machineService, AttributeType, OrderSortField, OrderType, OrderDiscountType, BundleCondition } from '@propeller-commerce/propeller-sdk-v2';
8
+ import { clsx } from 'clsx';
9
+ import { twMerge } from 'tailwind-merge';
8
10
  import { User } from 'lucide-react';
9
11
 
10
12
  // src/index.ts
@@ -714,12 +716,33 @@ async function initCart(config) {
714
716
  }
715
717
 
716
718
  // src/composables/react/useCart.ts
719
+ var DEFAULT_IMAGE_SEARCH_FILTERS = { page: 1, offset: 1 };
720
+ var DEFAULT_IMAGE_VARIANT_FILTERS = {
721
+ transformations: [
722
+ { name: "thumb", transformation: { format: "WEBP", height: 100, width: 100, fit: "BOUNDS" } }
723
+ ]
724
+ };
717
725
  function useCart(options) {
718
726
  const { graphqlClient, user, companyId, configuration, onCartCreated } = options;
719
727
  const language = options.language || configuration?.language || "NL";
720
728
  const [cart, setCart] = useState(null);
721
729
  const [createdCartId, setCreatedCartId] = useState("");
722
730
  const cartId = options.cartId || createdCartId;
731
+ const cartIdRef = useRef(cartId);
732
+ if (cartId && cartIdRef.current !== cartId) cartIdRef.current = cartId;
733
+ const rememberCart = useCallback((c) => {
734
+ setCart(c);
735
+ setCreatedCartId(c.cartId);
736
+ cartIdRef.current = c.cartId;
737
+ }, []);
738
+ const imageSearchFilters = useCallback(
739
+ () => configuration?.imageSearchFiltersGrid ?? DEFAULT_IMAGE_SEARCH_FILTERS,
740
+ [configuration]
741
+ );
742
+ const imageVariantFilters = useCallback(
743
+ () => configuration?.imageVariantFiltersSmall ?? DEFAULT_IMAGE_VARIANT_FILTERS,
744
+ [configuration]
745
+ );
723
746
  const [loading, setLoading] = useState(false);
724
747
  const [error, setError] = useState(null);
725
748
  const notesTimers = useRef({});
@@ -751,17 +774,15 @@ function useCart(options) {
751
774
  user,
752
775
  companyId,
753
776
  language,
754
- imageSearchFilters: configuration?.imageSearchFiltersGrid,
755
- imageVariantFilters: configuration?.imageVariantFiltersSmall,
777
+ imageSearchFilters: imageSearchFilters(),
778
+ imageVariantFilters: imageVariantFilters(),
756
779
  onCartCreated: (c) => {
757
- setCart(c);
758
- setCreatedCartId(c.cartId);
780
+ rememberCart(c);
759
781
  onCartCreated?.(c);
760
782
  }
761
783
  };
762
784
  const resolved = await initCart(config);
763
- setCart(resolved);
764
- setCreatedCartId(resolved.cartId);
785
+ rememberCart(resolved);
765
786
  return resolved;
766
787
  }, [graphqlClient, user, companyId, language, configuration, onCartCreated]);
767
788
  const addItem = useCallback(async (opts) => {
@@ -774,14 +795,13 @@ function useCart(options) {
774
795
  }
775
796
  const childItemInputs = opts.childItems?.map((id) => ({ productId: id, quantity: opts.quantity }));
776
797
  if (opts.onAddToCart) {
777
- const resultCart2 = opts.onAddToCart(opts.product, opts.cluster?.clusterId, opts.quantity, childItemInputs, opts.notes, opts.price);
778
- setCart(resultCart2);
779
- setCreatedCartId(resultCart2.cartId);
798
+ const resultCart2 = await opts.onAddToCart(opts.product, opts.cluster?.clusterId, opts.quantity, childItemInputs, opts.notes, opts.price);
799
+ rememberCart(resultCart2);
780
800
  const addedItem2 = resultCart2.items?.find((i) => i.productId === opts.product.productId) ?? null;
781
801
  opts.afterAddToCart?.(resultCart2, addedItem2);
782
802
  return ok({ cart: resultCart2, item: addedItem2 });
783
803
  }
784
- let resolvedCartId = opts.cartId || cartId;
804
+ let resolvedCartId = opts.cartId || cartIdRef.current || cartId;
785
805
  if (!resolvedCartId) {
786
806
  if (opts.createCart) {
787
807
  const c = await resolveCart();
@@ -793,11 +813,10 @@ function useCart(options) {
793
813
  id: resolvedCartId,
794
814
  input: { productId: opts.product.productId, quantity: opts.quantity, ...opts.cluster?.clusterId !== void 0 && { clusterId: opts.cluster.clusterId }, ...childItemInputs && { childItems: childItemInputs }, ...opts.notes && { notes: opts.notes }, ...opts.price !== void 0 && { price: opts.price } },
795
815
  language,
796
- imageSearchFilters: configuration?.imageSearchFiltersGrid,
797
- imageVariantFilters: configuration?.imageVariantFiltersSmall
816
+ imageSearchFilters: imageSearchFilters(),
817
+ imageVariantFilters: imageVariantFilters()
798
818
  });
799
- setCart(resultCart);
800
- setCreatedCartId(resultCart.cartId);
819
+ rememberCart(resultCart);
801
820
  const addedItem = resultCart.items?.find((i) => i.productId === opts.product.productId) ?? null;
802
821
  opts.afterAddToCart?.(resultCart, addedItem);
803
822
  return ok({ cart: resultCart, item: addedItem });
@@ -808,13 +827,25 @@ function useCart(options) {
808
827
  } finally {
809
828
  setLoading(false);
810
829
  }
811
- }, [graphqlClient, cartId, language, configuration, resolveCart]);
830
+ }, [graphqlClient, cartId, language, configuration, resolveCart, rememberCart, imageSearchFilters, imageVariantFilters]);
831
+ const addItems = useCallback(async (items) => {
832
+ const added = [];
833
+ let lastCart = null;
834
+ for (const item of items) {
835
+ const result = await addItem({ createCart: true, ...item });
836
+ if (!result.ok) return err(result.error);
837
+ lastCart = result.data.cart;
838
+ added.push(result.data.item);
839
+ }
840
+ if (!lastCart) return err("No items to add");
841
+ return ok({ cart: lastCart, items: added });
842
+ }, [addItem]);
812
843
  const updateItemQuantity = useCallback(async (cartItemId, quantity) => {
813
844
  if (!cartId) return void 0;
814
845
  setLoading(true);
815
846
  try {
816
847
  const service = createServices(graphqlClient).cart;
817
- const updated = await service.updateCartItem({ id: cartId, itemId: cartItemId, input: { quantity }, language, imageSearchFilters: configuration?.imageSearchFiltersGrid, imageVariantFilters: configuration?.imageVariantFiltersSmall });
848
+ const updated = await service.updateCartItem({ id: cartId, itemId: cartItemId, input: { quantity }, language, imageSearchFilters: imageSearchFilters(), imageVariantFilters: imageVariantFilters() });
818
849
  setCart(updated);
819
850
  return updated;
820
851
  } catch (e) {
@@ -830,7 +861,7 @@ function useCart(options) {
830
861
  if (!cartId) return;
831
862
  try {
832
863
  const service = createServices(graphqlClient).cart;
833
- const updated = await service.updateCartItem({ id: cartId, itemId: cartItemId, input: { notes }, language, imageSearchFilters: configuration?.imageSearchFiltersGrid, imageVariantFilters: configuration?.imageVariantFiltersSmall });
864
+ const updated = await service.updateCartItem({ id: cartId, itemId: cartItemId, input: { notes }, language, imageSearchFilters: imageSearchFilters(), imageVariantFilters: imageVariantFilters() });
834
865
  setCart(updated);
835
866
  } catch (e) {
836
867
  setError(e instanceof Error ? e.message : "Failed to update notes");
@@ -846,8 +877,8 @@ function useCart(options) {
846
877
  id: cartId,
847
878
  input: { itemId: cartItemId },
848
879
  language,
849
- imageSearchFilters: configuration?.imageSearchFiltersGrid,
850
- imageVariantFilters: configuration?.imageVariantFiltersSmall
880
+ imageSearchFilters: imageSearchFilters(),
881
+ imageVariantFilters: imageVariantFilters()
851
882
  });
852
883
  setCart(updated);
853
884
  return updated;
@@ -861,7 +892,7 @@ function useCart(options) {
861
892
  if (!cartId) return void 0;
862
893
  try {
863
894
  const service = createServices(graphqlClient).cart;
864
- const updated = await service.addActionCodeToCart({ id: cartId, input: { actionCode: code }, language, imageSearchFilters: configuration?.imageSearchFiltersGrid, imageVariantFilters: configuration?.imageVariantFiltersSmall });
895
+ const updated = await service.addActionCodeToCart({ id: cartId, input: { actionCode: code }, language, imageSearchFilters: imageSearchFilters(), imageVariantFilters: imageVariantFilters() });
865
896
  setCart(updated);
866
897
  return updated;
867
898
  } catch (e) {
@@ -872,7 +903,7 @@ function useCart(options) {
872
903
  if (!cartId) return void 0;
873
904
  try {
874
905
  const service = createServices(graphqlClient).cart;
875
- const updated = await service.removeActionCodeFromCart({ id: cartId, input: { actionCode: code }, language, imageSearchFilters: configuration?.imageSearchFiltersGrid, imageVariantFilters: configuration?.imageVariantFiltersSmall });
906
+ const updated = await service.removeActionCodeFromCart({ id: cartId, input: { actionCode: code }, language, imageSearchFilters: imageSearchFilters(), imageVariantFilters: imageVariantFilters() });
876
907
  setCart(updated);
877
908
  return updated;
878
909
  } catch (e) {
@@ -900,7 +931,7 @@ function useCart(options) {
900
931
  }
901
932
  }, [graphqlClient, cartId, language]);
902
933
  const getCrossupsells = useCallback(async (opts) => {
903
- const { productId, clusterId, types, taxZone, imageVariantFilters } = opts;
934
+ const { productId, clusterId, types, taxZone } = opts;
904
935
  if (!productId && !clusterId) return [];
905
936
  try {
906
937
  const service = createServices(graphqlClient).crossupsell;
@@ -913,8 +944,8 @@ function useCart(options) {
913
944
  ...clusterId && { clusterIdsFrom: [clusterId] }
914
945
  },
915
946
  language,
916
- imageSearchFilters: configuration?.imageSearchFiltersGrid,
917
- imageVariantFilters: imageVariantFilters ?? configuration?.imageVariantFiltersSmall,
947
+ imageSearchFilters: imageSearchFilters(),
948
+ imageVariantFilters: opts.imageVariantFilters ?? imageVariantFilters(),
918
949
  priceCalculateProductInput: {
919
950
  taxZone: taxZone || "NL",
920
951
  ...user && "company" in user && { companyId: user?.company?.companyId },
@@ -927,8 +958,8 @@ function useCart(options) {
927
958
  } catch {
928
959
  return [];
929
960
  }
930
- }, [graphqlClient, language, configuration, user]);
931
- return { cart, cartId, loading, error, checkoutAllowed, resolveCart, addItem, updateItemQuantity, updateItemNotes, deleteItem, addActionCode, removeActionCode, requestAuthorization, processCart, getCrossupsells, getMinQuantity, getStep };
961
+ }, [graphqlClient, language, user, imageSearchFilters, imageVariantFilters]);
962
+ return { cart, cartId, loading, error, checkoutAllowed, resolveCart, addItem, addItems, updateItemQuantity, updateItemNotes, deleteItem, addActionCode, removeActionCode, requestAuthorization, processCart, getCrossupsells, getMinQuantity, getStep };
932
963
  }
933
964
  function buildAddressInput(type, addr) {
934
965
  return {
@@ -1390,7 +1421,7 @@ function useFavorites(options) {
1390
1421
  if (onEdit) {
1391
1422
  onEdit(listId, data);
1392
1423
  cancelEdit();
1393
- onListChanged?.();
1424
+ onListChanged?.({ action: "updated", listId, ...data });
1394
1425
  return;
1395
1426
  }
1396
1427
  setSaving(true);
@@ -1405,7 +1436,7 @@ function useFavorites(options) {
1405
1436
  const updated = await service.updateFavoriteList(listId, { name: data.name, isDefault: data.isDefault });
1406
1437
  setLists((prev) => prev.map((l) => String(l.id) === listId ? updated : l));
1407
1438
  cancelEdit();
1408
- onListChanged?.();
1439
+ onListChanged?.({ action: "updated", listId, name: data.name, isDefault: data.isDefault });
1409
1440
  } catch (e) {
1410
1441
  setError(e instanceof Error ? e.message : "Failed to update list");
1411
1442
  } finally {
@@ -1422,7 +1453,7 @@ function useFavorites(options) {
1422
1453
  if (onDelete) {
1423
1454
  onDelete(listId);
1424
1455
  setListToDelete(null);
1425
- onListChanged?.();
1456
+ onListChanged?.({ action: "deleted", listId, name: list.name });
1426
1457
  return;
1427
1458
  }
1428
1459
  setSaving(true);
@@ -1431,7 +1462,7 @@ function useFavorites(options) {
1431
1462
  try {
1432
1463
  const service = createServices(graphqlClient).favoriteList;
1433
1464
  await service.deleteFavoriteList(listId);
1434
- onListChanged?.();
1465
+ onListChanged?.({ action: "deleted", listId, name: list.name });
1435
1466
  } catch (e) {
1436
1467
  setError(e instanceof Error ? e.message : "Failed to delete list");
1437
1468
  setLists((prev) => [...prev, list]);
@@ -1444,7 +1475,7 @@ function useFavorites(options) {
1444
1475
  const data = { name, isDefault };
1445
1476
  if (onCreate) {
1446
1477
  onCreate(data);
1447
- onListChanged?.();
1478
+ onListChanged?.({ action: "created", name, isDefault });
1448
1479
  return;
1449
1480
  }
1450
1481
  setSaving(true);
@@ -1461,7 +1492,7 @@ function useFavorites(options) {
1461
1492
  if (isCustomer(user)) createInput.customerId = user.customerId;
1462
1493
  const created = await service.createFavoriteList(createInput);
1463
1494
  setLists((prev) => [...prev, created]);
1464
- onListChanged?.();
1495
+ onListChanged?.({ action: "created", listId: created?.id, name, isDefault });
1465
1496
  } catch (e) {
1466
1497
  setError(e instanceof Error ? e.message : "Failed to create list");
1467
1498
  } finally {
@@ -2183,6 +2214,15 @@ function useProductInfo(options) {
2183
2214
  clusterImageUrl
2184
2215
  };
2185
2216
  }
2217
+
2218
+ // src/composables/shared/utils/listingUserId.ts
2219
+ function resolveListingUserId(user, configuration) {
2220
+ if (user && "contactId" in user) return user.contactId;
2221
+ if (user && "customerId" in user) return user.customerId;
2222
+ return configuration?.anonymousUserId;
2223
+ }
2224
+
2225
+ // src/composables/react/useProductSearch.ts
2186
2226
  var inflightFetches2 = /* @__PURE__ */ new Set();
2187
2227
  function buildAttributeInput(names) {
2188
2228
  if (!names || names.length === 0) return void 0;
@@ -2287,7 +2327,7 @@ function useProductSearch(options) {
2287
2327
  ] : [];
2288
2328
  const priceFilter = options.priceFilterMin !== void 0 || options.priceFilterMax !== void 0 ? { from: options.priceFilterMin ?? 0, to: options.priceFilterMax ?? 999999 } : void 0;
2289
2329
  const inventoryFilter = buildInventoryFilter(options.availability, options.minStock);
2290
- const userId = options.user && "contactId" in options.user ? options.user.contactId : options.user && "customerId" in options.user ? options.user.customerId : void 0;
2330
+ const userId = resolveListingUserId(options.user, configuration);
2291
2331
  const contactId = options.user && "contactId" in options.user ? options.user.contactId : void 0;
2292
2332
  const customerId = options.user && "customerId" in options.user ? options.user.customerId : void 0;
2293
2333
  const orderlistScope = options.orderlistIds && options.orderlistIds.length > 0 ? {
@@ -2424,7 +2464,7 @@ function useProductSearch(options) {
2424
2464
  applyOrderlists: options.applyOrderlists !== false,
2425
2465
  orderlistIds: options.orderlistIds
2426
2466
  } : { applyOrderlists: false };
2427
- const userId = options.user && "contactId" in options.user ? options.user.contactId : options.user && "customerId" in options.user ? options.user.customerId : void 0;
2467
+ const userId = resolveListingUserId(options.user, configuration);
2428
2468
  const contactId = options.user && "contactId" in options.user ? options.user.contactId : void 0;
2429
2469
  const customerId = options.user && "customerId" in options.user ? options.user.customerId : void 0;
2430
2470
  const inventoryFilter = buildInventoryFilter(options.availability, options.minStock);
@@ -2590,7 +2630,7 @@ function useQuickOrder(options) {
2590
2630
  try {
2591
2631
  const service = createServices(graphqlClient).category;
2592
2632
  const orderlistScope = orderlistIds && orderlistIds.length > 0 ? { applyOrderlists: applyOrderlists !== false, orderlistIds } : { applyOrderlists: false };
2593
- const userId = user && "contactId" in user ? user.contactId : user && "customerId" in user ? user.customerId : void 0;
2633
+ const userId = resolveListingUserId(user, configuration);
2594
2634
  const contactId = user && "contactId" in user ? user.contactId : void 0;
2595
2635
  const customerId = user && "customerId" in user ? user.customerId : void 0;
2596
2636
  const input = {
@@ -2732,7 +2772,7 @@ function useSpareParts(options) {
2732
2772
  [isControlled, options.parts, internalParts]
2733
2773
  );
2734
2774
  const isLoading = !isControlled && internalLoading;
2735
- const userId = options.user && "contactId" in options.user ? options.user.contactId : options.user && "customerId" in options.user ? options.user.customerId : void 0;
2775
+ const userId = resolveListingUserId(options.user, options.configuration);
2736
2776
  const contactId = options.user && "contactId" in options.user ? options.user.contactId : void 0;
2737
2777
  const customerId = options.user && "customerId" in options.user ? options.user.customerId : void 0;
2738
2778
  const userKey = `${contactId ?? ""}:${customerId ?? ""}`;
@@ -3035,9 +3075,7 @@ function useProductSlider(options) {
3035
3075
  }
3036
3076
  }
3037
3077
  function resolveUserId() {
3038
- if (options.user && "contactId" in options.user) return options.user.contactId;
3039
- if (options.user && "customerId" in options.user) return options.user.customerId;
3040
- return void 0;
3078
+ return resolveListingUserId(options.user, options.configuration);
3041
3079
  }
3042
3080
  const fetchCrossupsells = useCallback(async (input) => {
3043
3081
  setLoading(true);
@@ -4024,6 +4062,9 @@ LoginFormExport.RegisterLink = LoginFormRegisterLink;
4024
4062
  LoginFormExport.GuestCheckoutButton = LoginFormGuestCheckoutButton;
4025
4063
  LoginFormExport.ErrorMessage = LoginFormErrorMessage;
4026
4064
  var LoginForm_default = LoginFormExport;
4065
+ function cn(...inputs) {
4066
+ return twMerge(clsx(inputs));
4067
+ }
4027
4068
  function AccountIconAndMenu(rawProps) {
4028
4069
  const props = useInfraProps(rawProps);
4029
4070
  const LoginFormImpl = props.loginFormComponent ?? LoginForm_default;
@@ -4172,7 +4213,7 @@ function AccountIconAndMenu(rawProps) {
4172
4213
  onClick: (event) => handleIconClick(),
4173
4214
  "aria-label": getLabel(props.labels, "accountLabel", "Account"),
4174
4215
  "data-open": menuOpen ? "true" : "false",
4175
- className: `propeller-account-menu__trigger inline-flex items-center gap-2 px-3 py-2 rounded-control text-sm font-medium transition-colors text-white hover:bg-white/10${props.iconClassName ? " " + props.iconClassName : ""}`,
4216
+ className: cn(`propeller-account-menu__trigger inline-flex items-center gap-2 px-3 py-2 rounded-control text-sm font-medium transition-colors text-white hover:bg-white/10${props.iconClassName ? " " + props.iconClassName : ""}`),
4176
4217
  children: [
4177
4218
  /* @__PURE__ */ jsx(
4178
4219
  "svg",
@@ -4200,7 +4241,7 @@ function AccountIconAndMenu(rawProps) {
4200
4241
  menuOpen ? /* @__PURE__ */ jsxs(
4201
4242
  "div",
4202
4243
  {
4203
- className: `propeller-account-menu__popover absolute right-0 mt-2 w-80 bg-popover text-foreground rounded-container shadow-lg border border-border py-4 px-5 z-50${props.menuClassName ? " " + props.menuClassName : ""}`,
4244
+ className: cn(`propeller-account-menu__popover absolute right-0 mt-2 w-80 bg-popover text-foreground rounded-container shadow-lg border border-border py-4 px-5 z-50${props.menuClassName ? " " + props.menuClassName : ""}`),
4204
4245
  children: [
4205
4246
  !!props.user ? /* @__PURE__ */ jsxs(Fragment, { children: [
4206
4247
  /* @__PURE__ */ jsxs("div", { className: "propeller-account-menu__user pb-3 mb-3 border-b border-border", children: [
@@ -4411,6 +4452,64 @@ function ActionCode(rawProps) {
4411
4452
  ] });
4412
4453
  }
4413
4454
  var ActionCode_default = ActionCode;
4455
+ function CartBonusItems(rawProps) {
4456
+ const props = useInfraProps(rawProps);
4457
+ const items = props.bonusItems ?? props.cart?.bonusItems ?? [];
4458
+ if (items.length === 0) return null;
4459
+ const currency = props.currency ?? "\u20AC";
4460
+ const money = (value) => formatPrice(value, { symbol: currency, locale: localeForLanguage(props.language) });
4461
+ const productName = (item) => getLocalizedValue(item.product?.names, props.language, "Product");
4462
+ const productImage = (item) => item.product?.media?.images?.items?.[0]?.imageVariants?.[0]?.url || "";
4463
+ return /* @__PURE__ */ jsxs("div", { className: cn(`propeller-cart-bonus-items ${props.className || "mt-2"}`), children: [
4464
+ /* @__PURE__ */ jsx("h2", { className: "propeller-cart-bonus-items__title text-lg font-semibold mb-3", children: getLabel(props.labels, "title", "Bonus items") }),
4465
+ /* @__PURE__ */ jsx("div", { className: "propeller-cart-bonus-items__list space-y-4", children: items.map((item) => {
4466
+ const img = productImage(item);
4467
+ const name = productName(item);
4468
+ const total = props.includeTax ? item.totalPriceNet : item.totalPrice;
4469
+ return /* @__PURE__ */ jsxs(
4470
+ "div",
4471
+ {
4472
+ className: "propeller-cart-bonus-item flex items-center gap-4 bg-card p-4 rounded-container shadow-sm border border-border",
4473
+ children: [
4474
+ /* @__PURE__ */ jsx("div", { className: "propeller-cart-bonus-item__media w-20 h-20 flex-shrink-0 bg-surface-hover rounded-control overflow-hidden flex items-center justify-center", children: img ? /* @__PURE__ */ jsx("img", { className: "propeller-cart-bonus-item__image w-full h-full object-contain p-1", src: img, alt: name }) : /* @__PURE__ */ jsx(
4475
+ "svg",
4476
+ {
4477
+ fill: "none",
4478
+ viewBox: "0 0 24 24",
4479
+ stroke: "currentColor",
4480
+ className: "propeller-cart-bonus-item__image-placeholder w-8 h-8 text-foreground-subtle",
4481
+ strokeWidth: 1.5,
4482
+ children: /* @__PURE__ */ jsx(
4483
+ "path",
4484
+ {
4485
+ strokeLinecap: "round",
4486
+ strokeLinejoin: "round",
4487
+ d: "M2.25 15.75l5.159-5.159a2.25 2.25 0 013.182 0l5.159 5.159m-1.5-1.5l1.409-1.409a2.25 2.25 0 013.182 0l2.909 2.909M3.75 21h16.5A2.25 2.25 0 0022.5 18.75V5.25A2.25 2.25 0 0020.25 3H3.75A2.25 2.25 0 001.5 5.25v13.5A2.25 2.25 0 003.75 21z"
4488
+ }
4489
+ )
4490
+ }
4491
+ ) }),
4492
+ /* @__PURE__ */ jsxs("div", { className: "propeller-cart-bonus-item__body flex-1 min-w-0", children: [
4493
+ item.product?.sku ? /* @__PURE__ */ jsxs("p", { className: "propeller-cart-bonus-item__sku font-mono text-xs text-foreground-subtle", children: [
4494
+ getLabel(props.labels, "sku", "SKU"),
4495
+ ": ",
4496
+ item.product.sku
4497
+ ] }) : null,
4498
+ /* @__PURE__ */ jsx("p", { className: "propeller-cart-bonus-item__title font-semibold text-sm md:text-base text-foreground line-clamp-2", children: name })
4499
+ ] }),
4500
+ /* @__PURE__ */ jsxs("div", { className: "propeller-cart-bonus-item__qty text-sm text-muted-foreground whitespace-nowrap", children: [
4501
+ item.quantity,
4502
+ " \xD7"
4503
+ ] }),
4504
+ /* @__PURE__ */ jsx("div", { className: "propeller-cart-bonus-item__price font-semibold text-foreground whitespace-nowrap", children: money(total) })
4505
+ ]
4506
+ },
4507
+ item.itemId
4508
+ );
4509
+ }) })
4510
+ ] });
4511
+ }
4512
+ var CartBonusItems_default = CartBonusItems;
4414
4513
  function mergeGrouped(p) {
4415
4514
  const d = p.display;
4416
4515
  const e = p.events;
@@ -4444,6 +4543,7 @@ function AddToCart(rawProps) {
4444
4543
  const [modalVisible, setModalVisible] = useState(() => false);
4445
4544
  const [addedCartItem, setAddedCartItem] = useState(() => null);
4446
4545
  const [activeFullCart, setActiveFullCart] = useState(() => null);
4546
+ const [grantedBonusItems, setGrantedBonusItems] = useState(() => []);
4447
4547
  const [includeTax] = useState(() => false);
4448
4548
  function getProductUrl2() {
4449
4549
  return props.configuration?.urls?.getProductUrl(props.product, props.language) ?? "#";
@@ -4486,9 +4586,9 @@ function AddToCart(rawProps) {
4486
4586
  if (addedCartItem) {
4487
4587
  const useTax = props.includeTax !== void 0 ? !!props.includeTax : includeTax;
4488
4588
  const price = useTax ? addedCartItem.totalSumNet : addedCartItem.totalSum;
4489
- return formatPrice(price, { symbol: props.currency ?? "\u20AC" });
4589
+ return formatPrice(price, { symbol: props.currency ?? "\u20AC", locale: localeForLanguage(props.language) });
4490
4590
  }
4491
- return formatPrice(props.price !== void 0 ? props.price : props.product?.price?.gross, { symbol: props.currency ?? "\u20AC" });
4591
+ return formatPrice(props.price !== void 0 ? props.price : props.product?.price?.gross, { symbol: props.currency ?? "\u20AC", locale: localeForLanguage(props.language) });
4492
4592
  }
4493
4593
  function getModalSku() {
4494
4594
  if (addedCartItem) return addedCartItem.product?.sku || "";
@@ -4522,10 +4622,20 @@ function AddToCart(rawProps) {
4522
4622
  function closeModal() {
4523
4623
  setModalVisible(false);
4524
4624
  setAddedCartItem(null);
4625
+ setGrantedBonusItems([]);
4626
+ }
4627
+ function newBonusItems(before, after) {
4628
+ const granted = after?.bonusItems ?? [];
4629
+ if (granted.length === 0) return [];
4630
+ const previous = before?.bonusItems;
4631
+ if (!previous) return granted;
4632
+ const seen = new Map(previous.map((item) => [item.itemId, item.quantity ?? 0]));
4633
+ return granted.filter((item) => (item.quantity ?? 0) > (seen.get(item.itemId) ?? 0));
4525
4634
  }
4526
4635
  async function handleAddToCart() {
4527
4636
  if (!props.graphqlClient) return;
4528
4637
  if (props.beforeAddToCart && !props.beforeAddToCart()) return;
4638
+ const cartBeforeAdd = activeFullCart ?? cart ?? null;
4529
4639
  const result = await addItem({
4530
4640
  product: props.product,
4531
4641
  cluster: props.cluster,
@@ -4537,6 +4647,7 @@ function AddToCart(rawProps) {
4537
4647
  afterAddToCart: (resultCart, addedItem) => {
4538
4648
  setActiveFullCart(resultCart);
4539
4649
  setAddedCartItem(resolveAddedItem(resultCart, addedItem || null));
4650
+ setGrantedBonusItems(newBonusItems(cartBeforeAdd, resultCart));
4540
4651
  props.afterAddToCart?.(resultCart, addedItem || void 0);
4541
4652
  },
4542
4653
  enableStockValidation: props.enableStockValidation,
@@ -4561,7 +4672,7 @@ function AddToCart(rawProps) {
4561
4672
  return /* @__PURE__ */ jsxs(
4562
4673
  "div",
4563
4674
  {
4564
- className: `propeller-add-to-cart ${props.className || ""}`,
4675
+ className: cn(`propeller-add-to-cart ${props.className || ""}`),
4565
4676
  "data-loading": loading ? "true" : "false",
4566
4677
  children: [
4567
4678
  /* @__PURE__ */ jsxs("div", { className: "propeller-add-to-cart__controls flex flex-wrap items-center gap-2 w-full md:flex-nowrap", children: [
@@ -4833,12 +4944,22 @@ function AddToCart(rawProps) {
4833
4944
  /* @__PURE__ */ jsx("span", { className: "line-clamp-1", children: getLocalizedValue(child.product?.names, props.language, "Option") }),
4834
4945
  /* @__PURE__ */ jsx("span", { className: "text-foreground-subtle whitespace-nowrap ml-2", children: formatPrice(
4835
4946
  ((props.includeTax !== void 0 ? !!props.includeTax : includeTax) ? child.totalSumNet : child.totalSum) ?? 0,
4836
- { symbol: props.currency ?? "\u20AC" }
4947
+ { symbol: props.currency ?? "\u20AC", locale: localeForLanguage(props.language) }
4837
4948
  ) })
4838
4949
  ]
4839
4950
  },
4840
4951
  idx
4841
- )) }) : null
4952
+ )) }) : null,
4953
+ grantedBonusItems.length > 0 ? /* @__PURE__ */ jsx("div", { className: "propeller-add-to-cart__modal-bonus-items mt-4 pt-4 border-t border-border-subtle", children: /* @__PURE__ */ jsx(
4954
+ CartBonusItems_default,
4955
+ {
4956
+ bonusItems: grantedBonusItems,
4957
+ includeTax: props.includeTax,
4958
+ currency: props.currency,
4959
+ language: props.language,
4960
+ labels: props.bonusItemsLabels
4961
+ }
4962
+ ) }) : null
4842
4963
  ] }),
4843
4964
  /* @__PURE__ */ jsxs("div", { className: "propeller-add-to-cart__modal-actions flex gap-3 px-6 py-4 border-t border-border-subtle", children: [
4844
4965
  /* @__PURE__ */ jsx(
@@ -4931,7 +5052,14 @@ function AddToFavorite(rawProps) {
4931
5052
  setMemberListIds(newMemberIds);
4932
5053
  setSelectedListId("");
4933
5054
  setIsOpen(false);
4934
- if (props.onFavoriteChanged) props.onFavoriteChanged();
5055
+ if (props.onFavoriteChanged) {
5056
+ props.onFavoriteChanged({
5057
+ action: "added",
5058
+ listId: selectedListId,
5059
+ productId: props.productId,
5060
+ clusterId: props.clusterId
5061
+ });
5062
+ }
4935
5063
  } catch (error) {
4936
5064
  console.error("Error adding to favorite list:", error);
4937
5065
  } finally {
@@ -4948,7 +5076,14 @@ function AddToFavorite(rawProps) {
4948
5076
  setMemberListIds(newMemberIds);
4949
5077
  setSelectedListId("");
4950
5078
  setIsOpen(false);
4951
- if (props.onFavoriteChanged) props.onFavoriteChanged();
5079
+ if (props.onFavoriteChanged) {
5080
+ props.onFavoriteChanged({
5081
+ action: "removed",
5082
+ listId,
5083
+ productId: props.productId,
5084
+ clusterId: props.clusterId
5085
+ });
5086
+ }
4952
5087
  } catch (error) {
4953
5088
  console.error("Error removing from favorite list:", error);
4954
5089
  } finally {
@@ -4988,7 +5123,7 @@ function AddToFavorite(rawProps) {
4988
5123
  type: "button",
4989
5124
  onClick: (event) => toggleModal(),
4990
5125
  title: isFavorited() ? getLabel(props.labels, "removeFromFavorites", "Remove from favorites") : getLabel(props.labels, "addToFavorites", "Add to favorites"),
4991
- className: `propeller-add-to-favorite__btn inline-flex items-center justify-center rounded-control border p-2.5 transition-colors ${isFavorited() ? "border-primary/30 bg-primary/5 text-primary hover:bg-primary/10" : "border-border bg-card text-foreground-subtle hover:text-primary hover:border-primary/30 hover:bg-primary/5"} ${props.className || ""}`,
5126
+ className: cn(`propeller-add-to-favorite__btn inline-flex items-center justify-center rounded-control border p-2.5 transition-colors ${isFavorited() ? "border-primary/30 bg-primary/5 text-primary hover:bg-primary/10" : "border-border bg-card text-foreground-subtle hover:text-primary hover:border-primary/30 hover:bg-primary/5"} ${props.className || ""}`),
4992
5127
  children: [
4993
5128
  isFavorited() ? /* @__PURE__ */ jsx(
4994
5129
  "svg",
@@ -6137,7 +6272,7 @@ function AddressSelector(props) {
6137
6272
  setIsLoading(false);
6138
6273
  }
6139
6274
  }
6140
- return /* @__PURE__ */ jsxs("div", { className: `propeller-address-selector ${props.className || ""}`, children: [
6275
+ return /* @__PURE__ */ jsxs("div", { className: cn(`propeller-address-selector ${props.className || ""}`), children: [
6141
6276
  /* @__PURE__ */ jsxs(
6142
6277
  "button",
6143
6278
  {
@@ -6280,7 +6415,7 @@ function Breadcrumbs(props) {
6280
6415
  return index === displayItems.length - 1;
6281
6416
  }
6282
6417
  const showSeparatorBefore = (index) => props.showHome !== false || index > 0;
6283
- return /* @__PURE__ */ jsx("nav", { "aria-label": getLabel(props.labels, "breadcrumbAriaLabel", "Breadcrumb"), className: `propeller-breadcrumbs ${props.className || ""}`, children: /* @__PURE__ */ jsxs("ol", { className: "propeller-breadcrumbs__list flex flex-wrap items-center text-sm text-muted-foreground", children: [
6418
+ return /* @__PURE__ */ jsx("nav", { "aria-label": getLabel(props.labels, "breadcrumbAriaLabel", "Breadcrumb"), className: cn(`propeller-breadcrumbs ${props.className || ""}`), children: /* @__PURE__ */ jsxs("ol", { className: "propeller-breadcrumbs__list flex flex-wrap items-center text-sm text-muted-foreground", children: [
6284
6419
  props.showHome !== false ? /* @__PURE__ */ jsx("li", { className: "propeller-breadcrumbs__item flex items-center", "data-home": "true", children: /* @__PURE__ */ jsx(
6285
6420
  "a",
6286
6421
  {
@@ -6350,64 +6485,6 @@ function BreadcrumbsWithProvider(rawProps) {
6350
6485
  return /* @__PURE__ */ jsx(Breadcrumbs_default, { ...props });
6351
6486
  }
6352
6487
  var BreadcrumbsWithProvider_default = BreadcrumbsWithProvider;
6353
- function CartBonusItems(rawProps) {
6354
- const props = useInfraProps(rawProps);
6355
- const items = props.bonusItems ?? props.cart?.bonusItems ?? [];
6356
- if (items.length === 0) return null;
6357
- const currency = props.currency ?? "\u20AC";
6358
- const money = (value) => formatPrice(value, { symbol: currency });
6359
- const productName = (item) => getLocalizedValue(item.product?.names, props.language, "Product");
6360
- const productImage = (item) => item.product?.media?.images?.items?.[0]?.imageVariants?.[0]?.url || "";
6361
- return /* @__PURE__ */ jsxs("div", { className: `propeller-cart-bonus-items ${props.className || "mt-2"}`, children: [
6362
- /* @__PURE__ */ jsx("h2", { className: "propeller-cart-bonus-items__title text-lg font-semibold mb-3", children: getLabel(props.labels, "title", "Bonus items") }),
6363
- /* @__PURE__ */ jsx("div", { className: "propeller-cart-bonus-items__list space-y-4", children: items.map((item) => {
6364
- const img = productImage(item);
6365
- const name = productName(item);
6366
- const total = props.includeTax ? item.totalPriceNet : item.totalPrice;
6367
- return /* @__PURE__ */ jsxs(
6368
- "div",
6369
- {
6370
- className: "propeller-cart-bonus-item flex items-center gap-4 bg-card p-4 rounded-container shadow-sm border border-border",
6371
- children: [
6372
- /* @__PURE__ */ jsx("div", { className: "propeller-cart-bonus-item__media w-20 h-20 flex-shrink-0 bg-surface-hover rounded-control overflow-hidden flex items-center justify-center", children: img ? /* @__PURE__ */ jsx("img", { className: "propeller-cart-bonus-item__image w-full h-full object-contain p-1", src: img, alt: name }) : /* @__PURE__ */ jsx(
6373
- "svg",
6374
- {
6375
- fill: "none",
6376
- viewBox: "0 0 24 24",
6377
- stroke: "currentColor",
6378
- className: "propeller-cart-bonus-item__image-placeholder w-8 h-8 text-foreground-subtle",
6379
- strokeWidth: 1.5,
6380
- children: /* @__PURE__ */ jsx(
6381
- "path",
6382
- {
6383
- strokeLinecap: "round",
6384
- strokeLinejoin: "round",
6385
- d: "M2.25 15.75l5.159-5.159a2.25 2.25 0 013.182 0l5.159 5.159m-1.5-1.5l1.409-1.409a2.25 2.25 0 013.182 0l2.909 2.909M3.75 21h16.5A2.25 2.25 0 0022.5 18.75V5.25A2.25 2.25 0 0020.25 3H3.75A2.25 2.25 0 001.5 5.25v13.5A2.25 2.25 0 003.75 21z"
6386
- }
6387
- )
6388
- }
6389
- ) }),
6390
- /* @__PURE__ */ jsxs("div", { className: "propeller-cart-bonus-item__body flex-1 min-w-0", children: [
6391
- item.product?.sku ? /* @__PURE__ */ jsxs("p", { className: "propeller-cart-bonus-item__sku font-mono text-xs text-foreground-subtle", children: [
6392
- getLabel(props.labels, "sku", "SKU"),
6393
- ": ",
6394
- item.product.sku
6395
- ] }) : null,
6396
- /* @__PURE__ */ jsx("p", { className: "propeller-cart-bonus-item__title font-semibold text-sm md:text-base text-foreground line-clamp-2", children: name })
6397
- ] }),
6398
- /* @__PURE__ */ jsxs("div", { className: "propeller-cart-bonus-item__qty text-sm text-muted-foreground whitespace-nowrap", children: [
6399
- item.quantity,
6400
- " \xD7"
6401
- ] }),
6402
- /* @__PURE__ */ jsx("div", { className: "propeller-cart-bonus-item__price font-semibold text-foreground whitespace-nowrap", children: money(total) })
6403
- ]
6404
- },
6405
- item.itemId
6406
- );
6407
- }) })
6408
- ] });
6409
- }
6410
- var CartBonusItems_default = CartBonusItems;
6411
6488
 
6412
6489
  // src/composables/shared/utils/preselect.ts
6413
6490
  function pickPreselected(items, stored, keyOf) {
@@ -6421,7 +6498,7 @@ function CartCarriers(props) {
6421
6498
  const carriers = props.cart?.carriers || [];
6422
6499
  function formatCarrierPrice(price) {
6423
6500
  if (props.formatPrice) return props.formatPrice(price);
6424
- return formatPrice(price || 0, { symbol: props.currency ?? "\u20AC" });
6501
+ return formatPrice(price || 0, { symbol: props.currency ?? "\u20AC", locale: localeForLanguage(props.language) });
6425
6502
  }
6426
6503
  function handleSelect(carrier) {
6427
6504
  setSelectedName(carrier.name);
@@ -6505,7 +6582,7 @@ function ItemStock(props) {
6505
6582
  return /* @__PURE__ */ jsx(Fragment, { children: hasInventory() ? /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsxs(
6506
6583
  "div",
6507
6584
  {
6508
- className: `propeller-item-stock flex flex-wrap items-center gap-1.5 ${props.className || ""}`,
6585
+ className: cn(`propeller-item-stock flex flex-wrap items-center gap-1.5 ${props.className || ""}`),
6509
6586
  "data-available": isAvailable() ? "true" : "false",
6510
6587
  "data-stock": getStockStatusData(),
6511
6588
  children: [
@@ -6618,7 +6695,7 @@ function CartItem(rawProps) {
6618
6695
  function getFormattedPrice() {
6619
6696
  const item = props.cartItem;
6620
6697
  const price = props.includeTax ? item?.totalSumNet || 0 : item?.totalSum || 0;
6621
- return formatPrice(price, { symbol: props.currency ?? "\u20AC" });
6698
+ return formatPrice(price, { symbol: props.currency ?? "\u20AC", locale: localeForLanguage(props.language) });
6622
6699
  }
6623
6700
  function isBundleItem() {
6624
6701
  return !!props.cartItem.bundle;
@@ -6629,7 +6706,7 @@ function CartItem(rawProps) {
6629
6706
  function getBundlePrice2() {
6630
6707
  const price = props.cartItem.bundle?.price?.net;
6631
6708
  if (price === void 0 || price === null) return "";
6632
- return formatPrice(price, { symbol: props.currency ?? "\u20AC" });
6709
+ return formatPrice(price, { symbol: props.currency ?? "\u20AC", locale: localeForLanguage(props.language) });
6633
6710
  }
6634
6711
  function getBundleLeaderName() {
6635
6712
  const items = props.cartItem.bundle?.items;
@@ -6645,7 +6722,7 @@ function CartItem(rawProps) {
6645
6722
  if (!leader) return "";
6646
6723
  const price = leader.price?.net;
6647
6724
  if (price === void 0 || price === null) return "";
6648
- return formatPrice(price, { symbol: props.currency ?? "\u20AC" });
6725
+ return formatPrice(price, { symbol: props.currency ?? "\u20AC", locale: localeForLanguage(props.language) });
6649
6726
  }
6650
6727
  function getBundleNonLeaders2() {
6651
6728
  const items = props.cartItem.bundle?.items;
@@ -6658,7 +6735,7 @@ function CartItem(rawProps) {
6658
6735
  function getBundleItemPrice(bundleItem) {
6659
6736
  const price = bundleItem.price?.net;
6660
6737
  if (price === void 0 || price === null) return "";
6661
- return formatPrice(price, { symbol: props.currency ?? "\u20AC" });
6738
+ return formatPrice(price, { symbol: props.currency ?? "\u20AC", locale: localeForLanguage(props.language) });
6662
6739
  }
6663
6740
  function getCrossupsellName(item) {
6664
6741
  const product = item?.productTo || item?.clusterTo;
@@ -6751,7 +6828,7 @@ function CartItem(rawProps) {
6751
6828
  if (!price) return "";
6752
6829
  const value = props.includeTax ? price.net : price.gross;
6753
6830
  if (value === void 0 || value === null) return "";
6754
- return formatPrice(value, { symbol: props.currency ?? "\u20AC" });
6831
+ return formatPrice(value, { symbol: props.currency ?? "\u20AC", locale: localeForLanguage(props.language) });
6755
6832
  }
6756
6833
  async function handleAddCrossupsellToCart(item) {
6757
6834
  if (!props.cartId || addingCrossupsellId) return;
@@ -6834,7 +6911,7 @@ function CartItem(rawProps) {
6834
6911
  return /* @__PURE__ */ jsx(CartItemContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsx(
6835
6912
  "div",
6836
6913
  {
6837
- className: `propeller-cart-item flex flex-wrap md:flex-nowrap items-start gap-4 ${props.cardFrame === false ? "" : "bg-card p-4 rounded-container shadow-sm border border-border"} ${props.className || ""}`,
6914
+ className: cn(`propeller-cart-item flex flex-wrap md:flex-nowrap items-start gap-4 ${props.cardFrame === false ? "" : "bg-card p-4 rounded-container shadow-sm border border-border"} ${props.className || ""}`),
6838
6915
  "data-bundle": isBundleItem() ? "true" : "false",
6839
6916
  "data-loading": loading ? "true" : "false",
6840
6917
  children: rawProps.children
@@ -6844,7 +6921,7 @@ function CartItem(rawProps) {
6844
6921
  return /* @__PURE__ */ jsx(CartItemContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsxs(
6845
6922
  "div",
6846
6923
  {
6847
- className: `propeller-cart-item flex flex-wrap md:flex-nowrap items-start gap-4 ${props.cardFrame === false ? "" : "bg-card p-4 rounded-container shadow-sm border border-border"} ${props.className || ""}`,
6924
+ className: cn(`propeller-cart-item flex flex-wrap md:flex-nowrap items-start gap-4 ${props.cardFrame === false ? "" : "bg-card p-4 rounded-container shadow-sm border border-border"} ${props.className || ""}`),
6848
6925
  "data-bundle": isBundleItem() ? "true" : "false",
6849
6926
  "data-loading": loading ? "true" : "false",
6850
6927
  children: [
@@ -6991,7 +7068,7 @@ function CartItemChildItems(props = {}) {
6991
7068
  /* @__PURE__ */ jsx("span", { className: "text-foreground-subtle hidden sm:inline", children: "-" }),
6992
7069
  /* @__PURE__ */ jsx("span", { className: "text-foreground-subtle text-xs self-center", children: child.product.sku }),
6993
7070
  /* @__PURE__ */ jsx("div", { className: "flex-1 border-b border-dotted border-border mx-1 mb-1" }),
6994
- /* @__PURE__ */ jsx("span", { className: "font-semibold text-foreground", children: formatPrice(child.totalSum, { symbol: resolved.currency ?? "\u20AC" }) })
7071
+ /* @__PURE__ */ jsx("span", { className: "font-semibold text-foreground", children: formatPrice(child.totalSum, { symbol: resolved.currency ?? "\u20AC", locale: localeForLanguage(resolved.language) }) })
6995
7072
  ] }, idx))
6996
7073
  ] });
6997
7074
  }
@@ -7232,7 +7309,7 @@ function CartIconAndSidebar(rawProps) {
7232
7309
  const CartBonusItemsImpl = props.cartBonusItemsComponent ?? CartBonusItems_default;
7233
7310
  const CartItemImpl = props.cartItemComponent ?? CartItem_default;
7234
7311
  const currencySymbol = props.currency ?? "\u20AC";
7235
- const money = (value) => value === void 0 || value === null ? "" : formatPrice(value, { symbol: currencySymbol });
7312
+ const money = (value) => value === void 0 || value === null ? "" : formatPrice(value, { symbol: currencySymbol, locale: localeForLanguage(props.language) });
7236
7313
  const { requestAuthorization } = useCart({
7237
7314
  graphqlClient: props.graphqlClient,
7238
7315
  user: props.user ?? null,
@@ -7253,6 +7330,9 @@ function CartIconAndSidebar(rawProps) {
7253
7330
  const useTax = !!props.includeTax;
7254
7331
  const totalRaw = useTax ? props.cart?.total?.totalNet : props.cart?.total?.totalGross;
7255
7332
  const totalPrice = totalRaw === void 0 || totalRaw === null ? money(0) : money(totalRaw);
7333
+ function totalLabel(key) {
7334
+ return useTax ? getLabel(props.labels, key, "Total") : getLabel(props.labels, "totalExclVat", "Total excl. VAT");
7335
+ }
7256
7336
  const sidebarTitle = props.cartSidebarTitle || props.labels?.["cartSidebarTitle"] || "Shopping cart";
7257
7337
  const purchaserPAC = findPurchaserPAC(props.user, props.companyId);
7258
7338
  const totalGross = props.cart?.total?.totalGross ?? 0;
@@ -7316,7 +7396,7 @@ function CartIconAndSidebar(rawProps) {
7316
7396
  type: "button",
7317
7397
  onClick: () => handleIconClick(),
7318
7398
  "aria-label": getLabel(props.labels, "cartIconLabel", "Shopping cart"),
7319
- className: `propeller-cart-icon__trigger relative inline-flex items-center justify-center p-2 rounded-control transition-colors text-foreground${props.iconClassName ? " " + props.iconClassName : ""}`,
7399
+ className: cn(`propeller-cart-icon__trigger relative inline-flex items-center justify-center p-2 rounded-control transition-colors text-foreground${props.iconClassName ? " " + props.iconClassName : ""}`),
7320
7400
  children: [
7321
7401
  /* @__PURE__ */ jsx(
7322
7402
  "svg",
@@ -7342,7 +7422,7 @@ function CartIconAndSidebar(rawProps) {
7342
7422
  ),
7343
7423
  props.showTotals && isHovered && totalItems > 0 ? /* @__PURE__ */ jsxs("div", { className: "propeller-cart-icon__popover absolute top-full right-0 mt-1 z-40 bg-popover border border-border rounded-container shadow-lg px-3 py-2 min-w-[140px] text-sm whitespace-nowrap", children: [
7344
7424
  /* @__PURE__ */ jsxs("div", { className: "flex justify-between gap-4", children: [
7345
- /* @__PURE__ */ jsx("span", { className: "propeller-cart-icon__popover-label text-muted-foreground", children: getLabel(props.labels, "totalLabel", "Total") }),
7425
+ /* @__PURE__ */ jsx("span", { className: "propeller-cart-icon__popover-label text-muted-foreground", children: totalLabel("totalLabel") }),
7346
7426
  /* @__PURE__ */ jsx("span", { className: "propeller-cart-icon__popover-total font-semibold text-foreground", children: totalPrice })
7347
7427
  ] }),
7348
7428
  /* @__PURE__ */ jsxs("div", { className: "propeller-cart-icon__popover-count text-xs text-foreground-subtle mt-0.5", children: [
@@ -7368,7 +7448,7 @@ function CartIconAndSidebar(rawProps) {
7368
7448
  "aria-modal": "true",
7369
7449
  "aria-label": sidebarTitle,
7370
7450
  "data-open": sidebarOpen ? "true" : "false",
7371
- className: `propeller-cart-icon__sidebar fixed inset-y-0 right-0 z-[70] w-full max-w-md bg-card shadow-2xl transform transition-transform duration-300 ease-in-out border-l border-border${sidebarOpen ? " translate-x-0" : " translate-x-full"}${props.sidebarClassName ? " " + props.sidebarClassName : ""}`,
7451
+ className: cn(`propeller-cart-icon__sidebar fixed inset-y-0 right-0 z-[70] w-full max-w-md bg-card shadow-2xl transform transition-transform duration-300 ease-in-out border-l border-border${sidebarOpen ? " translate-x-0" : " translate-x-full"}${props.sidebarClassName ? " " + props.sidebarClassName : ""}`),
7372
7452
  children: /* @__PURE__ */ jsx("div", { className: "flex flex-col h-full", children: isMounted ? /* @__PURE__ */ jsxs(Fragment, { children: [
7373
7453
  /* @__PURE__ */ jsxs("div", { className: "propeller-cart-icon__sidebar-header flex items-center justify-between px-5 py-4 border-b border-border", children: [
7374
7454
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
@@ -7497,7 +7577,7 @@ function CartIconAndSidebar(rawProps) {
7497
7577
  " ",
7498
7578
  items.length > 0 ? /* @__PURE__ */ jsxs("div", { className: "propeller-cart-icon__sidebar-footer px-5 py-4 border-t border-border space-y-3 bg-surface-hover", children: [
7499
7579
  /* @__PURE__ */ jsxs("div", { className: "propeller-cart-icon__total-row flex justify-between items-center", children: [
7500
- /* @__PURE__ */ jsx("span", { className: "propeller-cart-icon__total-label text-sm font-medium text-muted-foreground", children: getLabel(props.labels, "total", "Total") }),
7580
+ /* @__PURE__ */ jsx("span", { className: "propeller-cart-icon__total-label text-sm font-medium text-muted-foreground", children: totalLabel("total") }),
7501
7581
  /* @__PURE__ */ jsx("span", { className: "propeller-cart-icon__total-value text-base font-bold text-foreground", children: totalPrice })
7502
7582
  ] }),
7503
7583
  showCheckoutButton && !showRequestAuthorizationButton ? /* @__PURE__ */ jsx(
@@ -7739,7 +7819,7 @@ function CartPaymethods(rawProps) {
7739
7819
  });
7740
7820
  function formatMethodPrice(price) {
7741
7821
  if (props.formatPrice) return props.formatPrice(price);
7742
- return formatPrice(price || 0, { symbol: props.currency ?? "\u20AC" });
7822
+ return formatPrice(price || 0, { symbol: props.currency ?? "\u20AC", locale: localeForLanguage(props.language) });
7743
7823
  }
7744
7824
  function methodName(method) {
7745
7825
  const code = (method.code || "").toLowerCase();
@@ -7825,7 +7905,7 @@ function CartSummary(rawProps) {
7825
7905
  if (props.formatPrice) {
7826
7906
  return props.formatPrice(price);
7827
7907
  }
7828
- return formatPrice(price || 0, { symbol: props.currency ?? "\u20AC" });
7908
+ return formatPrice(price || 0, { symbol: props.currency ?? "\u20AC", locale: localeForLanguage(props.language) });
7829
7909
  }
7830
7910
  function subtotal() {
7831
7911
  return props.cart?.total?.subTotal || 0;
@@ -7904,83 +7984,96 @@ function CartSummary(rawProps) {
7904
7984
  setRequestLoading(false);
7905
7985
  }
7906
7986
  }
7907
- return /* @__PURE__ */ jsxs("div", { className: "propeller-cart-summary w-full bg-card space-y-3", children: [
7908
- /* @__PURE__ */ jsx("h2", { className: "propeller-cart-summary__title text-xl font-bold mb-4", children: title() }),
7909
- showSubtotal() ? /* @__PURE__ */ jsxs("div", { className: "propeller-cart-summary__row flex justify-between text-muted-foreground", "data-row": "subtotal", children: [
7910
- /* @__PURE__ */ jsx("span", { className: "propeller-cart-summary__label", children: getLabel(props.labels, "subtotal", "Subtotal:") }),
7911
- /* @__PURE__ */ jsx("span", { className: "propeller-cart-summary__value", children: formatItemPrice(subtotal()) })
7912
- ] }) : null,
7913
- showDiscount() && hasDiscount() ? /* @__PURE__ */ jsxs("div", { className: "propeller-cart-summary__row flex justify-between text-success", "data-row": "discount", children: [
7914
- /* @__PURE__ */ jsx("span", { className: "propeller-cart-summary__label", children: getLabel(props.labels, "discount", "Discount:") }),
7915
- /* @__PURE__ */ jsxs("span", { className: "propeller-cart-summary__value", children: [
7916
- "-",
7917
- formatItemPrice(discountAmount())
7918
- ] })
7919
- ] }) : null,
7920
- hasTransactionCosts() ? /* @__PURE__ */ jsxs("div", { className: "propeller-cart-summary__row flex justify-between text-muted-foreground", "data-row": "transaction-costs", children: [
7921
- /* @__PURE__ */ jsx("span", { className: "propeller-cart-summary__label", children: getLabel(props.labels, "transactionCosts", "Transaction costs:") }),
7922
- /* @__PURE__ */ jsx("span", { className: "propeller-cart-summary__value", children: formatItemPrice(transactionCosts()) })
7923
- ] }) : null,
7924
- showShippingCosts() && hasShippingCosts() ? /* @__PURE__ */ jsxs("div", { className: "propeller-cart-summary__row flex justify-between text-muted-foreground", "data-row": "shipping-costs", children: [
7925
- /* @__PURE__ */ jsx("span", { className: "propeller-cart-summary__label", children: getLabel(props.labels, "shippingCosts", "Shipping costs:") }),
7926
- /* @__PURE__ */ jsx("span", { className: "propeller-cart-summary__value", children: formatItemPrice(shippingCosts()) })
7927
- ] }) : null,
7928
- showTotalExclVat() ? /* @__PURE__ */ jsxs("div", { className: "propeller-cart-summary__row flex justify-between text-muted-foreground pt-2 border-t", "data-row": "total-excl-vat", children: [
7929
- /* @__PURE__ */ jsx("span", { className: "propeller-cart-summary__label", children: getLabel(props.labels, "totalExclVat", "Total excl. VAT:") }),
7930
- /* @__PURE__ */ jsx("span", { className: "propeller-cart-summary__value", children: formatItemPrice(totalExclVat()) })
7931
- ] }) : null,
7932
- showVATs() && taxLevels().length > 0 ? /* @__PURE__ */ jsx(Fragment, { children: taxLevels()?.map((tax, index) => /* @__PURE__ */ jsxs("div", { className: "propeller-cart-summary__row flex justify-between text-muted-foreground text-sm", "data-row": "vat-line", children: [
7933
- /* @__PURE__ */ jsxs("span", { className: "propeller-cart-summary__label", children: [
7934
- tax.taxPercentage,
7935
- "% ",
7936
- getLabel(props.labels, "vat", "VAT"),
7937
- ":"
7938
- ] }),
7939
- /* @__PURE__ */ jsx("span", { className: "propeller-cart-summary__value", children: formatItemPrice(Number(tax.price)) })
7940
- ] }, index)) }) : null,
7941
- showTotalVat() && totalVat() > 0 ? /* @__PURE__ */ jsxs("div", { className: "propeller-cart-summary__row flex justify-between text-muted-foreground text-sm", "data-row": "total-vat", children: [
7942
- /* @__PURE__ */ jsx("span", { className: "propeller-cart-summary__label", children: getLabel(props.labels, "totalVat", "Total VAT:") }),
7943
- /* @__PURE__ */ jsx("span", { className: "propeller-cart-summary__value", children: formatItemPrice(totalVat()) })
7944
- ] }) : null,
7945
- /* @__PURE__ */ jsxs("div", { className: "propeller-cart-summary__row propeller-cart-summary__row--total flex justify-between text-xl font-bold pt-4 border-t text-foreground mt-2", "data-row": "total", children: [
7946
- /* @__PURE__ */ jsx("span", { className: "propeller-cart-summary__label", children: getLabel(props.labels, "total", "Total:") }),
7947
- /* @__PURE__ */ jsx("span", { className: "propeller-cart-summary__value", children: formatItemPrice(totalInclVat()) })
7948
- ] }),
7949
- showCheckoutButton() && !showRequestAuthorizationButton() ? /* @__PURE__ */ jsxs(Fragment, { children: [
7950
- /* @__PURE__ */ jsx(
7951
- "button",
7952
- {
7953
- type: "button",
7954
- className: "propeller-cart-summary__checkout-btn block w-full bg-secondary text-secondary-foreground text-center py-3 rounded-container hover:bg-secondary/90 transition font-semibold mt-4",
7955
- onClick: (event) => handleCheckoutClick(),
7956
- children: getLabel(props.labels, "checkoutButton", "Continue to Checkout")
7957
- }
7987
+ return /* @__PURE__ */ jsxs(
7988
+ "div",
7989
+ {
7990
+ className: cn(
7991
+ // Padding, radius and shadow to match ActionCode, which sits directly
7992
+ // under this panel on the cart page. Without them the summary painted
7993
+ // a card background with its text against the edges and a full-bleed
7994
+ // checkout button — the same column, two different card treatments.
7995
+ "propeller-cart-summary w-full bg-card p-6 rounded-container shadow space-y-3",
7996
+ props.className
7958
7997
  ),
7959
- " ",
7960
- !!props.onRequestQuoteClick && showRequestQuoteButton() ? /* @__PURE__ */ jsx(
7961
- "button",
7962
- {
7963
- type: "button",
7964
- className: "propeller-cart-summary__quote-btn block w-full bg-card border border-secondary text-secondary text-center py-3 rounded-container hover:bg-secondary/5 transition font-semibold mt-2",
7965
- onClick: (event) => props.onRequestQuoteClick && props.onRequestQuoteClick(props.cart),
7966
- children: getLabel(props.labels, "requestQuoteButton", "Request a Quote")
7967
- }
7968
- ) : null
7969
- ] }) : null,
7970
- showRequestAuthorizationButton() ? /* @__PURE__ */ jsxs(
7971
- "button",
7972
- {
7973
- type: "button",
7974
- className: "propeller-cart-summary__authorization-btn block w-full bg-secondary text-secondary-foreground text-center py-3 rounded-container hover:bg-secondary/90 transition font-semibold mt-4 disabled:opacity-50 disabled:cursor-not-allowed",
7975
- onClick: (event) => handleRequestAuthorizationClick(),
7976
- disabled: requestLoading,
7977
- children: [
7978
- requestLoading ? /* @__PURE__ */ jsx(Fragment, { children: getLabel(props.labels, "requestingAuthorization", "Requesting...") }) : null,
7979
- !requestLoading ? /* @__PURE__ */ jsx(Fragment, { children: getLabel(props.labels, "requestAuthorizationButton", "Request Authorization") }) : null
7980
- ]
7981
- }
7982
- ) : null
7983
- ] });
7998
+ children: [
7999
+ /* @__PURE__ */ jsx("h2", { className: "propeller-cart-summary__title text-xl font-bold mb-4", children: title() }),
8000
+ showSubtotal() ? /* @__PURE__ */ jsxs("div", { className: "propeller-cart-summary__row flex justify-between text-muted-foreground", "data-row": "subtotal", children: [
8001
+ /* @__PURE__ */ jsx("span", { className: "propeller-cart-summary__label", children: getLabel(props.labels, "subtotal", "Subtotal:") }),
8002
+ /* @__PURE__ */ jsx("span", { className: "propeller-cart-summary__value", children: formatItemPrice(subtotal()) })
8003
+ ] }) : null,
8004
+ showDiscount() && hasDiscount() ? /* @__PURE__ */ jsxs("div", { className: "propeller-cart-summary__row flex justify-between text-success", "data-row": "discount", children: [
8005
+ /* @__PURE__ */ jsx("span", { className: "propeller-cart-summary__label", children: getLabel(props.labels, "discount", "Discount:") }),
8006
+ /* @__PURE__ */ jsxs("span", { className: "propeller-cart-summary__value", children: [
8007
+ "-",
8008
+ formatItemPrice(discountAmount())
8009
+ ] })
8010
+ ] }) : null,
8011
+ hasTransactionCosts() ? /* @__PURE__ */ jsxs("div", { className: "propeller-cart-summary__row flex justify-between text-muted-foreground", "data-row": "transaction-costs", children: [
8012
+ /* @__PURE__ */ jsx("span", { className: "propeller-cart-summary__label", children: getLabel(props.labels, "transactionCosts", "Transaction costs:") }),
8013
+ /* @__PURE__ */ jsx("span", { className: "propeller-cart-summary__value", children: formatItemPrice(transactionCosts()) })
8014
+ ] }) : null,
8015
+ showShippingCosts() && hasShippingCosts() ? /* @__PURE__ */ jsxs("div", { className: "propeller-cart-summary__row flex justify-between text-muted-foreground", "data-row": "shipping-costs", children: [
8016
+ /* @__PURE__ */ jsx("span", { className: "propeller-cart-summary__label", children: getLabel(props.labels, "shippingCosts", "Shipping costs:") }),
8017
+ /* @__PURE__ */ jsx("span", { className: "propeller-cart-summary__value", children: formatItemPrice(shippingCosts()) })
8018
+ ] }) : null,
8019
+ showTotalExclVat() ? /* @__PURE__ */ jsxs("div", { className: "propeller-cart-summary__row flex justify-between text-muted-foreground pt-2 border-t", "data-row": "total-excl-vat", children: [
8020
+ /* @__PURE__ */ jsx("span", { className: "propeller-cart-summary__label", children: getLabel(props.labels, "totalExclVat", "Total excl. VAT:") }),
8021
+ /* @__PURE__ */ jsx("span", { className: "propeller-cart-summary__value", children: formatItemPrice(totalExclVat()) })
8022
+ ] }) : null,
8023
+ showVATs() && taxLevels().length > 0 ? /* @__PURE__ */ jsx(Fragment, { children: taxLevels()?.map((tax, index) => /* @__PURE__ */ jsxs("div", { className: "propeller-cart-summary__row flex justify-between text-muted-foreground text-sm", "data-row": "vat-line", children: [
8024
+ /* @__PURE__ */ jsxs("span", { className: "propeller-cart-summary__label", children: [
8025
+ tax.taxPercentage,
8026
+ "% ",
8027
+ getLabel(props.labels, "vat", "VAT"),
8028
+ ":"
8029
+ ] }),
8030
+ /* @__PURE__ */ jsx("span", { className: "propeller-cart-summary__value", children: formatItemPrice(Number(tax.price)) })
8031
+ ] }, index)) }) : null,
8032
+ showTotalVat() && totalVat() > 0 ? /* @__PURE__ */ jsxs("div", { className: "propeller-cart-summary__row flex justify-between text-muted-foreground text-sm", "data-row": "total-vat", children: [
8033
+ /* @__PURE__ */ jsx("span", { className: "propeller-cart-summary__label", children: getLabel(props.labels, "totalVat", "Total VAT:") }),
8034
+ /* @__PURE__ */ jsx("span", { className: "propeller-cart-summary__value", children: formatItemPrice(totalVat()) })
8035
+ ] }) : null,
8036
+ /* @__PURE__ */ jsxs("div", { className: "propeller-cart-summary__row propeller-cart-summary__row--total flex justify-between text-xl font-bold pt-4 border-t text-foreground mt-2", "data-row": "total", children: [
8037
+ /* @__PURE__ */ jsx("span", { className: "propeller-cart-summary__label", children: getLabel(props.labels, "total", "Total:") }),
8038
+ /* @__PURE__ */ jsx("span", { className: "propeller-cart-summary__value", children: formatItemPrice(totalInclVat()) })
8039
+ ] }),
8040
+ showCheckoutButton() && !showRequestAuthorizationButton() ? /* @__PURE__ */ jsxs(Fragment, { children: [
8041
+ /* @__PURE__ */ jsx(
8042
+ "button",
8043
+ {
8044
+ type: "button",
8045
+ className: "propeller-cart-summary__checkout-btn block w-full bg-secondary text-secondary-foreground text-center py-3 rounded-container hover:bg-secondary/90 transition font-semibold mt-4",
8046
+ onClick: (event) => handleCheckoutClick(),
8047
+ children: getLabel(props.labels, "checkoutButton", "Continue to Checkout")
8048
+ }
8049
+ ),
8050
+ " ",
8051
+ !!props.onRequestQuoteClick && showRequestQuoteButton() ? /* @__PURE__ */ jsx(
8052
+ "button",
8053
+ {
8054
+ type: "button",
8055
+ className: "propeller-cart-summary__quote-btn block w-full bg-card border border-secondary text-secondary text-center py-3 rounded-container hover:bg-secondary/5 transition font-semibold mt-2",
8056
+ onClick: (event) => props.onRequestQuoteClick && props.onRequestQuoteClick(props.cart),
8057
+ children: getLabel(props.labels, "requestQuoteButton", "Request a Quote")
8058
+ }
8059
+ ) : null
8060
+ ] }) : null,
8061
+ showRequestAuthorizationButton() ? /* @__PURE__ */ jsxs(
8062
+ "button",
8063
+ {
8064
+ type: "button",
8065
+ className: "propeller-cart-summary__authorization-btn block w-full bg-secondary text-secondary-foreground text-center py-3 rounded-container hover:bg-secondary/90 transition font-semibold mt-4 disabled:opacity-50 disabled:cursor-not-allowed",
8066
+ onClick: (event) => handleRequestAuthorizationClick(),
8067
+ disabled: requestLoading,
8068
+ children: [
8069
+ requestLoading ? /* @__PURE__ */ jsx(Fragment, { children: getLabel(props.labels, "requestingAuthorization", "Requesting...") }) : null,
8070
+ !requestLoading ? /* @__PURE__ */ jsx(Fragment, { children: getLabel(props.labels, "requestAuthorizationButton", "Request Authorization") }) : null
8071
+ ]
8072
+ }
8073
+ ) : null
8074
+ ]
8075
+ }
8076
+ );
7984
8077
  }
7985
8078
  var CartSummary_default = CartSummary;
7986
8079
  function CategoryDescription(props) {
@@ -8000,7 +8093,7 @@ function CategoryDescription(props) {
8000
8093
  return /* @__PURE__ */ jsx(Fragment, { children: !!html ? /* @__PURE__ */ jsxs(
8001
8094
  "div",
8002
8095
  {
8003
- className: `propeller-category-description mb-6 ${props.className || ""}`,
8096
+ className: cn(`propeller-category-description mb-6 ${props.className || ""}`),
8004
8097
  "data-expanded": expanded ? "true" : "false",
8005
8098
  "data-truncatable": shouldTruncate ? "true" : "false",
8006
8099
  children: [
@@ -8030,7 +8123,7 @@ function CategoryShortDescription(props) {
8030
8123
  (d) => d.language === props.language
8031
8124
  );
8032
8125
  const html = match?.value || "";
8033
- return /* @__PURE__ */ jsx(Fragment, { children: !!html ? /* @__PURE__ */ jsx("div", { className: `propeller-category-short-description mb-6 ${props.className || ""}`, children: /* @__PURE__ */ jsx(
8126
+ return /* @__PURE__ */ jsx(Fragment, { children: !!html ? /* @__PURE__ */ jsx("div", { className: cn(`propeller-category-short-description mb-6 ${props.className || ""}`), children: /* @__PURE__ */ jsx(
8034
8127
  "div",
8035
8128
  {
8036
8129
  className: "propeller-category-short-description__content prose prose-slate max-w-none text-muted-foreground",
@@ -8120,7 +8213,7 @@ function ClusterCard(rawProps) {
8120
8213
  const useTax = props.includeTax !== void 0 ? !!props.includeTax : false;
8121
8214
  const priceObj = contentHidden ? void 0 : cluster?.defaultProduct?.price;
8122
8215
  const priceValue = useTax ? priceObj?.net : priceObj?.gross;
8123
- const clusterPrice = props.showPrice === false ? "" : formatPrice(priceValue, { symbol: props.currency ?? "\u20AC" });
8216
+ const clusterPrice = props.showPrice === false ? "" : formatPrice(priceValue, { symbol: props.currency ?? "\u20AC", locale: localeForLanguage(props.language) });
8124
8217
  function handleClusterClick(e) {
8125
8218
  if (props.onClusterClick) {
8126
8219
  e.preventDefault();
@@ -8165,7 +8258,7 @@ function ClusterCard(rawProps) {
8165
8258
  return /* @__PURE__ */ jsx(ClusterCardContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsx(
8166
8259
  "div",
8167
8260
  {
8168
- className: `propeller-cluster-card group relative flex h-full overflow-hidden rounded-container border border-border bg-card shadow-sm transition-all duration-200 hover:shadow-md hover:border-secondary/20 ${isRow ? "flex-row flex-wrap md:flex-nowrap items-center" : "flex-col"} ${props.className ?? ""}`,
8261
+ className: cn(`propeller-cluster-card group relative flex h-full overflow-hidden rounded-container border border-border bg-card shadow-sm transition-all duration-200 hover:shadow-md hover:border-secondary/20 ${isRow ? "flex-row flex-wrap md:flex-nowrap items-center" : "flex-col"} ${props.className ?? ""}`),
8169
8262
  "data-cluster-id": cluster.clusterId,
8170
8263
  "data-layout": isRow ? "row" : "grid",
8171
8264
  children: rawProps.children
@@ -8175,7 +8268,7 @@ function ClusterCard(rawProps) {
8175
8268
  return /* @__PURE__ */ jsx(ClusterCardContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsxs(
8176
8269
  "div",
8177
8270
  {
8178
- className: `propeller-cluster-card group relative flex h-full overflow-hidden rounded-container border border-border bg-card shadow-sm transition-all duration-200 hover:shadow-md hover:border-secondary/20 ${isRow ? "flex-row flex-wrap md:flex-nowrap items-center" : "flex-col"} ${props.className || ""}`,
8271
+ className: cn(`propeller-cluster-card group relative flex h-full overflow-hidden rounded-container border border-border bg-card shadow-sm transition-all duration-200 hover:shadow-md hover:border-secondary/20 ${isRow ? "flex-row flex-wrap md:flex-nowrap items-center" : "flex-col"} ${props.className || ""}`),
8179
8272
  "data-layout": isRow ? "row" : "grid",
8180
8273
  children: [
8181
8274
  props.showImage !== false ? /* @__PURE__ */ jsx(ClusterCardImage, {}) : null,
@@ -8467,7 +8560,7 @@ function MachineCard(props) {
8467
8560
  return /* @__PURE__ */ jsx(
8468
8561
  "div",
8469
8562
  {
8470
- className: `propeller-machine-card group relative flex h-full flex-col overflow-hidden rounded-lg border border-border bg-background ${props.className ?? ""}`,
8563
+ className: cn(`propeller-machine-card group relative flex h-full flex-col overflow-hidden rounded-lg border border-border bg-background ${props.className ?? ""}`),
8471
8564
  children: /* @__PURE__ */ jsxs(
8472
8565
  "a",
8473
8566
  {
@@ -8528,7 +8621,7 @@ function LoginToOrderButton(props) {
8528
8621
  "button",
8529
8622
  {
8530
8623
  type: "button",
8531
- className: `propeller-login-to-order inline-flex items-center justify-center gap-2 h-10 px-4 w-full rounded-control bg-primary text-primary-foreground text-sm font-medium hover:opacity-90 transition-opacity ${props.className || ""}`,
8624
+ className: cn(`propeller-login-to-order inline-flex items-center justify-center gap-2 h-10 px-4 w-full rounded-control bg-primary text-primary-foreground text-sm font-medium hover:opacity-90 transition-opacity ${props.className || ""}`),
8532
8625
  onClick: () => {
8533
8626
  if (props.onLoginClick) props.onLoginClick();
8534
8627
  },
@@ -8546,7 +8639,7 @@ function ProductPriceDisplay(props) {
8546
8639
  }
8547
8640
  function formatPrice17(value) {
8548
8641
  if (value === null || value === void 0) return "";
8549
- return formatPrice(value, { symbol: props.currency ?? "\u20AC" });
8642
+ return formatPrice(value, { symbol: props.currency ?? "\u20AC", locale: localeForLanguage(props.language) });
8550
8643
  }
8551
8644
  function getOptionsTotal(useNet) {
8552
8645
  const options = props.options || [];
@@ -8589,7 +8682,7 @@ function ProductPriceDisplay(props) {
8589
8682
  function getSecondaryTaxLabel() {
8590
8683
  return props.includeTax ? getLabel(props.labels, "exclTax", "excl. VAT") : getLabel(props.labels, "inclTax", "incl. VAT");
8591
8684
  }
8592
- return /* @__PURE__ */ jsxs("div", { className: `propeller-product-price ${props.className || ""}`, "data-hidden": isHidden2() ? "true" : "false", children: [
8685
+ return /* @__PURE__ */ jsxs("div", { className: cn(`propeller-product-price ${props.className || ""}`), "data-hidden": isHidden2() ? "true" : "false", children: [
8593
8686
  isHidden2() && props.showLoginPrompt !== false ? /* @__PURE__ */ jsx("p", { className: "propeller-product-price__login-prompt text-sm text-muted-foreground italic", children: getLabel(props.labels, "loginToSeePrices", "Log in to see prices") }) : null,
8594
8687
  !isHidden2() && !!getLeadingPrice() ? /* @__PURE__ */ jsxs("div", { className: "propeller-product-price__content flex flex-col gap-0.5", children: [
8595
8688
  /* @__PURE__ */ jsxs("div", { className: "propeller-product-price__primary flex items-baseline gap-2", children: [
@@ -8635,6 +8728,11 @@ var RESOLVE_SPEC2 = {
8635
8728
  includeTax: { infra: "includeTax" },
8636
8729
  portalMode: { infra: "portalMode" },
8637
8730
  configuration: { infra: "configuration" },
8731
+ // Same entry ClusterCard has always had. Without it a shop priced in
8732
+ // anything but euros had no route to the cards at all: the grid resolved the
8733
+ // currency and then dropped it, and the card fell through to the package
8734
+ // default on every price it rendered.
8735
+ currency: { infra: "currency", default: "\u20AC" },
8638
8736
  columns: { grid: "columns", default: 3 },
8639
8737
  showPrice: { grid: "showPrice" },
8640
8738
  showStock: { grid: "showStock" },
@@ -8736,7 +8834,7 @@ function ProductCardRoot(rawProps) {
8736
8834
  return /* @__PURE__ */ jsx(ProductCardContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsx(
8737
8835
  "div",
8738
8836
  {
8739
- className: `propeller-product-card group relative flex h-full overflow-hidden rounded-container border border-border bg-card shadow-sm transition-all duration-200 hover:shadow-md hover:border-secondary/20 ${isRow ? "flex-row flex-wrap md:flex-nowrap items-center" : "flex-col"} ${props.className || ""}`,
8837
+ className: cn(`propeller-product-card group relative flex h-full overflow-hidden rounded-container border border-border bg-card shadow-sm transition-all duration-200 hover:shadow-md hover:border-secondary/20 ${isRow ? "flex-row flex-wrap md:flex-nowrap items-center" : "flex-col"} ${props.className || ""}`),
8740
8838
  "data-layout": isRow ? "row" : "grid",
8741
8839
  children: rawProps.children
8742
8840
  }
@@ -8745,7 +8843,7 @@ function ProductCardRoot(rawProps) {
8745
8843
  return /* @__PURE__ */ jsx(ProductCardContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsxs(
8746
8844
  "div",
8747
8845
  {
8748
- className: `propeller-product-card group relative flex h-full overflow-hidden rounded-container border border-border bg-card shadow-sm transition-all duration-200 hover:shadow-md hover:border-secondary/20 ${isRow ? "flex-row flex-wrap md:flex-nowrap items-center" : "flex-col"} ${props.className || ""}`,
8846
+ className: cn(`propeller-product-card group relative flex h-full overflow-hidden rounded-container border border-border bg-card shadow-sm transition-all duration-200 hover:shadow-md hover:border-secondary/20 ${isRow ? "flex-row flex-wrap md:flex-nowrap items-center" : "flex-col"} ${props.className || ""}`),
8749
8847
  "data-layout": isRow ? "row" : "grid",
8750
8848
  children: [
8751
8849
  props.showImage !== false ? /* @__PURE__ */ jsx(ProductCardImage, {}) : null,
@@ -8969,7 +9067,8 @@ function ProductCardPrice(props) {
8969
9067
  {
8970
9068
  price: product.price,
8971
9069
  includeTax: derived.useTax,
8972
- labels: resolved.priceLabels
9070
+ labels: resolved.priceLabels,
9071
+ currency: resolved.currency
8973
9072
  }
8974
9073
  ) });
8975
9074
  }
@@ -8980,6 +9079,8 @@ function ProductCardPrice(props) {
8980
9079
  includeTax: derived.useTax,
8981
9080
  priceSize: props.priceSize ?? "text-base sm:text-lg",
8982
9081
  labels: resolved.priceLabels,
9082
+ currency: resolved.currency,
9083
+ language: resolved.language,
8983
9084
  portalMode: resolved.portalMode,
8984
9085
  user: resolved.user,
8985
9086
  showLoginPrompt: false
@@ -9192,7 +9293,7 @@ function ProductGrid(rawProps) {
9192
9293
  return /* @__PURE__ */ jsx(ProductGridConfigProvider, { value: gridConfig, children: /* @__PURE__ */ jsx(ProductGridSearchContext.Provider, { value: compoundCtx, children: /* @__PURE__ */ jsx(
9193
9294
  "div",
9194
9295
  {
9195
- className: `propeller-product-grid w-full ${props.className || ""}`,
9296
+ className: cn(`propeller-product-grid w-full ${props.className || ""}`),
9196
9297
  "data-loading": getIsLoading() ? "true" : "false",
9197
9298
  "data-mode": "compound",
9198
9299
  children: rawProps.children
@@ -9202,7 +9303,7 @@ function ProductGrid(rawProps) {
9202
9303
  return /* @__PURE__ */ jsx(ProductGridConfigProvider, { value: gridConfig, children: /* @__PURE__ */ jsxs(
9203
9304
  "div",
9204
9305
  {
9205
- className: `propeller-product-grid w-full ${props.className || ""}`,
9306
+ className: cn(`propeller-product-grid w-full ${props.className || ""}`),
9206
9307
  "data-loading": getIsLoading() ? "true" : "false",
9207
9308
  children: [
9208
9309
  getIsLoading() ? /* @__PURE__ */ jsx("div", { className: `propeller-product-grid__skeleton-grid ${getGridColsClass()}`, children: getSkeletonItems()?.map((_, idx) => /* @__PURE__ */ jsxs(
@@ -9305,7 +9406,7 @@ function ProductGridItems(props) {
9305
9406
  const gridClass = cols === 1 ? "flex flex-col gap-4" : cols === 2 ? "grid grid-cols-2 gap-3 sm:gap-6 auto-rows-fr" : cols === 4 ? "grid grid-cols-2 lg:grid-cols-4 gap-3 sm:gap-6 auto-rows-fr" : cols === 5 ? "grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-5 gap-3 sm:gap-6 auto-rows-fr" : cols === 6 ? "grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-6 gap-3 sm:gap-6 auto-rows-fr" : "grid grid-cols-2 lg:grid-cols-3 gap-3 sm:gap-6 auto-rows-fr";
9306
9407
  if (isLoading) {
9307
9408
  const skeletonCount = cols === 2 ? 4 : cols === 4 ? 8 : cols === 5 ? 10 : cols === 6 ? 12 : 6;
9308
- return /* @__PURE__ */ jsx("div", { className: `propeller-product-grid__skeleton-grid ${gridClass} ${props.className ?? ""}`, children: Array.from({ length: skeletonCount }).map((_, idx) => /* @__PURE__ */ jsxs(
9409
+ return /* @__PURE__ */ jsx("div", { className: cn(`propeller-product-grid__skeleton-grid ${gridClass} ${props.className ?? ""}`), children: Array.from({ length: skeletonCount }).map((_, idx) => /* @__PURE__ */ jsxs(
9309
9410
  "div",
9310
9411
  {
9311
9412
  className: "propeller-product-grid__skeleton-card flex flex-col overflow-hidden rounded-container border border-border bg-card shadow-sm",
@@ -9327,7 +9428,7 @@ function ProductGridItems(props) {
9327
9428
  /* @__PURE__ */ jsx("p", { className: "propeller-product-grid__empty-message mt-1 text-sm text-muted-foreground", children: getLabel(props.labels, "noProductsHelp", "Try adjusting your filters or search term.") })
9328
9429
  ] }) });
9329
9430
  }
9330
- return /* @__PURE__ */ jsx("div", { className: `propeller-product-grid__grid ${gridClass} ${props.className ?? ""}`, children: items.map((item, idx) => {
9431
+ return /* @__PURE__ */ jsx("div", { className: cn(`propeller-product-grid__grid ${gridClass} ${props.className ?? ""}`), children: items.map((item, idx) => {
9331
9432
  const isCluster = "clusterId" in item && !!item.clusterId;
9332
9433
  const key = item.productId || item.clusterId || idx;
9333
9434
  return /* @__PURE__ */ jsxs(React6.Fragment, { children: [
@@ -9385,6 +9486,7 @@ ProductGridCompound.Pagination = ProductGridPagination;
9385
9486
  var ProductGrid_default = ProductGridCompound;
9386
9487
  function GridFilters(rawProps) {
9387
9488
  const props = useInfraProps(rawProps);
9489
+ const currencySymbol = props.currency ?? "\u20AC";
9388
9490
  const [selectedFilters, setSelectedFilters] = useState(
9389
9491
  () => ({ ...props.activeTextFilters || {} })
9390
9492
  );
@@ -9588,7 +9690,7 @@ function GridFilters(rawProps) {
9588
9690
  return /* @__PURE__ */ jsxs(
9589
9691
  "div",
9590
9692
  {
9591
- className: `propeller-grid-filters space-y-4 ${props.isMobile ? "pb-8" : "sticky top-24"} ${isPending ? "opacity-50 pointer-events-none" : ""} ${props.className || ""}`,
9693
+ className: cn(`propeller-grid-filters space-y-4 ${props.isMobile ? "pb-8" : "sticky top-24"} ${isPending ? "opacity-50 pointer-events-none" : ""} ${props.className || ""}`),
9592
9694
  "data-mobile": props.isMobile ? "true" : "false",
9593
9695
  "data-pending": isPending ? "true" : "false",
9594
9696
  children: [
@@ -9601,7 +9703,7 @@ function GridFilters(rawProps) {
9601
9703
  ] }),
9602
9704
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
9603
9705
  /* @__PURE__ */ jsxs("div", { className: "relative flex-1", children: [
9604
- /* @__PURE__ */ jsx("span", { className: "propeller-grid-filters__price-currency absolute left-2.5 top-1/2 -translate-y-1/2 text-xs text-foreground-subtle pointer-events-none", children: "\u20AC" }),
9706
+ /* @__PURE__ */ jsx("span", { className: "propeller-grid-filters__price-currency absolute left-2.5 top-1/2 -translate-y-1/2 text-xs text-foreground-subtle pointer-events-none", children: currencySymbol }),
9605
9707
  /* @__PURE__ */ jsx(
9606
9708
  "input",
9607
9709
  {
@@ -9620,7 +9722,7 @@ function GridFilters(rawProps) {
9620
9722
  ] }),
9621
9723
  /* @__PURE__ */ jsx("span", { className: "propeller-grid-filters__price-separator text-foreground-subtle text-sm select-none", children: "\u2013" }),
9622
9724
  /* @__PURE__ */ jsxs("div", { className: "relative flex-1", children: [
9623
- /* @__PURE__ */ jsx("span", { className: "propeller-grid-filters__price-currency absolute left-2.5 top-1/2 -translate-y-1/2 text-xs text-foreground-subtle pointer-events-none", children: "\u20AC" }),
9725
+ /* @__PURE__ */ jsx("span", { className: "propeller-grid-filters__price-currency absolute left-2.5 top-1/2 -translate-y-1/2 text-xs text-foreground-subtle pointer-events-none", children: currencySymbol }),
9624
9726
  /* @__PURE__ */ jsx(
9625
9727
  "input",
9626
9728
  {
@@ -9928,6 +10030,7 @@ var DEFAULT_LABELS = {
9928
10030
  };
9929
10031
  function GridToolbar(rawProps) {
9930
10032
  const props = useInfraProps(rawProps);
10033
+ const currencySymbol = props.currency ?? "\u20AC";
9931
10034
  const [currentSortField, setCurrentSortField] = useState(
9932
10035
  ProductSortField.CATEGORY_ORDER
9933
10036
  );
@@ -10012,7 +10115,7 @@ function GridToolbar(rawProps) {
10012
10115
  return /* @__PURE__ */ jsxs(
10013
10116
  "div",
10014
10117
  {
10015
- className: `propeller-grid-toolbar ${props.className || ""}`,
10118
+ className: cn(`propeller-grid-toolbar ${props.className || ""}`),
10016
10119
  "data-view-mode": currentViewMode,
10017
10120
  children: [
10018
10121
  /* @__PURE__ */ jsxs("div", { className: "propeller-grid-toolbar__bar flex flex-col sm:flex-row justify-between items-start sm:items-center gap-4 mb-4", children: [
@@ -10140,9 +10243,11 @@ function GridToolbar(rawProps) {
10140
10243
  },
10141
10244
  children: [
10142
10245
  getLabel59("price"),
10143
- ": \u20AC",
10246
+ ": ",
10247
+ currencySymbol,
10144
10248
  props.priceFilterMin ?? 0,
10145
- " \u2013 \u20AC",
10249
+ " \u2013 ",
10250
+ currencySymbol,
10146
10251
  props.priceFilterMax ?? "\u221E",
10147
10252
  /* @__PURE__ */ jsx("span", { className: "propeller-grid-toolbar__filter-badge-remove", children: "\xD7" })
10148
10253
  ]
@@ -10251,7 +10356,7 @@ function GridPagination(props) {
10251
10356
  return /* @__PURE__ */ jsx(
10252
10357
  "div",
10253
10358
  {
10254
- className: `propeller-grid-pagination ${props.className || ""}`,
10359
+ className: cn(`propeller-grid-pagination ${props.className || ""}`),
10255
10360
  "data-variant": variant,
10256
10361
  children: showPagination ? /* @__PURE__ */ jsxs(Fragment, { children: [
10257
10362
  variant === "compact" ? /* @__PURE__ */ jsxs("div", { className: "propeller-grid-pagination__compact flex justify-center items-center gap-2", children: [
@@ -10629,7 +10734,7 @@ function ClusterConfigurator(props) {
10629
10734
  initFromProduct(props.defaultProduct);
10630
10735
  }
10631
10736
  }, []);
10632
- return /* @__PURE__ */ jsx("div", { className: `propeller-cluster-configurator ${props.className || ""}`, children: !!props.config?.settings?.length ? /* @__PURE__ */ jsx("div", { className: "propeller-cluster-configurator__content flex flex-col gap-6", children: settingsWithValues?.map((setting) => /* @__PURE__ */ jsxs(
10737
+ return /* @__PURE__ */ jsx("div", { className: cn(`propeller-cluster-configurator ${props.className || ""}`), children: !!props.config?.settings?.length ? /* @__PURE__ */ jsx("div", { className: "propeller-cluster-configurator__content flex flex-col gap-6", children: settingsWithValues?.map((setting) => /* @__PURE__ */ jsxs(
10633
10738
  "div",
10634
10739
  {
10635
10740
  className: "propeller-cluster-configurator__group",
@@ -10778,7 +10883,7 @@ function ClusterInfo(rawProps) {
10778
10883
  props.onClusterLoaded(fetchedCluster);
10779
10884
  }
10780
10885
  }, [fetchedCluster]);
10781
- return /* @__PURE__ */ jsxs("div", { className: `propeller-cluster-info ${props.className || ""}`, "data-loading": loading ? "true" : "false", children: [
10886
+ return /* @__PURE__ */ jsxs("div", { className: cn(`propeller-cluster-info ${props.className || ""}`), "data-loading": loading ? "true" : "false", children: [
10782
10887
  loading && !props.cluster ? /* @__PURE__ */ jsxs("div", { className: "propeller-cluster-info__skeleton animate-pulse space-y-3", children: [
10783
10888
  /* @__PURE__ */ jsx("div", { className: "propeller-cluster-info__skeleton-line h-4 bg-surface-hover rounded w-1/4" }),
10784
10889
  /* @__PURE__ */ jsx("div", { className: "propeller-cluster-info__skeleton-line h-8 bg-surface-hover rounded w-3/4" })
@@ -10793,8 +10898,8 @@ function ClusterInfo(rawProps) {
10793
10898
  ] });
10794
10899
  }
10795
10900
  var ClusterInfo_default = ClusterInfo;
10796
- function formatPrice9(price, currency) {
10797
- return formatPrice(price, { symbol: currency });
10901
+ function formatPrice9(price, currency, language) {
10902
+ return formatPrice(price, { symbol: currency, locale: localeForLanguage(language) });
10798
10903
  }
10799
10904
  function getProductName2(product, language) {
10800
10905
  return getLocalizedValue(product.names, language, `Product ${product.productId}`);
@@ -10821,7 +10926,7 @@ function ClusterOptions(rawProps) {
10821
10926
  const products = (option.products || []).map((p) => ({
10822
10927
  productId: p.productId,
10823
10928
  productIdStr: p.productId.toString(),
10824
- label: hidePrices ? getProductName2(p, language) : `${getProductName2(p, language)} \u2014 ${formatPrice9(p.price?.gross || 0, props.currency ?? "\u20AC")}`
10929
+ label: hidePrices ? getProductName2(p, language) : `${getProductName2(p, language)} \u2014 ${formatPrice9(p.price?.gross || 0, props.currency ?? "\u20AC", language)}`
10825
10930
  }));
10826
10931
  let previewImageUrl = "";
10827
10932
  let previewName = "";
@@ -10833,7 +10938,7 @@ function ClusterOptions(rawProps) {
10833
10938
  if (selectedProduct) {
10834
10939
  previewImageUrl = getProductImageUrl4(selectedProduct);
10835
10940
  previewName = getProductName2(selectedProduct, language);
10836
- previewPrice = hidePrices ? "" : formatPrice9(selectedProduct.price?.gross || 0, props.currency ?? "\u20AC");
10941
+ previewPrice = hidePrices ? "" : formatPrice9(selectedProduct.price?.gross || 0, props.currency ?? "\u20AC", props.language);
10837
10942
  }
10838
10943
  }
10839
10944
  const isRequired = option.isRequired === YesNo.Y;
@@ -10869,7 +10974,7 @@ function ClusterOptions(rawProps) {
10869
10974
  }
10870
10975
  }
10871
10976
  const renderedOptions = getOptionsForRender();
10872
- return /* @__PURE__ */ jsx("div", { className: `propeller-cluster-options ${props.className || ""}`, children: renderedOptions.length > 0 ? /* @__PURE__ */ jsx("div", { className: "propeller-cluster-options__content flex flex-col gap-6", children: renderedOptions.map((option) => /* @__PURE__ */ jsxs(
10977
+ return /* @__PURE__ */ jsx("div", { className: cn(`propeller-cluster-options ${props.className || ""}`), children: renderedOptions.length > 0 ? /* @__PURE__ */ jsx("div", { className: "propeller-cluster-options__content flex flex-col gap-6", children: renderedOptions.map((option) => /* @__PURE__ */ jsxs(
10873
10978
  "div",
10874
10979
  {
10875
10980
  className: "propeller-cluster-options__group",
@@ -11322,7 +11427,7 @@ function FavoriteListItem(rawProps) {
11322
11427
  if (!priceObj) return "";
11323
11428
  const value = useTax ? priceObj.net : priceObj.gross;
11324
11429
  if (!value && value !== 0) return "";
11325
- return formatPrice(value, { symbol: currency });
11430
+ return formatPrice(value, { symbol: currency, locale: localeForLanguage(props.language) });
11326
11431
  })();
11327
11432
  function handleItemClick(e) {
11328
11433
  if (props.onItemClick) {
@@ -11362,7 +11467,7 @@ function FavoriteListItem(rawProps) {
11362
11467
  {
11363
11468
  onClick: (e) => handleItemClick(e),
11364
11469
  "data-type": isProduct ? "product" : "cluster",
11365
- className: `propeller-favorite-list-item flex flex-row items-center gap-4 rounded-container border border-border bg-card p-4 transition-colors hover:border-secondary/20 hover:shadow-sm cursor-pointer ${props.className || ""}`,
11470
+ className: cn(`propeller-favorite-list-item flex flex-row items-center gap-4 rounded-container border border-border bg-card p-4 transition-colors hover:border-secondary/20 hover:shadow-sm cursor-pointer ${props.className || ""}`),
11366
11471
  children: rawProps.children
11367
11472
  }
11368
11473
  ) });
@@ -11372,7 +11477,7 @@ function FavoriteListItem(rawProps) {
11372
11477
  {
11373
11478
  onClick: (e) => handleItemClick(e),
11374
11479
  "data-type": isProduct ? "product" : "cluster",
11375
- className: `propeller-favorite-list-item flex flex-row items-center gap-4 rounded-container border border-border bg-card p-4 transition-colors hover:border-secondary/20 hover:shadow-sm cursor-pointer ${props.className || ""}`,
11480
+ className: cn(`propeller-favorite-list-item flex flex-row items-center gap-4 rounded-container border border-border bg-card p-4 transition-colors hover:border-secondary/20 hover:shadow-sm cursor-pointer ${props.className || ""}`),
11376
11481
  children: [
11377
11482
  /* @__PURE__ */ jsx(FavoriteListItemImage, {}),
11378
11483
  /* @__PURE__ */ jsxs("div", { className: "propeller-favorite-list-item__body flex flex-col gap-0.5 min-w-0 flex-1", children: [
@@ -11886,7 +11991,7 @@ function FavoriteListDetails(rawProps) {
11886
11991
  fetchList();
11887
11992
  }
11888
11993
  }, [props.favoriteListId]);
11889
- return /* @__PURE__ */ jsxs("div", { className: `propeller-favorite-list-details ${props.className || ""}`, "data-loading": loading ? "true" : "false", children: [
11994
+ return /* @__PURE__ */ jsxs("div", { className: cn(`propeller-favorite-list-details ${props.className || ""}`), "data-loading": loading ? "true" : "false", children: [
11890
11995
  loading ? /* @__PURE__ */ jsx("div", { className: "propeller-favorite-list-details__skeleton space-y-4", children: [1, 2, 3]?.map((i) => /* @__PURE__ */ jsxs(
11891
11996
  "div",
11892
11997
  {
@@ -12331,7 +12436,7 @@ function FavoriteLists(rawProps) {
12331
12436
  setNewSetAsDefault(false);
12332
12437
  closeCreateModal();
12333
12438
  }
12334
- return /* @__PURE__ */ jsxs("div", { className: `propeller-favorite-lists ${props.className || ""}`, "data-loading": loading ? "true" : "false", children: [
12439
+ return /* @__PURE__ */ jsxs("div", { className: cn(`propeller-favorite-lists ${props.className || ""}`), "data-loading": loading ? "true" : "false", children: [
12335
12440
  props.allowFavoriteListCreate !== false && !loading && displayedLists.length > 0 ? /* @__PURE__ */ jsx("div", { className: "propeller-favorite-lists__toolbar flex justify-end mb-4", children: /* @__PURE__ */ jsxs(
12336
12441
  "button",
12337
12442
  {
@@ -12854,7 +12959,7 @@ function ForgotPassword(rawProps) {
12854
12959
  }
12855
12960
  var ForgotPassword_default = ForgotPassword;
12856
12961
  function GridTitle(props) {
12857
- return /* @__PURE__ */ jsx("div", { className: `propeller-grid-title mb-8 ${props.className || ""}`, children: /* @__PURE__ */ jsxs("div", { className: "propeller-grid-title__row flex items-baseline gap-3 mb-3", children: [
12962
+ return /* @__PURE__ */ jsx("div", { className: cn(`propeller-grid-title mb-8 ${props.className || ""}`), children: /* @__PURE__ */ jsxs("div", { className: "propeller-grid-title__row flex items-baseline gap-3 mb-3", children: [
12858
12963
  props.headingLevel === "h2" ? /* @__PURE__ */ jsx("h2", { className: "propeller-grid-title__heading text-3xl sm:text-4xl font-bold tracking-tight", children: props.title }) : null,
12859
12964
  props.headingLevel !== "h2" ? /* @__PURE__ */ jsx("h1", { className: "propeller-grid-title__heading text-3xl sm:text-4xl font-bold tracking-tight", children: props.title }) : null
12860
12965
  ] }) });
@@ -12897,12 +13002,12 @@ function ItemsOverview(rawProps) {
12897
13002
  const showPrice = props.showPrice !== void 0 ? props.showPrice : true;
12898
13003
  const items = props.cart?.items ?? [];
12899
13004
  const currencySymbol = props.currency ?? "\u20AC";
12900
- const money = (value) => value === void 0 || value === null ? "" : formatPrice(value, { symbol: currencySymbol });
13005
+ const money = (value) => value === void 0 || value === null ? "" : formatPrice(value, { symbol: currencySymbol, locale: localeForLanguage(props.language) });
12901
13006
  function formatItemPrice(price) {
12902
13007
  if (props.formatPrice) {
12903
13008
  return props.formatPrice(price);
12904
13009
  }
12905
- return formatPrice(price || 0, { symbol: currencySymbol });
13010
+ return formatPrice(price || 0, { symbol: currencySymbol, locale: localeForLanguage(props.language) });
12906
13011
  }
12907
13012
  function lineTotal(item) {
12908
13013
  return (useTax ? item.totalSumNet : item.totalSum) || 0;
@@ -13261,7 +13366,7 @@ function Menu(rawProps) {
13261
13366
  return /* @__PURE__ */ jsx(
13262
13367
  "div",
13263
13368
  {
13264
- className: `propeller-menu ${props.className || ""}`,
13369
+ className: cn(`propeller-menu ${props.className || ""}`),
13265
13370
  "data-variant": props.menuStyle || "custom",
13266
13371
  "data-loading": isLoading ? "true" : "false",
13267
13372
  children: customMenu
@@ -13271,7 +13376,7 @@ function Menu(rawProps) {
13271
13376
  return /* @__PURE__ */ jsxs(
13272
13377
  "div",
13273
13378
  {
13274
- className: `propeller-menu ${props.className || ""}`,
13379
+ className: cn(`propeller-menu ${props.className || ""}`),
13275
13380
  "data-variant": getMenuStyle(),
13276
13381
  "data-loading": isLoading ? "true" : "false",
13277
13382
  children: [
@@ -13417,7 +13522,7 @@ function OrderActions(rawProps) {
13417
13522
  // (the bug screenshot showed "Order / confirmation / (PDF)" on three lines).
13418
13523
  // `whitespace-nowrap` on the buttons is the belt-and-braces guarantee that
13419
13524
  // text never wraps even in narrow containers without flex sizing.
13420
- /* @__PURE__ */ jsxs("div", { className: `propeller-order-actions flex-shrink-0 ${props.className || ""}`, children: [
13525
+ /* @__PURE__ */ jsxs("div", { className: cn(`propeller-order-actions flex-shrink-0 ${props.className || ""}`), children: [
13421
13526
  /* @__PURE__ */ jsxs("div", { className: "propeller-order-actions__actions flex flex-row items-center gap-3 flex-shrink-0", children: [
13422
13527
  /* @__PURE__ */ jsxs(
13423
13528
  "button",
@@ -13505,20 +13610,21 @@ var OrderActions_default = OrderActions;
13505
13610
  function getProductName3(orderItem, language) {
13506
13611
  return getLocalizedValue(orderItem?.product?.names, language, "") || orderItem?.name || "Unknown Product";
13507
13612
  }
13508
- function getClusterUrl(orderItem, language) {
13613
+ function getClusterUrl(orderItem, language, urls) {
13509
13614
  const cluster = orderItem?.product?.cluster;
13510
13615
  if (!cluster) return "";
13511
13616
  const id = cluster.clusterId;
13512
13617
  const slug = getLocalizedValue(cluster.slugs, language, "");
13513
13618
  if (!id || !slug) return "";
13514
- return `/cluster/${id}/${slug}`;
13619
+ return urls?.getClusterUrl?.(cluster, language) || `/cluster/${id}/${slug}`;
13515
13620
  }
13516
- function getProductUrl(orderItem, language) {
13517
- const cu = getClusterUrl(orderItem, language);
13621
+ function getProductUrl(orderItem, language, urls) {
13622
+ const cu = getClusterUrl(orderItem, language, urls);
13518
13623
  if (cu) return cu;
13519
- const id = orderItem?.product?.productId;
13520
- const slug = getLocalizedValue(orderItem?.product?.slugs, language, "");
13521
- if (id && slug) return `/product/${id}/${slug}`;
13624
+ const product = orderItem?.product;
13625
+ const id = product?.productId;
13626
+ const slug = getLocalizedValue(product?.slugs, language, "");
13627
+ if (id && slug) return urls?.getProductUrl?.(product, language) || `/product/${id}/${slug}`;
13522
13628
  return "";
13523
13629
  }
13524
13630
  function OrderItemCard(props) {
@@ -13535,7 +13641,7 @@ function OrderItemCard(props) {
13535
13641
  const productName = getProductName3(item, props.language);
13536
13642
  const productSku = item?.product?.sku || item?.sku || "";
13537
13643
  const productImage = item?.product?.media?.images?.items?.[0]?.imageVariants?.[0]?.url || "";
13538
- const productUrl = getProductUrl(item, props.language);
13644
+ const productUrl = getProductUrl(item, props.language, props.configuration?.urls);
13539
13645
  const quantity = item?.quantity || 0;
13540
13646
  const priceTotal = item?.priceTotal || 0;
13541
13647
  const discount = item?.discount || 0;
@@ -13548,7 +13654,7 @@ function OrderItemCard(props) {
13548
13654
  return props.formatPrice(price);
13549
13655
  }
13550
13656
  if (!price && price !== 0) return "-";
13551
- return formatPrice(price, { symbol: props.currency ?? "\u20AC" });
13657
+ return formatPrice(price, { symbol: props.currency ?? "\u20AC", locale: localeForLanguage(props.language) });
13552
13658
  }
13553
13659
  const discountDisplay = discountPercentage > 0 ? `${formatItemPrice(discount)} (${discountPercentage.toFixed(2).replace(".", ",")}%)` : formatItemPrice(discount);
13554
13660
  return /* @__PURE__ */ jsxs("tbody", { className: "propeller-order-item-card", children: [
@@ -13667,7 +13773,7 @@ function OrderBonusItems(rawProps) {
13667
13773
  const bonusItems = getNettedBonusItems(allItems);
13668
13774
  if (bonusItems.length === 0) return null;
13669
13775
  const OrderItemCardImpl = props.orderItemCardComponent ?? OrderItemCard_default;
13670
- return /* @__PURE__ */ jsxs("div", { className: `propeller-order-bonus-items ${props.className || "mb-8"}`, children: [
13776
+ return /* @__PURE__ */ jsxs("div", { className: cn(`propeller-order-bonus-items ${props.className || "mb-8"}`), children: [
13671
13777
  /* @__PURE__ */ jsx("h3", { className: "propeller-order-bonus-items__title text-lg font-bold mb-3 text-foreground", children: getLabel(props.labels, "title", "Bonus items") }),
13672
13778
  /* @__PURE__ */ jsx("div", { className: "propeller-order-bonus-items__table bg-card rounded-container shadow overflow-hidden", children: /* @__PURE__ */ jsx("table", { className: "w-full", children: bonusItems.map((item) => /* @__PURE__ */ jsx(
13673
13779
  OrderItemCardImpl,
@@ -13713,7 +13819,7 @@ function OrderList(rawProps) {
13713
13819
  function formatPrice17(price) {
13714
13820
  if (props.formatPrice) return props.formatPrice(price);
13715
13821
  if (!price) return "-";
13716
- return formatPrice(price, { symbol: props.currency ?? "\u20AC" });
13822
+ return formatPrice(price, { symbol: props.currency ?? "\u20AC", locale: localeForLanguage(props.language) });
13717
13823
  }
13718
13824
  function getStatusColor(status) {
13719
13825
  if (props.getStatusColor) return props.getStatusColor(status);
@@ -13757,7 +13863,7 @@ function OrderList(rawProps) {
13757
13863
  }
13758
13864
  return fields;
13759
13865
  }
13760
- return /* @__PURE__ */ jsxs("div", { className: `propeller-order-list ${props.className || ""}`, "data-loading": loading ? "true" : "false", children: [
13866
+ return /* @__PURE__ */ jsxs("div", { className: cn(`propeller-order-list ${props.className || ""}`), "data-loading": loading ? "true" : "false", children: [
13761
13867
  props.enableSearch && searchFields().length > 0 ? /* @__PURE__ */ jsxs("div", { className: "propeller-order-list__filters mb-6 bg-card p-4 rounded-container shadow space-y-4", children: [
13762
13868
  searchFields().includes("term") ? /* @__PURE__ */ jsxs("div", { className: "propeller-order-list__search-field w-full", children: [
13763
13869
  /* @__PURE__ */ jsx("label", { className: "propeller-order-list__filter-label block text-sm font-medium text-muted-foreground capitalize mb-1", children: getColumnLabel("term") }),
@@ -14142,7 +14248,31 @@ function OrderList(rawProps) {
14142
14248
  ) })
14143
14249
  ] })
14144
14250
  ] }) : null
14145
- ] }) : /* @__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...") })
14251
+ ] }) : /* @__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.") }) }) }) : (
14252
+ // A centred line of text collapsed the list to one row and then
14253
+ // snapped back, which is what made a language switch on the account
14254
+ // pages look broken. Skeleton rows hold the layout instead.
14255
+ /* @__PURE__ */ jsx(
14256
+ "div",
14257
+ {
14258
+ className: `propeller-order-list__loading${props.flat ? "" : " bg-card rounded-container shadow"} p-4`,
14259
+ "aria-busy": "true",
14260
+ "aria-label": getLabel(props.labels, "loading", "Loading orders..."),
14261
+ children: Array.from({ length: 3 }).map((_, index) => /* @__PURE__ */ jsxs(
14262
+ "div",
14263
+ {
14264
+ className: "propeller-order-list__skeleton-row flex items-center gap-4 py-4 border-b border-border last:border-b-0 animate-pulse",
14265
+ children: [
14266
+ /* @__PURE__ */ jsx("div", { className: "propeller-order-list__skeleton-line h-4 bg-surface-hover rounded w-24" }),
14267
+ /* @__PURE__ */ jsx("div", { className: "propeller-order-list__skeleton-line h-4 bg-surface-hover rounded w-32" }),
14268
+ /* @__PURE__ */ jsx("div", { className: "propeller-order-list__skeleton-line h-4 bg-surface-hover rounded w-20 ml-auto" })
14269
+ ]
14270
+ },
14271
+ index
14272
+ ))
14273
+ }
14274
+ )
14275
+ )
14146
14276
  ] });
14147
14277
  }
14148
14278
  var OrderList_default = OrderList;
@@ -14183,7 +14313,7 @@ function QuickOrderInner(props) {
14183
14313
  } = props;
14184
14314
  const user = props.user ?? null;
14185
14315
  const graphqlClient = props.graphqlClient;
14186
- const displayPrice = (n) => props.formatPrice ? props.formatPrice(n) : formatPrice(n, { symbol: currency });
14316
+ const displayPrice = (n) => props.formatPrice ? props.formatPrice(n) : formatPrice(n, { symbol: currency, locale: localeForLanguage(props.language) });
14187
14317
  const L = (key, fallback) => getLabel(labels, key, fallback);
14188
14318
  const { submitting, searchProducts, submit } = useQuickOrder({
14189
14319
  graphqlClient,
@@ -14347,6 +14477,7 @@ function QuickOrderInner(props) {
14347
14477
  target: "_blank",
14348
14478
  rel: "noopener nofollow",
14349
14479
  className: "text-primary hover:underline text-sm inline-block mb-4",
14480
+ onClick: () => props.onTemplateDownload?.(),
14350
14481
  children: L("downloadTemplate", "Download XLSX template")
14351
14482
  }
14352
14483
  ) : null,
@@ -14510,7 +14641,7 @@ function OrderShipments(props) {
14510
14641
  const code = tat.code || "";
14511
14642
  return `${baseUrl}${code}`;
14512
14643
  }
14513
- return /* @__PURE__ */ jsxs("div", { className: `order-shipments ${props.className || ""}`, children: [
14644
+ return /* @__PURE__ */ jsxs("div", { className: cn(`order-shipments ${props.className || ""}`), children: [
14514
14645
  shipments.length > 0 ? /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
14515
14646
  /* @__PURE__ */ jsx("h2", { className: "text-xl font-semibold", children: getLabel(props.labels, "title", "Shipping details") }),
14516
14647
  /* @__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: [
@@ -14716,7 +14847,7 @@ function OrderSummary(props) {
14716
14847
  if (props.formatPrice) {
14717
14848
  return props.formatPrice(price);
14718
14849
  }
14719
- return formatPrice(price || 0, { symbol: props.currency ?? "\u20AC" });
14850
+ return formatPrice(price || 0, { symbol: props.currency ?? "\u20AC", locale: localeForLanguage(props.language) });
14720
14851
  }
14721
14852
  function numericDate(dateString) {
14722
14853
  const d = new Date(dateString);
@@ -14824,7 +14955,7 @@ function OrderTotals(props) {
14824
14955
  const postageData = props.order?.postageData;
14825
14956
  function formatItemPrice(price) {
14826
14957
  if (props.formatPrice) return props.formatPrice(price);
14827
- return formatPrice(price || 0, { symbol: props.currency ?? "\u20AC" });
14958
+ return formatPrice(price || 0, { symbol: props.currency ?? "\u20AC", locale: localeForLanguage(props.language) });
14828
14959
  }
14829
14960
  const subtotal = total?.gross || 0;
14830
14961
  const hasDiscount = !!total && total.discountType !== OrderDiscountType.N && total.discountValue > 0;
@@ -14911,7 +15042,7 @@ function PriceToggle(props) {
14911
15042
  return /* @__PURE__ */ jsxs(
14912
15043
  "div",
14913
15044
  {
14914
- className: `propeller-price-toggle flex items-center gap-2 ${props.className || ""}`,
15045
+ className: cn(`propeller-price-toggle flex items-center gap-2 ${props.className || ""}`),
14915
15046
  "data-state": isOn ? "on" : "off",
14916
15047
  children: [
14917
15048
  /* @__PURE__ */ jsx("span", { className: "propeller-price-toggle__label hidden sm:inline text-xs", children: label }),
@@ -14989,7 +15120,7 @@ function ProductBulkPrices(props) {
14989
15120
  function getPrice(tier) {
14990
15121
  const value = includeTax ? tier.net : tier.gross;
14991
15122
  if (value === null || value === void 0) return "";
14992
- return formatPrice(value, { symbol: props.currency ?? "\u20AC" });
15123
+ return formatPrice(value, { symbol: props.currency ?? "\u20AC", locale: localeForLanguage(props.language) });
14993
15124
  }
14994
15125
  function getQuantityLabel(tier, index) {
14995
15126
  const discount = tier.discount;
@@ -15000,13 +15131,14 @@ function ProductBulkPrices(props) {
15000
15131
  if (nextQty) return `${qty}\u2013${nextQty - 1}`;
15001
15132
  return `${qty}+`;
15002
15133
  }
15134
+ const title = props.labels?.title ?? "Volume pricing";
15003
15135
  return /* @__PURE__ */ jsx(Fragment, { children: !isHidden2 && hasItems ? /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsxs(
15004
15136
  "div",
15005
15137
  {
15006
- className: `propeller-product-bulk-prices ${props.className || ""}`,
15138
+ className: cn(`propeller-product-bulk-prices ${props.className || ""}`),
15007
15139
  "data-include-tax": includeTax ? "true" : "false",
15008
15140
  children: [
15009
- getLabel(props.labels, "title", "Volume pricing") ? /* @__PURE__ */ jsx("h3", { className: "propeller-product-bulk-prices__title text-base font-semibold text-foreground mb-3", children: getLabel(props.labels, "title", "Volume pricing") }) : null,
15141
+ title ? /* @__PURE__ */ jsx("h3", { className: "propeller-product-bulk-prices__title text-base font-semibold text-foreground mb-3", children: title }) : null,
15010
15142
  /* @__PURE__ */ jsx("div", { className: "propeller-product-bulk-prices__table-wrapper overflow-hidden rounded-container border border-border", children: /* @__PURE__ */ jsxs("table", { className: "propeller-product-bulk-prices__table w-full text-sm", children: [
15011
15143
  /* @__PURE__ */ jsx("thead", { className: "propeller-product-bulk-prices__thead bg-muted/50", children: /* @__PURE__ */ jsxs("tr", { children: [
15012
15144
  /* @__PURE__ */ jsx("th", { className: "propeller-product-bulk-prices__th propeller-product-bulk-prices__th--quantity px-4 py-2 text-left font-medium text-muted-foreground", children: getLabel(props.labels, "quantityFrom", "Qty from") }),
@@ -15053,7 +15185,7 @@ function ProductBundles(rawProps) {
15053
15185
  const props = useInfraProps(rawProps);
15054
15186
  const language = props.language;
15055
15187
  const currencySymbol = props.currency ?? "\u20AC";
15056
- const money = (value) => formatPrice(value, { symbol: currencySymbol });
15188
+ const money = (value) => formatPrice(value, { symbol: currencySymbol, locale: localeForLanguage(props.language) });
15057
15189
  const [isMounted, setIsMounted] = useState(false);
15058
15190
  const [addingBundleId, setAddingBundleId] = useState(null);
15059
15191
  const [lastAddedBundle, setLastAddedBundle] = useState(null);
@@ -15150,7 +15282,7 @@ function ProductBundles(rawProps) {
15150
15282
  useEffect(() => {
15151
15283
  fetchBundles(props.productId);
15152
15284
  }, [props.productId]);
15153
- return /* @__PURE__ */ jsx(Fragment, { children: isMounted && !isLoading && bundles.length > 0 ? /* @__PURE__ */ jsxs("div", { className: `propeller-product-bundles ${props.className || "mb-12"}`, children: [
15285
+ return /* @__PURE__ */ jsx(Fragment, { children: isMounted && !isLoading && bundles.length > 0 ? /* @__PURE__ */ jsxs("div", { className: cn(`propeller-product-bundles ${props.className || "mb-12"}`), children: [
15154
15286
  bundles.map((bundle, bundleIdx) => {
15155
15287
  const bundlePrice = getBundlePrice(bundle, includeTax);
15156
15288
  const originalPrice = getOriginalPrice(bundle, includeTax);
@@ -15244,7 +15376,7 @@ function ProductBundles(rawProps) {
15244
15376
  onClick: () => handleAddToCart(bundle),
15245
15377
  disabled: addingBundleId === bundle.id,
15246
15378
  "data-loading": addingBundleId === bundle.id ? "true" : "false",
15247
- children: addingBundleId === bundle.id ? getLabel(props.labels, "adding", "Adding...") : getLabel(props.labels, "addToCart", "In cart")
15379
+ children: addingBundleId === bundle.id ? getLabel(props.labels, "adding", "Adding...") : getLabel(props.labels, "addToCart", "Add to cart")
15248
15380
  }
15249
15381
  )
15250
15382
  ] }) : props.showLoginPrompt !== false ? /* @__PURE__ */ jsx("div", { className: "propeller-product-bundles__login-prompt text-center text-sm text-muted-foreground py-2", children: getLabel(
@@ -15449,7 +15581,7 @@ function ProductDescription(props) {
15449
15581
  return /* @__PURE__ */ jsx(Fragment, { children: !!html ? /* @__PURE__ */ jsxs(
15450
15582
  "div",
15451
15583
  {
15452
- className: `propeller-product-description ${props.className || ""}`,
15584
+ className: cn(`propeller-product-description ${props.className || ""}`),
15453
15585
  "data-expanded": expanded ? "true" : "false",
15454
15586
  "data-truncatable": shouldTruncate ? "true" : "false",
15455
15587
  children: [
@@ -15488,7 +15620,7 @@ function ProductDownloads(props) {
15488
15620
  const match = alts.find((a) => a.language === lang);
15489
15621
  return match?.value || alts?.[0]?.value || "Download";
15490
15622
  }
15491
- return /* @__PURE__ */ jsxs("div", { className: `propeller-product-downloads ${props.className || ""}`, children: [
15623
+ return /* @__PURE__ */ jsxs("div", { className: cn(`propeller-product-downloads ${props.className || ""}`), children: [
15492
15624
  hasItems ? /* @__PURE__ */ jsx("h3", { className: "propeller-product-downloads__title text-base font-semibold text-foreground mb-3", children: getLabel(props.labels, "title", "Downloads") }) : null,
15493
15625
  hasItems ? /* @__PURE__ */ jsx("ul", { className: "propeller-product-downloads__list space-y-2", children: items.map((doc, index) => /* @__PURE__ */ jsx("li", { className: "propeller-product-downloads__item", children: !!getDocumentUrl(doc) ? /* @__PURE__ */ jsxs(
15494
15626
  "a",
@@ -15559,7 +15691,7 @@ function ProductGallery(props) {
15559
15691
  if (images.length === 0) return;
15560
15692
  setSelectedIndex((idx) => (idx + 1) % images.length);
15561
15693
  }
15562
- return /* @__PURE__ */ jsxs("div", { className: `propeller-product-gallery ${props.className || ""}`, children: [
15694
+ return /* @__PURE__ */ jsxs("div", { className: cn(`propeller-product-gallery ${props.className || ""}`), children: [
15563
15695
  /* @__PURE__ */ jsxs("div", { className: "propeller-product-gallery__stage relative aspect-square bg-card overflow-hidden", children: [
15564
15696
  images.length === 0 ? /* @__PURE__ */ jsx("div", { className: "propeller-product-gallery__empty flex h-full w-full items-center justify-center bg-surface-hover", children: /* @__PURE__ */ jsx(
15565
15697
  "svg",
@@ -15894,13 +16026,13 @@ function ProductInfo(rawProps) {
15894
16026
  }
15895
16027
  };
15896
16028
  if (rawProps.children !== void 0) {
15897
- return /* @__PURE__ */ jsx(ProductInfoContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsx(ProductGridConfigProvider, { value: pdpConfig, children: /* @__PURE__ */ jsxs("div", { className: `propeller-product-info ${props.className || ""}`, children: [
16029
+ return /* @__PURE__ */ jsx(ProductInfoContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsx(ProductGridConfigProvider, { value: pdpConfig, children: /* @__PURE__ */ jsxs("div", { className: cn(`propeller-product-info ${props.className || ""}`), children: [
15898
16030
  props.beforeContent ? props.beforeContent(product) : null,
15899
16031
  rawProps.children,
15900
16032
  props.afterContent ? props.afterContent(product) : null
15901
16033
  ] }) }) });
15902
16034
  }
15903
- return /* @__PURE__ */ jsx(ProductInfoContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsx(ProductGridConfigProvider, { value: pdpConfig, children: /* @__PURE__ */ jsxs("div", { className: `propeller-product-info ${props.className || ""}`, children: [
16035
+ return /* @__PURE__ */ jsx(ProductInfoContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsx(ProductGridConfigProvider, { value: pdpConfig, children: /* @__PURE__ */ jsxs("div", { className: cn(`propeller-product-info ${props.className || ""}`), children: [
15904
16036
  props.beforeContent ? props.beforeContent(product) : null,
15905
16037
  /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-6", children: [
15906
16038
  /* @__PURE__ */ jsxs("div", { className: "propeller-product-info__media relative", children: [
@@ -15922,7 +16054,7 @@ function ProductInfo(rawProps) {
15922
16054
  props.afterContent ? props.afterContent(product) : null
15923
16055
  ] }) }) });
15924
16056
  }
15925
- return /* @__PURE__ */ jsxs("div", { className: `propeller-product-info ${props.className || ""}`, "data-loading": loading ? "true" : "false", children: [
16057
+ return /* @__PURE__ */ jsxs("div", { className: cn(`propeller-product-info ${props.className || ""}`), "data-loading": loading ? "true" : "false", children: [
15926
16058
  loading && !props.product ? /* @__PURE__ */ jsxs("div", { className: "propeller-product-info__skeleton animate-pulse space-y-3", children: [
15927
16059
  /* @__PURE__ */ jsx("div", { className: "propeller-product-info__skeleton-line h-4 bg-surface-hover rounded w-1/4" }),
15928
16060
  /* @__PURE__ */ jsx("div", { className: "propeller-product-info__skeleton-line h-8 bg-surface-hover rounded w-3/4" })
@@ -16198,7 +16330,7 @@ function ProductShortDescription(props) {
16198
16330
  "div",
16199
16331
  {
16200
16332
  dangerouslySetInnerHTML: { __html: html },
16201
- className: `propeller-product-short-description prose prose-slate max-w-none text-muted-foreground ${props.className || ""}`
16333
+ className: cn(`propeller-product-short-description prose prose-slate max-w-none text-muted-foreground ${props.className || ""}`)
16202
16334
  }
16203
16335
  ) : null });
16204
16336
  }
@@ -16365,7 +16497,7 @@ function ProductSlider(rawProps) {
16365
16497
  }, [sliderId, items().length]);
16366
16498
  return /* @__PURE__ */ jsxs(Fragment, { children: [
16367
16499
  " ",
16368
- !(isCrossUpsellMode() && !isLoading && items().length === 0) ? /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsxs("div", { className: `propeller-product-slider ${props.containerClassName || "mb-12"}`, "data-loading": isLoading ? "true" : "false", children: [
16500
+ !(isCrossUpsellMode() && !isLoading && items().length === 0) ? /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsxs("div", { className: cn(`propeller-product-slider ${props.containerClassName || "mb-12"}`), "data-loading": isLoading ? "true" : "false", children: [
16369
16501
  sliderTitle() || items().length > 0 ? /* @__PURE__ */ jsxs("div", { className: "propeller-product-slider__header flex items-center justify-between mb-6", children: [
16370
16502
  sliderTitle() ? /* @__PURE__ */ jsx("h2", { className: "propeller-product-slider__title text-2xl font-bold", children: sliderTitle() }) : null,
16371
16503
  items().length > desktopCount() ? /* @__PURE__ */ jsxs("div", { className: "propeller-product-slider__nav flex gap-2", children: [
@@ -16553,7 +16685,7 @@ function ProductSpecifications(rawProps) {
16553
16685
  return /* @__PURE__ */ jsx(Fragment, { children: !loading && (hasPublicAttributes() || props.packageDescription || hasSlotContent) ? /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsxs(
16554
16686
  "div",
16555
16687
  {
16556
- className: `propeller-product-specifications ${props.className || ""}`,
16688
+ className: cn(`propeller-product-specifications ${props.className || ""}`),
16557
16689
  "data-layout": props.layout === "list" ? "list" : "table",
16558
16690
  "data-grouped": props.grouping ? "true" : "false",
16559
16691
  children: [
@@ -16634,7 +16766,7 @@ function ProductVideos(props) {
16634
16766
  }
16635
16767
  return uri;
16636
16768
  }
16637
- return /* @__PURE__ */ jsxs("div", { className: `propeller-product-videos ${props.className || ""}`, children: [
16769
+ return /* @__PURE__ */ jsxs("div", { className: cn(`propeller-product-videos ${props.className || ""}`), children: [
16638
16770
  hasItems ? /* @__PURE__ */ jsx("h3", { className: "propeller-product-videos__title text-base font-semibold text-foreground mb-3", children: getLabel(props.labels, "title", "Videos") }) : null,
16639
16771
  hasItems ? /* @__PURE__ */ jsx("div", { className: "propeller-product-videos__list space-y-4", children: items.map((video, index) => /* @__PURE__ */ jsx(
16640
16772
  "div",
@@ -16732,7 +16864,7 @@ function ProductTabs(rawProps) {
16732
16864
  return /* @__PURE__ */ jsx(Fragment, { children: props.product ? /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsxs(
16733
16865
  "div",
16734
16866
  {
16735
- className: `propeller-product-tabs ${props.className || ""}`,
16867
+ className: cn(`propeller-product-tabs ${props.className || ""}`),
16736
16868
  "data-active-tab": activeTab,
16737
16869
  children: [
16738
16870
  /* @__PURE__ */ jsxs("div", { className: "propeller-product-tabs__desktop hidden md:block", children: [
@@ -17038,7 +17170,7 @@ function PurchaseAuthorizationConfigurator(rawProps) {
17038
17170
  onPurchaseAuthorizationDelete: props.onPurchaseAuthorizationDelete,
17039
17171
  afterPurchaseAuthorizationDelete: props.afterPurchaseAuthorizationDelete
17040
17172
  });
17041
- return /* @__PURE__ */ jsx("div", { className: `propeller-purchase-authorization-configurator ${props.className || ""}`, children: isAuthManager ? /* @__PURE__ */ jsxs(Fragment, { children: [
17173
+ return /* @__PURE__ */ jsx("div", { className: cn(`propeller-purchase-authorization-configurator ${props.className || ""}`), children: isAuthManager ? /* @__PURE__ */ jsxs(Fragment, { children: [
17042
17174
  /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
17043
17175
  /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
17044
17176
  /* @__PURE__ */ jsx("h2", { className: "text-xl font-semibold", children: getLabel(props.labels, "title", "Purchase Authorization Settings") }),
@@ -17383,7 +17515,7 @@ function PurchaseAuthorizationRequests(rawProps) {
17383
17515
  }
17384
17516
  function formatPrice17(price) {
17385
17517
  if (props.formatPrice) return props.formatPrice(price);
17386
- return formatPrice(price, { symbol: props.currency ?? "\u20AC" });
17518
+ return formatPrice(price, { symbol: props.currency ?? "\u20AC", locale: localeForLanguage(props.language) });
17387
17519
  }
17388
17520
  const columnLabelKeys = {
17389
17521
  date: ["colDate", "Date"],
@@ -17405,7 +17537,7 @@ function PurchaseAuthorizationRequests(rawProps) {
17405
17537
  if (fromBundle) return fromBundle;
17406
17538
  return item?.product?.sku || "";
17407
17539
  }
17408
- 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: [
17540
+ return /* @__PURE__ */ jsx("div", { className: cn(`propeller-purchase-authorization-requests ${props.className || ""}`), children: isAuthManager ? /* @__PURE__ */ jsxs("div", { className: "propeller-purchase-authorization-requests__content space-y-4", children: [
17409
17541
  !props.hideTitle ? /* @__PURE__ */ jsx("h2", { className: "propeller-purchase-authorization-requests__title text-xl font-semibold", children: getLabel(props.labels, "title", "Authorization Requests") }) : null,
17410
17542
  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,
17411
17543
  !loading ? /* @__PURE__ */ jsxs(Fragment, { children: [
@@ -18604,12 +18736,12 @@ function RegisterForm(rawProps) {
18604
18736
  ] });
18605
18737
  }
18606
18738
  var RegisterForm_default = RegisterForm;
18607
- function mapToSearchBarResult(item, language) {
18739
+ function mapToSearchBarResult(item, language, urls) {
18608
18740
  const isCluster = "clusterId" in item;
18609
18741
  const displayItem = isCluster ? item.defaultProduct : item;
18610
18742
  const id = isCluster ? item.clusterId : item.productId;
18611
18743
  const slug = getLocalizedValue(item.slugs, language, "");
18612
- const url = isCluster ? "/cluster/" + id + "/" + slug : "/product/" + id + "/" + slug;
18744
+ const url = isCluster ? urls?.getClusterUrl?.(item, language) || "/cluster/" + id + "/" + slug : urls?.getProductUrl?.(item, language) || "/product/" + id + "/" + slug;
18613
18745
  const priceNet = displayItem?.price?.net || 0;
18614
18746
  const priceGross = displayItem?.price?.gross || 0;
18615
18747
  const localizedName = language && item.names?.find((n) => n.language === language)?.value || item.names?.[0]?.value || "Product";
@@ -18649,13 +18781,19 @@ function SearchBar(rawProps) {
18649
18781
  applyOrderlists: props.applyOrderlists,
18650
18782
  productTrackAttributes: props.productTrackAttributes
18651
18783
  });
18652
- const results = searchResults.slice(0, maxResults).map((item) => mapToSearchBarResult(item, props.language));
18784
+ const results = searchResults.slice(0, maxResults).map(
18785
+ (item) => mapToSearchBarResult(
18786
+ item,
18787
+ props.language,
18788
+ props.configuration?.urls
18789
+ )
18790
+ );
18653
18791
  const itemsFound = searchItemsFound;
18654
18792
  function formatItemPrice(price) {
18655
18793
  if (props.formatPrice) {
18656
18794
  return props.formatPrice(price);
18657
18795
  }
18658
- return formatPrice(price || 0, { symbol: props.currency ?? "\u20AC" });
18796
+ return formatPrice(price || 0, { symbol: props.currency ?? "\u20AC", locale: localeForLanguage(props.language) });
18659
18797
  }
18660
18798
  const useTax = !!props.includeTax;
18661
18799
  function leadingPrice(result) {
@@ -18725,7 +18863,7 @@ function SearchBar(rawProps) {
18725
18863
  {
18726
18864
  ref: containerRef,
18727
18865
  "data-search-bar": true,
18728
- className: `propeller-search-bar ${props.containerClassName || "relative flex-1 max-w-2xl mx-8"}`,
18866
+ className: cn(`propeller-search-bar ${props.containerClassName || "relative flex-1 max-w-2xl mx-8"}`),
18729
18867
  "data-open": showDropdown ? "true" : "false",
18730
18868
  children: [
18731
18869
  /* @__PURE__ */ jsx("form", { className: "propeller-search-bar__form", onSubmit: (e) => handleSubmit(e), children: /* @__PURE__ */ jsxs("div", { className: "propeller-search-bar__input-wrapper relative", children: [
@@ -18754,7 +18892,14 @@ function SearchBar(rawProps) {
18754
18892
  {
18755
18893
  type: "search",
18756
18894
  autoComplete: "off",
18757
- className: "propeller-search-bar__input w-full pl-10 pr-10 py-2 bg-white/95 border border-white/20 rounded-container focus:outline-none focus:ring-2 focus:ring-secondary placeholder:text-muted-foreground",
18895
+ className: cn(
18896
+ // Themed surface + border rather than the white-on-white the
18897
+ // boilerplate's dark header band happened to make work: on a
18898
+ // light header `bg-white/95 border-white/20` rendered as an
18899
+ // invisible input.
18900
+ "propeller-search-bar__input w-full pl-10 pr-10 py-2 bg-card border border-input rounded-container focus:outline-none focus:ring-2 focus:ring-secondary placeholder:text-muted-foreground",
18901
+ props.inputClassName
18902
+ ),
18758
18903
  placeholder: props.placeholder || "Search products...",
18759
18904
  value: localTerm,
18760
18905
  onChange: (e) => handleInputChange(e.target.value)