@sonic-equipment/ui 121.0.0 → 123.0.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 (75) hide show
  1. package/dist/checkout/adyen-payment.d.ts +21 -0
  2. package/dist/checkout/adyen-payment.js +165 -0
  3. package/dist/checkout/parse-amount.d.ts +2 -0
  4. package/dist/checkout/parse-amount.js +10 -0
  5. package/dist/checkout/payment-details.d.ts +5 -0
  6. package/dist/checkout/payment-details.js +21 -0
  7. package/dist/checkout/payment.d.ts +6 -0
  8. package/dist/checkout/payment.js +69 -0
  9. package/dist/collapsables/accordion/accordion-item.d.ts +2 -1
  10. package/dist/collapsables/accordion/accordion-item.js +6 -2
  11. package/dist/collapsables/accordion/accordion.module.css.js +1 -1
  12. package/dist/config.js +1 -1
  13. package/dist/exports.d.ts +18 -0
  14. package/dist/forms/field-error/field-error.d.ts +14 -1
  15. package/dist/forms/field-error/field-error.js +15 -1
  16. package/dist/forms/input/input.d.ts +1 -0
  17. package/dist/forms/input/input.js +2 -2
  18. package/dist/forms/number-field/number-field.d.ts +3 -1
  19. package/dist/forms/number-field/number-field.js +3 -3
  20. package/dist/forms/text-field/text-field.d.ts +4 -1
  21. package/dist/forms/text-field/text-field.js +3 -3
  22. package/dist/forms/textarea/textarea.d.ts +1 -0
  23. package/dist/forms/textarea/textarea.js +10 -10
  24. package/dist/icons/stroke/stroke-information-icon.js +7 -0
  25. package/dist/index.js +20 -2
  26. package/dist/intl/translation-id.d.ts +1 -1
  27. package/dist/pages/cart-page/cart-page.js +1 -0
  28. package/dist/shared/api/storefront/hooks/authentication/use-create-guest-account.d.ts +4 -0
  29. package/dist/shared/api/storefront/hooks/authentication/use-create-guest-account.js +21 -0
  30. package/dist/shared/api/storefront/hooks/authentication/use-patch-session.d.ts +4 -0
  31. package/dist/shared/api/storefront/hooks/authentication/use-patch-session.js +15 -0
  32. package/dist/shared/api/storefront/hooks/authentication/use-sign-in.js +14 -9
  33. package/dist/shared/api/storefront/hooks/authentication/use-sign-out.js +1 -2
  34. package/dist/shared/api/storefront/hooks/cart/use-add-product-to-current-cart.js +1 -7
  35. package/dist/shared/api/storefront/hooks/cart/use-delete-cart-line-by-id.js +1 -4
  36. package/dist/shared/api/storefront/hooks/cart/use-fetch-current-cart.js +3 -1
  37. package/dist/shared/api/storefront/hooks/cart/use-patch-cart.d.ts +3 -4
  38. package/dist/shared/api/storefront/hooks/cart/use-patch-cart.js +6 -8
  39. package/dist/shared/api/storefront/hooks/cart/use-place-order.d.ts +3 -3
  40. package/dist/shared/api/storefront/hooks/cart/use-place-order.js +7 -8
  41. package/dist/shared/api/storefront/hooks/cart/use-update-cart-line-by-id.js +1 -13
  42. package/dist/shared/api/storefront/hooks/customer/use-fetch-bill-to-addresses.d.ts +1 -0
  43. package/dist/shared/api/storefront/hooks/customer/use-fetch-bill-to-addresses.js +14 -0
  44. package/dist/shared/api/storefront/hooks/customer/use-fetch-ship-to-addresses.d.ts +3 -0
  45. package/dist/shared/api/storefront/hooks/customer/use-fetch-ship-to-addresses.js +15 -0
  46. package/dist/shared/api/storefront/hooks/customer/use-update-bill-to-address.d.ts +6 -0
  47. package/dist/shared/api/storefront/hooks/customer/use-update-bill-to-address.js +17 -0
  48. package/dist/shared/api/storefront/hooks/payment/use-create-adyen-session.d.ts +3 -0
  49. package/dist/shared/api/storefront/hooks/payment/use-create-adyen-session.js +10 -0
  50. package/dist/shared/api/storefront/hooks/payment/use-fetch-adyen-config.d.ts +1 -0
  51. package/dist/shared/api/storefront/hooks/payment/use-fetch-adyen-config.js +14 -0
  52. package/dist/shared/api/storefront/hooks/payment/use-invalidate-adyen.d.ts +1 -0
  53. package/dist/shared/api/storefront/hooks/payment/use-invalidate-adyen.js +9 -0
  54. package/dist/shared/api/storefront/model/shop.model.d.ts +17 -0
  55. package/dist/shared/api/storefront/services/cart-service.d.ts +15 -2
  56. package/dist/shared/api/storefront/services/cart-service.js +68 -3
  57. package/dist/shared/api/storefront/services/customer-service.d.ts +8 -0
  58. package/dist/shared/api/storefront/services/customer-service.js +31 -0
  59. package/dist/shared/api/storefront/services/payment-service.d.ts +8 -0
  60. package/dist/shared/api/storefront/services/payment-service.js +29 -0
  61. package/dist/shared/feature-flags/use-feature-flags.d.ts +1 -1
  62. package/dist/shared/feature-flags/use-feature-flags.js +1 -1
  63. package/dist/shared/model/address.d.ts +2 -0
  64. package/dist/shared/model/address.js +7 -0
  65. package/dist/shared/model/countries.d.ts +225 -0
  66. package/dist/shared/model/countries.js +260 -0
  67. package/dist/shared/utils/price.d.ts +38 -0
  68. package/dist/shared/utils/price.js +39 -1
  69. package/dist/shared/utils/random.d.ts +10 -0
  70. package/dist/shared/utils/random.js +16 -0
  71. package/dist/styles.css +169 -77
  72. package/dist/tooltip/tooltip.d.ts +9 -0
  73. package/dist/tooltip/tooltip.js +21 -0
  74. package/dist/tooltip/tooltip.module.css.js +3 -0
  75. package/package.json +2 -2
