@sonic-equipment/ui 135.0.0 → 137.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 (51) hide show
  1. package/dist/algolia/algolia-initialization.js +2 -1
  2. package/dist/algolia/algolia-insights-provider.js +3 -3
  3. package/dist/algolia/algolia-searchclient-offline.js +3 -2
  4. package/dist/algolia/use-algolia-insights.js +24 -23
  5. package/dist/buttons/link/link.d.ts +2 -1
  6. package/dist/buttons/link/link.js +4 -2
  7. package/dist/collapsables/accordion/accordion-item.d.ts +2 -1
  8. package/dist/collapsables/accordion/accordion-item.js +13 -4
  9. package/dist/config.js +2 -2
  10. package/dist/country-selector/country-select/country-select.d.ts +6 -0
  11. package/dist/country-selector/country-select/country-select.js +10 -4
  12. package/dist/exports.d.ts +5 -0
  13. package/dist/footer/footer.d.ts +9 -0
  14. package/dist/footer/footer.js +14 -0
  15. package/dist/footer/footer.model.d.ts +18 -0
  16. package/dist/footer/footer.module.css.js +3 -0
  17. package/dist/header/header.d.ts +1 -0
  18. package/dist/header/header.js +9 -0
  19. package/dist/index.js +5 -0
  20. package/dist/intl/utils.js +2 -1
  21. package/dist/logging/logger.d.ts +11 -0
  22. package/dist/logging/logger.js +22 -0
  23. package/dist/logging/use-log-error.d.ts +1 -0
  24. package/dist/logging/use-log-error.js +12 -0
  25. package/dist/media/image/image.js +11 -4
  26. package/dist/notifications/announcements/announcement-provider.js +3 -6
  27. package/dist/pages/checkout/order-confirmation-page/order-confirmation-page-content.js +7 -1
  28. package/dist/pages/checkout/payment-page/components/adyen-payment.js +40 -28
  29. package/dist/pages/checkout/payment-page/components/payment.js +26 -16
  30. package/dist/pages/checkout/shipping-page/components/edit-address.d.ts +4 -2
  31. package/dist/pages/checkout/shipping-page/components/edit-address.js +6 -5
  32. package/dist/pages/checkout/shipping-page/hooks/use-patch-shipping-details.d.ts +6 -2
  33. package/dist/pages/checkout/shipping-page/hooks/use-patch-shipping-details.js +27 -8
  34. package/dist/pages/checkout/shipping-page/shipping-page-content.d.ts +2 -1
  35. package/dist/pages/checkout/shipping-page/shipping-page-content.js +2 -2
  36. package/dist/pages/checkout/shipping-page/shipping-page.js +6 -6
  37. package/dist/pages/product/search-result-page/search-results-page.js +1 -1
  38. package/dist/shared/api/shared/hooks/use-awaitable-mutation.d.ts +21 -20
  39. package/dist/shared/api/storefront/hooks/cart/use-patch-cart.d.ts +1 -3
  40. package/dist/shared/api/storefront/hooks/cart/use-patch-cart.js +4 -6
  41. package/dist/shared/api/storefront/hooks/cart/use-place-order.d.ts +1 -1
  42. package/dist/shared/api/storefront/hooks/cart/use-place-order.js +6 -5
  43. package/dist/shared/api/storefront/services/cart-service.js +7 -7
  44. package/dist/shared/ga/data-layer.js +3 -2
  45. package/dist/shared/model/image.d.ts +1 -2
  46. package/dist/shared/providers/global-state-provider.js +3 -5
  47. package/dist/shared/utils/debug.d.ts +2 -0
  48. package/dist/shared/utils/debug.js +21 -0
  49. package/dist/shared/utils/environment.js +4 -2
  50. package/dist/styles.css +105 -12
  51. package/package.json +1 -1
@@ -42,34 +42,44 @@ function AdyenPayment({ amount, cartId, countryCode, currencyCode, customerId, d
42
42
  if (!state.details.redirectResult) {
43
43
  return onError(new Error('No redirectResult'), null);
44
44
  }
45
- const result = await getAdyenPaymentDetails({
46
- redirectResult: state.details.redirectResult,
47
- });
48
- if (amount.toFixed(2).replaceAll(/[,.]/gi, '') !== adyenAmount)
49
- return onError(new Error('Invalid amount'), result);
50
- if (customerId !== adyenCustomerId)
51
- return onError(new Error('Invalid customer'), result);
52
- return handlePaymentResponse(result, onComplete, onError);
45
+ try {
46
+ const result = await getAdyenPaymentDetails({
47
+ redirectResult: state.details.redirectResult,
48
+ });
49
+ if (amount.toFixed(2).replaceAll(/[,.]/gi, '') !== adyenAmount)
50
+ return onError(new Error('Invalid amount'), result);
51
+ if (customerId !== adyenCustomerId)
52
+ return onError(new Error('Invalid customer'), result);
53
+ return handlePaymentResponse(result, onComplete, onError);
54
+ }
55
+ catch (error) {
56
+ return onError(error, null);
57
+ }
53
58
  }),
