@propeller-commerce/propeller-v2-react-ui 0.4.23 → 0.4.25

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -8,6 +8,47 @@ once it reaches 1.0. Until then (the `0.x` line) the public API may change
8
8
  between minor versions; breaking changes are called out below and in
9
9
  [MIGRATION.md](./MIGRATION.md).
10
10
 
11
+ ## [0.4.25] - 2026-07-20
12
+
13
+ ### Fixed
14
+
15
+ - **Raw enums no longer leak to the UI.** `OrderList` + `OrderSummary` gained a
16
+ `statusLabels` prop (raw status → localized, e.g. `NEW`→"Nieuw"), and
17
+ `OrderSummary` a `paymethodLabels` prop (raw method → localized, mapping both
18
+ the order-path `REKENING` and quote-path `ACCOUNT` variants to one label).
19
+ Unknown keys fall back to the raw value.
20
+ - `AddressCard`: new `showTypeBadge` prop (@default true) — set `false` to hide
21
+ the invoice/delivery chip where a heading already names the type.
22
+ - **Concatenated sentences → placeholder interpolation** (fixes broken Dutch
23
+ word order + missing spaces):
24
+ - `FavoriteLists` delete confirm: full-sentence `deleteConfirm` with a
25
+ `{name}` placeholder (the verb was stranded before the object, no space
26
+ before the quote).
27
+ - `CartOverview` / `QuoteActions` terms consent: `termsConsent` with a `{link}`
28
+ placeholder (was "de<a>…", no space, English order).
29
+ - `LoginForm` account-header prompt: `noAccount` with a `{link}` placeholder
30
+ (was "account?Create an Account", no space).
31
+ - **Pluralization**: `FavoriteLists` item count uses `itemSingular`/`itemPlural`
32
+ by count ("1 artikel" not "1 artikelen"); `GridToolbar` product count uses
33
+ `productSingular`/`productPlural` (+ a space).
34
+
35
+ ## [0.4.24] - 2026-07-20
36
+
37
+ ### Fixed
38
+
39
+ - **Date formatting**: `OrderList`, `OrderSummary`, `CartOverview`,
40
+ `OrderShipments`, `PurchaseAuthorizationRequests`, `FavoriteLists` rendered
41
+ dates via locale-less/`'en-US'` `toLocaleDateString` (US M/D/YYYY) or an
42
+ inconsistent `D.M.YYYY` — Dutch readers misparse M/D by months. All now use a
43
+ consistent numeric `DD-MM-YYYY` fallback (still overridable via
44
+ `props.formatDate`).
45
+ - `CartIconAndSidebar`: new `cartItemLabels` prop, forwarded to the mini-cart's
46
+ inner `CartItem` rows so the line labels (e.g. the `qtyPrefix` "Aantal:")
47
+ localize; previously they fell back to English ("Qty:").
48
+ - `CartPaymethods`: new `paymethodLabels` prop — a code→localized-name map so
49
+ the host can override un-localized backend method names (e.g. "On pickup"→
50
+ "Bij afhalen"). Lookup: `paymethodLabels[code]` → `method.name` → `method.code`.
51
+
11
52
  ## [0.4.23] - 2026-07-17
12
53
 
13
54
  ### Fixed
package/dist/index.cjs CHANGED
@@ -3278,10 +3278,15 @@ function LoginForm(rawProps) {
3278
3278
  ] }) : null,
3279
3279
  props.accountHeaderLoginForm ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "propeller-login-form__footer flex flex-col gap-2 text-sm pt-3 text-center", children: [
3280
3280
  /* @__PURE__ */ jsxRuntime.jsx(LoginFormForgotPasswordLink, {}),
3281
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "propeller-login-form__register text-xs text-muted-foreground", children: [
3282
- propellerV2CoreUi.getLabel(props.labels, "noAccount", "Don't have an account?"),
3283
- /* @__PURE__ */ jsxRuntime.jsx(LoginFormRegisterLink, {})
3284
- ] })
3281
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "propeller-login-form__register text-xs text-muted-foreground", children: (() => {
3282
+ const tpl = propellerV2CoreUi.getLabel(props.labels, "noAccount", "Don't have an account? {link}");
3283
+ const [before, after = ""] = tpl.split("{link}");
3284
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3285
+ before,
3286
+ /* @__PURE__ */ jsxRuntime.jsx(LoginFormRegisterLink, {}),
3287
+ after
3288
+ ] });
3289
+ })() })
3285
3290
  ] }) : null