@@ -0,0 +1,21 @@
1
+ import { MutableRefObject } from 'react';
2
+ import Dropin from '@adyen/adyen-web/dist/types/components/Dropin';
3
+ import { AdyenPaymentModel } from 'shared/api/storefront/model/shop.model';
4
+ import '@adyen/adyen-web/dist/adyen.css';
5
+ interface AdyenPaymentProps {
6
+ amount: number;
7
+ billToId: string;
8
+ cartId: string;
9
+ countryCode: string;
10
+ currencyCode: string;
11
+ dropinRef: MutableRefObject<Dropin | null>;
12
+ environment: 'test' | 'live' | 'live-us' | 'live-au' | 'live-apse' | 'live-in';
13
+ locale: string;
14
+ onComplete: (result: AdyenPaymentModel) => Promise<void>;
15
+ onError: (error: unknown, result: AdyenPaymentModel) => void;
16
+ orderAmount: number;
17
+ redirectResult: string | undefined;
18
+ returnUrl: string;
19
+ }
20
+ export declare function AdyenPayment({ amount, billToId, cartId, countryCode, currencyCode, dropinRef, environment, locale, onComplete, onError, orderAmount, redirectResult, returnUrl, }: AdyenPaymentProps): import("react/jsx-runtime").JSX.Element;
21
+ export {};
@@ -0,0 +1,165 @@
1
+ import { jsx } from 'react/jsx-runtime';
2
+ import { useRef, useEffect } from 'react';
3
+ import AdyenCheckout from '@adyen/adyen-web';
4
+ import qs from 'query-string';
5
+ import { useCreateAdyenSession } from '../shared/api/storefront/hooks/payment/use-create-adyen-session.js';
6
+ import { useFetchAdyenConfig } from '../shared/api/storefront/hooks/payment/use-fetch-adyen-config.js';
7
+ import { getAdyenPaymentDetails, postAdyenPayment } from '../shared/api/storefront/services/cart-service.js';
8
+ import { parseAmount } from './parse-amount.js';
9
+
10
+ function AdyenPayment({ amount, billToId, cartId, countryCode, currencyCode, dropinRef, environment, locale, onComplete, onError, orderAmount, redirectResult, returnUrl, }) {
11
+ const dropinDivRef = useRef(null);
12
+ const { data: adyenSettings } = useFetchAdyenConfig();
13
+ const { data: adyenSession, error, mutate: createAdyenSession, } = useCreateAdyenSession();
14
+ useEffect(() => {
15
+ createAdyenSession({
16
+ cartId,
17
+ orderAmount,
18
+ returnUrl,
19
+ });
20
+ }, [cartId, countryCode, orderAmount, returnUrl, createAdyenSession]);
21
+ useEffect(() => {
22
+ if (!adyenSettings || !adyenSession || !dropinDivRef.current)
23
+ return;
24
+ const options = {
25
+ amount: parseAmount(amount, countryCode),
26
+ analytics: {
27
+ enabled: false,
28
+ },
29
+ clientKey: adyenSettings.clientKey,
30
+ countryCode,
31
+ environment,
32
+ locale,
33
+ onAdditionalDetails: (async (state, _component) => {
34
+ if (!state.details.redirectResult) {
35
+ throw new Error('No redirectResult');
36
+ }
37
+ const result = await getAdyenPaymentDetails({
38
+ redirectResult: state.details.redirectResult,
39
+ });
40
+ const { amount: adyenAmount, customerId: adyenCustomerId } = getAndRemoveAdyenQueryParams();
41
+ if (amount.toFixed(2).replaceAll(/[,.]/gi, '') !== adyenAmount)
42
+ return onError(new Error('Invalid amount'), result);
43
+ if (billToId !== adyenCustomerId)
44
+ return onError(new Error('Invalid customer'), result);
45
+ return handlePaymentResponse(result, onComplete, onError);
46
+ }),
47
+ onSubmit: (async (state, _component) => {
48
+ if (state.data.paymentMethod.type === 'paybybank') {
49
+ state.data.countryCode = countryCode;
50
+ }
51
+ const result = await postAdyenPayment({
52
+ currencyCode,
53
+ data: state.data,
54
+ orderAmount,
55
+ returnUrl,
56
+ webOrderNumber: adyenSession.webOrderNumber,
57
+ });
58
+ if (result.action) {
59
+ if (result.action.type === 'redirect') {
60
+ return handleRedirectPaymentAction(result);
61
+ }
62
+ throw new Error('Invalid payment response');
63
+ }
64
+ return handlePaymentResponse(result, onComplete, onError);
65
+ }),
66
+ session: {
67
+ ...adyenSession,
68
+ id: adyenSession.transactionId,
69
+ },
70
+ showPayButton: false,
71
+ };
72
+ (async function loadAdyen() {
73
+ if (!dropinDivRef.current)
74
+ return;
75
+ const checkout = await AdyenCheckout(options);
76
+ const dropIn = checkout.create('dropin');
77
+ if (redirectResult)
78
+ checkout.submitDetails({ details: { redirectResult } });
79
+ if (dropinRef.current)
80
+ dropinRef.current.unmount();
81
+ dropinRef.current = dropIn.mount(dropinDivRef.current);
82
+ })();
83
+ }, [
84
+ billToId,
85
+ adyenSettings,
86
+ adyenSession,
87
+ amount,
88
+ countryCode,
89
+ currencyCode,
90
+ environment,
91
+ locale,
92
+ orderAmount,
93
+ redirectResult,
94
+ returnUrl,
95
+ dropinRef,
96
+ onComplete,
97
+ onError,
98
+ ]);
99
+ if (error)
100
+ return jsx("div", { children: String(error) });
101
+ return jsx("div", { ref: dropinDivRef, id: "dropin" });
102
+ }
103
+ function getAndRemoveAdyenQueryParams() {
104
+ if (typeof window === 'undefined')
105
+ return {};
106
+ const params = qs.parse(window.location.search || '');
107
+ const { amount, customerId, redirectResult } = params;
108
+ delete params['redirectResult'];
109
+ delete params['amount'];
110
+ delete params['customerId'];
111
+ history?.pushState({}, '', `${window.location.pathname}${qs.stringify(params) ? `?${qs.stringify(params)}` : ''}`);
112
+ return { amount, customerId, redirectResult };
113
+ }
114
+ async function handlePaymentResponse(result, onSubmit, onError) {
115
+ try {
116
+ if (result.action) {
117
+ if (result.action.type === 'redirect') {
118
+ handleRedirectPaymentAction(result);
119
+ }
120
+ else {
121
+ throw new Error('Adyen_Error');
122
+ }
123
+ }
124
+ else {
125
+ switch (result.resultCode) {
126
+ case 'Pending':
127
+ case 'Received':
128
+ case 'Authorised':
129
+ return await onSubmit(result);
130
+ case 'Refused':
131
+ throw new Error('Adyen_Refused');
132
+ case 'Cancelled':
133
+ throw new Error('Adyen_Cancelled');
134
+ default:
135
+ throw new Error('Adyen_Error');
136
+ }
137
+ }
138
+ }
139
+ catch (error) {
140
+ onError(error, result);
141
+ }
142
+ }
143
+ function handleRedirectPaymentAction(adyenPaymentResult) {
144
+ if (typeof window === 'undefined' || typeof document === 'undefined')
145
+ return;
146
+ if (adyenPaymentResult.action.method === 'GET') {
147
+ window.location.href = adyenPaymentResult.action.url;
148
+ }
149
+ else if (adyenPaymentResult.action.method === 'POST') {
150
+ const form = document.createElement('form');
151
+ form.method = 'POST';
152
+ form.action = adyenPaymentResult.action.url;
153
+ for (const key in adyenPaymentResult.action.data) {
154
+ const input = document.createElement('input');
155
+ input.name = key;
156
+ input.value = adyenPaymentResult.action.data[key];
157
+ form.append(input);
158
+ }
159
+ document.body.append(form);
160
+ form.submit();
161
+ form.remove();
162
+ }
163
+ }
164
+
165
+ export { AdyenPayment };
@@ -0,0 +1,2 @@
1
+ import { PaymentAmountExtended } from '@adyen/adyen-web/dist/types/types';
2
+ export declare function parseAmount(amount: string | number, countryCode: string): PaymentAmountExtended;
@@ -0,0 +1,10 @@
1
+ import { getCurrencyByCountryCode } from '../shared/utils/price.js';
2
+
3
+ function parseAmount(amount, countryCode) {
4
+ return {
5
+ currency: getCurrencyByCountryCode(countryCode),
6
+ value: Number(amount),
7
+ };
8
+ }
9
+
10
+ export { parseAmount };
@@ -0,0 +1,5 @@
1
+ import { CartModel } from '../shared/api/storefront/model/shop.model';
2
+ export declare function PaymentDetails({ cart, onCartChanged, }: {
3
+ cart: CartModel;
4
+ onCartChanged: (cart: CartModel) => void;
5
+ }): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,21 @@
1
+ import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
2
+ import { useState, useEffect } from 'react';
3
+ import { TextField } from '../forms/text-field/text-field.js';
4
+ import { useFormattedMessage } from '../intl/use-formatted-message.js';
5
+ import { useDebouncedCallback } from '../shared/hooks/use-debounced-callback.js';
6
+
7
+ function PaymentDetails({ cart, onCartChanged, }) {
8
+ const [vatNumber, setVatNumber] = useState(cart.customerVatNumber);
9
+ const [poNumber, setPONumber] = useState(cart.poNumber);
10
+ const t = useFormattedMessage();
11
+ const onCartChangedDebounced = useDebouncedCallback(onCartChanged, 500);
12
+ useEffect(() => {
13
+ if (!vatNumber || !poNumber)
14
+ return;
15
+ onCartChangedDebounced({ ...cart, customerVatNumber: vatNumber, poNumber });
16
+ // eslint-disable-next-line react-hooks/exhaustive-deps
17
+ }, [vatNumber, poNumber]);
18
+ return (jsxs(Fragment, { children: [jsx(TextField, { isRequired: true, showLabel: true, label: t('VAT Number'), minLength: 8, onChange: setVatNumber, value: vatNumber }), jsx(TextField, { isRequired: true, showLabel: true, label: t('PO Number'), onChange: setPONumber, value: poNumber })] }));
19
+ }
20
+
21
+ export { PaymentDetails };
@@ -0,0 +1,6 @@
1
+ import { AdyenPaymentModel, CartModel } from '../shared/api/storefront/model/shop.model';
2
+ export declare function Payment({ cart: _cart, onError, onPaymentComplete, }: {
3
+ cart: CartModel;
4
+ onError: (error: unknown, result: AdyenPaymentModel) => void;
5
+ onPaymentComplete: () => void;
6
+ }): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,69 @@
1
+ import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
2
+ import { useRef, useEffect, useCallback } from 'react';
3
+ import { Form } from 'react-aria-components';
4
+ import qs from 'query-string';
5
+ import { Button } from '../buttons/button/button.js';
6
+ import { usePatchCart } from '../shared/api/storefront/hooks/cart/use-patch-cart.js';
7
+ import { usePlaceOrder } from '../shared/api/storefront/hooks/cart/use-place-order.js';
8
+ import { currencySymbolToISO } from '../shared/model/currency.js';
9
+ import { AdyenPayment } from './adyen-payment.js';
10
+ import { PaymentDetails } from './payment-details.js';
11
+
12
+ function Payment({ cart: _cart, onError, onPaymentComplete, }) {
13
+ const patchCart = usePatchCart();
14
+ const placeOrder = usePlaceOrder();
15
+ const dropinRef = useRef(null);
16
+ const cartRef = useRef(_cart);
17
+ const cart = cartRef.current;
18
+ const { redirectResult } =
19
+ // eslint-disable-next-line ssr-friendly/no-dom-globals-in-react-fc
20
+ typeof window === 'undefined' ? {} : qs.parse(window.location.search || '');
21
+ const allowSubmit = !redirectResult;
22
+ const countryCode = _cart.billTo?.country?.abbreviation;
23
+ useEffect(() => {
24
+ cartRef.current = _cart;
25
+ }, [_cart]);
26
+ async function onSubmit() {
27
+ const cart = cartRef.current;
28
+ dropinRef.current?.showValidation();
29
+ if (!cart.customerVatNumber)
30
+ return;
31
+ if (dropinRef.current) {
32
+ if (!dropinRef.current.isValid)
33
+ return;
34
+ await patchCart({ cart });
35
+ dropinRef.current.submit();
36
+ }
37
+ }
38
+ const onComplete = useCallback(async (result) => {
39
+ const cart = cartRef.current;
40
+ await placeOrder({
41
+ cart: {
42
+ ...cart,
43
+ paymentMethod: null,
44
+ paymentOptions: {
45
+ ...cart.paymentOptions,
46
+ adyenPspReference: result.pspReference,
47
+ isAdyenDropIn: true,
48
+ },
49
+ },
50
+ });
51
+ return onPaymentComplete();
52
+ }, [onPaymentComplete, placeOrder]);
53
+ return (jsxs(Fragment, { children: [jsx("h2", { children: "Payment" }), jsxs(Form, { onSubmit: e => {
54
+ e.preventDefault();
55
+ onSubmit();
56
+ }, children: [!redirectResult && (jsx(PaymentDetails, { cart: cart, onCartChanged: cart => {
57
+ cartRef.current = cart;
58
+ } })), cart.paymentMethod?.name === 'PBI' && 'Pay by invoice', cart.paymentMethod?.name !== 'PBI' &&
59
+ cart.paymentOptions &&
60
+ cart.billTo?.id &&
61
+ countryCode && (jsx(AdyenPayment, { amount: cart.orderGrandTotal, billToId: cart.billTo.id, cartId: cart.trackId, countryCode: countryCode, currencyCode: currencySymbolToISO[cart.currencySymbol], dropinRef: dropinRef, environment: "test", locale: "nl-NL", onComplete: onComplete, onError: onError, orderAmount: cart.orderGrandTotal, redirectResult: !redirectResult || Array.isArray(redirectResult)
62
+ ? undefined
63
+ : redirectResult, returnUrl: typeof window === 'undefined'
64
+ ? ''
65
+ : // eslint-disable-next-line ssr-friendly/no-dom-globals-in-react-fc
66
+ `${window.location.pathname}${window.location.search ? `?${window.location.search}` : ''}` })), jsx(Button, { isDisabled: !allowSubmit, type: "submit", children: "Pay" })] })] }));
67
+ }
68
+
69
+ export { Payment };
@@ -2,6 +2,7 @@ import { ReactNode } from 'react';
2
2
  export type BorderType = 'top' | 'middle' | 'middle-accentuated' | 'bottom';
