@akinon/next 2.0.0-beta.2 → 2.0.0-beta.20

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 (189) hide show
  1. package/.eslintrc.js +12 -0
  2. package/CHANGELOG.md +377 -7
  3. package/__tests__/next-config.test.ts +83 -0
  4. package/__tests__/tsconfig.json +23 -0
  5. package/api/auth.ts +133 -44
  6. package/api/barcode-search.ts +59 -0
  7. package/api/cache.ts +41 -5
  8. package/api/client.ts +21 -4
  9. package/api/form.ts +85 -0
  10. package/api/image-proxy.ts +75 -0
  11. package/api/product-categories.ts +53 -0
  12. package/api/similar-product-list.ts +63 -0
  13. package/api/similar-products.ts +111 -0
  14. package/api/virtual-try-on.ts +382 -0
  15. package/assets/styles/index.scss +84 -0
  16. package/babel.config.js +6 -0
  17. package/bin/pz-generate-routes.js +115 -0
  18. package/bin/pz-prebuild.js +1 -0
  19. package/bin/pz-predev.js +1 -0
  20. package/bin/pz-run-tests.js +99 -0
  21. package/bin/run-prebuild-tests.js +46 -0
  22. package/components/accordion.tsx +20 -5
  23. package/components/button.tsx +51 -36
  24. package/components/client-root.tsx +138 -2
  25. package/components/file-input.tsx +65 -3
  26. package/components/index.ts +1 -0
  27. package/components/input.tsx +1 -1
  28. package/components/link.tsx +46 -16
  29. package/components/logger-popup.tsx +213 -0
  30. package/components/modal.tsx +32 -16
  31. package/components/plugin-module.tsx +62 -3
  32. package/components/price.tsx +2 -2
  33. package/components/select.tsx +1 -1
  34. package/components/selected-payment-option-view.tsx +21 -0
  35. package/components/theme-editor/blocks/accordion-block.tsx +136 -0
  36. package/components/theme-editor/blocks/block-renderer-registry.tsx +77 -0
  37. package/components/theme-editor/blocks/button-block.tsx +593 -0
  38. package/components/theme-editor/blocks/counter-block.tsx +348 -0
  39. package/components/theme-editor/blocks/divider-block.tsx +20 -0
  40. package/components/theme-editor/blocks/embed-block.tsx +208 -0
  41. package/components/theme-editor/blocks/group-block.tsx +116 -0
  42. package/components/theme-editor/blocks/hotspot-block.tsx +147 -0
  43. package/components/theme-editor/blocks/icon-block.tsx +230 -0
  44. package/components/theme-editor/blocks/image-block.tsx +137 -0
  45. package/components/theme-editor/blocks/image-gallery-block.tsx +269 -0
  46. package/components/theme-editor/blocks/input-block.tsx +123 -0
  47. package/components/theme-editor/blocks/link-block.tsx +216 -0
  48. package/components/theme-editor/blocks/lottie-block.tsx +325 -0
  49. package/components/theme-editor/blocks/map-block.tsx +89 -0
  50. package/components/theme-editor/blocks/slider-block.tsx +595 -0
  51. package/components/theme-editor/blocks/tab-block.tsx +10 -0
  52. package/components/theme-editor/blocks/text-block.tsx +52 -0
  53. package/components/theme-editor/blocks/video-block.tsx +122 -0
  54. package/components/theme-editor/components/action-toolbar.tsx +305 -0
  55. package/components/theme-editor/components/designer-overlay.tsx +74 -0
  56. package/components/theme-editor/components/with-designer-features.tsx +142 -0
  57. package/components/theme-editor/dynamic-font-loader.tsx +79 -0
  58. package/components/theme-editor/hooks/use-designer-features.tsx +100 -0
  59. package/components/theme-editor/hooks/use-external-designer.tsx +95 -0
  60. package/components/theme-editor/hooks/use-native-widget-data.ts +188 -0
  61. package/components/theme-editor/hooks/use-visibility-context.ts +27 -0
  62. package/components/theme-editor/placeholder-registry.ts +31 -0
  63. package/components/theme-editor/sections/before-after-section.tsx +245 -0
  64. package/components/theme-editor/sections/contact-form-section.tsx +563 -0
  65. package/components/theme-editor/sections/countdown-campaign-banner-section.tsx +433 -0
  66. package/components/theme-editor/sections/coupon-banner-section.tsx +710 -0
  67. package/components/theme-editor/sections/divider-section.tsx +62 -0
  68. package/components/theme-editor/sections/featured-product-spotlight-section.tsx +507 -0
  69. package/components/theme-editor/sections/find-in-store-section.tsx +1995 -0
  70. package/components/theme-editor/sections/hover-showcase-section.tsx +326 -0
  71. package/components/theme-editor/sections/image-hotspot-section.tsx +142 -0
  72. package/components/theme-editor/sections/installment-options-section.tsx +1065 -0
  73. package/components/theme-editor/sections/notification-banner-section.tsx +173 -0
  74. package/components/theme-editor/sections/order-tracking-lookup-section.tsx +1379 -0
  75. package/components/theme-editor/sections/posts-slider-section.tsx +472 -0
  76. package/components/theme-editor/sections/pre-order-launch-banner-section.tsx +663 -0
  77. package/components/theme-editor/sections/section-renderer-registry.tsx +89 -0
  78. package/components/theme-editor/sections/section-wrapper.tsx +135 -0
  79. package/components/theme-editor/sections/shipping-threshold-progress-section.tsx +586 -0
  80. package/components/theme-editor/sections/stats-counter-section.tsx +486 -0
  81. package/components/theme-editor/sections/tabs-section.tsx +578 -0
  82. package/components/theme-editor/theme-block.tsx +102 -0
  83. package/components/theme-editor/theme-placeholder-client.tsx +218 -0
  84. package/components/theme-editor/theme-placeholder-wrapper.tsx +732 -0
  85. package/components/theme-editor/theme-placeholder.tsx +288 -0
  86. package/components/theme-editor/theme-section.tsx +1224 -0
  87. package/components/theme-editor/theme-settings-context.tsx +13 -0
  88. package/components/theme-editor/utils/index.ts +792 -0
  89. package/components/theme-editor/utils/iterator-utils.ts +234 -0
  90. package/components/theme-editor/utils/publish-window.ts +86 -0
  91. package/components/theme-editor/utils/visibility-rules.ts +188 -0
  92. package/data/client/account.ts +17 -2
  93. package/data/client/api.ts +2 -0
  94. package/data/client/basket.ts +66 -5
  95. package/data/client/checkout.ts +391 -99
  96. package/data/client/misc.ts +38 -2
  97. package/data/client/product.ts +19 -2
  98. package/data/client/user.ts +16 -8
  99. package/data/server/category.ts +11 -9
  100. package/data/server/flatpage.ts +11 -4
  101. package/data/server/form.ts +15 -4
  102. package/data/server/landingpage.ts +11 -4
  103. package/data/server/list.ts +5 -4
  104. package/data/server/menu.ts +11 -3
  105. package/data/server/product.ts +111 -55
  106. package/data/server/seo.ts +14 -4
  107. package/data/server/special-page.ts +5 -4
  108. package/data/server/widget.ts +90 -5
  109. package/data/urls.ts +16 -5
  110. package/hocs/client/with-segment-defaults.tsx +2 -2
  111. package/hocs/server/with-segment-defaults.tsx +65 -20
  112. package/hooks/index.ts +4 -0
  113. package/hooks/use-localization.ts +24 -10
  114. package/hooks/use-logger-context.tsx +114 -0
  115. package/hooks/use-logger.ts +92 -0
  116. package/hooks/use-loyalty-availability.ts +21 -0
  117. package/hooks/use-payment-options.ts +2 -1
  118. package/hooks/use-pz-params.ts +37 -0
  119. package/hooks/use-router.ts +51 -14
  120. package/hooks/use-sentry-uncaught-errors.ts +24 -0
  121. package/instrumentation/index.ts +10 -1
  122. package/instrumentation/node.ts +2 -20
  123. package/jest.config.js +25 -0
  124. package/lib/cache-handler.mjs +534 -16
  125. package/lib/cache.ts +272 -37
  126. package/localization/index.ts +2 -1
  127. package/localization/provider.tsx +2 -5
  128. package/middlewares/bfcache-headers.ts +18 -0
  129. package/middlewares/checkout-provider.ts +1 -1
  130. package/middlewares/complete-gpay.ts +32 -26
  131. package/middlewares/complete-masterpass.ts +33 -26
  132. package/middlewares/complete-wallet.ts +182 -0
  133. package/middlewares/default.ts +360 -215
  134. package/middlewares/index.ts +10 -2
  135. package/middlewares/locale.ts +34 -11
  136. package/middlewares/masterpass-rest-callback.ts +230 -0
  137. package/middlewares/oauth-login.ts +200 -57
  138. package/middlewares/pretty-url.ts +21 -8
  139. package/middlewares/redirection-payment.ts +32 -26
  140. package/middlewares/saved-card-redirection.ts +33 -26
  141. package/middlewares/three-d-redirection.ts +32 -26
  142. package/middlewares/url-redirection.ts +11 -1
  143. package/middlewares/wallet-complete-redirection.ts +206 -0
  144. package/package.json +25 -10
  145. package/plugins.d.ts +19 -4
  146. package/plugins.js +10 -1
  147. package/redux/actions.ts +47 -0
  148. package/redux/middlewares/checkout.ts +63 -138
  149. package/redux/middlewares/index.ts +14 -10
  150. package/redux/middlewares/pre-order/address.ts +7 -2
  151. package/redux/middlewares/pre-order/attribute-based-shipping-option.ts +7 -1
  152. package/redux/middlewares/pre-order/data-source-shipping-option.ts +7 -1
  153. package/redux/middlewares/pre-order/delivery-option.ts +7 -1
  154. package/redux/middlewares/pre-order/index.ts +16 -10
  155. package/redux/middlewares/pre-order/installment-option.ts +8 -1
  156. package/redux/middlewares/pre-order/payment-option-reset.ts +37 -0
  157. package/redux/middlewares/pre-order/payment-option.ts +7 -1
  158. package/redux/middlewares/pre-order/pre-order-validation.ts +8 -3
  159. package/redux/middlewares/pre-order/redirection.ts +8 -2
  160. package/redux/middlewares/pre-order/set-pre-order.ts +6 -2
  161. package/redux/middlewares/pre-order/shipping-option.ts +7 -1
  162. package/redux/middlewares/pre-order/shipping-step.ts +5 -1
  163. package/redux/reducers/checkout.ts +23 -3
  164. package/redux/reducers/index.ts +11 -3
  165. package/redux/reducers/root.ts +7 -2
  166. package/redux/reducers/widget.ts +80 -0
  167. package/sentry/index.ts +69 -13
  168. package/tailwind/content.js +16 -0
  169. package/types/commerce/account.ts +5 -1
  170. package/types/commerce/checkout.ts +35 -1
  171. package/types/commerce/widget.ts +33 -0
  172. package/types/index.ts +101 -6
  173. package/types/next-auth.d.ts +2 -2
  174. package/types/widget.ts +80 -0
  175. package/utils/app-fetch.ts +7 -2
  176. package/utils/generate-commerce-search-params.ts +3 -2
  177. package/utils/get-checkout-path.ts +3 -0
  178. package/utils/get-root-hostname.ts +28 -0
  179. package/utils/index.ts +64 -10
  180. package/utils/localization.ts +4 -0
  181. package/utils/mobile-3d-iframe.ts +8 -2
  182. package/utils/override-middleware.ts +7 -12
  183. package/utils/pz-segments.ts +92 -0
  184. package/utils/redirect-ignore.ts +35 -0
  185. package/utils/redirect.ts +9 -3
  186. package/utils/redirection-iframe.ts +8 -2
  187. package/utils/widget-styles.ts +107 -0
  188. package/views/error-page.tsx +93 -0
  189. package/with-pz-config.js +13 -6
