@propeller-commerce/propeller-v2-react-ui 0.4.12 → 0.4.14

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,43 @@ 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.14] - 2026-06-26
12
+
13
+ ### Added
14
+
15
+ - **`useCheckout().placeOrder` now supports PSP (deferred-payment) orders.**
16
+ - `orderStatus` accepts `'UNFINISHED'` (and any backend status string), not
17
+ just `'NEW'` / `'REQUEST'` — for an order awaiting an external payment whose
18
+ final status the PSP webhook sets later.
19
+ - New `finalizeOrder?: boolean` option (default `true`). Pass `false` to defer
20
+ the order-confirmation email, confirm event, PDF attachment, **and cart
21
+ deletion** to payment time — so a shopper handed off to a PSP isn't emailed
22
+ and their cart isn't cleared before they've paid.
23
+
24
+ Both are backward compatible: existing callers (which omit `finalizeOrder`)
25
+ behave exactly as before — a normal order and a quote still finalize at
26
+ placement.
27
+
28
+ ## [0.4.13] - 2026-06-25
29
+
30
+ ### Added
31
+
32
+ - **Payment-method logos in `CartPaymethods`.** The component now renders each
33
+ method's `logo` (SDK `CartPaymethod.logo`, available in
34
+ `@propeller-commerce/propeller-sdk-v2` `^0.11.3`) as a square tile — logo on
35
+ top, name below — matching the carrier tiles. Falls back to the method name
36
+ when a method has no logo. New `showPaymethodLogo?: boolean` prop (default
37
+ `true`) mirrors `CartCarriers`' `showCarrierLogo`.
38
+
39
+ ### Changed
40
+
41
+ - **`CartPaymethods` and `CartCarriers` now lay out as a square logo grid**
42
+ (`grid-cols-2 sm:3 lg:4`, `aspect-square` tiles, centered logo + name, price
43
+ badge in the corner) instead of the previous single-column name rows. Same
44
+ selection behaviour, BEM classes, and `data-selected` hooks.
45
+ - **Bumped `@propeller-commerce/propeller-sdk-v2` to `^0.11.3`** — adds the
46
+ `logo` field to `CartPaymethod`.
47
+
11
48
  ## [0.4.12] - 2026-06-24
12
49
 
13
50
  ### Changed