3
3
  export interface AccordionItemProps {
4
4
  _pseudo?: 'none' | 'focus' | 'hover' | 'active';
5
+ allowToggle?: boolean;
5
6
  borderType?: BorderType | BorderType[];
6
7
  children: ReactNode;
7
8
  className?: string;
@@ -11,4 +12,4 @@ export interface AccordionItemProps {
11
12
  size?: 'md' | 'lg';
12
13
  title: ReactNode;
13
14
  }
14
- export declare function AccordionItem({ _pseudo, borderType, children, className, id, initialIsOpen, isDisabled, size, title, }: AccordionItemProps): import("react/jsx-runtime").JSX.Element;
15
+ export declare function AccordionItem({ _pseudo, allowToggle, borderType, children, className, id, initialIsOpen, isDisabled, size, title, }: AccordionItemProps): import("react/jsx-runtime").JSX.Element;
@@ -7,12 +7,16 @@ import { useDisclosure } from '../../shared/hooks/use-disclosure.js';
7
7
  import { ensureArray } from '../../shared/utils/array.js';
8
8
  import styles from './accordion.module.css.js';
9
9
 
10
- function AccordionItem({ _pseudo = 'none', borderType = 'bottom', children, className, id, initialIsOpen = false, isDisabled = false, size, title, }) {
10
+ function AccordionItem({ _pseudo = 'none', allowToggle = true, borderType = 'bottom', children, className, id, initialIsOpen = false, isDisabled = false, size, title, }) {
11
11
  const { isOpen, toggle } = useDisclosure(initialIsOpen);
12
12
  const panelId = `panel-${id}`;
13
13
  return (jsxs("div", { className: clsx(className, ...ensureArray(borderType).map(type => styles[`border-type-${type}`]), styles['accordion-item'], {
14
14
  [styles['is-open']]: isOpen,
15
- }), children: [jsx("h3", { children: jsxs("button", { "aria-controls": panelId, "aria-expanded": isOpen, className: clsx(styles.button, styles[_pseudo]), disabled: isDisabled, id: id, onClick: toggle, type: "button", children: [title, jsx("span", { className: styles.icon, children: size === 'lg' ? (jsx(GlyphsChevronsBoldDownIcon, {})) : (jsx(GlyphsChevronsSlimDownIcon, {})) })] }) }), jsx("div", { "aria-labelledby": id, className: styles.panel, id: panelId, role: "region", children: jsx("div", { className: styles.content, children: children }) })] }));
15
+ [styles['allow-toggle']]: allowToggle,
16
+ }), children: [jsx("h3", { children: jsxs("button", { "aria-controls": panelId, "aria-expanded": isOpen, className: clsx(styles.button, styles[_pseudo]), disabled: isDisabled, id: id, onClick: () => {
17
+ if (allowToggle)
18
+ toggle();
19
+ }, type: "button", children: [title, jsx("span", { className: styles.icon, children: size === 'lg' ? (jsx(GlyphsChevronsBoldDownIcon, {})) : (jsx(GlyphsChevronsSlimDownIcon, {})) })] }) }), jsx("div", { "aria-labelledby": id, className: styles.panel, id: panelId, role: "region", children: jsx("div", { className: styles.content, children: children }) })] }));
16
20
  }