@@ -1,7 +1,9 @@
1
1
  import {
2
2
  EmailSubscriptionType,
3
3
  MenuItemType,
4
- WidgetResultType
4
+ WidgetResultType,
5
+ WidgetSchemaType,
6
+ DynamicWidgetResultType
5
7
  } from '../../types';
6
8
  import { buildClientRequestUrl } from '../../utils';
7
9
  import { misc, widgets } from '../urls';
@@ -80,11 +82,20 @@ export const miscApi = api.injectEndpoints({
80
82
  };
81
83
  }
82
84
  }),
85
+ // change any type
83
86
  getWidget: builder.query<WidgetResultType<any>, string>({
84
87
  query: (slug: string) => ({
85
88
  url: buildClientRequestUrl(widgets.getWidget(slug))
86
89
  })
87
90
  }),
91
+ getWidgetSchema: builder.query<
92
+ WidgetSchemaType<DynamicWidgetResultType>,
93
+ string
94
+ >({
95
+ query: (widgetSlug: string) => ({
96
+ url: buildClientRequestUrl(widgets.getWidgetSchema(widgetSlug))
97
+ })
98
+ }),
88
99
  getMenu: builder.query<MenuItemType[], GetMenuParams>({
89
100
  query: ({ depth, parent }) => ({
90
101
  url: buildClientRequestUrl(misc.menus(depth, parent))
@@ -92,6 +103,29 @@ export const miscApi = api.injectEndpoints({
92
103
  transformResponse: (response: { menu: MenuItemType[] }) => {
93
104
  return response.menu;
94
105
  }
106
+ }),
107
+ getBukalemunImageUrl: builder.query<
108
+ any,
109
+ { current_chapter: string; sku: string; selected_attributes: any }
110
+ >({
111
+ query: ({ current_chapter, sku, selected_attributes }) => {
112
+ const data = {
113
+ ...selected_attributes,
114
+ current_chapter,
115
+ sku
116
+ };
117
+
118
+ const params = new URLSearchParams(data);
119
+
120
+ return {
121
+ url: buildClientRequestUrl(
122
+ misc.bukalemunImageUrl(params.toString()),
123
+ {
124
+ responseType: 'json'
125
+ }
126
+ )
127
+ };
128
+ }
95
129
  })
96
130
  }),
97
131
  overrideExisting: true
@@ -102,5 +136,7 @@ export const {
102
136
  useEmailSubscriptionMutation,
103
137
  useSetLanguageMutation,
104
138
  useGetWidgetQuery,
105
- useGetMenuQuery
139
+ useGetWidgetSchemaQuery,
140
+ useGetMenuQuery,
141
+ useGetBukalemunImageUrlQuery
106
142
  } = miscApi;
@@ -69,12 +69,28 @@ export const productApi = api.injectEndpoints({
69
69
  }),
70
70
  method: 'POST',
71
71
  body
72
- })
72
+ }),
73
+ invalidatesTags: ['MiniBasket']
73
74
  }),