package/dist/index.cjs CHANGED
@@ -1015,6 +1015,8 @@ function useCheckout(options) {
1015
1015
  const cartService = propellerV2CoreUi.createServices(graphqlClient).cart;
1016
1016
  const orderService = propellerV2CoreUi.createServices(graphqlClient).order;
1017
1017
  const { cartId, orderStatus, reference, notes, isQuoteMode } = opts;
1018
+ const finalizeOrder = opts.finalizeOrder ?? true;
1019
+ const sendConfirmation = finalizeOrder && !isQuoteMode;
1018
1020
  if (reference || notes) {
1019
1021
  await cartService.updateCart({
1020
1022
  id: cartId,
@@ -1036,10 +1038,13 @@ function useCheckout(options) {
1036
1038
  orderId,
1037
1039
  status: orderStatus,
1038
1040
  payStatus: propellerSdkV2.PaymentStatuses.OPEN,
1039
- sendOrderConfirmationEmail: !isQuoteMode,
1040
- addPDFAttachment: !isQuoteMode,
1041
- triggerOrderSendConfirmEvent: !isQuoteMode,
1042
- deleteCart: true
1041
+ sendOrderConfirmationEmail: sendConfirmation,
1042
+ addPDFAttachment: sendConfirmation,
1043
+ triggerOrderSendConfirmEvent: sendConfirmation,
1044
+ // Keep the cart only for an unfinalized (PSP-pending) order so the
1045
+ // shopper can retry payment; clear it once the order is finalized
1046
+ // (a normal order or a quote).
1047
+ deleteCart: finalizeOrder
1043
1048
  });
1044
1049
  if (isQuoteMode) {
1045
1050
  await orderService.triggerQuoteSendRequest({ orderId, language });
@@ -5897,28 +5902,27 @@ function CartCarriers(props) {
5897
5902
  }
5898
5903
  }, [props.cart, selectedName, props.onCarrierSelect, carriers, props]);
5899
5904
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `propeller-cart-carriers ${containerClass}`, children: [
5900
- carriers.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "propeller-cart-carriers__grid grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-3", children: carriers.map((carrier, index) => /* @__PURE__ */ jsxRuntime.jsxs(
5901
- "div",
5902
- {
5903
- onClick: () => handleSelect(carrier),
5904
- "data-selected": selectedName === carrier.name ? "true" : "false",
5905
- className: `propeller-cart-carriers__carrier cursor-pointer border border-border rounded-container p-4 flex flex-col gap-2 transition-all ${selectedName === carrier.name ? "border-secondary bg-secondary/5 shadow-sm" : "hover:border-secondary/30"}`,
5906
- children: [
5907
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "propeller-cart-carriers__carrier-row flex justify-between items-center", children: [
5908
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
5909
- showLogo && (carrier.logo || "") ? /* @__PURE__ */ jsxRuntime.jsx("img", { className: "propeller-cart-carriers__carrier-logo h-6 w-auto", src: carrier.logo || "", alt: carrier.name }) : null,
5910
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "propeller-cart-carriers__carrier-name font-medium", children: carrier.name })
5911
- ] }),
5912
- props.showPrice !== false ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "propeller-cart-carriers__carrier-price text-xs bg-surface-hover text-muted-foreground px-2 py-1 rounded-full", children: formatCarrierPrice(carrier.price) }) : null
5913
- ] }),
5914
- carrier.deliveryDeadline ? /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "propeller-cart-carriers__carrier-deadline text-xs text-muted-foreground", children: [
5915
- propellerV2CoreUi.getLabel(props.labels, "deliveryDeadline", "Delivery deadline:"),
5916
- carrier.deliveryDeadline
5917
- ] }) : null
5918
- ]
5919
- },
5920
- `${carrier.name}-${index}`
5921
- )) }) : null,
5905
+ carriers.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "propeller-cart-carriers__grid grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-4 gap-3", children: carriers.map((carrier, index) => {
5906
+ const logoUrl = showLogo ? carrier.logo || "" : "";
5907
+ return /* @__PURE__ */ jsxRuntime.jsxs(
5908
+ "div",
5909
+ {
5910
+ onClick: () => handleSelect(carrier),
5911
+ "data-selected": selectedName === carrier.name ? "true" : "false",
5912
+ className: `propeller-cart-carriers__carrier relative cursor-pointer border rounded-container p-3 flex flex-col items-center justify-center gap-2 text-center aspect-square transition-all ${selectedName === carrier.name ? "border-secondary bg-secondary/5 shadow-sm" : "border-border hover:border-secondary/30"}`,
5913
+ children: [
5914
+ props.showPrice !== false ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "propeller-cart-carriers__carrier-price absolute top-2 right-2 text-xs bg-surface-hover text-muted-foreground px-2 py-0.5 rounded-full", children: formatCarrierPrice(carrier.price) }) : null,
5915
+ logoUrl ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "propeller-cart-carriers__carrier-logo-wrap flex items-center justify-center h-10 w-full", children: /* @__PURE__ */ jsxRuntime.jsx("img", { className: "propeller-cart-carriers__carrier-logo max-h-10 max-w-[80%] w-auto object-contain", src: logoUrl, alt: carrier.name }) }) : null,
5916
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "propeller-cart-carriers__carrier-name font-medium text-sm", children: carrier.name }),
5917
+ carrier.deliveryDeadline ? /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "propeller-cart-carriers__carrier-deadline text-xs text-muted-foreground", children: [
5918
+ propellerV2CoreUi.getLabel(props.labels, "deliveryDeadline", "Delivery deadline:"),
5919
+ carrier.deliveryDeadline
5920
+ ] }) : null
5921
+ ]
5922
+ },
5923
+ `${carrier.name}-${index}`
5924
+ );
5925
+ }) }) : null,
5922
5926
  carriers.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "propeller-cart-carriers__empty text-muted-foreground italic", children: propellerV2CoreUi.getLabel(props.labels, "noCarriers", "No carriers available.") }) : null
5923
5927
  ] });
5924
5928
  }