3286
3291
  ]
3287
3292
  }
@@ -5450,7 +5455,8 @@ function AddressCard(rawProps) {
5450
5455
  ] });
5451
5456
  }
5452
5457
  function AddressCardTypeBadge(props) {
5453
- const { derived } = useAddressCardContext();
5458
+ const { derived, resolved } = useAddressCardContext();
5459
+ if (resolved.showTypeBadge === false) return null;
5454
5460
  if (!derived.addressType) return null;
5455
5461
  return /* @__PURE__ */ jsxRuntime.jsx(
5456
5462
  "span",
@@ -6930,6 +6936,7 @@ function CartIconAndSidebar(rawProps) {
6930
6936
  language: props.language,
6931
6937
  configuration: props.configuration,
6932
6938
  companyId: props.companyId,
6939
+ labels: props.cartItemLabels,
6933
6940
  cardFrame: false,
6934
6941
  showDelete: false,
6935
6942
  readOnlyQuantity: true,
@@ -7035,11 +7042,11 @@ function CartOverview(props) {
7035
7042
  function requestDate() {
7036
7043
  const date = props.cart?.postageData?.requestDate;
7037
7044
  if (!date) return "";
7038
- try {
7039
- return new Date(date).toLocaleDateString();
7040
- } catch {
7041
- return date;
7042
- }
7045
+ const d = new Date(date);
7046
+ if (isNaN(d.getTime())) return date;
7047
+ const day = String(d.getDate()).padStart(2, "0");
7048
+ const month = String(d.getMonth() + 1).padStart(2, "0");
7049
+ return `${day}-${month}-${d.getFullYear()}`;
7043
7050
  }
7044
7051
  function handleTermsLinkClick(event) {
7045
7052
  event.preventDefault();
@@ -7148,18 +7155,23 @@ function CartOverview(props) {
7148
7155
  onChange: (event) => setTermsAccepted(event.target.checked)
7149
7156
  }
7150
7157
  ),
7151
- /* @__PURE__ */ jsxRuntime.jsxs("label", { htmlFor: "cart-overview-terms", className: "text-sm leading-none", children: [
7152
- propellerV2CoreUi.getLabel(props.labels, "termsPrefix", "I agree to the"),
7153
- /* @__PURE__ */ jsxRuntime.jsx(
7154
- "a",
7155
- {
7156
- href: "#",
7157
- className: "text-primary hover:underline font-medium",
7158
- onClick: handleTermsLinkClick,
7159
- children: propellerV2CoreUi.getLabel(props.labels, "termsLink", "Terms and Conditions")
7160
- }
7161
- )
7162
- ] })
7158
+ /* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: "cart-overview-terms", className: "text-sm leading-none", children: (() => {
7159
+ const tpl = propellerV2CoreUi.getLabel(props.labels, "termsConsent", "I agree to the {link}");
7160
+ const [before, after = ""] = tpl.split("{link}");
7161
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
7162
+ before,
7163
+ /* @__PURE__ */ jsxRuntime.jsx(
7164
+ "a",
7165
+ {
7166
+ href: "#",
7167
+ className: "text-primary hover:underline font-medium",
7168
+ onClick: handleTermsLinkClick,
7169
+ children: propellerV2CoreUi.getLabel(props.labels, "termsLink", "Terms and Conditions")
7170
+ }
7171
+ ),
7172
+ after
7173
+ ] });
7174
+ })() })
7163
7175
  ] }) : null,
7164
7176
  showPurchaseButton ? /* @__PURE__ */ jsxRuntime.jsxs(
7165
7177
  "button",
@@ -7202,6 +7214,10 @@ function CartPaymethods(rawProps) {
7202
7214
  if (props.formatPrice) return props.formatPrice(price);
7203
7215
  return propellerV2CoreUi.formatPrice(price || 0, { symbol: props.currency ?? "\u20AC" });
7204
7216
  }
7217
+ function methodName(method) {
7218
+ const code = (method.code || "").toLowerCase();
7219
+ return props.paymethodLabels?.[code] || method.name || method.code || "";
7220
+ }
7205
7221
  function handleSelect(method) {
7206
7222
  setSelectedCode(method.code);
7207
7223
  if (props.onPaymethodSelect) props.onPaymethodSelect(method);
@@ -7232,10 +7248,10 @@ function CartPaymethods(rawProps) {
7232
7248
  {
7233
7249
  className: "propeller-cart-paymethods__method-logo max-h-10 max-w-[80%] w-auto object-contain",
7234
7250
  src: logoUrl,
7235
- alt: method.name || method.code
7251
+ alt: methodName(method)
7236
7252
  }
7237
7253
  ) }) : null,
