@akinon/next 2.0.0-beta.0 → 2.0.0-beta.10

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 (69) hide show
  1. package/.eslintrc.js +12 -0
  2. package/CHANGELOG.md +56 -0
  3. package/api/auth.ts +17 -0
  4. package/api/client.ts +3 -2
  5. package/bin/run-prebuild-tests.js +46 -0
  6. package/components/accordion.tsx +1 -1
  7. package/components/button.tsx +51 -36
  8. package/components/client-root.tsx +20 -0
  9. package/components/input.tsx +1 -1
  10. package/components/modal.tsx +1 -1
  11. package/components/pz-root.tsx +1 -1
  12. package/components/select.tsx +1 -1
  13. package/components/selected-payment-option-view.tsx +1 -1
  14. package/data/client/api.ts +2 -0
  15. package/data/client/basket.ts +27 -5
  16. package/data/client/checkout.ts +62 -7
  17. package/data/client/misc.ts +25 -1
  18. package/data/client/product.ts +19 -2
  19. package/data/client/user.ts +16 -8
  20. package/data/server/flatpage.ts +8 -4
  21. package/data/server/form.ts +12 -4
  22. package/data/server/landingpage.ts +8 -4
  23. package/data/server/menu.ts +7 -2
  24. package/data/server/product.ts +16 -5
  25. package/data/server/seo.ts +11 -4
  26. package/data/server/widget.ts +19 -4
  27. package/data/urls.ts +11 -3
  28. package/hocs/client/with-segment-defaults.tsx +1 -1
  29. package/hocs/server/with-segment-defaults.tsx +6 -3
  30. package/hooks/index.ts +1 -0
  31. package/hooks/use-router.ts +5 -2
  32. package/hooks/use-sentry-uncaught-errors.ts +24 -0
  33. package/instrumentation/index.ts +10 -0
  34. package/lib/cache-handler.mjs +2 -2
  35. package/lib/cache.ts +4 -4
  36. package/localization/index.ts +2 -1
  37. package/middlewares/default.ts +6 -15
  38. package/middlewares/locale.ts +31 -10
  39. package/middlewares/url-redirection.ts +16 -0
  40. package/package.json +8 -7
  41. package/plugins.js +2 -1
  42. package/redux/middlewares/checkout.ts +16 -144
  43. package/redux/middlewares/index.ts +4 -2
  44. package/redux/middlewares/pre-order/address.ts +50 -0
  45. package/redux/middlewares/pre-order/attribute-based-shipping-option.ts +46 -0
  46. package/redux/middlewares/pre-order/data-source-shipping-option.ts +43 -0
  47. package/redux/middlewares/pre-order/delivery-option.ts +40 -0
  48. package/redux/middlewares/pre-order/index.ts +29 -0
  49. package/redux/middlewares/pre-order/installment-option.ts +42 -0
  50. package/redux/middlewares/pre-order/payment-option.ts +34 -0
  51. package/redux/middlewares/pre-order/pre-order-validation.ts +24 -0
  52. package/redux/middlewares/pre-order/redirection.ts +40 -0
  53. package/redux/middlewares/pre-order/set-pre-order.ts +22 -0
  54. package/redux/middlewares/pre-order/shipping-option.ts +44 -0
  55. package/redux/middlewares/pre-order/shipping-step.ts +38 -0
  56. package/redux/reducers/checkout.ts +8 -2
  57. package/redux/reducers/index.ts +5 -3
  58. package/redux/reducers/root.ts +7 -2
  59. package/sentry/index.ts +36 -17
  60. package/types/commerce/account.ts +5 -1
  61. package/types/commerce/checkout.ts +24 -0
  62. package/types/index.ts +8 -4
  63. package/utils/app-fetch.ts +2 -2
  64. package/utils/index.ts +11 -8
  65. package/utils/localization.ts +4 -0
  66. package/utils/override-middleware.ts +25 -0
  67. package/utils/redirect.ts +2 -2
  68. package/views/error-page.tsx +93 -0
  69. package/with-pz-config.js +4 -3