54
59
  onSubmit: (async (state, _component) => {
55
- dropinDivRef.current?.classList.add(styles.loading);
56
- if (state.data.paymentMethod.type === 'paybybank') {
57
- state.data.countryCode = countryCode;
58
- }
59
- const result = await postAdyenPayment({
60
- currencyCode,
61
- data: state.data,
62
- orderAmount,
63
- returnUrl,
64
- webOrderNumber: adyenSession.webOrderNumber,
65
- });
66
- if (result.action) {
67
- if (result.action.type === 'redirect') {
68
- return handleRedirectPaymentAction(result);
60
+ try {
61
+ dropinDivRef.current?.classList.add(styles.loading);
62
+ if (state.data.paymentMethod.type === 'paybybank') {
63
+ state.data.countryCode = countryCode;
69
64
  }
70
- return onError(new Error('Invalid payment response'), result);
65
+ const result = await postAdyenPayment({
66
+ currencyCode,
67
+ data: state.data,
68
+ orderAmount,
69
+ returnUrl,
70
+ webOrderNumber: adyenSession.webOrderNumber,
71
+ });
72
+ if (result.action) {
73
+ if (result.action.type === 'redirect') {
74
+ return handleRedirectPaymentAction(result);
75
+ }
76
+ return onError(new Error('Invalid payment response'), result);
77
+ }
78
+ return handlePaymentResponse(result, onComplete, onError);
79
+ }
80
+ catch (error) {
81
+ return onError(error, null);
71
82
  }
72
- return handlePaymentResponse(result, onComplete, onError);
73
83
  }),
74
84
  session: {
75
85
  ...adyenSession,
@@ -117,10 +127,12 @@ function getAndRemoveAdyenQueryParams() {
117
127
  return {};
118
128
  const params = qs.parse(window.location.search || '');
119
129
  const { amount, customerId, redirectResult } = params;
120
- delete params['redirectResult'];
121
- delete params['amount'];
122
- delete params['customerId'];
123
- history?.pushState({}, '', `${window.location.pathname}${qs.stringify(params) ? `?${qs.stringify(params)}` : ''}`);
130
+ if (redirectResult) {
131
+ delete params['redirectResult'];
132
+ delete params['amount'];
133
+ delete params['customerId'];
134
+ history?.pushState({}, '', `${window.location.pathname}${qs.stringify(params) ? `?${qs.stringify(params)}` : ''}`);
135
+ }
124
136
  return { amount, customerId, redirectResult };
125
137
  }
126
138
  async function handlePaymentResponse(result, onSubmit, onError) {
@@ -12,7 +12,9 @@ import { TextField } from '../../../../forms/text-field/text-field.js';
12
12
  import { InfoIconTooltip } from '../../../../info-icon-tooltip/info-icon-tooltip.js';
13
13
  import { FormattedMessage } from '../../../../intl/formatted-message.js';
14
14
  import { useFormattedMessage } from '../../../../intl/use-formatted-message.js';
15
+ import { logger } from '../../../../logging/logger.js';
15
16
  import { usePatchSession } from '../../../../shared/api/storefront/hooks/authentication/use-patch-session.js';
17
+ import { useInvalidateCurrentCart } from '../../../../shared/api/storefront/hooks/cart/use-invalidate-current-cart.js';
16
18
  import { usePatchCart } from '../../../../shared/api/storefront/hooks/cart/use-patch-cart.js';
17
19
  import { usePlaceOrder } from '../../../../shared/api/storefront/hooks/cart/use-place-order.js';
18
20
  import { useInvalidateAdyen } from '../../../../shared/api/storefront/hooks/payment/use-invalidate-adyen.js';
@@ -31,6 +33,7 @@ function Payment({ atp, cart: _cart, form, onError: _onError, onPaymentComplete,
31
33
  const { isLoading: isPatchingSession } = usePatchSession();
32
34
  const { isLoading: isPlacingCart, mutate: placeOrder } = usePlaceOrder();
33
35
  const { sendPurchaseEventFromPaymentPage } = useAlgoliaInsights();
36
+ const invalidateCurrentCart = useInvalidateCurrentCart();
34
37
  const dropinRef = useRef(null);
35
38
  const [paymentError, setPaymentError] = useState();
36
39
  const [apiError, setAPIError] = useState();
@@ -151,7 +154,7 @@ function Payment({ atp, cart: _cart, form, onError: _onError, onPaymentComplete,
151
154
  if (isAdyenPayment) {
152
155
  /* Adyen Payment */
153
156
  if (!dropinRef.current) {
154
- console.warn('Adyen Dropin not ready');
157
+ logger.warn('Adyen Dropin not ready');
155
158
  return;
156
159
  }
157
160
  dropinRef.current.showValidation();
@@ -168,20 +171,26 @@ function Payment({ atp, cart: _cart, form, onError: _onError, onPaymentComplete,
168
171
  requestedDeliveryDate: formData.get('deliveryDate')?.toString(),
169
172
  };
170
173
  try {
171
- cartRef.current = await patchCart({
172
- cart: updatedCart,
173
- });
174
- }
175
- catch (error) {
176
- console.error(error);
177
- setAPIError(error);
178
- }
179
- try {
180
- dropinRef.current.submit();
174
+ try {
175
+ cartRef.current = await patchCart({
176
+ cart: updatedCart,
177
+ });
178
+ }
179
+ catch (error) {
180
+ setAPIError(error);
181
+ throw error;
182
+ }
183
+ try {
184
+ dropinRef.current.submit();
185
+ }
186
+ catch (error) {
187
+ setPaymentError(error);
188
+ throw error;
189
+ }
181
190
  }
182
191
  catch (error) {
183
- console.error(error);
184
- setPaymentError(error);
192
+ logger.error(error);
193
+ invalidateCurrentCart();
185
194
  }
186
195
  }
187
196
  else {
@@ -196,8 +205,9 @@ function Payment({ atp, cart: _cart, form, onError: _onError, onPaymentComplete,
196
205
  return onPaymentComplete({ cartId: cart.trackId });
197
206
  }
198
207
  catch (error) {
199
- console.error(error);
208
+ logger.error(error);
200
209
  setPaymentError(error);
210
+ invalidateCurrentCart();
201
211
  }
202
212
  }
203
213
  }
@@ -224,7 +234,7 @@ function Payment({ atp, cart: _cart, form, onError: _onError, onPaymentComplete,
224
234
  return onPaymentComplete({ cartId: cart.trackId });
225
235
  }
226
236
  catch (error) {
227
- console.error(error);
237
+ logger.error(error);
228
238
  setAPIError(error);
229
239
  }
230
240
  }, [onPaymentComplete, onPlaceOrderCompleted, placeOrder]);
@@ -232,7 +242,7 @@ function Payment({ atp, cart: _cart, form, onError: _onError, onPaymentComplete,
232
242
  invalidateAdyen();
233
243
  // invalidateCurrentCart()
234
244
  setPaymentError(error);
235
- console.error(error);
245
+ logger.error(error);
236
246
  _onError?.(error, result);
237
247
  }, [_onError, invalidateAdyen]);
238
248
  return (jsxs(Form, { className: styles['payment-form'], "data-test-selector": "paymentForm", id: form, onSubmit: e => {
@@ -1,4 +1,4 @@
1
- import { CountryModel } from '../../../../shared/api/storefront/model/storefront.model';
1
+ import { BillToModel, CountryModel } from '../../../../shared/api/storefront/model/storefront.model';
2
2
  export declare const EDIT_ADDRESS_FORM_ID = "billToForm";
3
3
  interface Address {
4
4
  address1: string;
@@ -8,12 +8,14 @@ interface Address {
8
8
  city: string;
9
9
  companyName: string;
10
10
  country: CountryModel;
11
+ email: string;
11
12
  firstName: string;
12
13
  lastName: string;
13
14
  phone: string;
14
15
  postalCode: string;
15
16
  }
16
- export declare function EditAddresses({ countries, isLoading, isPickup, onSubmit, }: {
17
+ export declare function EditAddresses({ billTo, countries, isLoading, isPickup, onSubmit, }: {
18
+ billTo: BillToModel | undefined | null;
17
19
  countries: CountryModel[];
18
20
  isLoading: boolean;
19
21
  isPickup: boolean;
@@ -15,10 +15,10 @@ import { SonicAddress } from './sonic-address.js';
15
15
  import styles from './edit-address.module.css.js';
16
16
 
17
17
  const EDIT_ADDRESS_FORM_ID = 'billToForm';
18
- function EditAddresses({ countries, isLoading, isPickup, onSubmit, }) {
18
+ function EditAddresses({ billTo, countries, isLoading, isPickup, onSubmit, }) {
19
19
  const t = useFormattedMessage();
20
- const [companyName, setCompanyName] = useState('');
21
- const [lastName, setLastName] = useState('');
20
+ const [companyName, setCompanyName] = useState(billTo?.companyName || '');
21
+ const [lastName, setLastName] = useState(billTo?.lastName || '');
22
22
  const { data: cart } = useFetchCurrentCart();
23
23
  return (jsxs(Fragment, { children: [jsx(CheckoutPageSection, { title: jsx(FormattedMessage, { id: "Billing address" }), children: jsx(CheckoutPageSectionContent, { children: jsxs(Form, { className: styles.form, "data-test-selector": "billToAddressForm", id: EDIT_ADDRESS_FORM_ID, onSubmit: e => {
24
24
  e.preventDefault();
@@ -36,6 +36,7 @@ function EditAddresses({ countries, isLoading, isPickup, onSubmit, }) {
36
36
  city: formData.get('address1')?.toString() || '',
37
37
  companyName: formData.get('companyName')?.toString() || '',
38
38
  country,
39
+ email: formData.get('email')?.toString() || '',
39
40
  firstName: formData.get('firstName')?.toString() || '',
40
41
  lastName: formData.get('address1')?.toString() || '',
41
42
  phone: formData.get('phone')?.toString() || '',
@@ -43,7 +44,7 @@ function EditAddresses({ countries, isLoading, isPickup, onSubmit, }) {
43
44
  },
44
45
  notes: formData.get('notes')?.toString() || '',
45
46
  });
46
- }, children: [jsx(TextField, { isDisabled: isLoading, label: t('First name'), name: "firstName", showLabel: true }), jsx(TextField, { isDisabled: isLoading, isRequired: !companyName, label: t('Last name'), minLength: 3, name: "lastName", onChange: setLastName, showLabel: true, value: lastName }, `lastname-${Boolean(companyName)}`), jsx(TextField, { isDisabled: isLoading, label: t('Company name'), name: "companyName", onChange: setCompanyName, showLabel: true, value: companyName }), jsx(TextField, { isDisabled: isLoading, label: t('Attention'), name: "attention", showLabel: true }), jsx("div", { className: styles['span-2'], children: jsx(TextField, { isRequired: true, isDisabled: isLoading, label: `${t('Address')} 1`, maxLength: 30, minLength: 3, name: "address1", showLabel: true }) }), jsx("div", { className: styles['span-2'], children: jsx(TextField, { isDisabled: isLoading, label: `${t('Address')} 2`, maxLength: 30, minLength: 3, name: "address2", showLabel: true }) }), jsx("div", { className: styles['span-2'], children: jsx(TextField, { isDisabled: isLoading, label: `${t('Address')} 3`, maxLength: 30, minLength: 3, name: "address3", showLabel: true }) }), jsx(TextField, { isRequired: true, isDisabled: isLoading, label: t('Postal Code'), maxLength: 10, minLength: 4, name: "postalCode", showLabel: true }), jsx(TextField, { isRequired: true, isDisabled: isLoading, label: t('City'), maxLength: 30, minLength: 3, name: "city", showLabel: true }), jsx("div", { className: styles['span-2'], children: jsx(CountrySelect, { isRequired: true, countries: countries, "data-test-selector": "countrySelect", isDisabled: isLoading, name: "countrySelect" }) }), jsx("div", { className: styles['span-2'], children: jsx(TextField, { isRequired: true, isDisabled: isLoading, label: t('Phone'), name: "phone", showLabel: true, validate: value => {
47
+ }, children: [jsx(TextField, { defaultValue: billTo?.firstName, isDisabled: isLoading, label: t('First name'), name: "firstName", showLabel: true }), jsx(TextField, { isDisabled: isLoading, isRequired: !companyName, label: t('Last name'), minLength: 3, name: "lastName", onChange: setLastName, showLabel: true, value: lastName }, `lastname-${Boolean(companyName)}`), jsx(TextField, { defaultValue: billTo?.companyName, isDisabled: isLoading, label: t('Company name'), name: "companyName", onChange: setCompanyName, showLabel: true, value: companyName }), jsx(TextField, { defaultValue: billTo?.attention, isDisabled: isLoading, label: t('Attention'), name: "attention", showLabel: true }), jsx("div", { className: styles['span-2'], children: jsx(TextField, { isRequired: true, defaultValue: billTo?.address1, isDisabled: isLoading, label: `${t('Address')} 1`, maxLength: 30, minLength: 3, name: "address1", showLabel: true }) }), jsx("div", { className: styles['span-2'], children: jsx(TextField, { defaultValue: billTo?.address2, isDisabled: isLoading, label: `${t('Address')} 2`, maxLength: 30, minLength: 3, name: "address2", showLabel: true }) }), jsx("div", { className: styles['span-2'], children: jsx(TextField, { defaultValue: billTo?.address3, isDisabled: isLoading, label: `${t('Address')} 3`, maxLength: 30, minLength: 3, name: "address3", showLabel: true }) }), jsx(TextField, { isRequired: true, defaultValue: billTo?.postalCode, isDisabled: isLoading, label: t('Postal Code'), maxLength: 10, minLength: 4, name: "postalCode", showLabel: true }), jsx(TextField, { isRequired: true, defaultValue: billTo?.city, isDisabled: isLoading, label: t('City'), maxLength: 30, minLength: 3, name: "city", showLabel: true }), jsx("div", { className: styles['span-2'], children: jsx(CountrySelect, { isRequired: true, countries: countries, "data-test-selector": "countrySelect", defaultSelectedCountry: countries.find(country => country.id === billTo?.country?.id), isDisabled: isLoading, name: "countrySelect" }) }), jsx("div", { className: styles['span-2'], children: jsx(TextField, { isRequired: true, defaultValue: billTo?.phone, isDisabled: isLoading, label: t('Phone'), name: "phone", showLabel: true, validate: value => {
47
48
  if (!value)
48
49
  return value;
49
50
  return (validatePhone(value) ||
@@ -53,7 +54,7 @@ function EditAddresses({ countries, isLoading, isPickup, onSubmit, }) {
53
54
  return value;
54
55
  return (validateEmail(value) ||
55
56
  t('Please enter a valid e-mail address'));
56
- } }) }), jsx("div", { className: styles['span-2'], children: jsx(TextField, { isDisabled: isLoading, isMultiline: true, label: t('Add order notes'), name: "notes", rows: 3, showLabel: true }) })] }) }) }), jsx(CheckoutPageSection, { title: jsx(FormattedMessage, { id: isPickup ? 'Pickup address' : 'Shipping address' }), children: jsx(CheckoutPageSectionContent, { children: jsx(Fragment, { children: isPickup ? (jsx(SonicAddress, {})) : (jsxs("div", { className: styles['use-invoice-checkbox'], children: [jsx(Checkbox, { "data-test-selector": "checkboxUseBillingAddress", isDisabled: true, isSelected: true, children: jsx(FormattedMessage, { id: "Use billing address" }) }), jsx(InfoIconTooltip, { variant: "stroke", children: t('Changing your address is currently not possible. Please contact customer support to change your address.') })] })) }) }) })] }));
57
+ } }) }), jsx("div", { className: styles['span-2'], children: jsx(TextField, { defaultValue: cart?.notes, isDisabled: isLoading, isMultiline: true, label: t('Add order notes'), name: "notes", rows: 3, showLabel: true }) })] }) }) }), jsx(CheckoutPageSection, { title: jsx(FormattedMessage, { id: isPickup ? 'Pickup address' : 'Shipping address' }), children: jsx(CheckoutPageSectionContent, { children: jsx(Fragment, { children: isPickup ? (jsx(SonicAddress, {})) : (jsxs("div", { className: styles['use-invoice-checkbox'], children: [jsx(Checkbox, { "data-test-selector": "checkboxUseBillingAddress", isDisabled: true, isSelected: true, children: jsx(FormattedMessage, { id: "Use billing address" }) }), jsx(InfoIconTooltip, { variant: "stroke", children: t('Changing your address is currently not possible. Please contact customer support to change your address.') })] })) }) }) })] }));
57
58
  }
58
59
 
59
60
  export { EDIT_ADDRESS_FORM_ID, EditAddresses };
@@ -1,4 +1,4 @@
1
- import { BillToModel, CartModel } from '../../../../shared/api/storefront/model/storefront.model';
1
+ import { BillToModel, CartModel, SessionModel } from '../../../../shared/api/storefront/model/storefront.model';
2
2
  export declare function usePatchShippingDetails(): {
3
3
  error: unknown;
4
4
  isError: boolean;
@@ -8,5 +8,9 @@ export declare function usePatchShippingDetails(): {
8
8
  billTo?: BillToModel;
9
9
  cart: CartModel;
10
10
  notes: string | undefined;
11
- }) => Promise<void>;
11
+ }) => Promise<{
12
+ patchedBillTo: BillToModel | undefined;
13
+ patchedCart: CartModel;
14
+ patchedSession: SessionModel | undefined;
15
+ }>;
12
16
  };
@@ -1,19 +1,38 @@
1
1
  import { useAwaitableMutation } from '../../../../shared/api/shared/hooks/use-awaitable-mutation.js';
2
+ import { patchSession } from '../../../../shared/api/storefront/services/authentication-service.js';
2
3
  import { patchCart } from '../../../../shared/api/storefront/services/cart-service.js';
3
4
  import { patchBillToAddress } from '../../../../shared/api/storefront/services/customer-service.js';
4
5
 
5
6
  function usePatchShippingDetails() {
6
7
  return useAwaitableMutation({
7
8
  mutationFn: async ({ billTo, cart, notes, }) => {
8
- await Promise.all([
9
- billTo && patchBillToAddress({ billTo }),
10
- patchCart({ cart: { ...cart, notes } }),
11
- ].filter(Boolean));
9
+ const patchedBillTo = billTo
10
+ ? await patchBillToAddress({ billTo })
11
+ : undefined;
12
+ const patchedSession = patchedBillTo
13
+ ? await patchSession({
14
+ session: {
15
+ billTo: { id: patchedBillTo.id },
16
+ customerWasUpdated: true,
17
+ shipTo: { id: cart.shipTo?.id || patchedBillTo.id },
18
+ },
19
+ })
20
+ : undefined;
21
+ const patchedCart = await patchCart({
22
+ cart: { ...cart, billTo: patchedBillTo, notes },
23
+ });
24
+ return { patchedBillTo, patchedCart, patchedSession };
12
25
  },
13
- onSuccess: ({ queryClient }) => {
14
- queryClient.removeQueries({ queryKey: ['customer'] });
15
- queryClient.removeQueries({ queryKey: ['carts'] });
16
- queryClient.removeQueries({ queryKey: ['session'] });
26
+ onSuccess: ({ data: { patchedBillTo, patchedCart, patchedSession }, queryClient, }) => {
27
+ if (patchedBillTo)
28
+ queryClient.setQueryData(['customer', 'bill-to-addresses'], patchedBillTo);
29
+ if (patchedSession) {
30
+ queryClient.setQueryData(['session'], patchedSession);
31
+ }
32
+ else if (patchedBillTo) {
33
+ queryClient.removeQueries({ queryKey: ['session'] });
34
+ }
35
+ queryClient.setQueryData(['carts', patchedCart.id], patchedCart);
17
36
  },
18
37
  });
19
38
  }
@@ -5,10 +5,11 @@ export interface ShippingPageContentProps {
5
5
  editAddress: ReactNode;
6
6
  errorPatchBillingAddress?: unknown;
7
7
  fulfillmentMethods: string[] | undefined;
8
+ isGuest: boolean;
8
9
  isLoadingFulfillmentMethods: boolean;
9
10
  isPatching: boolean;
10
11
  isPatchingSession: boolean;
11
12
  onChangeFulfillmentMethod: (value: string) => void;
12
13
  readOnlyAddress: ReactNode;
13
14
  }
14
- export declare function ShippingPageContent({ cart, editAddress, errorPatchBillingAddress, fulfillmentMethods, isLoadingFulfillmentMethods, isPatching, isPatchingSession, onChangeFulfillmentMethod, readOnlyAddress, }: ShippingPageContentProps): import("react/jsx-runtime").JSX.Element;
15
+ export declare function ShippingPageContent({ cart, editAddress, errorPatchBillingAddress, fulfillmentMethods, isGuest, isLoadingFulfillmentMethods, isPatching, isPatchingSession, onChangeFulfillmentMethod, readOnlyAddress, }: ShippingPageContentProps): import("react/jsx-runtime").JSX.Element;
@@ -14,7 +14,7 @@ import { CheckoutPageSectionContent } from '../layouts/checkout-page-layout/comp
14
14
  import { EDIT_ADDRESS_FORM_ID } from './components/edit-address.js';
15
15
  import styles from './shipping-page.module.css.js';
16
16
 
17
- function ShippingPageContent({ cart, editAddress, errorPatchBillingAddress, fulfillmentMethods, isLoadingFulfillmentMethods, isPatching, isPatchingSession, onChangeFulfillmentMethod, readOnlyAddress, }) {
17
+ function ShippingPageContent({ cart, editAddress, errorPatchBillingAddress, fulfillmentMethods, isGuest, isLoadingFulfillmentMethods, isPatching, isPatchingSession, onChangeFulfillmentMethod, readOnlyAddress, }) {
18
18
  const t = useFormattedMessage();
19
19
  const fulfillmentMethodOptions = fulfillmentMethods?.reduce((acc, method) => ({
20
20
  ...acc,
@@ -34,7 +34,7 @@ function ShippingPageContent({ cart, editAddress, errorPatchBillingAddress, fulf
34
34
  primary: (jsx(Button, { withArrow: true, "data-test-selector": "checkoutShippingCartTotalContinueButton", form: EDIT_ADDRESS_FORM_ID, isDisabled: isPatching, isLoading: isPatching || isPatchingSession ? (jsx(FormattedMessage, { id: "Updating address" })) : undefined, type: "submit", children: jsx(FormattedMessage, { id: "Continue shopping" }) })),
35
35
  }, mobileSummary: jsx(CartTotalsSummary, { totalAmount: cart.orderGrandTotalDisplay }), overview: jsx(CartTotals, { fulfillmentMethod: fulfillmentMethods && fulfillmentMethods.length === 1
36
36
  ? cart.fulfillmentMethod
37
- : undefined, shippingCost: cart.shippingAndHandlingDisplay, subtotal: cart.orderSubTotalDisplay, tax: cart.totalTaxDisplay, total: cart.orderGrandTotalDisplay, vatPercentage: cart.cartLines?.[0]?.pricing?.vatRate }), children: [jsxs(Fragment, { children: [fulfillmentMethods && fulfillmentMethods.length > 1 && (jsx(CheckoutPageSection, { hasBorder: true, title: t('Fulfillment method'), children: jsx(CheckoutPageSectionContent, { children: jsx("div", { className: styles['fulfillment-select-wrapper'], children: jsx(Select, { isRequired: true, showLabel: true, "data-test-selector": "fulfillmentMethodSelect", defaultSelectedOption: cart.fulfillmentMethod, isLoading: isLoadingFulfillmentMethods, label: t('Fulfillment method'), name: "fulfillmentMethod", onChange: onChangeFulfillmentMethod, options: fulfillmentMethodOptions || {}, variant: "solid" }) }) }) })), hasBillToAddress ? readOnlyAddress : editAddress] }), Boolean(errorPatchBillingAddress) && (jsx("div", { className: styles['error-message'], children: jsx(FormattedMessage, { id: "An unexpected error occured" }) }))] }) }));
37
+ : undefined, shippingCost: cart.shippingAndHandlingDisplay, subtotal: cart.orderSubTotalDisplay, tax: cart.totalTaxDisplay, total: cart.orderGrandTotalDisplay, vatPercentage: cart.cartLines?.[0]?.pricing?.vatRate }), children: [jsxs(Fragment, { children: [fulfillmentMethods && fulfillmentMethods.length > 1 && (jsx(CheckoutPageSection, { hasBorder: true, title: t('Fulfillment method'), children: jsx(CheckoutPageSectionContent, { children: jsx("div", { className: styles['fulfillment-select-wrapper'], children: jsx(Select, { isRequired: true, showLabel: true, "data-test-selector": "fulfillmentMethodSelect", defaultSelectedOption: cart.fulfillmentMethod, isLoading: isLoadingFulfillmentMethods, label: t('Fulfillment method'), name: "fulfillmentMethod", onChange: onChangeFulfillmentMethod, options: fulfillmentMethodOptions || {}, variant: "solid" }) }) }) })), hasBillToAddress && !isGuest ? readOnlyAddress : editAddress] }), Boolean(errorPatchBillingAddress) && (jsx("div", { className: styles['error-message'], children: jsx(FormattedMessage, { id: "An unexpected error occured" }) }))] }) }));
38
38
  }
