@akinon/next 1.44.0 → 1.45.0-rc.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.
- package/CHANGELOG.md +242 -0
- package/api/client.ts +33 -9
- package/assets/styles/index.css +49 -0
- package/assets/styles/index.css.map +1 -0
- package/assets/styles/index.scss +50 -26
- package/components/input.tsx +21 -7
- package/components/link.tsx +17 -13
- package/components/pagination.tsx +1 -2
- package/components/price.tsx +11 -4
- package/components/selected-payment-option-view.tsx +26 -38
- package/data/client/account.ts +10 -9
- package/data/client/address.ts +32 -8
- package/data/client/api.ts +1 -1
- package/data/client/basket.ts +6 -9
- package/data/client/checkout.ts +47 -4
- package/data/server/category.ts +2 -2
- package/data/server/list.ts +2 -2
- package/data/server/product.ts +15 -13
- package/data/server/special-page.ts +2 -2
- package/data/urls.ts +5 -1
- package/hooks/index.ts +2 -1
- package/hooks/use-message-listener.ts +24 -0
- package/hooks/use-payment-options.ts +2 -1
- package/lib/cache-handler.mjs +33 -0
- package/lib/cache.ts +18 -6
- package/middlewares/default.ts +50 -2
- package/middlewares/locale.ts +32 -30
- package/middlewares/pretty-url.ts +4 -0
- package/middlewares/url-redirection.ts +4 -0
- package/package.json +5 -4
- package/plugins.d.ts +1 -0
- package/redux/middlewares/checkout.ts +70 -11
- package/redux/reducers/checkout.ts +24 -5
- package/redux/reducers/config.ts +2 -0
- package/routes/pretty-url.tsx +194 -0
- package/types/commerce/account.ts +1 -0
- package/types/commerce/address.ts +1 -1
- package/types/commerce/checkout.ts +30 -0
- package/types/commerce/misc.ts +2 -0
- package/types/commerce/order.ts +12 -0
- package/types/index.ts +28 -2
- package/utils/app-fetch.ts +1 -1
- package/utils/generate-commerce-search-params.ts +6 -2
- package/utils/index.ts +27 -6
- package/utils/menu-generator.ts +2 -2
- package/utils/redirection-iframe.ts +85 -0
- package/utils/server-translation.ts +5 -1
- package/with-pz-config.js +11 -1
package/middlewares/locale.ts
CHANGED
|
@@ -5,22 +5,6 @@ import { LocaleUrlStrategy } from '../localization';
|
|
|
5
5
|
import { urlLocaleMatcherRegex } from '../utils';
|
|
6
6
|
import logger from '../utils/log';
|
|
7
7
|
|
|
8
|
-
const getMatchedLocale = (pathname: string) => {
|
|
9
|
-
let matchedLocale = pathname.match(urlLocaleMatcherRegex)?.[0] ?? '';
|
|
10
|
-
matchedLocale = matchedLocale.replace('/', '');
|
|
11
|
-
|
|
12
|
-
if (!matchedLocale.length) {
|
|
13
|
-
if (
|
|
14
|
-
settings.localization.localeUrlStrategy !==
|
|
15
|
-
LocaleUrlStrategy.ShowAllLocales
|
|
16
|
-
) {
|
|
17
|
-
matchedLocale = settings.localization.defaultLocaleValue;
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
return matchedLocale;
|
|
22
|
-
};
|
|
23
|
-
|
|
24
8
|
const withLocale =
|
|
25
9
|
(middleware: NextMiddleware) =>
|
|
26
10
|
async (req: PzNextRequest, event: NextFetchEvent) => {
|
|
@@ -28,12 +12,12 @@ const withLocale =
|
|
|
28
12
|
|
|
29
13
|
try {
|
|
30
14
|
const url = req.nextUrl.clone();
|
|
31
|
-
const
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
15
|
+
const {
|
|
16
|
+
locales,
|
|
17
|
+
localeUrlStrategy,
|
|
18
|
+
defaultLocaleValue,
|
|
19
|
+
redirectToDefaultLocale
|
|
20
|
+
} = settings.localization;
|
|
37
21
|
|
|
38
22
|
if (!defaultLocaleValue) {
|
|
39
23
|
logger.error('Default locale value is not defined in settings.', {
|
|
@@ -45,16 +29,34 @@ const withLocale =
|
|
|
45
29
|
}
|
|
46
30
|
|
|
47
31
|
if (
|
|
48
|
-
|
|
49
|
-
localeUrlStrategy === LocaleUrlStrategy.ShowAllLocales
|
|
50
|
-
redirectToDefaultLocale &&
|
|
51
|
-
req.method === 'GET'
|
|
32
|
+
locales.length === 1 &&
|
|
33
|
+
localeUrlStrategy === LocaleUrlStrategy.ShowAllLocales
|
|
52
34
|
) {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
}
|
|
35
|
+
const singleLocale = locales[0].value;
|
|
36
|
+
const pathParts = url.pathname.split('/').filter(Boolean);
|
|
56
37
|
|
|
57
|
-
|
|
38
|
+
if (pathParts[0] === singleLocale) {
|
|
39
|
+
url.pathname = '/' + pathParts.slice(1).join('/');
|
|
40
|
+
return NextResponse.redirect(url);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
req.middlewareParams.rewrites.locale = singleLocale;
|
|
44
|
+
} else {
|
|
45
|
+
const matchedLocale =
|
|
46
|
+
url.pathname.match(urlLocaleMatcherRegex)?.[0]?.replace('/', '') ||
|
|
47
|
+
'';
|
|
48
|
+
if (
|
|
49
|
+
!matchedLocale &&
|
|
50
|
+
localeUrlStrategy === LocaleUrlStrategy.ShowAllLocales &&
|
|
51
|
+
redirectToDefaultLocale &&
|
|
52
|
+
req.method === 'GET'
|
|
53
|
+
) {
|
|
54
|
+
url.pathname = `/${defaultLocaleValue}${url.pathname}`;
|
|
55
|
+
return NextResponse.redirect(url);
|
|
56
|
+
}
|
|
57
|
+
req.middlewareParams.rewrites.locale =
|
|
58
|
+
matchedLocale || defaultLocaleValue;
|
|
59
|
+
}
|
|
58
60
|
} catch (error) {
|
|
59
61
|
logger.error('withLocale error', {
|
|
60
62
|
error,
|
|
@@ -56,6 +56,10 @@ const resolvePrettyUrl = async (pathname: string, ip: string | null) => {
|
|
|
56
56
|
const withPrettyUrl =
|
|
57
57
|
(middleware: NextMiddleware) =>
|
|
58
58
|
async (req: PzNextRequest, event: NextFetchEvent) => {
|
|
59
|
+
if (Settings.usePrettyUrlRoute) {
|
|
60
|
+
return middleware(req, event);
|
|
61
|
+
}
|
|
62
|
+
|
|
59
63
|
const url = req.nextUrl.clone();
|
|
60
64
|
const matchedLanguagePrefix = url.pathname.match(
|
|
61
65
|
urlLocaleMatcherRegex
|
|
@@ -11,6 +11,10 @@ import { ROUTES } from 'routes';
|
|
|
11
11
|
const withUrlRedirection =
|
|
12
12
|
(middleware: NextMiddleware) =>
|
|
13
13
|
async (req: PzNextRequest, event: NextFetchEvent) => {
|
|
14
|
+
if (settings.usePrettyUrlRoute) {
|
|
15
|
+
return middleware(req, event);
|
|
16
|
+
}
|
|
17
|
+
|
|
14
18
|
const url = req.nextUrl.clone();
|
|
15
19
|
const ip = req.headers.get('x-forwarded-for') ?? '';
|
|
16
20
|
const pathnameWithoutLocale = url.pathname.replace(
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@akinon/next",
|
|
3
3
|
"description": "Core package for Project Zero Next",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.45.0-rc.0",
|
|
5
5
|
"private": false,
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"bin": {
|
|
@@ -20,21 +20,22 @@
|
|
|
20
20
|
"@opentelemetry/sdk-trace-node": "1.19.0",
|
|
21
21
|
"@opentelemetry/semantic-conventions": "1.19.0",
|
|
22
22
|
"@reduxjs/toolkit": "1.9.7",
|
|
23
|
+
"@neshca/cache-handler": "1.5.1",
|
|
23
24
|
"cross-spawn": "7.0.3",
|
|
24
25
|
"generic-pool": "3.9.0",
|
|
25
26
|
"react-redux": "8.1.3",
|
|
26
27
|
"react-string-replace": "1.1.1",
|
|
27
|
-
"redis": "4.
|
|
28
|
-
"semver": "7.
|
|
28
|
+
"redis": "4.6.13",
|
|
29
|
+
"semver": "7.6.2",
|
|
29
30
|
"set-cookie-parser": "2.6.0"
|
|
30
31
|
},
|
|
31
32
|
"devDependencies": {
|
|
33
|
+
"@akinon/eslint-plugin-projectzero": "1.45.0-rc.0",
|
|
32
34
|
"@types/react-redux": "7.1.30",
|
|
33
35
|
"@types/set-cookie-parser": "2.4.7",
|
|
34
36
|
"@typescript-eslint/eslint-plugin": "6.7.4",
|
|
35
37
|
"@typescript-eslint/parser": "6.7.4",
|
|
36
38
|
"eslint": "^8.14.0",
|
|
37
|
-
"@akinon/eslint-plugin-projectzero": "1.44.0",
|
|
38
39
|
"eslint-config-prettier": "8.5.0"
|
|
39
40
|
}
|
|
40
41
|
}
|
package/plugins.d.ts
CHANGED
|
@@ -12,6 +12,7 @@ declare module '@akinon/pz-masterpass/src/utils' {
|
|
|
12
12
|
declare module '@akinon/pz-masterpass/src/redux/reducer' {
|
|
13
13
|
export const setError: any;
|
|
14
14
|
export const setOtpModalVisible: any;
|
|
15
|
+
export const setCvcRequired: any;
|
|
15
16
|
}
|
|
16
17
|
|
|
17
18
|
declare module '@akinon/pz-otp' {
|
|
@@ -16,8 +16,10 @@ import {
|
|
|
16
16
|
setPreOrder,
|
|
17
17
|
setRetailStores,
|
|
18
18
|
setShippingOptions,
|
|
19
|
+
setDataSourceShippingOptions,
|
|
19
20
|
setShippingStepCompleted,
|
|
20
|
-
setCreditPaymentOptions
|
|
21
|
+
setCreditPaymentOptions,
|
|
22
|
+
setAttributeBasedShippingOptions
|
|
21
23
|
} from '../../redux/reducers/checkout';
|
|
22
24
|
import { RootState, TypedDispatch } from 'redux/store';
|
|
23
25
|
import { checkoutApi } from '../../data/client/checkout';
|
|
@@ -26,10 +28,11 @@ import { getCookie, setCookie } from '../../utils';
|
|
|
26
28
|
import settings from 'settings';
|
|
27
29
|
import { LocaleUrlStrategy } from '../../localization';
|
|
28
30
|
import { showMobile3dIframe } from '../../utils/mobile-3d-iframe';
|
|
31
|
+
import { showRedirectionIframe } from '../../utils/redirection-iframe';
|
|
29
32
|
|
|
30
33
|
interface CheckoutResult {
|
|
31
34
|
payload: {
|
|
32
|
-
errors?:
|
|
35
|
+
errors?: Record<string, string[]>;
|
|
33
36
|
pre_order?: PreOrder;
|
|
34
37
|
context_list?: CheckoutContext[];
|
|
35
38
|
};
|
|
@@ -73,8 +76,10 @@ export const preOrderMiddleware: Middleware = ({
|
|
|
73
76
|
deliveryOptions,
|
|
74
77
|
addressList: addresses,
|
|
75
78
|
shippingOptions,
|
|
79
|
+
dataSourceShippingOptions,
|
|
76
80
|
paymentOptions,
|
|
77
|
-
installmentOptions
|
|
81
|
+
installmentOptions,
|
|
82
|
+
attributeBasedShippingOptions
|
|
78
83
|
} = getState().checkout;
|
|
79
84
|
const { endpoints: apiEndpoints } = checkoutApi;
|
|
80
85
|
|
|
@@ -125,6 +130,40 @@ export const preOrderMiddleware: Middleware = ({
|
|
|
125
130
|
dispatch(apiEndpoints.setShippingOption.initiate(shippingOptions[0].pk));
|
|
126
131
|
}
|
|
127
132
|
|
|
133
|
+
if (
|
|
134
|
+
dataSourceShippingOptions.length > 0 &&
|
|
135
|
+
!preOrder.data_source_shipping_options
|
|
136
|
+
) {
|
|
137
|
+
const selectedDataSourceShippingOptionsPks =
|
|
138
|
+
dataSourceShippingOptions.map(
|
|
139
|
+
(opt) => opt.data_source_shipping_options[0].pk
|
|
140
|
+
);
|
|
141
|
+
|
|
142
|
+
dispatch(
|
|
143
|
+
apiEndpoints.setDataSourceShippingOptions.initiate(
|
|
144
|
+
selectedDataSourceShippingOptionsPks
|
|
145
|
+
)
|
|
146
|
+
);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
if (
|
|
150
|
+
Object.keys(attributeBasedShippingOptions).length > 0 &&
|
|
151
|
+
!preOrder.attribute_based_shipping_options
|
|
152
|
+
) {
|
|
153
|
+
const initialSelectedOptions: Record<string, number> = Object.fromEntries(
|
|
154
|
+
Object.entries(attributeBasedShippingOptions).map(([key, options]) => [
|
|
155
|
+
key,
|
|
156
|
+
options[0].pk
|
|
157
|
+
])
|
|
158
|
+
);
|
|
159
|
+
|
|
160
|
+
dispatch(
|
|
161
|
+
apiEndpoints.setAttributeBasedShippingOptions.initiate(
|
|
162
|
+
initialSelectedOptions
|
|
163
|
+
)
|
|
164
|
+
);
|
|
165
|
+
}
|
|
166
|
+
|
|
128
167
|
if (!preOrder.payment_option && paymentOptions.length > 0) {
|
|
129
168
|
dispatch(apiEndpoints.setPaymentOption.initiate(paymentOptions[0].pk));
|
|
130
169
|
}
|
|
@@ -163,6 +202,7 @@ export const contextListMiddleware: Middleware = ({
|
|
|
163
202
|
if (result?.payload?.context_list) {
|
|
164
203
|
result.payload.context_list.forEach((context) => {
|
|
165
204
|
const redirectUrl = context.page_context.redirect_url;
|
|
205
|
+
const isIframe = context.page_context.is_frame ?? false;
|
|
166
206
|
|
|
167
207
|
if (redirectUrl) {
|
|
168
208
|
const currentLocale = getCookie('pz-locale');
|
|
@@ -181,16 +221,19 @@ export const contextListMiddleware: Middleware = ({
|
|
|
181
221
|
}
|
|
182
222
|
|
|
183
223
|
const urlObj = new URL(url, window.location.origin);
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
/iPad|iPhone|iPod|Android/i.test(navigator.userAgent)) &&
|
|
224
|
+
const isMobileDevice =
|
|
225
|
+
isMobileApp ||
|
|
226
|
+
/iPad|iPhone|iPod|Android/i.test(navigator.userAgent);
|
|
227
|
+
const isIframePaymentOptionExcluded =
|
|
189
228
|
!settings.checkout?.iframeExcludedPaymentOptions?.includes(
|
|
190
229
|
result.payload?.pre_order?.payment_option?.slug
|
|
191
|
-
)
|
|
192
|
-
)
|
|
230
|
+
);
|
|
231
|
+
urlObj.searchParams.set('t', new Date().getTime().toString());
|
|
232
|
+
|
|
233
|
+
if (isMobileDevice && !isIframePaymentOptionExcluded) {
|
|
193
234
|
showMobile3dIframe(urlObj.toString());
|
|
235
|
+
} else if (isIframe && !isIframePaymentOptionExcluded) {
|
|
236
|
+
showRedirectionIframe(urlObj.toString());
|
|
194
237
|
} else {
|
|
195
238
|
window.location.href = urlObj.toString();
|
|
196
239
|
}
|
|
@@ -220,12 +263,28 @@ export const contextListMiddleware: Middleware = ({
|
|
|
220
263
|
dispatch(setShippingOptions(context.page_context.shipping_options));
|
|
221
264
|
}
|
|
222
265
|
|
|
266
|
+
if (context.page_context.data_sources) {
|
|
267
|
+
dispatch(
|
|
268
|
+
setDataSourceShippingOptions(context.page_context.data_sources)
|
|
269
|
+
);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
if (context.page_context.attribute_based_shipping_options) {
|
|
273
|
+
dispatch(
|
|
274
|
+
setAttributeBasedShippingOptions(
|
|
275
|
+
context.page_context.attribute_based_shipping_options
|
|
276
|
+
)
|
|
277
|
+
);
|
|
278
|
+
}
|
|
279
|
+
|
|
223
280
|
if (context.page_context.payment_options) {
|
|
224
281
|
dispatch(setPaymentOptions(context.page_context.payment_options));
|
|
225
282
|
}
|
|
226
283
|
|
|
227
284
|
if (context.page_context.credit_payment_options) {
|
|
228
|
-
dispatch(
|
|
285
|
+
dispatch(
|
|
286
|
+
setCreditPaymentOptions(context.page_context.credit_payment_options)
|
|
287
|
+
);
|
|
229
288
|
}
|
|
230
289
|
|
|
231
290
|
if (context.page_context.payment_choices) {
|
|
@@ -14,12 +14,13 @@ import {
|
|
|
14
14
|
CheckoutCreditPaymentOption,
|
|
15
15
|
PreOrder,
|
|
16
16
|
RetailStore,
|
|
17
|
-
ShippingOption
|
|
17
|
+
ShippingOption,
|
|
18
|
+
DataSource,
|
|
19
|
+
AttributeBasedShippingOption
|
|
18
20
|
} from '../../types';
|
|
19
21
|
|
|
20
22
|
export interface CheckoutState {
|
|
21
|
-
|
|
22
|
-
errors: any;
|
|
23
|
+
errors: Record<string, string[]>;
|
|
23
24
|
hasGiftBox: boolean;
|
|
24
25
|
canGuestPurchase: boolean;
|
|
25
26
|
steps: {
|
|
@@ -37,6 +38,7 @@ export interface CheckoutState {
|
|
|
37
38
|
addressList: Address[];
|
|
38
39
|
deliveryOptions: DeliveryOption[];
|
|
39
40
|
shippingOptions: ShippingOption[];
|
|
41
|
+
dataSourceShippingOptions: DataSource[];
|
|
40
42
|
paymentOptions: PaymentOption[];
|
|
41
43
|
creditPaymentOptions: CheckoutCreditPaymentOption[];
|
|
42
44
|
selectedCreditPaymentPk: number;
|
|
@@ -47,6 +49,8 @@ export interface CheckoutState {
|
|
|
47
49
|
selectedBankAccountPk: number;
|
|
48
50
|
loyaltyBalance?: string;
|
|
49
51
|
retailStores: RetailStore[];
|
|
52
|
+
attributeBasedShippingOptions: AttributeBasedShippingOption[];
|
|
53
|
+
selectedShippingOptions: Record<string, number>;
|
|
50
54
|
}
|
|
51
55
|
|
|
52
56
|
const initialState: CheckoutState = {
|
|
@@ -68,6 +72,7 @@ const initialState: CheckoutState = {
|
|
|
68
72
|
addressList: [],
|
|
69
73
|
deliveryOptions: [],
|
|
70
74
|
shippingOptions: [],
|
|
75
|
+
dataSourceShippingOptions: [],
|
|
71
76
|
paymentOptions: [],
|
|
72
77
|
creditPaymentOptions: [],
|
|
73
78
|
selectedCreditPaymentPk: null,
|
|
@@ -76,7 +81,9 @@ const initialState: CheckoutState = {
|
|
|
76
81
|
installmentOptions: [],
|
|
77
82
|
bankAccounts: [],
|
|
78
83
|
selectedBankAccountPk: null,
|
|
79
|
-
retailStores: []
|
|
84
|
+
retailStores: [],
|
|
85
|
+
attributeBasedShippingOptions: [],
|
|
86
|
+
selectedShippingOptions: {}
|
|
80
87
|
};
|
|
81
88
|
|
|
82
89
|
const checkoutSlice = createSlice({
|
|
@@ -122,6 +129,9 @@ const checkoutSlice = createSlice({
|
|
|
122
129
|
setShippingOptions(state, { payload }) {
|
|
123
130
|
state.shippingOptions = payload;
|
|
124
131
|
},
|
|
132
|
+
setDataSourceShippingOptions(state, { payload }) {
|
|
133
|
+
state.dataSourceShippingOptions = payload;
|
|
134
|
+
},
|
|
125
135
|
setPaymentOptions(state, { payload }) {
|
|
126
136
|
state.paymentOptions = payload;
|
|
127
137
|
},
|
|
@@ -151,6 +161,12 @@ const checkoutSlice = createSlice({
|
|
|
151
161
|
},
|
|
152
162
|
setRetailStores(state, { payload }) {
|
|
153
163
|
state.retailStores = payload;
|
|
164
|
+
},
|
|
165
|
+
setAttributeBasedShippingOptions(state, { payload }) {
|
|
166
|
+
state.attributeBasedShippingOptions = payload;
|
|
167
|
+
},
|
|
168
|
+
setSelectedShippingOptions: (state, { payload }) => {
|
|
169
|
+
state.selectedShippingOptions = payload;
|
|
154
170
|
}
|
|
155
171
|
}
|
|
156
172
|
});
|
|
@@ -169,6 +185,7 @@ export const {
|
|
|
169
185
|
setAddressList,
|
|
170
186
|
setDeliveryOptions,
|
|
171
187
|
setShippingOptions,
|
|
188
|
+
setDataSourceShippingOptions,
|
|
172
189
|
setPaymentOptions,
|
|
173
190
|
setCreditPaymentOptions,
|
|
174
191
|
setSelectedCreditPaymentPk,
|
|
@@ -178,7 +195,9 @@ export const {
|
|
|
178
195
|
setBankAccounts,
|
|
179
196
|
setSelectedBankAccountPk,
|
|
180
197
|
setLoyaltyBalance,
|
|
181
|
-
setRetailStores
|
|
198
|
+
setRetailStores,
|
|
199
|
+
setAttributeBasedShippingOptions,
|
|
200
|
+
setSelectedShippingOptions
|
|
182
201
|
} = checkoutSlice.actions;
|
|
183
202
|
|
|
184
203
|
export default checkoutSlice.reducer;
|
package/redux/reducers/config.ts
CHANGED
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import { URLS } from '@akinon/next/data/urls';
|
|
2
|
+
import { Metadata, PageProps } from '@akinon/next/types';
|
|
3
|
+
import logger from '@akinon/next/utils/log';
|
|
4
|
+
import { notFound } from 'next/navigation';
|
|
5
|
+
|
|
6
|
+
type PrettyUrlResult = {
|
|
7
|
+
matched: boolean;
|
|
8
|
+
path?: string;
|
|
9
|
+
pk?: number;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
const resolvePrettyUrlHandler =
|
|
13
|
+
(pathname: string, ip: string | null) => async () => {
|
|
14
|
+
let results = [] as { old_path: string }[];
|
|
15
|
+
let prettyUrlResult: PrettyUrlResult = {
|
|
16
|
+
matched: false
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
try {
|
|
20
|
+
const requestUrl = URLS.misc.prettyUrls(`/${pathname}/`);
|
|
21
|
+
|
|
22
|
+
logger.debug(`Resolving pretty url`, { pathname, requestUrl, ip });
|
|
23
|
+
|
|
24
|
+
const start = Date.now();
|
|
25
|
+
const apiResponse = await fetch(requestUrl, {
|
|
26
|
+
next: {
|
|
27
|
+
revalidate: 0
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
const data = await apiResponse.json();
|
|
31
|
+
({ results } = data);
|
|
32
|
+
const end = Date.now();
|
|
33
|
+
console.warn('Pretty url response time', end - start, requestUrl);
|
|
34
|
+
|
|
35
|
+
const matched = results.length > 0;
|
|
36
|
+
const [{ old_path: path } = { old_path: '' }] = results;
|
|
37
|
+
let pk;
|
|
38
|
+
|
|
39
|
+
if (matched) {
|
|
40
|
+
const pkRegex = /\/(\d+)\/$/;
|
|
41
|
+
const match = path.match(pkRegex);
|
|
42
|
+
pk = match ? parseInt(match[1]) : undefined;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
prettyUrlResult = {
|
|
46
|
+
matched,
|
|
47
|
+
path,
|
|
48
|
+
pk
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
logger.trace('Pretty url result', { prettyUrlResult, ip });
|
|
52
|
+
} catch (error) {
|
|
53
|
+
logger.error('Error resolving pretty url', { error, pathname, ip });
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return prettyUrlResult;
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
export async function generateMetadata({ params }: PageProps) {
|
|
60
|
+
let result: Metadata = {};
|
|
61
|
+
const { prettyurl } = params;
|
|
62
|
+
const pageSlug = prettyurl
|
|
63
|
+
.filter((x) => !x.startsWith('searchparams'))
|
|
64
|
+
.join('/');
|
|
65
|
+
|
|
66
|
+
const searchParams = Object.fromEntries(
|
|
67
|
+
new URLSearchParams(
|
|
68
|
+
decodeURIComponent(
|
|
69
|
+
prettyurl
|
|
70
|
+
.find((x) => x.startsWith('searchparams'))
|
|
71
|
+
?.replace('searchparams%7C', '')
|
|
72
|
+
) ?? {}
|
|
73
|
+
).entries()
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
const prettyUrlResult = await resolvePrettyUrlHandler(pageSlug, null)();
|
|
77
|
+
|
|
78
|
+
if (!prettyUrlResult.matched) {
|
|
79
|
+
return notFound();
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const commonProps = {
|
|
83
|
+
params: {
|
|
84
|
+
...params,
|
|
85
|
+
pk: prettyUrlResult.pk
|
|
86
|
+
},
|
|
87
|
+
searchParams
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
try {
|
|
91
|
+
if (prettyUrlResult.path.startsWith('/product/')) {
|
|
92
|
+
await import('@product/[pk]/page').then(async (module) => {
|
|
93
|
+
result = await module['generateMetadata']?.(commonProps);
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if (prettyUrlResult.path.startsWith('/group-product/')) {
|
|
98
|
+
await import('@group-product/[pk]/page').then(async (module) => {
|
|
99
|
+
result = await module['generateMetadata']?.(commonProps);
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (prettyUrlResult.path.startsWith('/category/')) {
|
|
104
|
+
await import('@category/[pk]/page').then(async (module) => {
|
|
105
|
+
result = await module['generateMetadata']?.(commonProps);
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (prettyUrlResult.path.startsWith('/special-page/')) {
|
|
110
|
+
await import('@special-page/[pk]/page').then(async (module) => {
|
|
111
|
+
result = await module['generateMetadata']?.(commonProps);
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (prettyUrlResult.path.startsWith('/flat-page/')) {
|
|
116
|
+
await import('@flat-page/[pk]/page').then(async (module) => {
|
|
117
|
+
result = await module['generateMetadata']?.(commonProps);
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
// eslint-disable-next-line no-empty
|
|
121
|
+
} catch (error) {}
|
|
122
|
+
|
|
123
|
+
return result;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export const dynamic = 'force-static';
|
|
127
|
+
export const revalidate = 300;
|
|
128
|
+
|
|
129
|
+
export default async function Page({ params }) {
|
|
130
|
+
const { prettyurl } = params;
|
|
131
|
+
const pageSlug = prettyurl
|
|
132
|
+
.filter((x) => !x.startsWith('searchparams'))
|
|
133
|
+
.join('/');
|
|
134
|
+
|
|
135
|
+
const urlSearchParams = new URLSearchParams(
|
|
136
|
+
decodeURIComponent(
|
|
137
|
+
prettyurl
|
|
138
|
+
.find((x) => x.startsWith('searchparams'))
|
|
139
|
+
?.replace('searchparams%7C', '')
|
|
140
|
+
) ?? {}
|
|
141
|
+
);
|
|
142
|
+
|
|
143
|
+
const searchParams = {};
|
|
144
|
+
|
|
145
|
+
for (const [key, value] of urlSearchParams.entries() as unknown as Array<
|
|
146
|
+
[string, string]
|
|
147
|
+
>) {
|
|
148
|
+
if (!searchParams[key]) {
|
|
149
|
+
searchParams[key] = [];
|
|
150
|
+
}
|
|
151
|
+
searchParams[key].push(value);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const result = await resolvePrettyUrlHandler(pageSlug, null)();
|
|
155
|
+
|
|
156
|
+
if (!result.matched) {
|
|
157
|
+
return notFound();
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const commonProps = {
|
|
161
|
+
params: {
|
|
162
|
+
...params,
|
|
163
|
+
pk: result.pk
|
|
164
|
+
},
|
|
165
|
+
searchParams
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
if (result.path.startsWith('/category/')) {
|
|
169
|
+
const CategoryPage = (await import('@category/[pk]/page')).default;
|
|
170
|
+
return <CategoryPage {...commonProps} />;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
if (result.path.startsWith('/product/')) {
|
|
174
|
+
const ProductPage = (await import('@product/[pk]/page')).default;
|
|
175
|
+
return <ProductPage {...commonProps} />;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
if (result.path.startsWith('/group-product/')) {
|
|
179
|
+
const GroupProduct = (await import('@group-product/[pk]/page')).default;
|
|
180
|
+
return <GroupProduct {...commonProps} />;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
if (result.path.startsWith('/special-page/')) {
|
|
184
|
+
const SpecialPage = (await import('@special-page/[pk]/page')).default;
|
|
185
|
+
return <SpecialPage {...commonProps} />;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
if (result.path.startsWith('/flat-page/')) {
|
|
189
|
+
const FlatPage = (await import('@flat-page/[pk]/page')).default;
|
|
190
|
+
return <FlatPage {...commonProps} />;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
return null;
|
|
194
|
+
}
|
|
@@ -33,6 +33,23 @@ export interface ShippingOption {
|
|
|
33
33
|
slug: string;
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
+
export interface DataSource {
|
|
37
|
+
pk: number;
|
|
38
|
+
name: string;
|
|
39
|
+
data_source_shipping_options: DataSourceShippingOption[];
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export interface DataSourceShippingOption {
|
|
43
|
+
pk: number;
|
|
44
|
+
shipping_amount: string;
|
|
45
|
+
shipping_option_name: string;
|
|
46
|
+
shipping_option_logo: string | null;
|
|
47
|
+
data_source: {
|
|
48
|
+
pk: number;
|
|
49
|
+
title: string | null;
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
|
|
36
53
|
export interface CheckoutAddressType {
|
|
37
54
|
label: string;
|
|
38
55
|
text: string;
|
|
@@ -78,6 +95,8 @@ export interface PreOrder {
|
|
|
78
95
|
retail_store?: RetailStore;
|
|
79
96
|
gift_box?: GiftBox;
|
|
80
97
|
credit_payment_option?: CheckoutCreditPaymentOption;
|
|
98
|
+
data_source_shipping_options: any;
|
|
99
|
+
attribute_based_shipping_options?: AttributeBasedShippingOption[];
|
|
81
100
|
}
|
|
82
101
|
|
|
83
102
|
export interface GuestLoginFormParams {
|
|
@@ -117,6 +136,7 @@ export interface CheckoutContext {
|
|
|
117
136
|
redirect_url?: string;
|
|
118
137
|
context_data?: any;
|
|
119
138
|
balance?: string;
|
|
139
|
+
attribute_based_shipping_options?: AttributeBasedShippingOption[];
|
|
120
140
|
[key: string]: any;
|
|
121
141
|
};
|
|
122
142
|
}
|
|
@@ -142,3 +162,13 @@ export interface BankAccount {
|
|
|
142
162
|
pk: number;
|
|
143
163
|
sort_order: number;
|
|
144
164
|
}
|
|
165
|
+
|
|
166
|
+
export interface AttributeBasedShippingOption {
|
|
167
|
+
pk: number;
|
|
168
|
+
shipping_amount: string | null;
|
|
169
|
+
shipping_option_name: string | null;
|
|
170
|
+
shipping_option_logo: string | null;
|
|
171
|
+
attribute_value: string | null;
|
|
172
|
+
attribute_key: string;
|
|
173
|
+
[key: string]: any;
|
|
174
|
+
}
|
package/types/commerce/misc.ts
CHANGED