@@ -1,7 +1,7 @@
1
1
  import { api } from './api';
2
2
  import { user } from '../urls';
3
3
  import { ForgotPasswordFormType, Order } from '../../types';
4
- import { buildClientRequestUrl } from '../../utils';
4
+ import { buildClientRequestUrl, getCookie } from '../../utils';
5
5
 
6
6
  interface GetCaptchaResponse {
7
7
  siteKey: string;
@@ -64,13 +64,21 @@ const userApi = api.injectEndpoints({
64
64
  })
65
65
  }),
66
66
  forgotPassword: build.mutation<void, ForgotPasswordFormType>({
67
- query: (body) => ({
68
- url: buildClientRequestUrl(user.forgotPassword, {
69
- contentType: 'application/json'
70
- }),
71
- method: 'POST',
72
- body
73
- })
67
+ query: (body) => {
68
+ const frontendId = getCookie('pz-frontend-id');
69
+ const headers = frontendId
70
+ ? { 'x-frontend-id': frontendId }
71
+ : undefined;
72
+
73
+ return {
74
+ url: buildClientRequestUrl(user.forgotPassword, {
75
+ contentType: 'application/json'
76
+ }),
77
+ method: 'POST',
78
+ body,
79
+ headers
80
+ };
81
+ }
74
82
  }),