7238
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "propeller-cart-paymethods__method-name font-medium text-sm", children: method.name || method.code })
7254
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "propeller-cart-paymethods__method-name font-medium text-sm", children: methodName(method) })
7239
7255
  ]
7240
7256
  },
7241
7257
  method.code
@@ -9692,10 +9708,11 @@ function FavoriteLists(rawProps) {
9692
9708
  if (props.formatDate) return props.formatDate(dateString);
9693
9709
  if (!dateString) return "-";
9694
9710
  const d = new Date(dateString);
9711
+ if (isNaN(d.getTime())) return dateString;
9695
9712
  const day = String(d.getDate()).padStart(2, "0");
9696
9713
  const month = String(d.getMonth() + 1).padStart(2, "0");
9697
9714
  const year = d.getFullYear();
9698
- return `${day}/${month}/${year}`;
9715
+ return `${day}-${month}-${year}`;
9699
9716
  }
9700
9717
  function getProductCount(list) {
9701
9718
  const products = list.products;
@@ -9919,7 +9936,7 @@ function FavoriteLists(rawProps) {
9919
9936
  ),
9920
9937
  getTotalCount(list),
9921
9938
  "\xA0",
9922
- propellerV2CoreUi.getLabel(props.labels, "items", "items")
9939
+ getTotalCount(list) === 1 ? propellerV2CoreUi.getLabel(props.labels, "itemSingular", "item") : propellerV2CoreUi.getLabel(props.labels, "itemPlural", "items")
9923
9940
  ] }) : null
9924
9941
  ] })
9925
9942
  ] }) : null
@@ -10103,15 +10120,15 @@ function FavoriteLists(rawProps) {
10103
10120
  )
10104
10121
  ] }),
10105
10122
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4", children: [
10106
- /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "propeller-favorite-lists__delete-prompt", children: [
10107
- propellerV2CoreUi.getLabel(props.labels, "deleteConfirm", "Are you sure you want to delete"),
10108
- /* @__PURE__ */ jsxRuntime.jsxs("strong", { children: [
10109
- '"',
10110
- listToDelete?.name,
10111
- '"'
10112
- ] }),
10113
- "?"
10114
- ] }),
10123
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "propeller-favorite-lists__delete-prompt", children: (() => {
10124
+ const tpl = propellerV2CoreUi.getLabel(props.labels, "deleteConfirm", 'Are you sure you want to delete "{name}"?');
10125
+ const [before, after = ""] = tpl.split("{name}");
10126
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
10127
+ before,
10128
+ /* @__PURE__ */ jsxRuntime.jsx("strong", { children: listToDelete?.name }),
10129
+ after
10130
+ ] });
10131
+ })() }),
10115
10132
  /* @__PURE__ */ jsxRuntime.jsx("p", { className: "propeller-favorite-lists__delete-warning text-sm text-destructive", children: propellerV2CoreUi.getLabel(props.labels, "deleteWarning", "This action cannot be undone.") })
10116
10133
  ] }),
10117
10134
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-end gap-3 pt-6", children: [
@@ -10695,6 +10712,8 @@ var DEFAULT_LABELS2 = {
10695
10712
  [propellerSdkV2.SortOrder.DESC]: "High to Low",
10696
10713
  clearAll: "Clear All",
10697
10714
  products: " Products",
10715
+ productSingular: "Product",
10716
+ productPlural: "Products",
10698
10717
  from: "from",
10699
10718
  results: "results",
10700
10719
  perPage: " per page",
@@ -10788,7 +10807,8 @@ function GridToolbar(rawProps) {
10788
10807
  /* @__PURE__ */ jsxRuntime.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: [
10789
10808
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "propeller-grid-toolbar__count text-sm text-muted-foreground font-medium", children: props.itemsFound > 0 ? /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
10790
10809
  props.itemsFound,
10791
- getLabel53("products")
10810
+ "\xA0",
10811
+ props.itemsFound === 1 ? getLabel53("productSingular") : getLabel53("productPlural")
10792
10812
  ] }) : null }),