17
21
 
18
22
  export { AccordionItem };
@@ -1,3 +1,3 @@
1
- var styles = {"accordion":"accordion-module-9WvAH","indented":"accordion-module-6CcEH","white":"accordion-module-CaVdG","accordion-item":"accordion-module-lf9d-","lg":"accordion-module-0qnae","with-seperators":"accordion-module-yOLrW","button":"accordion-module--Rwpb","icon":"accordion-module-Y50uq","focus":"accordion-module-M4BZs","panel":"accordion-module-KZjMo","content":"accordion-module-ejMH3","border-type-bottom":"accordion-module-oTdZK","border-type-top":"accordion-module-0mrLq","border-type-middle":"accordion-module-aAr-R","is-open":"accordion-module-W0F1z","border-type-middle-accentuated":"accordion-module-OB98a"};
1
+ var styles = {"accordion":"accordion-module-9WvAH","indented":"accordion-module-6CcEH","white":"accordion-module-CaVdG","accordion-item":"accordion-module-lf9d-","lg":"accordion-module-0qnae","with-seperators":"accordion-module-yOLrW","button":"accordion-module--Rwpb","icon":"accordion-module-Y50uq","focus":"accordion-module-M4BZs","allow-toggle":"accordion-module-QEO2d","panel":"accordion-module-KZjMo","content":"accordion-module-ejMH3","border-type-bottom":"accordion-module-oTdZK","border-type-top":"accordion-module-0mrLq","border-type-middle":"accordion-module-aAr-R","is-open":"accordion-module-W0F1z","border-type-middle-accentuated":"accordion-module-OB98a"};
2
2
 
