@akinon/next 2.0.0-beta.2 → 2.0.0-beta.21
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.
- package/.eslintrc.js +12 -0
- package/CHANGELOG.md +400 -7
- package/__tests__/next-config.test.ts +83 -0
- package/__tests__/tsconfig.json +23 -0
- package/api/auth.ts +381 -60
- package/api/barcode-search.ts +59 -0
- package/api/cache.ts +41 -5
- package/api/client.ts +21 -4
- package/api/form.ts +85 -0
- package/api/image-proxy.ts +75 -0
- package/api/product-categories.ts +53 -0
- package/api/similar-product-list.ts +63 -0
- package/api/similar-products.ts +111 -0
- package/api/virtual-try-on.ts +382 -0
- package/assets/styles/index.scss +84 -0
- package/babel.config.js +6 -0
- package/bin/pz-generate-routes.js +115 -0
- package/bin/pz-install-plugins.js +1 -1
- package/bin/pz-prebuild.js +1 -0
- package/bin/pz-predev.js +1 -0
- package/bin/pz-run-tests.js +99 -0
- package/bin/run-prebuild-tests.js +46 -0
- package/components/accordion.tsx +20 -5
- package/components/button.tsx +51 -36
- package/components/client-root.tsx +138 -2
- package/components/file-input.tsx +65 -3
- package/components/index.ts +1 -0
- package/components/input.tsx +1 -1
- package/components/link.tsx +46 -16
- package/components/logger-popup.tsx +213 -0
- package/components/modal.tsx +32 -16
- package/components/plugin-module.tsx +62 -3
- package/components/price.tsx +2 -2
- package/components/select.tsx +1 -1
- package/components/selected-payment-option-view.tsx +21 -0
- package/data/client/account.ts +17 -2
- package/data/client/api.ts +2 -0
- package/data/client/basket.ts +66 -5
- package/data/client/checkout.ts +391 -99
- package/data/client/misc.ts +38 -2
- package/data/client/product.ts +19 -2
- package/data/client/user.ts +16 -8
- package/data/server/category.ts +11 -9
- package/data/server/flatpage.ts +11 -4
- package/data/server/form.ts +15 -4
- package/data/server/landingpage.ts +11 -4
- package/data/server/list.ts +5 -4
- package/data/server/menu.ts +11 -3
- package/data/server/product.ts +111 -55
- package/data/server/seo.ts +14 -4
- package/data/server/special-page.ts +5 -4
- package/data/server/widget.ts +90 -5
- package/data/urls.ts +16 -5
- package/hocs/client/with-segment-defaults.tsx +2 -2
- package/hocs/server/with-segment-defaults.tsx +65 -20
- package/hooks/index.ts +4 -0
- package/hooks/use-localization.ts +24 -10
- package/hooks/use-logger-context.tsx +114 -0
- package/hooks/use-logger.ts +92 -0
- package/hooks/use-loyalty-availability.ts +21 -0
- package/hooks/use-payment-options.ts +2 -1
- package/hooks/use-pz-params.ts +37 -0
- package/hooks/use-router.ts +51 -14
- package/hooks/use-sentry-uncaught-errors.ts +24 -0
- package/instrumentation/index.ts +10 -1
- package/instrumentation/node.ts +2 -20
- package/jest.config.js +25 -0
- package/lib/cache-handler.mjs +534 -16
- package/lib/cache.ts +272 -37
- package/localization/index.ts +2 -1
- package/localization/provider.tsx +2 -5
- package/middlewares/bfcache-headers.ts +18 -0
- package/middlewares/checkout-provider.ts +1 -1
- package/middlewares/complete-gpay.ts +32 -26
- package/middlewares/complete-masterpass.ts +33 -26
- package/middlewares/complete-wallet.ts +182 -0
- package/middlewares/default.ts +360 -215
- package/middlewares/index.ts +10 -2
- package/middlewares/locale.ts +34 -11
- package/middlewares/masterpass-rest-callback.ts +230 -0
- package/middlewares/oauth-login.ts +200 -57
- package/middlewares/pretty-url.ts +21 -8
- package/middlewares/redirection-payment.ts +32 -26
- package/middlewares/saved-card-redirection.ts +33 -26
- package/middlewares/three-d-redirection.ts +32 -26
- package/middlewares/url-redirection.ts +11 -1
- package/middlewares/wallet-complete-redirection.ts +206 -0
- package/package.json +24 -9
- package/plugins.d.ts +19 -4
- package/plugins.js +10 -1
- package/redux/actions.ts +47 -0
- package/redux/middlewares/checkout.ts +63 -138
- package/redux/middlewares/index.ts +14 -10
- package/redux/middlewares/pre-order/address.ts +7 -2
- package/redux/middlewares/pre-order/attribute-based-shipping-option.ts +7 -1
- package/redux/middlewares/pre-order/data-source-shipping-option.ts +7 -1
- package/redux/middlewares/pre-order/delivery-option.ts +7 -1
- package/redux/middlewares/pre-order/index.ts +16 -10
- package/redux/middlewares/pre-order/installment-option.ts +8 -1
- package/redux/middlewares/pre-order/payment-option-reset.ts +37 -0
- package/redux/middlewares/pre-order/payment-option.ts +7 -1
- package/redux/middlewares/pre-order/pre-order-validation.ts +8 -3
- package/redux/middlewares/pre-order/redirection.ts +8 -2
- package/redux/middlewares/pre-order/set-pre-order.ts +6 -2
- package/redux/middlewares/pre-order/shipping-option.ts +7 -1
- package/redux/middlewares/pre-order/shipping-step.ts +5 -1
- package/redux/reducers/checkout.ts +23 -3
- package/redux/reducers/index.ts +11 -3
- package/redux/reducers/root.ts +7 -2
- package/redux/reducers/widget.ts +80 -0
- package/sentry/index.ts +69 -13
- package/tailwind/content.js +16 -0
- package/types/commerce/account.ts +5 -1
- package/types/commerce/checkout.ts +35 -1
- package/types/commerce/widget.ts +33 -0
- package/types/index.ts +114 -6
- package/types/next-auth.d.ts +2 -2
- package/types/widget.ts +80 -0
- package/utils/app-fetch.ts +7 -2
- package/utils/generate-commerce-search-params.ts +3 -2
- package/utils/get-checkout-path.ts +3 -0
- package/utils/get-root-hostname.ts +28 -0
- package/utils/index.ts +64 -10
- package/utils/localization.ts +4 -0
- package/utils/mobile-3d-iframe.ts +8 -2
- package/utils/override-middleware.ts +7 -12
- package/utils/pz-segments.ts +92 -0
- package/utils/redirect-ignore.ts +35 -0
- package/utils/redirect.ts +9 -3
- package/utils/redirection-iframe.ts +8 -2
- package/utils/widget-styles.ts +107 -0
- package/views/error-page.tsx +93 -0
- package/with-pz-config.js +21 -7
package/data/client/misc.ts
CHANGED
|
@@ -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
|
-
|
|
139
|
+
useGetWidgetSchemaQuery,
|
|
140
|
+
useGetMenuQuery,
|
|
141
|
+
useGetBukalemunImageUrlQuery
|
|
106
142
|
} = miscApi;
|
package/data/client/product.ts
CHANGED
|
@@ -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;
|
package/data/client/user.ts
CHANGED
|
@@ -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
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
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 }) => ({
|
package/data/server/category.ts
CHANGED
|
@@ -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?:
|
|
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
|
|
52
|
-
? `${rawData
|
|
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?:
|
|
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
|
|
142
|
-
? `${rawData
|
|
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
|
};
|
package/data/server/flatpage.ts
CHANGED
|
@@ -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
|
};
|
package/data/server/form.ts
CHANGED
|
@@ -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 = (
|
|
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
|
};
|
package/data/server/list.ts
CHANGED
|
@@ -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:
|
|
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:
|
|
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
|
};
|
package/data/server/menu.ts
CHANGED
|
@@ -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
|
};
|
package/data/server/product.ts
CHANGED
|
@@ -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?:
|
|
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(
|
|
26
|
-
: product.getProductByPk(
|
|
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
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
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
|
-
|
|
75
|
+
const categoryUrl = product.categoryUrl(data.product.pk);
|
|
49
76
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
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
|
-
|
|
89
|
+
const menuItemModel = productCategoryData?.results[0]?.menuitemmodel;
|
|
63
90
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
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
|
-
|
|
99
|
+
const breadcrumbUrl = product.breadcrumbUrl(menuItemModel);
|
|
73
100
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
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
|
-
|
|
87
|
-
|
|
88
|
-
|
|
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
|
-
|
|
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
|
-
|
|
141
|
+
numericPkForCache,
|
|
103
142
|
searchParams ?? new URLSearchParams()
|
|
104
143
|
),
|
|
105
144
|
locale,
|
|
106
|
-
getProductDataHandler({
|
|
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
|
};
|
package/data/server/seo.ts
CHANGED
|
@@ -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({
|
|
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
|
};
|