@sazito/checkout 0.2.1 → 0.4.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.
Files changed (37) hide show
  1. package/README.md +54 -0
  2. package/dist/chunks/{labels-BlZiVd3n.cjs → labels-CnPllzhT.cjs} +28 -9
  3. package/dist/chunks/labels-CnPllzhT.cjs.map +1 -0
  4. package/dist/chunks/{labels-CTR6b-KZ.js → labels-e8w4zRbg.js} +28 -9
  5. package/dist/chunks/labels-e8w4zRbg.js.map +1 -0
  6. package/dist/chunks/{use-checkout-DwHd4uFh.js → use-checkout-BM810__v.js} +5 -3
  7. package/dist/chunks/use-checkout-BM810__v.js.map +1 -0
  8. package/dist/chunks/{use-checkout-BEaLKgNa.cjs → use-checkout-DPtLgxlA.cjs} +5 -3
  9. package/dist/chunks/use-checkout-DPtLgxlA.cjs.map +1 -0
  10. package/dist/core/index.cjs +3 -1
  11. package/dist/core/index.cjs.map +1 -1
  12. package/dist/core/index.d.cts +27 -3
  13. package/dist/core/index.d.ts +27 -3
  14. package/dist/core/index.js +2 -1
  15. package/dist/core/index.js.map +1 -1
  16. package/dist/next/index.cjs +34 -13
  17. package/dist/next/index.cjs.map +1 -1
  18. package/dist/next/index.d.cts +48 -9
  19. package/dist/next/index.d.ts +48 -9
  20. package/dist/next/index.js +35 -14
  21. package/dist/next/index.js.map +1 -1
  22. package/dist/next/payment-return.cjs +40 -0
  23. package/dist/next/payment-return.cjs.map +1 -0
  24. package/dist/next/payment-return.d.cts +26 -0
  25. package/dist/next/payment-return.d.ts +26 -0
  26. package/dist/next/payment-return.js +38 -0
  27. package/dist/next/payment-return.js.map +1 -0
  28. package/dist/react/index.cjs +2 -2
  29. package/dist/react/index.d.cts +9 -1
  30. package/dist/react/index.d.ts +9 -1
  31. package/dist/react/index.js +2 -2
  32. package/dist/styles.css +29 -28
  33. package/package.json +15 -1
  34. package/dist/chunks/labels-BlZiVd3n.cjs.map +0 -1
  35. package/dist/chunks/labels-CTR6b-KZ.js.map +0 -1
  36. package/dist/chunks/use-checkout-BEaLKgNa.cjs.map +0 -1
  37. package/dist/chunks/use-checkout-DwHd4uFh.js.map +0 -1
@@ -94,14 +94,32 @@ interface CheckoutCredentials {
94
94
  id: number;
95
95
  identifier: string;
96
96
  };
97
+ payment?: {
98
+ id: number;
99
+ identifier: string;
100
+ };
101
+ }
102
+ /** Normalized payment callback data accepted by `SazitoCheckoutPage`. */
103
+ interface CheckoutPaymentReturn {
104
+ payment: {
105
+ id: number;
106
+ identifier: string;
107
+ };
108
+ params: Record<string, string>;
97
109
  }