74
75
  getInstallments: build.query<any, any>({
75
76
  query: (productPk) => ({
76
77
  url: buildClientRequestUrl(product.installments(productPk))
77
78
  })
79
+ }),
80
+ getBundleProductData: build.query<
81
+ any,
82
+ { productPk: string; queryString: string }
83
+ >({
84
+ query: ({ productPk, queryString }) => {
85
+ return {
86
+ url: buildClientRequestUrl(
87
+ product.bundleProduct(productPk, queryString),
88
+ {
89
+ responseType: 'json'
90
+ }
91
+ )
92
+ };
93
+ }
78
94
  })
79
95
  }),
80
96
  overrideExisting: true
@@ -85,5 +101,6 @@ export const {
85
101
  useGetProductByPkQuery,
86
102
  useGetRetailStoreStockMutation,
87
103
  useGetInstallmentsQuery,
88
- useGetProductByParamsQuery
104
+ useGetProductByParamsQuery,
105
+ useGetBundleProductDataQuery
89
106
  } = productApi;
@@ -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 }) => ({
@@ -1,4 +1,4 @@
1
- import { GetCategoryResponse } from '../../types';
1
+ import { GetCategoryResponse, SearchParams } from '../../types';
2
2
  import { generateCommerceSearchParams } from '../../utils';
3
3
  import appFetch, { FetchResponseType } from '../../utils/app-fetch';
4
4
  import { category, product } from '../urls';
@@ -12,7 +12,7 @@ function getCategoryDataHandler(
12
12
  pk: number,
13
13
  locale: string,
14
14
  currency: string,
15
- searchParams?: URLSearchParams,
15
+ searchParams?: SearchParams,
16
16
  headers?: Record<string, string>
17
17
  ) {
18
18
  return async function () {
@@ -48,8 +48,8 @@ function getCategoryDataHandler(
48
48
  logger.fatal('Error while parsing category data', {
49
49
  handler: 'getCategoryDataHandler',
50
50
  error,
51
- rawData: rawData.startsWith('<!DOCTYPE html>')
52
- ? `${rawData.substring(0, 50)}...`
51
+ rawData: rawData?.startsWith?.('<!DOCTYPE html>')
52
+ ? `${rawData?.substring(0, 50)}...`
53
53
  : rawData
54
54
  });
55
55
  }
@@ -90,7 +90,7 @@ export const getCategoryData = ({
90
90
  pk: number;
91
91
  locale?: string;
92
92
  currency?: string;
93
- searchParams?: URLSearchParams;
93
+ searchParams?: SearchParams;
94
94
  headers?: Record<string, string>;
95
95
  }) => {
96
96
  return Cache.wrap(
@@ -98,7 +98,8 @@ export const getCategoryData = ({
98
98
  locale,
99
99
  getCategoryDataHandler(pk, locale, currency, searchParams, headers),
100
100
  {
101
- expire: 300
101
+ expire: 300,
102
+ compressed: true
102
103
  }
103
104
  );
104
105
  };
@@ -138,8 +139,8 @@ function getCategoryBySlugDataHandler(
138
139
  logger.fatal('Error while parsing category data', {
139
140
  handler: 'getCategoryBySlugDataHandler',
140
141
  error,
141
- rawData: rawData.startsWith('<!DOCTYPE html>')
142
- ? `${rawData.substring(0, 50)}...`
142
+ rawData: rawData?.startsWith?.('<!DOCTYPE html>')
143
+ ? `${rawData?.substring(0, 50)}...`
143
144
  : rawData
144
145
  });
145
146
  }
@@ -158,7 +159,8 @@ export const getCategoryBySlugData = async ({
158
159
  locale,
159
160
  getCategoryBySlugDataHandler(slug, locale, currency),
160
161
  {
161
- expire: 300
162
+ expire: 300,
163
+ compressed: true
162
164
  }
163
165
  );
164
166
  };
@@ -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,20 @@ 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),
46
+ {
47
+ compressed: true
48
+ }
42
49
  );
43
50
  };
@@ -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,20 @@ 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),
47
+ {
48
+ compressed: true
49
+ }
39
50
  );
40
51
  };