75
83
  otpLogin: build.mutation<void, { phone: string }>({
76
84
  query: ({ phone }) => ({
@@ -7,7 +7,8 @@ import { ServerVariables } from '../../utils/server-variables';
7
7
  const getFlatPageDataHandler = (
8
8
  pk: number,
9
9
  locale: string,
10
- currency: string
10
+ currency: string,
11
+ headers?: Record<string, string>
11
12
  ) => {
12
13
  return async function () {
13
14
  const data = await appFetch<FlatPage>({
@@ -17,7 +18,8 @@ const getFlatPageDataHandler = (
17
18
  init: {
18
19
  headers: {
19
20
  Accept: 'application/json',
20
- 'Content-Type': 'application/json'
21
+ 'Content-Type': 'application/json',
22
+ ...(headers ?? {})
21
23
  }
22
24
  }
23
25
  });
@@ -29,15 +31,17 @@ const getFlatPageDataHandler = (
29
31
  export const getFlatPageData = ({
30
32
  pk,
31
33
  locale = ServerVariables.locale,
32
- currency = ServerVariables.currency
34
+ currency = ServerVariables.currency,
35
+ headers
33
36
  }: {
34
37
  pk: number;
35
38
  locale?: string;
36
39
  currency?: string;
40
+ headers?: Record<string, string>;
37
41
  }) => {
38
42
  return Cache.wrap(
39
43
  CacheKey.FlatPage(pk),
40
44
  locale,
41
- getFlatPageDataHandler(pk, locale, currency)
45
+ getFlatPageDataHandler(pk, locale, currency, headers)
42
46
  );
43
47
  };
@@ -5,7 +5,12 @@ import appFetch from '../../utils/app-fetch';
5
5
  import { ServerVariables } from '../../utils/server-variables';
6
6
  import { form } from '../urls';
7
7
 
8
- const getFormDataHandler = (pk: number, locale: string, currency: string) => {
8
+ const getFormDataHandler = (
9
+ pk: number,
10
+ locale: string,
11
+ currency: string,
12
+ headers?: Record<string, string>
13
+ ) => {
9
14
  return async function () {
10
15
  const data = await appFetch<FormType>({
11
16
  url: form.getForm(pk),
@@ -14,7 +19,8 @@ const getFormDataHandler = (pk: number, locale: string, currency: string) => {
14
19
  init: {
15
20
  headers: {
16
21
  Accept: 'application/json',
17
- 'Content-Type': 'application/json'
22
+ 'Content-Type': 'application/json',
23
+ ...(headers ?? {})
18
24
  }
19
25
  }
20
26
  });
@@ -26,15 +32,17 @@ const getFormDataHandler = (pk: number, locale: string, currency: string) => {
26
32
  export const getFormData = ({
27
33
  pk,
28
34
  locale = ServerVariables.locale,
29
- currency = ServerVariables.currency
35
+ currency = ServerVariables.currency,
36
+ headers
30
37
  }: {
31
38
  pk: number;
32
39
  locale?: string;
33
40
  currency?: string;
41
+ headers?: Record<string, string>;
34
42
  }) => {
35
43
  return Cache.wrap(
36
44
  CacheKey.Form(pk),
37
45
  locale,
38
- getFormDataHandler(pk, locale, currency)
46
+ getFormDataHandler(pk, locale, currency, headers)
39
47
  );
40
48
  };
@@ -7,7 +7,8 @@ import { ServerVariables } from '../../utils/server-variables';
7
7
  const getLandingPageHandler = (
8
8
  pk: number,
9
9
  locale: string,
10
- currency: string
10
+ currency: string,
11
+ headers?: Record<string, string>
11
12
  ) => {
12
13
  return async function () {
13
14
  const data = await appFetch<LandingPage>({
@@ -17,7 +18,8 @@ const getLandingPageHandler = (
17
18
  init: {
18
19
  headers: {
19
20
  Accept: 'application/json',
20
- 'Content-Type': 'application/json'
21
+ 'Content-Type': 'application/json',
22
+ ...(headers ?? {})
21
23
  }
22
24
  }
23
25
  });
@@ -29,15 +31,17 @@ const getLandingPageHandler = (
29
31
  export const getLandingPageData = ({
30
32
  pk,
31
33
  locale = ServerVariables.locale,
32
- currency = ServerVariables.currency
34
+ currency = ServerVariables.currency,
35
+ headers
33
36
  }: {
34
37
  pk: number;
35
38
  locale?: string;
36
39
  currency?: string;
40
+ headers?: Record<string, string>;
37
41
  }) => {
38
42
  return Cache.wrap(
39
43
  CacheKey.LandingPage(pk),
40
44
  locale,
41
- getLandingPageHandler(pk, locale, currency)
45
+ getLandingPageHandler(pk, locale, currency, headers)
42
46
  );
43
47
  };
@@ -13,6 +13,7 @@ interface MenuHandlerParams {
13
13
  currency?: string;
14
14
  depth?: number;
15
15
  parent?: string;
16
+ headers?: Record<string, string>;
16
17
  }
17
18
 
18
19
  const DEFAULT_DEPTH = 3;
@@ -22,13 +23,17 @@ const getMenuHandler =
22
23
  locale = ServerVariables.locale,
23
24
  currency = ServerVariables.currency,
24
25
  depth,
25
- parent
26
+ parent,
27
+ headers
26
28
  }: MenuHandlerParams = {}) =>
27
29
  async () => {
28
30
  const response = await appFetch<MenuResponse>({
29
31
  url: misc.menus(depth ?? DEFAULT_DEPTH, parent),
30
32
  locale,
31
- currency
33
+ currency,
34
+ init: {
35
+ headers
36
+ }
32
37
  });
33
38
 
34
39
  return response?.menu;
@@ -11,6 +11,7 @@ type GetProduct = {
11
11
  currency?: string;
12
12
  searchParams?: URLSearchParams;
13
13
  groupProduct?: boolean;
14
+ headers?: Record<string, string>;
14
15
  };
15
16
 
16
17
  const getProductDataHandler = ({
@@ -18,7 +19,8 @@ const getProductDataHandler = ({
18
19
  locale,
19
20
  currency,
20
21
  searchParams,
21
- groupProduct
22
+ groupProduct,
23
+ headers
22
24
  }: GetProduct) => {
23
25
  return async function () {
24
26
  let url = groupProduct
@@ -29,7 +31,7 @@ const getProductDataHandler = ({
29
31
  url +=
30
32
  '?' +
31
33
  Object.keys(searchParams)
32
- .map((key) => `${key}=${searchParams[key]}`)
34
+ .map((key) => `${key}=${encodeURIComponent(searchParams[key])}`)
33
35
  .join('&');
34
36
  }
35
37
 
@@ -40,7 +42,8 @@ const getProductDataHandler = ({
40
42
  init: {
41
43
  headers: {
42
44
  Accept: 'application/json',
43
- 'Content-Type': 'application/json'
45
+ 'Content-Type': 'application/json',
46
+ ...(headers ?? {})
44
47
  }
45
48
  }
46
49
  });
@@ -95,7 +98,8 @@ export const getProductData = async ({
95
98
  locale = ServerVariables.locale,
96
99
  currency = ServerVariables.currency,
97
100
  searchParams,
98
- groupProduct
101
+ groupProduct,
102
+ headers
99
103
  }: GetProduct) => {
100
104
  return Cache.wrap(
101
105
  CacheKey[groupProduct ? 'GroupProduct' : 'Product'](
@@ -103,7 +107,14 @@ export const getProductData = async ({
103
107
  searchParams ?? new URLSearchParams()
104
108
  ),
105
109
  locale,
106
- getProductDataHandler({ pk, locale, currency, searchParams, groupProduct }),
110
+ getProductDataHandler({
111
+ pk,
112
+ locale,
113
+ currency,
114
+ searchParams,
115
+ groupProduct,
116
+ headers
117
+ }),
107
118
  {
108
119
  expire: 300
109
120
  }
@@ -7,9 +7,10 @@ interface SeoDataParams {
7
7
  url: string;
8
8
  locale?: string;
9
9
  currency?: string;
10
+ headers?: Record<string, string>;
10
11
  }
11
12
 
12
- function getSeoDataHandler({ url, locale, currency }: SeoDataParams) {
13
+ function getSeoDataHandler({ url, locale, currency, headers }: SeoDataParams) {
13
14
  return async function () {
14
15
  let data = {} as {
15
16
  title: string;
@@ -19,7 +20,12 @@ function getSeoDataHandler({ url, locale, currency }: SeoDataParams) {
19
20
  };
20
21
 
21
22
  try {
22
- data = await appFetch({ url: misc.cmsSeo(url), locale, currency });
23
+ data = await appFetch({
24
+ url: misc.cmsSeo(url),
25
+ locale,
26
+ currency,
27
+ init: { headers }
28
+ });
23
29
  } catch (error) {
24
30
  // logger.error('Error while fetching seo data', { url, error });
25
31
  }
@@ -31,11 +37,12 @@ function getSeoDataHandler({ url, locale, currency }: SeoDataParams) {
31
37
  export const getSeoData = async (
32
38
  url,
33
39
  locale = ServerVariables.locale,
34
- currency = ServerVariables.currency
40
+ currency = ServerVariables.currency,
41
+ headers?: Record<string, string>
35
42
  ) => {
36
43
  return Cache.wrap(
37
44
  CacheKey.Seo(url),
38
45
  locale,
39
- getSeoDataHandler({ url, locale, currency })
46
+ getSeoDataHandler({ url, locale, currency, headers })
40
47
  );
41
48
  };
@@ -6,29 +6,44 @@ import { widgets } from '../urls';
6
6
  import { ServerVariables } from '../../utils/server-variables';
7
7
 
8
8
  const getWidgetDataHandler =
9
- (slug: string, locale: string, currency: string) => async () => {
9
+ (
10
+ slug: string,
11
+ locale: string,
12
+ currency: string,
13
+ headers?: Record<string, string>
14
+ ) =>
15
+ async () => {
10
16
  if (!slug) {
11
17
  return null;
12
18
  }
13
19
 
14
- return await appFetch({ url: widgets.getWidget(slug), locale, currency });
20
+ return await appFetch({
21
+ url: widgets.getWidget(slug),
22
+ locale,
23
+ currency,
24
+ init: {
25
+ headers
26
+ }
27
+ });
15
28
  };
16
29
 
17
30
  export const getWidgetData = async <T>({
18
31
  slug,
19
32
  locale = ServerVariables.locale,
20
33
  currency = ServerVariables.currency,
21
- cacheOptions
34
+ cacheOptions,
35
+ headers
22
36
  }: {
23
37
  slug: string;
24
38
  locale?: string;
25
39
  currency?: string;
26
40
  cacheOptions?: CacheOptions;
41
+ headers?: Record<string, string>;
27
42
  }): Promise<WidgetResultType<T>> => {
28
43
  return Cache.wrap(
29
44
  CacheKey.Widget(slug),
30
45
  locale,
31
- getWidgetDataHandler(slug, locale, currency),
46
+ getWidgetDataHandler(slug, locale, currency, headers),
32
47
  cacheOptions
33
48
  );
34
49
  };
package/data/urls.ts CHANGED
@@ -74,7 +74,10 @@ export const address = {
74
74
 
75
75
  export const basket = {
76
76
  getBasket: '/baskets/basket/',
77
+ getMiniBasket: '/baskets/basket/mini/',
77
78
  getBasketDetail: (namespace: string) => `/baskets/basket/${namespace}/`,
79
+ getMiniBasketDetail: (namespace: string) =>
80
+ `/baskets/basket/${namespace}/mini/`,
78
81
  getAllBaskets: '/baskets/basket-list/',
79
82
  removeBasket: (pk: number) => `/baskets/basket-list/${pk}/`,
80
83
  selectMainBasket: (pk: number) => `/baskets/basket-list/id/${pk}/main/`,
@@ -137,7 +140,9 @@ export const checkout = {
137
140
  '/orders/checkout/?page=AttributeBasedShippingOptionSelectionPage',
138
141
  deliveryBagsPage: '/orders/checkout/?page=DeliveryBagsPage',
139
142
  setOrderSelectionPage: '/orders/checkout/?page=OrderSelectionPage',
140
- loyaltyCardPage: '/orders/checkout/?page=LoyaltyCardPage'
143
+ loyaltyCardPage: '/orders/checkout/?page=LoyaltyCardPage',
144
+ sendSmsPage: '/orders/checkout/?page=SendSmsPage',
145
+ verifySmsPage: '/orders/checkout/?page=VerifySmsPage'
141
146
  };
142
147
 
143
148
  export const flatpage = {
@@ -160,7 +165,8 @@ export const misc = {
160
165
  parent ? `&parent=${parent}` : ''
161
166
  }`,
162
167
  cmsSeo: (slug: string | string[]) => `/cms/seo/?url=${slug ? slug : '/'}`,
163
- setCurrency: '/users/activate-currency/'
168
+ setCurrency: '/users/activate-currency/',
169
+ bukalemunImageUrl: (params: string) => `/bukalemun/?${params}`
164
170
  };
165
171
 
166
172
  export const product = {
@@ -174,7 +180,9 @@ export const product = {
174
180
  slug: (slug: string) => `/${slug}/`,
175
181
  categoryUrl: (pk: number) => `/products/${pk}/category_nodes/?limit=1`,
176
182
  breadcrumbUrl: (menuitemmodel: string) =>
177
- `/menus/generate_breadcrumb/?item=${menuitemmodel}&generator_name=menu_item`
183
+ `/menus/generate_breadcrumb/?item=${menuitemmodel}&generator_name=menu_item`,
184
+ bundleProduct: (productPk: string, queryString: string) =>
185
+ `/bundle-product/${productPk}/?${queryString}`
178
186
  };
179
187
 
180
188
  export const wishlist = {
@@ -1,5 +1,5 @@
1
1
  import { LayoutProps, PageProps, RootLayoutProps } from '../../types';
2
- import React from 'react';
2
+ import React, { JSX } from 'react';
3
3
 
4
4
  type SegmentType = 'client-root' | 'layout' | 'page';
5
5
 
@@ -1,4 +1,5 @@
1
1
  import settings from 'settings';
2
+ import { JSX } from 'react';
2
3
  import { LayoutProps, PageProps, RootLayoutProps } from '../../types';
3
4
  import { redirect } from 'next/navigation';
4
5
  import { ServerVariables } from '../../utils/server-variables';
@@ -21,6 +22,8 @@ export const withSegmentDefaults =
21
22
  async (props: T) => {
22
23
  let componentProps = { ...props };
23
24
 
25
+ const { locale, currency } = await props.params;
26
+
24
27
  if (options.segmentType === 'root-layout') {
25
28
  componentProps = (await addRootLayoutProps(
26
29
  componentProps as RootLayoutProps
@@ -29,8 +32,8 @@ export const withSegmentDefaults =
29
32
  checkRedisVariables();
30
33
  }
31
34
 
32
- ServerVariables.locale = props.params.locale;
33
- ServerVariables.currency = props.params.currency;
35
+ ServerVariables.locale = await locale;
36
+ ServerVariables.currency = await currency;
34
37
 
35
38
  return await (
36
39
  <>
@@ -40,7 +43,7 @@ export const withSegmentDefaults =
40
43
  };
41
44
 
42
45
  const addRootLayoutProps = async (componentProps: RootLayoutProps) => {
43
- const params = componentProps.params;
46
+ const params = await componentProps.params;
44
47
 
45
48
  if (
46
49
  params.commerce !== encodeURIComponent(decodeURI(settings.commerceUrl)) ||
package/hooks/index.ts CHANGED
@@ -10,3 +10,4 @@ export * from './use-mobile-iframe-handler';
10
10
  export * from './use-payment-options';
11
11
  export * from './use-pagination';
12
12
  export * from './use-message-listener';
13
+ export * from './use-sentry-uncaught-errors';
@@ -27,8 +27,11 @@ export const useRouter = () => {
27
27
  );
28
28
 
29
29
  url.pathname = `${
30
- locale === defaultLocale?.value &&
31
- localeUrlStrategy === LocaleUrlStrategy.HideDefaultLocale
30
+ localeUrlStrategy === LocaleUrlStrategy.Subdomain ||
31
+ (locale === defaultLocale?.value &&
32
+ [LocaleUrlStrategy.HideDefaultLocale].includes(
33
+ localeUrlStrategy as LocaleUrlStrategy
34
+ ))
32
35
  ? ''
33
36
  : `/${locale}`
34
37
  }${pathnameWithoutLocale}`;
@@ -0,0 +1,24 @@
1
+ import { useEffect } from 'react';
2
+ import * as Sentry from '@sentry/nextjs';
3
+ import { ClientLogType } from '@akinon/next/sentry';
4
+
5
+ export const useSentryUncaughtErrors = (error: Error & { digest?: string }) => {
6
+ useEffect(() => {
7
+ Sentry.withScope(function (scope) {
8
+ scope.setLevel('fatal');
9
+ scope.setTags({
10
+ APP_TYPE: 'ProjectZeroNext',
11
+ TYPE: 'Client',
12
+ LOG_TYPE: ClientLogType.UNCAUGHT_ERROR_PAGE
13
+ });
14
+ scope.setExtra('error', error);
15
+
16
+ const error_ = new Error('FATAL: Uncaught client error');
17
+ error_.name = 'UNCAUGHT_ERROR_PAGE';
18
+
19
+ Sentry.captureException(error_, {
20
+ fingerprint: ['UNCAUGHT_ERROR_PAGE', error.digest]
21
+ });
22
+ });
23
+ }, [error]);
24
+ };
@@ -1,5 +1,15 @@
1
+ import { initSentry } from '../sentry';
2
+ import * as Sentry from '@sentry/nextjs';
3
+
1
4
  export async function register() {
2
5
  if (process.env.NEXT_RUNTIME === 'nodejs') {
3
6
  await import('./node');
7
+ initSentry('Server');
8
+ }
9
+
10
+ if (process.env.NEXT_RUNTIME === 'edge') {
11
+ initSentry('Edge');
4
12
  }
5
13
  }
14
+
15
+ export const onRequestError = Sentry.captureRequestError;
@@ -23,10 +23,10 @@ CacheHandler.onCreation(async () => {
23
23
  timeoutMs: 5000
24
24
  });
25
25
 
26
- const localHandler = createLruHandler();
26
+ // const localHandler = createLruHandler();
27
27
 
28
28
  return {
29
- handlers: [redisHandler, localHandler]
29
+ handlers: [redisHandler]
30
30
  };
31
31
  });
32
32
 
package/lib/cache.ts CHANGED
@@ -156,10 +156,6 @@ export class Cache {
156
156
  handler: () => Promise<T>,
157
157
  options?: CacheOptions
158
158
  ): Promise<T> {
159
- if (Settings.usePrettyUrlRoute) {
160
- return await handler();
161
- }
162
-
163
159
  const requiredVariables = [
164
160
  process.env.CACHE_HOST,
165
161
  process.env.CACHE_PORT,
@@ -178,6 +174,10 @@ export class Cache {
178
174
  const _options = Object.assign(defaultOptions, options);
179
175
  const formattedKey = Cache.formatKey(key, locale);
180
176
 
177
+ if (Settings.usePrettyUrlRoute) {
178
+ _options.expire = 120;
179
+ }
180
+
181
181
  logger.debug('Cache wrap', { key, formattedKey, _options });
182
182
 
183
183
  if (_options.cache) {
@@ -1,5 +1,6 @@
1
1
  export enum LocaleUrlStrategy {
2
2
  HideAllLocales = 'hide-all-locales',
3
3
  HideDefaultLocale = 'hide-default-locale',
4
- ShowAllLocales = 'show-all-locales'
4
+ ShowAllLocales = 'show-all-locales',
5
+ Subdomain = 'subdomain'
5
6
  }
@@ -95,7 +95,9 @@ const withPzDefault =
95
95
 
96
96
  if (
97
97
  req.nextUrl.pathname.includes('/orders/hooks/') ||
98
- req.nextUrl.pathname.includes('/orders/checkout-with-token/')
98
+ req.nextUrl.pathname.includes('/orders/checkout-with-token/') ||
99
+ req.nextUrl.pathname.includes('/hooks/cash_register/complete/') ||
100
+ req.nextUrl.pathname.includes('/hooks/cash_register/pre_order/')
99
101
  ) {
100
102
  const queryString = searchParams.toString();
101
103
  const currency = searchParams.get('currency')?.toLowerCase();
@@ -285,20 +287,9 @@ const withPzDefault =
285
287
  url.pathname =
286
288
  url.pathname +
287
289
  (/\/$/.test(url.pathname) ? '' : '/') +
288
- `searchparams|${url.searchParams.toString()}`;
289
- }
290
-
291
- if (
292
- !req.middlewareParams.found &&
293
- Settings.customNotFoundEnabled
294
- ) {
295
- let pathname = url.pathname
296
- .replace(/\/+$/, '')
297
- .split('/');
298
- url.pathname = url.pathname.replace(
299
- pathname.pop(),
300
- 'pz-not-found'
301
- );
290
+ `searchparams|${encodeURIComponent(
291
+ url.searchParams.toString()
292
+ )}`;
302
293
  }
303
294
 
304
295
  Settings.rewrites.forEach((rewrite) => {
@@ -4,17 +4,32 @@ import { PzNextRequest } from '.';
4
4
  import { LocaleUrlStrategy } from '../localization';
5
5
  import { urlLocaleMatcherRegex } from '../utils';
6
6
  import logger from '../utils/log';
7
+ import { getUrlPathWithLocale } from '../utils/localization';
7
8
 
8
- const getMatchedLocale = (pathname: string) => {
9
+ const getMatchedLocale = (pathname: string, req: PzNextRequest) => {
9
10
  let matchedLocale = pathname.match(urlLocaleMatcherRegex)?.[0] ?? '';
10
11
  matchedLocale = matchedLocale.replace('/', '');
11
12
 
13
+ const { localeUrlStrategy, defaultLocaleValue } = settings.localization;
14
+
15
+ if (localeUrlStrategy === LocaleUrlStrategy.Subdomain) {
16
+ const host = req.headers.get('x-forwarded-host');
17
+
18
+ if (host) {
19
+ const subDomain = host.split('.')[0] || '';
20
+ const subDomainLocaleMatched = `/${subDomain}`.match(
21
+ urlLocaleMatcherRegex
22
+ );
23
+
24
+ if (subDomainLocaleMatched && subDomainLocaleMatched[0]) {
25
+ matchedLocale = subDomainLocaleMatched[0].slice(1);
26
+ }
27
+ }
28
+ }
29
+
12
30
  if (!matchedLocale.length) {
13
- if (
14
- settings.localization.localeUrlStrategy !==
15
- LocaleUrlStrategy.ShowAllLocales
16
- ) {
17
- matchedLocale = settings.localization.defaultLocaleValue;
31
+ if (localeUrlStrategy !== LocaleUrlStrategy.ShowAllLocales) {
32
+ matchedLocale = defaultLocaleValue;
18
33
  }
19
34
  }
20
35
 
@@ -28,7 +43,7 @@ const withLocale =
28
43
 
29
44
  try {
30
45
  const url = req.nextUrl.clone();
31
- const matchedLocale = getMatchedLocale(url.pathname);
46
+ const matchedLocale = getMatchedLocale(url.pathname, req);
32
47
  let { localeUrlStrategy, defaultLocaleValue, redirectToDefaultLocale } =
33
48
  settings.localization;
34
49
 
@@ -50,8 +65,15 @@ const withLocale =
50
65
  redirectToDefaultLocale &&
51
66
  req.method === 'GET'
52
67
  ) {
53
- url.pathname = `/${defaultLocaleValue}${url.pathname}`;
54
- return NextResponse.redirect(url);
68
+ // Redirect to existing or default locale
69
+
70
+ url.pathname = getUrlPathWithLocale(
71
+ url.pathname,
72
+ req.cookies.get('pz-locale')?.value
73
+ );
74
+
75
+ // Use 303 for POST requests
76
+ return NextResponse.redirect(url, 303);
55
77
  }
56
78
 
57
79
  req.middlewareParams.rewrites.locale = matchedLocale;
@@ -61,7 +83,6 @@ const withLocale =
61
83
  ip
62
84
  });
63
85
  }
64
-
65
86
  return middleware(req, event);
66
87
  };
67
88
 
@@ -60,6 +60,22 @@ const withUrlRedirection =
60
60
 
61
61
  const setCookies = request.headers.getSetCookie();
62
62
 
63
+ if (settings.commerceRedirectionIgnoreList) {
64
+ const shouldIgnoreRedirect =
65
+ settings.commerceRedirectionIgnoreList.some((ignorePath) =>
66
+ redirectUrl.pathname.startsWith(
67
+ getUrlPathWithLocale(
68
+ ignorePath,
69
+ req.middlewareParams.rewrites.locale
70
+ )
71
+ )
72
+ );
73
+
74
+ if (shouldIgnoreRedirect) {
75
+ return middleware(req, event);
76
+ }
77
+ }
78
+
63
79
  const response = NextResponse.redirect(redirectUrl.toString(), {
64
80
  status: request.status
65
81
  });