3
3
  export { styles as default };
package/dist/config.js CHANGED
@@ -3,7 +3,7 @@ import main from './shared/utils/merge.js';
3
3
 
4
4
  const env = (typeof process === 'undefined'
5
5
  ? { VITE_SHOP_API_URL: ""}
6
- : main(process.env, { VITE_SHOP_API_URL: ""}));
6
+ : main({ ...process.env }, { VITE_SHOP_API_URL: ""}));
7
7
  const validateEnvVariable = (name, value) => {
8
8
  if (value)
9
9
  return value;
package/dist/exports.d.ts CHANGED
@@ -55,6 +55,10 @@ export * from './carousel/usp-carousel/product-usp-carousel-slide';
55
55
  export * from './carousel/usp-carousel/usp-carousel';
56
56
  export * from './cart-totals/cart-totals';
57
57
  export * from './cart-totals/cart-totals-summary';
58
+ export * from './checkout/adyen-payment';
59
+ export * from './checkout/parse-amount';
60
+ export * from './checkout/payment';
61
+ export * from './checkout/payment-details';
58
62
  export * from './collapsables/accordion/accordion';
59
63
  export * from './collapsables/accordion/accordion-item';
60
64
  export * from './collapsables/show-all/show-all';
@@ -163,9 +167,11 @@ export * from './shared/api/bff/hooks/use-fetch-announcements';
163
167
  export * from './shared/api/bff/hooks/use-fetch-product-details-page-data';
164
168
  export * from './shared/api/bff/hooks/use-fetch-product-listing-page-data';
165
169
  export * from './shared/api/bff/services/bff-service';
170
+ export * from './shared/api/storefront/hooks/authentication/use-create-guest-account';
166
171
  export * from './shared/api/storefront/hooks/authentication/use-fetch-session';
167
172
  export * from './shared/api/storefront/hooks/authentication/use-invalidate-session';
168
173
  export * from './shared/api/storefront/hooks/authentication/use-is-authenticated';
174
+ export * from './shared/api/storefront/hooks/authentication/use-patch-session';
169
175
  export * from './shared/api/storefront/hooks/authentication/use-sign-in';
170
176
  export * from './shared/api/storefront/hooks/authentication/use-sign-out';
171
177
  export * from './shared/api/storefront/hooks/cart/use-add-product-to-current-cart';
@@ -184,6 +190,12 @@ export * from './shared/api/storefront/hooks/cart/use-patch-cart';
184
190
  export * from './shared/api/storefront/hooks/cart/use-place-order';
185
191
  export * from './shared/api/storefront/hooks/cart/use-save-cart-for-later';
186
192
  export * from './shared/api/storefront/hooks/cart/use-update-cart-line-by-id';
193
+ export * from './shared/api/storefront/hooks/customer/use-fetch-bill-to-addresses';
194
+ export * from './shared/api/storefront/hooks/customer/use-fetch-ship-to-addresses';
195
+ export * from './shared/api/storefront/hooks/customer/use-update-bill-to-address';
196
+ export * from './shared/api/storefront/hooks/payment/use-create-adyen-session';
197
+ export * from './shared/api/storefront/hooks/payment/use-fetch-adyen-config';
198
+ export * from './shared/api/storefront/hooks/payment/use-invalidate-adyen';
187
199
  export * from './shared/api/storefront/hooks/translation/use-fetch-translations';
188
200
  export * from './shared/api/storefront/hooks/website/use-fetch-countries';
189
201
  export * from './shared/api/storefront/hooks/website/use-fetch-countries-languages';
@@ -198,6 +210,8 @@ export * from './shared/api/storefront/hooks/wishlist/use-fetch-all-wishlists-it
198
210
  export * from './shared/api/storefront/hooks/wishlist/use-fetch-wishlists';
199
211
  export * from './shared/api/storefront/services/authentication-service';
200
212
  export * from './shared/api/storefront/services/cart-service';
213
+ export * from './shared/api/storefront/services/customer-service';
214
+ export * from './shared/api/storefront/services/payment-service';
201
215
  export * from './shared/api/storefront/services/translation-service';
202
216
  export * from './shared/api/storefront/services/website-service';
203
217
  export * from './shared/api/storefront/services/wishlist-service';
@@ -215,8 +229,10 @@ export * from './shared/hooks/use-scroll-lock';
215
229
  export * from './shared/hooks/use-scroll-to';
216
230
  export * from './shared/hooks/use-session-storage';
217
231
  export * from './shared/hooks/use-watch-css-property';
232
+ export * from './shared/model/address';
218
233
  export * from './shared/model/announcement';
219
234
  export * from './shared/model/category';
235
+ export * from './shared/model/countries';
220
236
  export * from './shared/model/countries-languages';
221
237
  export * from './shared/model/currency';
222
238
  export * from './shared/model/hit';
@@ -238,6 +254,7 @@ export * from './shared/utils/environment';
238
254
  export * from './shared/utils/event-emitter';
239
255
  export * from './shared/utils/merge';
240
256
  export * from './shared/utils/price';
257
+ export * from './shared/utils/random';
241
258
  export * from './shared/utils/time';
242
259
  export * from './shared/utils/uuid';
243
260
  export * from './shared/utils/wait';
@@ -251,4 +268,5 @@ export * from './toast/toast-provider';
251
268
  export * from './toast/types';
252
269
  export * from './toast/use-toast';
253
270
  export * from './tokens/tokens';
271
+ export * from './tooltip/tooltip';
254
272
  export * from './typography/heading/heading';
@@ -1,5 +1,18 @@
1
+ import { ReactNode } from 'react';
2
+ export type ValidationError = string | string[];
3
+ export type ValidateFunction<T> = (value: T) => ValidationError | true | null | undefined;
4
+ export interface ValidationResult {
5
+ /** Whether the input value is invalid. */
6
+ isInvalid: boolean;
7
+ /** The native validation details for the input. */
8
+ validationDetails: ValidityState;
9
+ /** The current error messages for the input if it is invalid, otherwise an empty array. */
10
+ validationErrors: string[];
11
+ }
1
12
  interface FieldErrorProps {
2
- children?: string;
13
+ children?: ReactNode | ((values: ValidationResult & {
14
+ defaultChildren: ReactNode;
15
+ }) => ReactNode);
3
16
  }
4
17
  export declare function FieldError({ children }: FieldErrorProps): import("react/jsx-runtime").JSX.Element;
5
18
  export {};
@@ -1,10 +1,24 @@
1
1
  "use client";
2
2
  import { jsx } from 'react/jsx-runtime';
3
3
  import { FieldError as FieldError$1 } from 'react-aria-components';
4
+ import { useFormattedMessage } from '../../intl/use-formatted-message.js';
4
5
  import styles from './field-error.module.css.js';
5
6
 
6
7
  function FieldError({ children }) {
7
- return (jsx(FieldError$1, { className: styles['field-error'], children: children }));
8
+ const t = useFormattedMessage();
9
+ return (jsx(FieldError$1, { className: styles['field-error'], children: children ||
10
+ (result => {
11
+ if (!result.isInvalid)
12
+ return;
13
+ if (result.validationDetails.customError)
14
+ return result.validationErrors[0];
15
+ const validationErrorType = Object.entries(result.validationDetails)
16
+ .filter(([, value]) => value)
17
+ .map(([key]) => key)[0];
18
+ if (validationErrorType)
19
+ return t(`validation.${validationErrorType}`);
20
+ return t('validation.invalid');
21
+ }) }));
8
22
  }
9
23
 
10
24
  export { FieldError };
@@ -3,6 +3,7 @@ import { Input as AriaInput } from 'react-aria-components';
3
3
  export interface InputProps extends Omit<ComponentProps<typeof AriaInput>, 'size'> {
4
4
  _pseudo?: 'focus' | 'none';
5
5
  autoGrow?: boolean;
6
+ label: string;
6
7
  size?: 'md' | 'lg';
7
8
  value?: string | number;
8
9
  }
@@ -10,7 +10,7 @@ import styles from './input.module.css.js';
10
10
  * This component is used to create an input that grows as the user types.
11
11
  * It uses a shadow input to calculate the width of the input.
12
12
  */
13
- const Input = forwardRef(({ _pseudo = 'none', autoGrow, size = 'lg', ...inputProps }, inputRef) => {
13
+ const Input = forwardRef(({ _pseudo = 'none', autoGrow, label, size = 'lg', ...inputProps }, inputRef) => {
14
14
  const [props, ref] = useContextProps(inputProps, inputRef, InputContext);
15
15
  const { defaultValue, onChange, value: controlledValue } = props;
16
16
  const [uncontrolledValue, setUncontrolledValue] = useState(defaultValue);
@@ -20,7 +20,7 @@ const Input = forwardRef(({ _pseudo = 'none', autoGrow, size = 'lg', ...inputPro
20
20
  ? onChange?.(event)
21
21
  : setUncontrolledValue(event.target.value);
22
22
  const { pressProps } = usePress({});
23
- return (jsx("div", { className: clsx(styles['input-container'], styles[size], styles[_pseudo]), children: jsxs("div", { className: clsx({ [styles['growing-input']]: autoGrow }), children: [jsx(Input$1, { size: autoGrow ? 1 : undefined, ...props, ...pressProps, ref: ref, onChange: handleChange, onClick: e => {
23
+ return (jsx("div", { className: clsx(styles['input-container'], styles[size], styles[_pseudo]), children: jsxs("div", { className: clsx({ [styles['growing-input']]: autoGrow }), children: [jsx(Input$1, { "aria-label": label, size: autoGrow ? 1 : undefined, ...props, ...pressProps, ref: ref, onChange: handleChange, onClick: e => {
24
24
  e.preventDefault();
25
25
  e.stopPropagation();
26
26
  e.target.focus();
@@ -1,4 +1,5 @@
1
1
  import { FormEventHandler, KeyboardEvent } from 'react';
2
+ import { ValidateFunction } from '../field-error/field-error';
2
3
  export type NumberFieldSize = 'md' | 'lg';
3
4
  interface NumberFieldProps {
4
5
  autoFocus?: boolean;
@@ -20,6 +21,7 @@ interface NumberFieldProps {
20
21
  placeholder?: string;
21
22
  showLabel?: boolean;
22
23
  size?: NumberFieldSize;
24
+ validate?: ValidateFunction<number>;
23
25
  value?: number;
24
26
  withButtons?: boolean;
25
27
  }
@@ -27,5 +29,5 @@ interface NumberFieldProps {
27
29
  * This component is used to create a number field.
28
30
  * This field can also grow when a user types in text.
29
31
  */
30
- export declare function NumberField({ autoFocus, autoGrow, defaultValue, formatOptions, isDisabled, isInvalid, isReadOnly, isRequired, label, maxLength, maxValue, minValue, name, onChange, onInput, onKeyUp, placeholder, showLabel, size, value, withButtons, }: NumberFieldProps): import("react/jsx-runtime").JSX.Element;
32
+ export declare function NumberField({ autoFocus, autoGrow, defaultValue, formatOptions, isDisabled, isInvalid, isReadOnly, isRequired, label, maxLength, maxValue, minValue, name, onChange, onInput, onKeyUp, placeholder, showLabel, size, validate, value, withButtons, }: NumberFieldProps): import("react/jsx-runtime").JSX.Element;
31
33
  export {};
@@ -15,12 +15,12 @@ import styles from './number-field.module.css.js';
15
15
  * This component is used to create a number field.
16
16
  * This field can also grow when a user types in text.
17
17
  */
18
- function NumberField({ autoFocus, autoGrow, defaultValue, formatOptions = { style: 'decimal', useGrouping: false }, isDisabled, isInvalid, isReadOnly, isRequired, label, maxLength, maxValue, minValue, name, onChange, onInput, onKeyUp, placeholder, showLabel = false, size = 'lg', value, withButtons, }) {
18
+ function NumberField({ autoFocus, autoGrow, defaultValue, formatOptions = { style: 'decimal', useGrouping: false }, isDisabled, isInvalid, isReadOnly, isRequired, label, maxLength, maxValue, minValue, name, onChange, onInput, onKeyUp, placeholder, showLabel = false, size = 'lg', validate, value, withButtons, }) {
19
19
  const inputRef = useRef(null);
20
- return (jsxs(NumberField$1, { "aria-label": label, autoFocus: autoFocus, className: clsx(styles.field, styles[size]), defaultValue: defaultValue, formatOptions: formatOptions, isDisabled: isDisabled, isInvalid: isInvalid, isReadOnly: isReadOnly, isRequired: isRequired, maxValue: maxValue, minValue: minValue, name: name, onChange: onChange, onInput: onInput, value: value, children: [showLabel && jsx(Label, { isRequired: isRequired, children: label }), jsxs("div", { className: styles['button-input-container'], children: [withButtons && (jsx(Button, { "data-test-selector": "decrement", isDisabled: isDisabled,
20
+ return (jsxs(NumberField$1, { "aria-label": label, autoFocus: autoFocus, className: clsx(styles.field, styles[size]), defaultValue: defaultValue, formatOptions: formatOptions, isDisabled: isDisabled, isInvalid: isInvalid, isReadOnly: isReadOnly, isRequired: isRequired, maxValue: maxValue, minValue: minValue, name: name, onChange: onChange, onInput: onInput, validate: validate, value: value, children: [showLabel && jsx(Label, { isRequired: isRequired, children: label }), jsxs("div", { className: styles['button-input-container'], children: [withButtons && (jsx(Button, { "data-test-selector": "decrement", isDisabled: isDisabled,
21
21
  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
22
22
  // @ts-expect-error
23
- onClick: e => e.preventDefault(), onPressStart: e => e.target.focus(), slot: "decrement", children: (value || 0) <= 1 ? jsx(StrokeTrashIcon, {}) : jsx(StrokeCollapseIcon, {}) })), jsx(Input, { ref: inputRef, autoGrow: autoGrow, maxLength: maxLength, onFocus: e => (e.target.selectionStart = e.target.value.length || 0), onKeyUp: e => onKeyUp?.(e), placeholder: placeholder, size: size }), withButtons && (jsx(Button, { "data-test-selector": "increment", isDisabled: isDisabled,
23
+ onClick: e => e.preventDefault(), onPressStart: e => e.target.focus(), slot: "decrement", children: (value || 0) <= 1 ? jsx(StrokeTrashIcon, {}) : jsx(StrokeCollapseIcon, {}) })), jsx(Input, { ref: inputRef, autoGrow: autoGrow, label: label, maxLength: maxLength, onFocus: e => (e.target.selectionStart = e.target.value.length || 0), onKeyUp: e => onKeyUp?.(e), placeholder: placeholder, size: size }), withButtons && (jsx(Button, { "data-test-selector": "increment", isDisabled: isDisabled,
24
24
  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
25
25
  // @ts-expect-error
26
26
  onClick: e => e.preventDefault(), onPressStart: e => e.target.focus(), slot: "increment", children: jsx(StrokeExpandIcon, {}) }))] }), jsx(FieldError, {})] }));
@@ -1,4 +1,5 @@
1
1
  import { FormEventHandler, KeyboardEvent } from 'react';
2
+ import { ValidateFunction } from '../field-error/field-error';
2
3
  interface TextFieldProps {
3
4
  autoFocus?: boolean;
4
5
  autoGrow?: boolean;
@@ -10,6 +11,7 @@ interface TextFieldProps {
10
11
  isRequired?: boolean;
11
12
  label: string;
12
13
  maxLength?: number;
14
+ minLength?: number;
13
15
  name?: string;
14
16
  onChange?: (value: string) => void;
15
17
  onInput?: FormEventHandler<HTMLInputElement>;
@@ -18,6 +20,7 @@ interface TextFieldProps {
18
20
  rows?: number;
19
21
  showLabel?: boolean;
20
22
  size?: 'md' | 'lg';
23
+ validate?: ValidateFunction<string>;
21
24
  value?: string;
22
25
  }
23
26
  /**
@@ -25,5 +28,5 @@ interface TextFieldProps {
25
28
  * It can be used as a single line input or as a textarea.
26
29
  * This field can also grow when a user types in text.
27
30
  */
28
- export declare function TextField({ autoFocus, autoGrow, defaultValue, isDisabled, isInvalid, isMultiline, isReadOnly, isRequired, label, maxLength, name, onChange, onInput, onKeyUp, placeholder, rows, showLabel, size, value, }: TextFieldProps): import("react/jsx-runtime").JSX.Element;
31
+ export declare function TextField({ autoFocus, autoGrow, defaultValue, isDisabled, isInvalid, isMultiline, isReadOnly, isRequired, label, maxLength, minLength, name, onChange, onInput, onKeyUp, placeholder, rows, showLabel, size, validate, value, }: TextFieldProps): import("react/jsx-runtime").JSX.Element;
29
32
  export {};
@@ -13,10 +13,10 @@ import styles from './text-field.module.css.js';
13
13
  * It can be used as a single line input or as a textarea.
14
14
  * This field can also grow when a user types in text.
15
15
  */
16
- function TextField({ autoFocus, autoGrow, defaultValue, isDisabled, isInvalid, isMultiline, isReadOnly, isRequired, label, maxLength, name, onChange, onInput, onKeyUp, placeholder, rows, showLabel = false, size = 'lg', value, }) {
17
- return (jsxs(TextField$1, { "aria-label": label, autoFocus: autoFocus, className: clsx(styles.field, styles[size]), defaultValue: defaultValue, isDisabled: isDisabled, isInvalid: isInvalid, isReadOnly: isReadOnly, isRequired: isRequired, maxLength: maxLength, name: name, onChange: value => {
16
+ function TextField({ autoFocus, autoGrow, defaultValue, isDisabled, isInvalid, isMultiline, isReadOnly, isRequired, label, maxLength, minLength, name, onChange, onInput, onKeyUp, placeholder, rows, showLabel = false, size = 'lg', validate, value, }) {
17
+ return (jsxs(TextField$1, { "aria-label": label, autoFocus: autoFocus, className: clsx(styles.field, styles[size]), defaultValue: defaultValue, isDisabled: isDisabled, isInvalid: isInvalid, isReadOnly: isReadOnly, isRequired: isRequired, maxLength: maxLength, minLength: minLength, name: name, onChange: value => {
18
18
  onChange?.(value);
19
- }, onInput: onInput, onKeyUp: e => onKeyUp?.(e), value: value, children: [showLabel && jsx(Label, { isRequired: isRequired, children: label }), isMultiline ? (jsx(TextArea, { autoGrow: autoGrow, placeholder: placeholder, rows: rows, size: size })) : (jsx(Input, { autoGrow: autoGrow, placeholder: placeholder, size: size })), jsx(FieldError, {})] }));
19
+ }, onInput: onInput, onKeyUp: e => onKeyUp?.(e), validate: validate, value: value, children: [showLabel && jsx(Label, { isRequired: isRequired, children: label }), isMultiline ? (jsx(TextArea, { autoGrow: autoGrow, label: label, placeholder: placeholder, rows: rows, size: size })) : (jsx(Input, { autoGrow: autoGrow, label: label, placeholder: placeholder, size: size })), jsx(FieldError, {})] }));
20
20
  }
21
21
 
22
22
  export { TextField };
@@ -2,6 +2,7 @@ import { ComponentProps, FC } from 'react';
2
2
  import { TextArea as AriaTextArea } from 'react-aria-components';
3
3
  export interface TextAreaProps extends Omit<ComponentProps<typeof AriaTextArea>, 'size'> {
4
4
  autoGrow?: boolean;
5
+ label: string;
5
6
  size?: 'md' | 'lg';
6
7
  }
7
8
  /**