@@ -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,20 @@ 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),
46
+ {
47
+ compressed: true
48
+ }
42
49
  );
43
50
  };
@@ -1,6 +1,6 @@
1
1
  import { Cache, CacheKey } from '../../lib/cache';
2
2
  import { category } from '../urls';
3
- import { GetCategoryResponse } from '../../types';
3
+ import { GetCategoryResponse, SearchParams } from '../../types';
4
4
  import { generateCommerceSearchParams } from '../../utils';
5
5
  import appFetch, { FetchResponseType } from '../../utils/app-fetch';
6
6
  import { parse } from 'lossless-json';
@@ -10,7 +10,7 @@ import { ServerVariables } from '../../utils/server-variables';
10
10
  const getListDataHandler = (
11
11
  locale,
12
12
  currency,
13
- searchParams: URLSearchParams,
13
+ searchParams: SearchParams,
14
14
  headers?: Record<string, string>
15
15
  ) => {
16
16
  return async function () {
@@ -63,7 +63,7 @@ export const getListData = async ({
63
63
  }: {
64
64
  locale?: string;
65
65
  currency?: string;
66
- searchParams: URLSearchParams;
66
+ searchParams: SearchParams;
67
67
  headers?: Record<string, string>;
68
68
  }) => {
69
69
  return Cache.wrap(
@@ -71,7 +71,8 @@ export const getListData = async ({
71
71
  locale,
72
72
  getListDataHandler(locale, currency, searchParams, headers),
73
73
  {
74
- expire: 300
74
+ expire: 300,
75
+ compressed: true
75
76
  }
76
77
  );
77
78
  };
@@ -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;
@@ -43,6 +48,9 @@ export const getMenu = async (params?: MenuHandlerParams) => {
43
48
  return Cache.wrap(
44
49
  CacheKey.Menu(params?.depth ?? DEFAULT_DEPTH, params?.parent),
45
50
  params?.locale ?? ServerVariables.locale,
46
- getMenuHandler(params)
51
+ getMenuHandler(params),
52
+ {
53
+ compressed: true
54
+ }
47
55
  );
48
56
  };
@@ -1,16 +1,17 @@
1
1
  import { Cache, CacheKey } from '../../lib/cache';
2
2
  import { product } from '../urls';
3
- import { ProductCategoryResult, ProductResult } from '../../types';
3
+ import { ProductCategoryResult, ProductResult, SearchParams } from '../../types';
4
4
  import appFetch from '../../utils/app-fetch';
5
5
  import { ServerVariables } from '../../utils/server-variables';
6
6
  import logger from '../../utils/log';
7
7
 
8
8
  type GetProduct = {
9
- pk: number;
9
+ pk: number | string;
10
10
  locale?: string;
11
11
  currency?: string;
12
- searchParams?: URLSearchParams;
12
+ searchParams?: SearchParams;
13
13
  groupProduct?: boolean;
14
+ headers?: Record<string, string>;
14
15
  };
15
16
 
16
17
  const getProductDataHandler = ({
@@ -18,75 +19,109 @@ 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 () {
26
+ // Convert pk to number if it's a string and validate
27
+ const numericPk = typeof pk === 'string' ? parseInt(pk, 10) : pk;
28
+
29
+ if (isNaN(numericPk)) {
30
+ logger.warn('Invalid product pk provided', {
31
+ handler: 'getProductDataHandler',
32
+ pk,
33
+ numericPk
34
+ });
35
+ return null;
36
+ }
37
+
24
38
  let url = groupProduct
25
- ? product.getGroupProductByPk(pk)
26
- : product.getProductByPk(pk);
39
+ ? product.getGroupProductByPk(numericPk)
40
+ : product.getProductByPk(numericPk);
27
41
 
28
42
  if (searchParams) {
29
43
  url +=
30
44
  '?' +
31
45
  Object.keys(searchParams)
32
- .map((key) => `${key}=${searchParams[key]}`)
46
+ .map((key) => `${key}=${encodeURIComponent(searchParams[key])}`)
33
47
  .join('&');
34
48
  }
35
49
 
36
- const data = await appFetch<ProductResult>({
37
- url,
38
- locale,
39
- currency,
40
- init: {
41
- headers: {
42
- Accept: 'application/json',
43
- 'Content-Type': 'application/json'
50
+ try {
51
+ const data = await appFetch<ProductResult>({
52
+ url,
53
+ locale,
54
+ currency,
55
+ init: {
56
+ headers: {
57
+ Accept: 'application/json',
58
+ 'Content-Type': 'application/json',
59
+ ...(headers ?? {})
60
+ }
44
61
  }
62
+ });
63
+
64
+ // If product data is not found, return null to trigger 404
65
+ if (!data?.product?.pk) {
66
+ logger.warn('Product not found', {
67
+ handler: 'getProductDataHandler',
68
+ pk: numericPk,
69
+ hasData: !!data,
70
+ hasProduct: !!data?.product
71
+ });
72
+ return null;
45
73
  }
46
- });
47
74
 
48
- const categoryUrl = product.categoryUrl(data.product.pk);
75
+ const categoryUrl = product.categoryUrl(data.product.pk);
49
76
 
50
- const productCategoryData = await appFetch<ProductCategoryResult>({
51
- url: categoryUrl,
52
- locale,
53
- currency,
54
- init: {
55
- headers: {
56
- Accept: 'application/json',
57
- 'Content-Type': 'application/json'
77
+ const productCategoryData = await appFetch<ProductCategoryResult>({
78
+ url: categoryUrl,
79
+ locale,
80
+ currency,
81
+ init: {
82
+ headers: {
83
+ Accept: 'application/json',
84
+ 'Content-Type': 'application/json'
85
+ }
58
86
  }
59
- }
60
- });
87
+ });
61
88
 
62
- const menuItemModel = productCategoryData?.results[0]?.menuitemmodel;
89
+ const menuItemModel = productCategoryData?.results[0]?.menuitemmodel;
63
90
 
64
- if (!menuItemModel) {
65
- logger.warn('menuItemModel is undefined, skipping breadcrumbData fetch', {
66
- handler: 'getProductDataHandler',
67
- pk
68
- });
69
- return { data, breadcrumbData: undefined };
70
- }
91
+ if (!menuItemModel) {
92
+ logger.warn('menuItemModel is undefined, skipping breadcrumbData fetch', {
93
+ handler: 'getProductDataHandler',
94
+ pk: numericPk
95
+ });
96
+ return { data, breadcrumbData: undefined };
97
+ }
71
98
 
72
- const breadcrumbUrl = product.breadcrumbUrl(menuItemModel);
99
+ const breadcrumbUrl = product.breadcrumbUrl(menuItemModel);
73
100
 
74
- const breadcrumbData = await appFetch<any>({
75
- url: breadcrumbUrl,
76
- locale,
77
- currency,
78
- init: {
79
- headers: {
80
- Accept: 'application/json',
81
- 'Content-Type': 'application/json'
101
+ const breadcrumbData = await appFetch<any>({
102
+ url: breadcrumbUrl,
103
+ locale,
104
+ currency,
105
+ init: {
106
+ headers: {
107
+ Accept: 'application/json',
108
+ 'Content-Type': 'application/json'
109
+ }
82
110
  }
83
- }
84
- });
111
+ });
85
112
 
86
- return {
87
- data,
88
- breadcrumbData: breadcrumbData?.menu
89
- };
113
+ return {
114
+ data,
115
+ breadcrumbData: breadcrumbData?.menu
116
+ };
117
+ } catch (error) {
118
+ logger.error('Error in getProductDataHandler', {
119
+ handler: 'getProductDataHandler',
120
+ pk: numericPk,
121
+ error: error.message
122
+ });
123
+ return null;
124
+ }
90
125
  };
91
126
  };
92
127
 
@@ -95,17 +130,38 @@ export const getProductData = async ({
95
130
  locale = ServerVariables.locale,
96
131
  currency = ServerVariables.currency,
97
132
  searchParams,
98
- groupProduct
133
+ groupProduct,
134
+ headers
99
135
  }: GetProduct) => {
100
- return Cache.wrap(
136
+ // Convert pk to number for cache key if it's a string
137
+ const numericPkForCache = typeof pk === 'string' ? parseInt(pk, 10) : pk;
138
+
139
+ const result = await Cache.wrap(
101
140
  CacheKey[groupProduct ? 'GroupProduct' : 'Product'](
102
- pk,
141
+ numericPkForCache,
103
142
  searchParams ?? new URLSearchParams()
104
143
  ),
105
144
  locale,
106
- getProductDataHandler({ pk, locale, currency, searchParams, groupProduct }),
145
+ getProductDataHandler({
146
+ pk,
147
+ locale,
148
+ currency,
149
+ searchParams,
150
+ groupProduct,
151
+ headers
152
+ }),
107
153
  {
108
- expire: 300
154
+ expire: 300,
155
+ compressed: true
109
156
  }
110
157
  );
158
+
159
+ // If product data is not found, throw 404 error
160
+ if (!result) {
161
+ const error = new Error('Product not found') as Error & { status: number };
162
+ error.status = 404;
163
+ throw error;
164
+ }
165
+
166
+ return result;
111
167
  };
@@ -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,15 @@ 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 }),
47
+ {
48
+ compressed: true
49
+ }
40
50
  );
41
51
  };