@@ -7167,11 +7171,15 @@ function isOnAccountMethod(method) {
7167
7171
  const code = (method.code || "").toLowerCase();
7168
7172
  return code === "on_account" || code === "onaccount" || code === "on-account";
7169
7173
  }
7174
+ function getLogoUrl(method) {
7175
+ return method.logo || "";
7176
+ }
7170
7177
  function CartPaymethods(rawProps) {
7171
7178
  const props = useInfraProps(rawProps);
7172
7179
  const [selectedCode, setSelectedCode] = React6.useState("");
7173
7180
  const containerClass = props.paymentsContainerClass || "cart-paymethods";
7174
7181
  const showOnAccountForGuests = !!props.showOnAccountForGuests;
7182
+ const showLogo = props.showPaymethodLogo !== false;
7175
7183
  const isGuest = !props.user;
7176
7184
  const payMethods = (props.cart?.payMethods || []).filter((m) => {
7177
7185
  if (!m?.code) return false;
@@ -7197,19 +7205,30 @@ function CartPaymethods(rawProps) {
7197
7205
  }
7198
7206
  }, [props.cart, selectedCode, props.onPaymethodSelect, payMethods, props]);
7199
7207
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `propeller-cart-paymethods ${containerClass}`, children: [
7200
- payMethods.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "propeller-cart-paymethods__grid grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-3", children: payMethods.map((method, index) => /* @__PURE__ */ jsxRuntime.jsx(
7201
- "div",
7202
- {
7203
- onClick: () => handleSelect(method),
7204
- "data-selected": selectedCode === method.code ? "true" : "false",
7205
- className: `propeller-cart-paymethods__method cursor-pointer border border-border rounded-container p-4 flex flex-col gap-2 transition-all ${selectedCode === method.code ? "border-secondary bg-secondary/5 shadow-sm" : "hover:border-secondary/30"}`,
7206
- children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "propeller-cart-paymethods__method-row flex justify-between items-center", children: [
7207
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-2", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "propeller-cart-paymethods__method-name font-medium", children: method.name || method.code }) }),
7208
- method.price > 0 ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "propeller-cart-paymethods__method-price text-xs bg-surface-hover text-muted-foreground px-2 py-1 rounded-full", children: formatMethodPrice(method.price) }) : null
7209
- ] })
7210
- },
7211
- method.code
7212
- )) }) : null,
7208
+ payMethods.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "propeller-cart-paymethods__grid grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-4 gap-3", children: payMethods.map((method, index) => {
7209
+ const logoUrl = showLogo ? getLogoUrl(method) : "";
7210
+ return /* @__PURE__ */ jsxRuntime.jsxs(
7211
+ "div",
7212
+ {
7213
+ onClick: () => handleSelect(method),
7214
+ "data-selected": selectedCode === method.code ? "true" : "false",
7215
+ className: `propeller-cart-paymethods__method relative cursor-pointer border rounded-container p-3 flex flex-col items-center justify-center gap-2 text-center aspect-square transition-all ${selectedCode === method.code ? "border-secondary bg-secondary/5 shadow-sm" : "border-border hover:border-secondary/30"}`,
7216
+ children: [
7217
+ method.price > 0 ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "propeller-cart-paymethods__method-price absolute top-2 right-2 text-xs bg-surface-hover text-muted-foreground px-2 py-0.5 rounded-full", children: formatMethodPrice(method.price) }) : null,
7218
+ logoUrl ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "propeller-cart-paymethods__method-logo-wrap flex items-center justify-center h-10 w-full", children: /* @__PURE__ */ jsxRuntime.jsx(
7219
+ "img",
7220
+ {
7221
+ className: "propeller-cart-paymethods__method-logo max-h-10 max-w-[80%] w-auto object-contain",
7222
+ src: logoUrl,
7223
+ alt: method.name || method.code
7224
+ }
7225
+ ) }) : null,
7226
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "propeller-cart-paymethods__method-name font-medium text-sm", children: method.name || method.code })
7227
+ ]
7228
+ },
7229
+ method.code
7230
+ );
7231
+ }) }) : null,
7213
7232
  payMethods.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "propeller-cart-paymethods__empty text-muted-foreground italic", children: propellerV2CoreUi.getLabel(props.labels, "noMethods", "No payment methods available.") }) : null
7214
7233
  ] });
7215
7234
  }