39
39
 
40
40
  export { ShippingPageContent };
@@ -1,7 +1,6 @@
1
1
  import { jsx } from 'react/jsx-runtime';
2
2
  import { useRef, useEffect } from 'react';
3
3
  import { useFetchSession } from '../../../shared/api/storefront/hooks/authentication/use-fetch-session.js';
4
- import { useIsAuthenticated } from '../../../shared/api/storefront/hooks/authentication/use-is-authenticated.js';
5
4
  import { usePatchSession } from '../../../shared/api/storefront/hooks/authentication/use-patch-session.js';
6
5
  import { useFetchCurrentCart } from '../../../shared/api/storefront/hooks/cart/use-fetch-current-cart.js';
7
6
  import { useFetchFulfillmentMethodsForCurrentCart } from '../../../shared/api/storefront/hooks/customer/use-fetch-fulfillment-methods-for-current-cart.js';
@@ -18,17 +17,17 @@ import { usePatchShippingDetails } from './hooks/use-patch-shipping-details.js';
18
17
  import { ShippingPageContent } from './shipping-page-content.js';
19
18
 
20
19
  function ShippingPage() {
21
- const isAuthenticated = useIsAuthenticated();
22
20
  const { createEcommerceEvent, dataLayer } = useDataLayer();
23
21
  const gaEventPushed = useRef(false);
24
22
  const { data: cart, error: errorFetchCart, isLoading: isLoadingCart, refetch: refetchCart, } = useFetchCurrentCart();
23
+ const { data: session } = useFetchSession();
25
24
  const { data: countries, isLoading: isLoadingCountries } = useFetchCountries({
26
- enabled: hasNo(cart?.billTo?.address1),
25
+ enabled: hasNo(cart?.billTo?.address1) || Boolean(session?.isGuest),
27
26
  });
28
- const { data: session } = useFetchSession();
29
27
  const { data: fulfillmentMethods, isLoading: isLoadingFulfillmentMethods } = useFetchFulfillmentMethodsForCurrentCart();
30
28
  const { isLoading: isPatchingSession, mutate: patchSession } = usePatchSession();
31
29
  const { error: errorPatchBillingAddress, isError, isLoading: isPatching, isSuccess, mutate: patchShippingDetails, } = usePatchShippingDetails();
30
+ const isAuthenticated = session?.isAuthenticated;
32
31
  const isLoading = isLoadingCart || isLoadingCountries || isLoadingFulfillmentMethods;
33
32
  const { isNavigating, navigate } = useNavigate();
34
33
  const isPickup = cart?.fulfillmentMethod === 'PickUp';
@@ -75,13 +74,14 @@ function ShippingPage() {
75
74
  if (isLoading || isNavigating || isError || isSuccess)
76
75
  return jsx(LoadingPage, {});
77
76
  if (!isAuthenticated ||
77
+ hasNo(session) ||
78
78
  hasNo(cart) ||
79
79
  hasNo(cart.cartLines) ||
80
80
  cart.cartLines.length === 0 ||
81
81
  hasNo(cart.billTo) ||
82
82
  (hasNo(cart.billTo.address1) && hasNo(countries)))
83
83
  return null;
84
- return (jsx(ShippingPageContent, { cart: cart, editAddress: jsx(EditAddresses, { countries: countries || [], isLoading: isPatching, isPickup: isPickup, onSubmit: async ({ address, notes }) => {
84
+ return (jsx(ShippingPageContent, { cart: cart, editAddress: jsx(EditAddresses, { billTo: cart.billTo, countries: countries || [], isLoading: isPatching, isPickup: isPickup, onSubmit: async ({ address, notes }) => {
85
85
  if (!cart.billTo)
86
86
  return;
87
87
  await patchShippingDetails({
@@ -93,7 +93,7 @@ function ShippingPage() {
93
93
  cart,
94
94
  event: { event: 'add_shipping_info' },
95
95
  }));
96
- } }), errorPatchBillingAddress: errorPatchBillingAddress, fulfillmentMethods: fulfillmentMethods, isLoadingFulfillmentMethods: isLoadingFulfillmentMethods, isPatching: isPatching, isPatchingSession: isPatchingSession, onChangeFulfillmentMethod: async (value) => {
96
+ } }), errorPatchBillingAddress: errorPatchBillingAddress, fulfillmentMethods: fulfillmentMethods, isGuest: session.isGuest, isLoadingFulfillmentMethods: isLoadingFulfillmentMethods, isPatching: isPatching, isPatchingSession: isPatchingSession, onChangeFulfillmentMethod: async (value) => {
97
97
  await patchSession({
98
98
  session: {
99
99
  ...session,
@@ -37,7 +37,7 @@ function SearchResultsPageContent({ keyword }) {
37
37
  const { hits, isLoading } = useAlgoliaHits();
38
38
  const hasHits = hits.length > 0;
39
39
  const t = useFormattedMessage();
40
- return (jsxs(Fragment, { children: [isLoading !== false && !hasHits && jsx(LoadingPage, {}), isLoading === false && !hasHits && (jsx(NoResults, { content: jsxs("p", { children: [jsx(FormattedMessage, { id: "You could try checking the spelling of your search query" }), jsx("br", {}), jsx(FormattedMessage, { id: "Try another search" }), jsx("br", {}), jsx(FormattedMessage, { id: "Are you looking for information about our service? Please visit our customer support page" })] }), title: t("Unfortnately, We found no articles for your search '{0}'", {
40
+ return (jsxs(Fragment, { children: [isLoading !== false && !hasHits && jsx(LoadingPage, {}), isLoading === false && !hasHits && (jsx(NoResults, { content: jsxs(Fragment, { children: [jsx(FormattedMessage, { id: "You could try checking the spelling of your search query" }), jsx("br", {}), jsx(FormattedMessage, { id: "Try another search" }), jsx("br", {}), jsx(FormattedMessage, { id: "Are you looking for information about our service? Please visit our customer support page" })] }), title: t("Unfortnately, We found no articles for your search '{0}'", {
41
41
  replacementValues: { 0: keyword },
42
42
  }) })), jsxs("div", { style: {
43
43
  display: hasHits ? undefined : 'none',
@@ -1,29 +1,30 @@
1
1
  import { QueryClient } from '@tanstack/react-query';
2
- export type InferPromiseResult<T> = T extends (...args: any) => Promise<infer TResult> ? TResult : never;
3
- interface UseAwaitableMutationArgs<T extends (...args: any) => Promise<TResult>, TResult = InferPromiseResult<T>> {
2
+ export type OnError<T extends (...args: any) => Promise<unknown>> = (args: {
3
+ args: Parameters<T>;
4
+ error: unknown;
5
+ queryClient: QueryClient;
6
+ }) => void;
7
+ export type OnSuccess<T extends (...args: any) => Promise<TResult>, TResult = Awaited<ReturnType<T>>> = (args: {
8
+ args: Parameters<T>;
9
+ data: TResult;
10
+ queryClient: QueryClient;
11
+ }) => void;
12
+ export type OnComplete<T extends (...args: any) => Promise<TResult>, TResult = Awaited<ReturnType<T>>> = (args: {
13
+ args: Parameters<T>;
14
+ data: TResult | undefined;
15
+ error: unknown | undefined;
16
+ queryClient: QueryClient;
17
+ }) => void;
18
+ export interface UseAwaitableMutationArgs<T extends (...args: any) => Promise<TResult>, TResult = Awaited<ReturnType<T>>> {
4
19
  mutationFn: T;
5
- onComplete?: (args: {
6
- args: Parameters<T>;
7
- data: TResult | undefined;
8
- error: unknown | undefined;
9
- queryClient: QueryClient;
10
- }) => void;
11
- onError?: (args: {
12
- args: Parameters<T>;
13
- error: unknown;
14
- queryClient: QueryClient;
15
- }) => void;
16
- onSuccess?: (args: {
17
- args: Parameters<T>;
18
- data: TResult;
19
- queryClient: QueryClient;
20
- }) => void;
20
+ onComplete?: OnComplete<T, TResult>;
21
+ onError?: OnError<T>;
22
+ onSuccess?: OnSuccess<T, TResult>;
21
23
  }
22
- export declare function useAwaitableMutation<T extends (...args: any) => Promise<TResult>, TResult = InferPromiseResult<T>>({ mutationFn, onComplete, onError, onSuccess, }: UseAwaitableMutationArgs<T, TResult>): {
24
+ export declare function useAwaitableMutation<T extends (...args: any) => Promise<TResult>, TResult = Awaited<ReturnType<T>>>({ mutationFn, onComplete, onError, onSuccess, }: UseAwaitableMutationArgs<T, TResult>): {
23
25
  error: unknown;
24
26
  isError: boolean;
25
27
  isLoading: boolean;
26
28
  isSuccess: boolean;
27
29
  mutate: (...args: Parameters<T>) => Promise<TResult>;
28
30
  };
29
- export {};
@@ -1,6 +1,4 @@
1
- export declare function usePatchCart({ skipInvalidation, }?: {
2
- skipInvalidation?: boolean;
3
- }): {
1
+ export declare function usePatchCart(): {
4
2
  error: unknown;
5
3
  isError: boolean;
6
4
  isLoading: boolean;
@@ -2,15 +2,13 @@ import { useCallback } from 'react';
2
2
  import { useAwaitableMutation } from '../../../shared/hooks/use-awaitable-mutation.js';
3
3
  import { patchCart } from '../../services/cart-service.js';
4
4
 
5
- function usePatchCart({ skipInvalidation = false, } = {}) {
5
+ function usePatchCart() {
6
6
  const onError = useCallback(({ args: [{ cart }], queryClient }) => {
7
7
  queryClient.invalidateQueries({ queryKey: ['carts', cart.id] });
8
8
  }, []);
9
- const onSuccess = useCallback(({ args: [{ cart }], queryClient }) => {
10
- if (skipInvalidation)
11
- return;
12
- queryClient.removeQueries({ queryKey: ['carts', cart.id] });
13
- }, [skipInvalidation]);
9
+ const onSuccess = useCallback(({ args: [{ cart }], data, queryClient }) => {
10
+ queryClient.setQueryData(['carts', cart.id], data);
11
+ }, []);
14
12
  return useAwaitableMutation({
15
13
  mutationFn: patchCart,
16
14
  onError,
@@ -6,5 +6,5 @@ export declare const usePlaceOrder: () => {
6
6
  mutate: (args_0: {
7
7
  cart: import("../../model/storefront.model").CartModel;
8
8
  isPending?: boolean;
9
- }) => Promise<any>;
9
+ }) => Promise<import("../../model/storefront.model").CartModel>;
10
10
  };
@@ -3,15 +3,16 @@ import { useAwaitableMutation } from '../../../shared/hooks/use-awaitable-mutati
3
3
  import { placeOrder } from '../../services/cart-service.js';
4
4
 
5
5
  const usePlaceOrder = () => {
6
- const onComplete = useCallback(({ args: [{ cart }], queryClient }) => {
7
- queryClient.removeQueries({ queryKey: ['carts', cart.id] });
6
+ const onSuccess = useCallback(({ data: cart, queryClient }) => {
7
+ queryClient.invalidateQueries({ queryKey: ['carts', 'current'] });
8
+ queryClient.setQueryData(['carts', cart.id], cart);
8
9
  }, []);
9
- const onSuccess = useCallback(({ data: updatedCart, queryClient }) => {
10
- queryClient.removeQueries({ queryKey: ['carts', updatedCart.id] });
10
+ const onError = useCallback(({ queryClient }) => {
11
+ queryClient.invalidateQueries({ queryKey: ['carts'] });
11
12
  }, []);
12
13
  return useAwaitableMutation({
13
14
  mutationFn: placeOrder,
14
- onComplete,
15
+ onError,
15
16
  onSuccess,
16
17
  });
17
18
  };
@@ -37,16 +37,16 @@ async function patchCartLineById({ cartLine, cartLineId, }) {
37
37
  });
38
38
  }
39
39
  async function patchCart({ cart, }) {
40
- await request({
40
+ const { body } = await request({
41
41
  body: cart,
42
42
  credentials: 'include',
43
43
  headers: {
44
44
  'Content-Type': 'application/json',
45
45
  },
46
46
  method: 'PATCH',
47
- url: `${config.SHOP_API_URL}/api/v1/carts/current`,
47
+ url: `${config.BFF_API_URL}/api/v1/carts/current`,
48
48
  });
49
- return await fetchCart(cart);
49
+ return body;
50
50
  }
51
51
  async function deleteCurrentCart() {
52
52
  const { body } = await request({
@@ -103,16 +103,16 @@ async function placeOrder({ cart, isPending, }) {
103
103
  : isPending
104
104
  ? 'PendingPaymentValidation'
105
105
  : 'Submitted';
106
- await request({
106
+ const { body } = await request({
107
107
  body: { ...cart, status: newStatus },
108
108
  credentials: 'include',
109
109
  headers: {
110
110
  'Content-Type': 'application/json',
111
111
  },
112
112
  method: 'PATCH',
113
- url: `${config.SHOP_API_URL}/api/v1/carts/current`,
113
+ url: `${config.BFF_API_URL}/api/v1/carts/current`,
114
114
  });
115
- return await fetchCart(cart);
115
+ return body;
116
116
  }
117
117
  async function saveCartForLater({ cart }) {
118
118
  // USER NEEDS TO BE LOGGED IN
@@ -123,7 +123,7 @@ async function saveCartForLater({ cart }) {
123
123
  'Content-Type': 'application/json',
124
124
  },
125
125
  method: 'PATCH',
126
- url: `${config.SHOP_API_URL}/api/v1/carts/current`,
126
+ url: `${config.BFF_API_URL}/api/v1/carts/current`,
127
127
  });
128
128
  return body;
129
129
  }
@@ -1,8 +1,9 @@
1
+ import { logger } from '../../logging/logger.js';
2
+
1
3
  const _dataLayer = [];
2
4
  _dataLayer.push = (function (_push) {
3
5
  return (...items) => {
4
- // eslint-disable-next-line no-console
5
- console.log('dataLayer.push', items.length === 1 ? items[0] : items);
6
+ logger.info('dataLayer.push', items.length === 1 ? items[0] : items);
6
7
  return _push(...items);
7
8
  };
8
9
  })(_dataLayer.push.bind(_dataLayer));
@@ -1,4 +1,4 @@
1
- interface DPRSrcSet {
1
+ export interface DPRSrcSet {
2
2
  1: string;
3
3
  2: string;
4
4
  3: string;
@@ -24,4 +24,3 @@ export interface ResponsiveImageType {
24
24
  sm: DPRSrcSet;
25
25
  }
26
26
  export declare function isResponsiveImage(image: ImageType | ResponsiveImageType | undefined): image is ResponsiveImageType;
27
- export {};
@@ -73,11 +73,9 @@ function useGlobalState(key, initialState) {
73
73
  state.removeEventListener('stateChanged', updateState);
74
74
  };
75
75
  }, [state]);
76
- function updateGlobalState(valueOrFn) {
77
- state.value =
78
- valueOrFn instanceof Function ? valueOrFn(state.value) : valueOrFn;
79
- }
80
- return [rerenderState, useCallback(updateGlobalState, [updateGlobalState])];
76
+ const setGlobalState = useCallback((valueOrFn) => (state.value =
77
+ valueOrFn instanceof Function ? valueOrFn(state.value) : valueOrFn), [state]);
78
+ return [rerenderState, setGlobalState];
81
79
  }
82
80
 
83
81
  export { GlobalStateProvider, GlobalStateProviderContext, useGlobalState };
@@ -0,0 +1,2 @@
1
+ export declare function trackPropertyChange(name: string, value: unknown): void;
2
+ export declare function trackPropertyChange(obj: Record<string, unknown>): void;