10793
10813
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "propeller-grid-toolbar__controls flex flex-wrap items-center gap-3", children: [
10794
10814
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -11840,7 +11860,11 @@ function OrderList(rawProps) {
11840
11860
  function formatDate(dateString) {
11841
11861
  if (props.formatDate) return props.formatDate(dateString);
11842
11862
  if (!dateString) return "-";
11843
- return new Date(dateString).toLocaleDateString();
11863
+ const d = new Date(dateString);
11864
+ if (isNaN(d.getTime())) return dateString;
11865
+ const day = String(d.getDate()).padStart(2, "0");
11866
+ const month = String(d.getMonth() + 1).padStart(2, "0");
11867
+ return `${day}-${month}-${d.getFullYear()}`;
11844
11868
  }
11845
11869
  function formatPrice17(price) {
11846
11870
  if (props.formatPrice) return props.formatPrice(price);
@@ -11860,6 +11884,9 @@ function OrderList(rawProps) {
11860
11884
  return "bg-warning/10 text-warning";
11861
11885
  }
11862
11886
  }
11887
+ function statusLabel(status) {
11888
+ return props.statusLabels?.[status] || status;
11889
+ }
11863
11890
  function getColumnLabel(col) {
11864
11891
  if (props.columnConfig && props.columnConfig[col]) {
11865
11892
  return props.columnConfig[col];
@@ -12180,7 +12207,7 @@ function OrderList(rawProps) {
12180
12207
  {
12181
12208
  className: `propeller-order-list__status px-2 inline-flex text-xs leading-5 font-semibold rounded-full ${getStatusColor(order.status)}`,
12182
12209
  "data-status": order.status,
12183
- children: order.status
12210
+ children: statusLabel(order.status)
12184
12211
  }
12185
12212
  ) : null,
12186
12213
  col === "total" ? /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: formatPrice17(order.total?.net) }) : null,
@@ -12277,7 +12304,10 @@ function OrderShipments(props) {
12277
12304
  function formatDate(dateStr) {
12278
12305
  if (!dateStr) return "-";
12279
12306
  const d = new Date(dateStr);
12280
- return `${d.getDate()}.${d.getMonth() + 1}.${d.getFullYear()}`;
12307
+ if (isNaN(d.getTime())) return dateStr;
12308
+ const day = String(d.getDate()).padStart(2, "0");
12309
+ const month = String(d.getMonth() + 1).padStart(2, "0");
12310
+ return `${day}-${month}-${d.getFullYear()}`;
12281
12311
  }
12282
12312
  function getOrderItemForShipmentItem(shipmentItem) {
12283
12313
  if (!props.order?.items || !shipmentItem.orderItemId) return null;
@@ -12479,11 +12509,13 @@ function OrderSummary(props) {
12479
12509
  const showRemarks = props.showRemarks !== void 0 ? props.showRemarks : true;
12480
12510
  const orderNumber = order?.id || "";
12481
12511
  const orderDate = order?.createdAt || "";
12482
- const orderStatus = order?.status || "";
12512
+ const rawStatus = order?.status || "";
12513
+ const orderStatus = rawStatus ? props.statusLabels?.[rawStatus] || rawStatus : "";
12483
12514
  const orderTotal = Number(order?.total?.net || 0);
12484
12515
  const orderReference = order?.reference || "";
12485
12516
  const orderRemarks = order?.remarks || "";
12486
- const paymentMethod = order?.paymentData?.method || "";
12517
+ const rawPaymentMethod = order?.paymentData?.method || "";
12518
+ const paymentMethod = rawPaymentMethod ? props.paymethodLabels?.[rawPaymentMethod.toLowerCase()] || rawPaymentMethod : "";
12487
12519
  const carrierName = order?.postageData?.carrier || "";
12488
12520
  const addresses = order?.addresses || [];
12489
12521
  const invoiceAddress = addresses.find((a) => a.type === "invoice") || null;
@@ -12494,15 +12526,18 @@ function OrderSummary(props) {
12494
12526
  }
12495
12527
  return propellerV2CoreUi.formatPrice(price || 0, { symbol: props.currency ?? "\u20AC" });
12496
12528
  }
12529
+ function numericDate(dateString) {
12530
+ const d = new Date(dateString);
12531
+ if (isNaN(d.getTime())) return dateString;
12532
+ const day = String(d.getDate()).padStart(2, "0");
12533
+ const month = String(d.getMonth() + 1).padStart(2, "0");
12534
+ return `${day}-${month}-${d.getFullYear()}`;
12535
+ }
12497
12536
  function formatOrderDate(dateString) {
12498
12537
  if (props.formatDate) {
12499
12538
  return props.formatDate(dateString);
12500
12539
  }
12501
- try {
12502
- return new Date(dateString).toLocaleDateString("en-US");
12503
- } catch {
12504
- return dateString;
12505
- }
12540
+ return numericDate(dateString);
12506
12541
  }
12507
12542
  const requestDateRaw = order?.postageData?.requestDate;
12508
12543
  let requestDate = "";
@@ -12510,11 +12545,7 @@ function OrderSummary(props) {
12510
12545
  if (props.formatDate) {
12511
12546
  requestDate = props.formatDate(requestDateRaw);
12512
12547
  } else {
12513
- try {
12514
- requestDate = new Date(requestDateRaw).toLocaleDateString("en-US");
12515
- } catch {
12516
- requestDate = requestDateRaw;
12517
- }
12548
+ requestDate = numericDate(requestDateRaw);
12518
12549
  }
12519
12550
  }
12520
12551
  const getCountryName = (code) => propellerV2CoreUi.getCountryName(code, props.countries);
@@ -15935,7 +15966,10 @@ function PurchaseAuthorizationRequests(rawProps) {
15935
15966
  if (props.formatDate) return props.formatDate(dateStr);
15936
15967
  if (!dateStr) return "-";
15937
15968
  const d = new Date(dateStr);
15938
- return `${d.getDate()}.${d.getMonth() + 1}.${d.getFullYear()}`;
15969
+ if (isNaN(d.getTime())) return dateStr;
15970
+ const day = String(d.getDate()).padStart(2, "0");
15971
+ const month = String(d.getMonth() + 1).padStart(2, "0");
15972
+ return `${day}-${month}-${d.getFullYear()}`;
15939
15973
  }
15940
15974
  function formatPrice17(price) {
15941
15975
  if (props.formatPrice) return props.formatPrice(price);
@@ -16169,18 +16203,23 @@ function QuoteActions(rawProps) {
16169
16203
  onChange: (event) => handleTermsChange(event.target.checked)
16170
16204
  }
16171
16205
  ),
16172
- /* @__PURE__ */ jsxRuntime.jsxs("label", { htmlFor: "quote-actions-terms", className: "text-sm leading-none", children: [
16173
- propellerV2CoreUi.getLabel(props.labels, "termsPrefix", "I agree to the"),
16174
- /* @__PURE__ */ jsxRuntime.jsx(
16175
- "a",
16176
- {
16177
- href: "#",
16178
- className: "text-primary hover:underline font-medium",
16179
- onClick: (event) => handleTermsLinkClick(event),
16180
- children: propellerV2CoreUi.getLabel(props.labels, "termsLink", "Terms and Conditions")
16181
- }
16182
- )
16183
- ] })
16206
+ /* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: "quote-actions-terms", className: "text-sm leading-none", children: (() => {
16207
+ const tpl = propellerV2CoreUi.getLabel(props.labels, "termsConsent", "I agree to the {link}");
16208
+ const [before, after = ""] = tpl.split("{link}");
16209
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
16210
+ before,
16211
+ /* @__PURE__ */ jsxRuntime.jsx(
16212
+ "a",
16213
+ {
16214
+ href: "#",
16215
+ className: "text-primary hover:underline font-medium",
16216
+ onClick: (event) => handleTermsLinkClick(event),
16217
+ children: propellerV2CoreUi.getLabel(props.labels, "termsLink", "Terms and Conditions")
16218
+ }
16219
+ ),
16220
+ after
16221
+ ] });
16222
+ })() })
16184
16223
  ] }) : null,
16185
16224
  /* @__PURE__ */ jsxRuntime.jsxs(
16186
16225
  "button",