110
+ /** Search-param shape exposed by current Next.js App Router pages. */
111
+ type PaymentReturnSearchParams = Record<string, string | string[] | undefined>;
98
112
  interface CheckoutConfig {
99
113
  locale?: CheckoutLocale;
100
114
  direction?: CheckoutDirection;
101
115
  theme?: CheckoutTheme;
102
116
  /** URL for the "continue shopping" / back-to-store action. */
103
117
  continueShoppingUrl?: string;
104
- /** URL the gateway returns to after payment. Defaults to current URL. */
118
+ /**
119
+ * Reserved for gateways that support a caller-provided return URL.
120
+ * Current Sazito legacy callbacks use their generated nested result path.
121
+ * @deprecated Use an optional catch-all route with `parsePaymentReturn`.
122
+ */
105
123
  returnUrl?: string;
106
124
  /** Pending-payment poll interval in ms (default 15000). */
107
125
  pollIntervalMs?: number;
@@ -335,8 +353,27 @@ interface RenderButtonProps {
335
353
  /** Localised label for the current step. */
336
354
  children: ReactNode;
337
355
  }
338
- interface RenderEmptyCartProps$1 {
356
+ interface RenderEmptyCartProps {
339
357
  continueShoppingUrl?: string;
358
+ title: ReactNode;
359
+ description: ReactNode;
360
+ actionLabel: ReactNode;
361
+ icon: ReactNode;
362
+ }
363
+ /** Content-level customisation for the built-in empty-cart screen. */
364
+ interface EmptyCartOptions {
365
+ /** Empty-state heading. Defaults to the active locale. */
366
+ title?: ReactNode;
367
+ /** Supporting copy below the heading. Defaults to the active locale. */
368
+ description?: ReactNode;
369
+ /** Label for the back-to-store action. Defaults to the active locale. */
370
+ actionLabel?: ReactNode;
371
+ /** Replace the built-in cart illustration. */
372
+ icon?: ReactNode;
373
+ /** Override config.continueShoppingUrl for this action only. */
374
+ actionUrl?: string;
375
+ /** Hide the action even when a continue-shopping URL is configured. */
376
+ hideAction?: boolean;
340
377
  }
341
378
  interface SazitoCheckoutProps {
342
379
  theme?: CheckoutTheme;
@@ -344,9 +381,10 @@ interface SazitoCheckoutProps {
344
381
  className?: string;
345
382
  renderNextButton?: (props: RenderButtonProps) => ReactNode;
346
383
  renderBackButton?: (props: RenderButtonProps) => ReactNode;
347
- renderEmptyCart?: (props: RenderEmptyCartProps$1) => ReactNode;
384
+ renderEmptyCart?: (props: RenderEmptyCartProps) => ReactNode;
385
+ emptyCart?: EmptyCartOptions;
348
386
  }
349
- declare function SazitoCheckout({ theme, continueShoppingUrl, className, renderNextButton, renderBackButton, renderEmptyCart, }: SazitoCheckoutProps): react_jsx_runtime.JSX.Element;
387
+ declare function SazitoCheckout({ theme, continueShoppingUrl, className, renderNextButton, renderBackButton, renderEmptyCart, emptyCart, }: SazitoCheckoutProps): react_jsx_runtime.JSX.Element;
350
388
 
351
389
  interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
352
390
  variant?: 'primary' | 'outline' | 'ghost';
@@ -388,19 +426,20 @@ interface ErrorBannerProps {
388
426
  }
389
427
  declare function ErrorBanner({ message, asChild, children, className }: ErrorBannerProps): react_jsx_runtime.JSX.Element;
390
428
 
391
- interface RenderEmptyCartProps {
392
- continueShoppingUrl?: string;
393
- }
394
429
  interface SazitoCheckoutPageProps {
395
430
  credentials?: CheckoutCredentials;
396
431
  config?: CheckoutConfig;
432
+ /** Parsed nested gateway callback. Prefer `parsePaymentReturn()` to create it. */
433
+ paymentReturn?: CheckoutPaymentReturn;
434
+ /** @deprecated Prefer `paymentReturn`; retained for query-only callbacks. */
397
435
  paymentReturnParams?: Record<string, string>;
398
436
  className?: string;
399
437
  renderNextButton?: (props: RenderButtonProps) => React.ReactNode;
400
438
  renderBackButton?: (props: RenderButtonProps) => React.ReactNode;
401
439
  renderEmptyCart?: (props: RenderEmptyCartProps) => React.ReactNode;
440
+ emptyCart?: EmptyCartOptions;
402
441
  }
403
- declare function SazitoCheckoutPage({ credentials, config, paymentReturnParams, className, renderNextButton, renderBackButton, renderEmptyCart, }: SazitoCheckoutPageProps): react_jsx_runtime.JSX.Element;
442
+ declare function SazitoCheckoutPage({ credentials, config, paymentReturn, paymentReturnParams, className, renderNextButton, renderBackButton, renderEmptyCart, emptyCart, }: SazitoCheckoutPageProps): react_jsx_runtime.JSX.Element;
404
443
 
405
444
  interface CheckoutProviderProps {
406
445
  /** Override the SazitoProvider client for this checkout instance only. */
@@ -433,4 +472,4 @@ interface SazitoProviderProps {
433
472
  declare function SazitoProvider({ client, children }: SazitoProviderProps): react_jsx_runtime.JSX.Element;
434
473
 
435
474
  export { Button, CheckoutProvider, ErrorBanner, Field, ProductPlaceholder, SazitoCheckout, SazitoCheckoutPage, SazitoProvider, SectionTitle, Spinner, useCheckout };
436
- export type { ButtonProps, CheckoutProviderProps, ErrorBannerProps, FieldProps, ProductPlaceholderProps, RenderButtonProps, RenderEmptyCartProps as RenderEmptyCartPageProps, RenderEmptyCartProps$1 as RenderEmptyCartProps, SazitoCheckoutPageProps, SazitoCheckoutProps, SazitoProviderProps, SectionTitleProps, SpinnerProps };
475
+ export type { ButtonProps, CheckoutPaymentReturn, CheckoutProviderProps, EmptyCartOptions, ErrorBannerProps, FieldProps, PaymentReturnSearchParams, ProductPlaceholderProps, RenderButtonProps, RenderEmptyCartProps as RenderEmptyCartPageProps, RenderEmptyCartProps, SazitoCheckoutPageProps, SazitoCheckoutProps, SazitoProviderProps, SectionTitleProps, SpinnerProps };
@@ -94,14 +94,32 @@ interface CheckoutCredentials {
94
94
  id: number;
95
95
  identifier: string;
96
96
  };
97
+ payment?: {
98
+ id: number;
99
+ identifier: string;
100
+ };
101
+ }
102
+ /** Normalized payment callback data accepted by `SazitoCheckoutPage`. */
103
+ interface CheckoutPaymentReturn {
104
+ payment: {
105
+ id: number;
106
+ identifier: string;
107
+ };
108
+ params: Record<string, string>;
97
109
  }
110
+ /** Search-param shape exposed by current Next.js App Router pages. */
111
+ type PaymentReturnSearchParams = Record<string, string | string[] | undefined>;
98
112
  interface CheckoutConfig {
99
113
  locale?: CheckoutLocale;
100
114
  direction?: CheckoutDirection;
101
115
  theme?: CheckoutTheme;
102
116
  /** URL for the "continue shopping" / back-to-store action. */
103
117
  continueShoppingUrl?: string;
104
- /** URL the gateway returns to after payment. Defaults to current URL. */
118
+ /**
119
+ * Reserved for gateways that support a caller-provided return URL.
120
+ * Current Sazito legacy callbacks use their generated nested result path.
121
+ * @deprecated Use an optional catch-all route with `parsePaymentReturn`.
122
+ */
105
123
  returnUrl?: string;
106
124
  /** Pending-payment poll interval in ms (default 15000). */
107
125
  pollIntervalMs?: number;
@@ -335,8 +353,27 @@ interface RenderButtonProps {
335
353
  /** Localised label for the current step. */
336
354
  children: ReactNode;
337
355
  }
338
- interface RenderEmptyCartProps$1 {
356
+ interface RenderEmptyCartProps {
339
357
  continueShoppingUrl?: string;
358
+ title: ReactNode;
359
+ description: ReactNode;
360
+ actionLabel: ReactNode;
361
+ icon: ReactNode;
362
+ }
363
+ /** Content-level customisation for the built-in empty-cart screen. */
364
+ interface EmptyCartOptions {
365
+ /** Empty-state heading. Defaults to the active locale. */
366
+ title?: ReactNode;
367
+ /** Supporting copy below the heading. Defaults to the active locale. */
368
+ description?: ReactNode;
369
+ /** Label for the back-to-store action. Defaults to the active locale. */
370
+ actionLabel?: ReactNode;
371
+ /** Replace the built-in cart illustration. */
372
+ icon?: ReactNode;
373
+ /** Override config.continueShoppingUrl for this action only. */
374
+ actionUrl?: string;
375
+ /** Hide the action even when a continue-shopping URL is configured. */
376
+ hideAction?: boolean;
340
377
  }
341
378
  interface SazitoCheckoutProps {
342
379
  theme?: CheckoutTheme;
@@ -344,9 +381,10 @@ interface SazitoCheckoutProps {
344
381
  className?: string;
345
382
  renderNextButton?: (props: RenderButtonProps) => ReactNode;
346
383
  renderBackButton?: (props: RenderButtonProps) => ReactNode;
347
- renderEmptyCart?: (props: RenderEmptyCartProps$1) => ReactNode;
384
+ renderEmptyCart?: (props: RenderEmptyCartProps) => ReactNode;
385
+ emptyCart?: EmptyCartOptions;
348
386
  }
349
- declare function SazitoCheckout({ theme, continueShoppingUrl, className, renderNextButton, renderBackButton, renderEmptyCart, }: SazitoCheckoutProps): react_jsx_runtime.JSX.Element;
387
+ declare function SazitoCheckout({ theme, continueShoppingUrl, className, renderNextButton, renderBackButton, renderEmptyCart, emptyCart, }: SazitoCheckoutProps): react_jsx_runtime.JSX.Element;
350
388
 
351
389
  interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
352
390
  variant?: 'primary' | 'outline' | 'ghost';
@@ -388,19 +426,20 @@ interface ErrorBannerProps {
388
426
  }
389
427
  declare function ErrorBanner({ message, asChild, children, className }: ErrorBannerProps): react_jsx_runtime.JSX.Element;
390
428
 
391
- interface RenderEmptyCartProps {
392
- continueShoppingUrl?: string;
393
- }
394
429
  interface SazitoCheckoutPageProps {
395
430
  credentials?: CheckoutCredentials;
396
431
  config?: CheckoutConfig;
432
+ /** Parsed nested gateway callback. Prefer `parsePaymentReturn()` to create it. */
433
+ paymentReturn?: CheckoutPaymentReturn;
434
+ /** @deprecated Prefer `paymentReturn`; retained for query-only callbacks. */
397
435
  paymentReturnParams?: Record<string, string>;
398
436
  className?: string;
399
437
  renderNextButton?: (props: RenderButtonProps) => React.ReactNode;
400
438
  renderBackButton?: (props: RenderButtonProps) => React.ReactNode;
401
439
  renderEmptyCart?: (props: RenderEmptyCartProps) => React.ReactNode;
440
+ emptyCart?: EmptyCartOptions;
402
441
  }
403
- declare function SazitoCheckoutPage({ credentials, config, paymentReturnParams, className, renderNextButton, renderBackButton, renderEmptyCart, }: SazitoCheckoutPageProps): react_jsx_runtime.JSX.Element;
442
+ declare function SazitoCheckoutPage({ credentials, config, paymentReturn, paymentReturnParams, className, renderNextButton, renderBackButton, renderEmptyCart, emptyCart, }: SazitoCheckoutPageProps): react_jsx_runtime.JSX.Element;
404
443
 
405
444
  interface CheckoutProviderProps {
406
445
  /** Override the SazitoProvider client for this checkout instance only. */
@@ -433,4 +472,4 @@ interface SazitoProviderProps {
433
472
  declare function SazitoProvider({ client, children }: SazitoProviderProps): react_jsx_runtime.JSX.Element;
434
473
 
435
474
  export { Button, CheckoutProvider, ErrorBanner, Field, ProductPlaceholder, SazitoCheckout, SazitoCheckoutPage, SazitoProvider, SectionTitle, Spinner, useCheckout };
436
- export type { ButtonProps, CheckoutProviderProps, ErrorBannerProps, FieldProps, ProductPlaceholderProps, RenderButtonProps, RenderEmptyCartProps as RenderEmptyCartPageProps, RenderEmptyCartProps$1 as RenderEmptyCartProps, SazitoCheckoutPageProps, SazitoCheckoutProps, SazitoProviderProps, SectionTitleProps, SpinnerProps };
475
+ export type { ButtonProps, CheckoutPaymentReturn, CheckoutProviderProps, EmptyCartOptions, ErrorBannerProps, FieldProps, PaymentReturnSearchParams, ProductPlaceholderProps, RenderButtonProps, RenderEmptyCartProps as RenderEmptyCartPageProps, RenderEmptyCartProps, SazitoCheckoutPageProps, SazitoCheckoutProps, SazitoProviderProps, SectionTitleProps, SpinnerProps };
@@ -1,9 +1,9 @@
1
1
  'use client';
2
2
  import { jsx, Fragment, jsxs } from 'react/jsx-runtime';
3
3
  import { isValidElement, cloneElement, useMemo, useState, useRef, useEffect, useCallback } from 'react';
4
- import { u as useCheckout, b as useSazitoClient, C as CheckoutProvider } from '../chunks/use-checkout-DwHd4uFh.js';
5
- export { S as SazitoProvider } from '../chunks/use-checkout-DwHd4uFh.js';
6
- import { m as formatPercent, E as sortCartItemsNewestFirst, H as toPersianDigits, r as isDigitalServiceGroup, t as isValidIranianMobile, z as normalizeIranianPhone, A as paymentMethodInfo, l as formatNumber } from '../chunks/labels-CTR6b-KZ.js';
4
+ import { u as useCheckout, b as useSazitoClient, C as CheckoutProvider } from '../chunks/use-checkout-BM810__v.js';
5
+ export { S as SazitoProvider } from '../chunks/use-checkout-BM810__v.js';
6
+ import { m as formatPercent, E as sortCartItemsNewestFirst, H as toPersianDigits, r as isDigitalServiceGroup, t as isValidIranianMobile, z as normalizeIranianPhone, A as paymentMethodInfo, l as formatNumber } from '../chunks/labels-e8w4zRbg.js';
7
7
  import '@sazito/client-sdk';
8
8
 
9
9
  /**
@@ -185,17 +185,29 @@ function attrHexColor(value) {
185
185
  }
186
186
  return toHexColor(value);
187
187
  }
188
- function CartStep({ continueShoppingUrl, renderEmpty, }) {
188
+ function CartStep({ continueShoppingUrl, emptyCart, renderEmpty, }) {
189
189
  const { state, actions, money, t } = useCheckout();
190
190
  const cart = state.cart;
191
191
  const busy = state.flags.updatingCart;
192
192
  const newestCartItems = useMemo(() => sortCartItemsNewestFirst(cart?.items ?? []), [cart?.items]);
193
193
  const invoiceItemsByVariant = new Map((state.invoice?.items ?? []).map((item) => [item.productVariantId, item]));
194
194
  if (!cart || cart.items.length === 0) {
195
+ const title = emptyCart?.title ?? t.cartEmpty;
196
+ const description = emptyCart?.description ?? t.cartEmptyHint;
197
+ const actionLabel = emptyCart?.actionLabel ?? t.continueShopping;
198
+ const actionUrl = emptyCart?.actionUrl ?? continueShoppingUrl;
199
+ const visibleActionUrl = emptyCart?.hideAction ? undefined : actionUrl;
200
+ const icon = emptyCart?.icon ?? jsx(CartIcon, {});
195
201
  if (renderEmpty) {
196
- return renderEmpty({ continueShoppingUrl });
202
+ return renderEmpty({
203
+ continueShoppingUrl: visibleActionUrl,
204
+ title,
205
+ description,
206
+ actionLabel,
207
+ icon,
208
+ });
197
209
  }
198
- return (jsx("section", { className: "szc-empty", role: "status", "aria-live": "polite", children: jsxs("div", { className: "szc-empty__card", children: [jsx("span", { className: "szc-empty__badge", children: jsx(CartIcon, {}) }), jsxs("div", { className: "szc-empty__copy", children: [jsx("h3", { className: "szc-empty__title", children: t.cartEmpty }), jsx("p", { className: "szc-empty__hint", children: t.cartEmptyHint })] }), continueShoppingUrl ? (jsx(Button, { className: "szc-empty__cta", variant: "primary", onClick: () => { window.location.href = continueShoppingUrl; }, children: t.continueShopping })) : null] }) }));
210
+ return (jsx("section", { className: "szc-empty", role: "status", "aria-live": "polite", children: jsxs("div", { className: "szc-empty__card", children: [jsx("span", { className: "szc-empty__badge", "aria-hidden": "true", children: icon }), jsxs("div", { className: "szc-empty__copy", children: [jsx("h2", { className: "szc-empty__title", children: title }), jsx("p", { className: "szc-empty__hint", children: description })] }), visibleActionUrl ? (jsx(Button, { className: "szc-empty__cta", variant: "primary", asChild: true, children: jsx("a", { href: visibleActionUrl, children: actionLabel }) })) : null] }) }));
199
211
  }
200
212
  return (jsx("section", { className: "szc-step-panel", children: jsx("ul", { className: "szc-cart-list", children: newestCartItems.map((item) => {
201
213
  const max = item.product.maxOrderQuantity;
@@ -758,12 +770,13 @@ function themeVars(theme) {
758
770
  function CheckoutLoading({ label }) {
759
771
  return (jsxs("div", { className: "szc-checkout-loading", role: "status", "aria-live": "polite", children: [jsx(Spinner, { className: "szc-checkout-loading__spinner" }), jsx("span", { children: label })] }));
760
772
  }
761
- function SazitoCheckout({ theme, continueShoppingUrl, className, renderNextButton, renderBackButton, renderEmptyCart, }) {
773
+ function SazitoCheckout({ theme, continueShoppingUrl, className, renderNextButton, renderBackButton, renderEmptyCart, emptyCart, }) {
762
774
  const { state, actions, t, summary, money } = useCheckout();
763
775
  const { step, direction, flags, error } = state;
764
776
  const isResult = step === 'result';
765
777
  const bootstrapping = step === 'cart' && !error && (!state.cart || !state.invoice || flags.bootstrapping);
766
- const fatal = error && !state.cart && step === 'cart';
778
+ const emptyCartError = error?.code === 'no_cart';
779
+ const fatal = error && !state.cart && step === 'cart' && !emptyCartError;
767
780
  const cartEmpty = !state.cart || state.cart.items.length === 0;
768
781
  const footerVisible = (step === 'cart' && !cartEmpty) || step === 'shipping' || step === 'payment';
769
782
  const nextBusy = state.status === 'working' ||
@@ -831,20 +844,28 @@ function SazitoCheckout({ theme, continueShoppingUrl, className, renderNextButto
831
844
  ? CardIcon
832
845
  : ClipboardIcon;
833
846
  const mobileHead = (jsxs("div", { className: "szc-mobile-head", children: [footerVisible && backVisible ? (jsx("button", { type: "button", className: "szc-mobile-head__back", "aria-label": t.back, onClick: backOnClick, children: jsx("svg", { className: "szc-back-arrow", viewBox: "0 0 16 16", width: "18", height: "18", fill: "none", "aria-hidden": "true", children: jsx("path", { d: "M9.5 3.5 5 8l4.5 4.5", stroke: "currentColor", strokeWidth: "1.8", strokeLinecap: "round", strokeLinejoin: "round" }) }) })) : (jsx("span", {})), jsxs("span", { className: "szc-mobile-head__title", children: [jsx("span", { className: "szc-mobile-head__dot", children: jsx(HeadIcon, {}) }), headTitle] }), flowIndex >= 0 ? (jsx("span", { className: "szc-mobile-head__count", children: t.stepOf(formatNumber(flowIndex + 1, state.locale), formatNumber(flowSteps.length, state.locale)) })) : (jsx("span", {}))] }));
834
- return (jsxs("div", { className: `szc-root${className ? ` ${className}` : ''}`, dir: direction, style: themeVars(theme), children: [mobileHead, jsx(Stepper, {}), bootstrapping ? (jsx(CheckoutLoading, { label: t.loading })) : fatal ? (jsx(ErrorBanner, { message: error.message })) : isResult ? (jsx("div", { className: "szc-result-wrap", children: jsx(ResultStep, { continueShoppingUrl: continueShoppingUrl }) })) : (jsx(Fragment, { children: jsxs("div", { className: `szc-layout${cartEmpty ? ' szc-layout--full' : ''}`, children: [jsxs("main", { className: "szc-main", children: [error ? jsx(ErrorBanner, { message: error.message }) : null, step === 'cart' ? jsx(CartStep, { continueShoppingUrl: continueShoppingUrl, renderEmpty: renderEmptyCart }) : null, step === 'shipping' ? jsx(ShippingStep, {}) : null, step === 'payment' ? jsx(PaymentStep, {}) : null, actionsVisible && backButtonNode ? (jsx("div", { className: "szc-back-row", children: backButtonNode })) : null] }), !cartEmpty ? (jsxs("div", { className: "szc-side", children: [jsx(OrderSummary, {}), actionsVisible ? jsx("div", { className: "szc-side__cta", children: nextButtonNode }) : null] })) : null] }) })), actionsVisible ? (jsx("div", { className: "szc-footer-bar", children: jsxs("div", { className: "szc-footer", children: [jsxs("div", { className: "szc-footer__total", children: [jsx("span", { className: "szc-footer__total-label", children: t.total }), jsx("span", { className: "szc-footer__total-value", children: money(summary.total) })] }), jsx("div", { className: "szc-footer__actions", children: nextButtonNode })] }) })) : null] }));
847
+ return (jsxs("div", { className: `szc-root${className ? ` ${className}` : ''}`, dir: direction, style: themeVars(theme), children: [mobileHead, jsx(Stepper, {}), bootstrapping ? (jsx(CheckoutLoading, { label: t.loading })) : fatal ? (jsx(ErrorBanner, { message: error.message })) : isResult ? (jsx("div", { className: "szc-result-wrap", children: jsx(ResultStep, { continueShoppingUrl: continueShoppingUrl }) })) : (jsx(Fragment, { children: jsxs("div", { className: `szc-layout${cartEmpty ? ' szc-layout--full' : ''}`, children: [jsxs("main", { className: "szc-main", children: [error && !emptyCartError ? jsx(ErrorBanner, { message: error.message }) : null, step === 'cart' ? (jsx(CartStep, { continueShoppingUrl: continueShoppingUrl, emptyCart: emptyCart, renderEmpty: renderEmptyCart })) : null, step === 'shipping' ? jsx(ShippingStep, {}) : null, step === 'payment' ? jsx(PaymentStep, {}) : null, actionsVisible && backButtonNode ? (jsx("div", { className: "szc-back-row", children: backButtonNode })) : null] }), !cartEmpty ? (jsxs("div", { className: "szc-side", children: [jsx(OrderSummary, {}), actionsVisible ? jsx("div", { className: "szc-side__cta", children: nextButtonNode }) : null] })) : null] }) })), actionsVisible ? (jsx("div", { className: "szc-footer-bar", children: jsxs("div", { className: "szc-footer", children: [jsxs("div", { className: "szc-footer__total", children: [jsx("span", { className: "szc-footer__total-label", children: t.total }), jsx("span", { className: "szc-footer__total-value", children: money(summary.total) })] }), jsx("div", { className: "szc-footer__actions", children: nextButtonNode })] }) })) : null] }));
835
848
  }
836
849
 
837
- function SazitoCheckoutPage({ credentials, config, paymentReturnParams, className, renderNextButton, renderBackButton, renderEmptyCart, }) {
838
- const isReturn = paymentReturnParams != null;
850
+ function SazitoCheckoutPage({ credentials, config, paymentReturn, paymentReturnParams, className, renderNextButton, renderBackButton, renderEmptyCart, emptyCart, }) {
851
+ const returnParams = paymentReturn?.params ?? paymentReturnParams;
852
+ const isReturn = returnParams != null;
853
+ const checkoutCredentials = paymentReturn
854
+ ? { ...credentials, payment: paymentReturn.payment }
855
+ : credentials;
839
856
  const client = useSazitoClient();
840
- return (jsxs(CheckoutProvider, { client: client, credentials: credentials, config: config, autoStart: !isReturn, children: [isReturn ? jsx(ResolveReturn, { params: paymentReturnParams }) : null, jsx(SazitoCheckout, { theme: config?.theme, continueShoppingUrl: config?.continueShoppingUrl, className: className, renderNextButton: renderNextButton, renderBackButton: renderBackButton, renderEmptyCart: renderEmptyCart })] }));
857
+ return (jsxs(CheckoutProvider, { client: client, credentials: checkoutCredentials, config: config, autoStart: !isReturn, children: [returnParams ? jsx(ResolveReturn, { params: returnParams }) : null, jsx(SazitoCheckout, { theme: config?.theme, continueShoppingUrl: config?.continueShoppingUrl, className: className, renderNextButton: renderNextButton, renderBackButton: renderBackButton, renderEmptyCart: renderEmptyCart, emptyCart: emptyCart })] }));
841
858
  }
842
859
  function ResolveReturn({ params }) {
843
860
  const { actions } = useCheckout();
861
+ const resolvedKey = useRef(null);
862
+ const paramsKey = JSON.stringify(Object.entries(params).sort(([a], [b]) => a.localeCompare(b)));
844
863
  useEffect(() => {
864
+ if (resolvedKey.current === paramsKey)
865
+ return;
866
+ resolvedKey.current = paramsKey;
845
867
  void actions.resolvePaymentReturn(params);
846
- // eslint-disable-next-line react-hooks/exhaustive-deps
847
- }, []);
868
+ }, [actions, params, paramsKey]);
848
869
  return null;
849
870
  }
850
871