@akinon/next 1.41.0 → 1.42.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 +25 -0
- package/api/client.ts +18 -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 +20 -7
- package/components/link.tsx +17 -13
- package/components/price.tsx +10 -4
- package/components/selected-payment-option-view.tsx +26 -38
- package/data/client/account.ts +10 -9
- package/data/client/checkout.ts +26 -3
- package/data/server/category.ts +2 -2
- package/data/server/list.ts +2 -2
- package/data/server/product.ts +2 -5
- package/data/server/special-page.ts +2 -2
- package/data/urls.ts +2 -0
- package/hocs/server/with-segment-defaults.tsx +2 -2
- 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 +9 -0
- package/middlewares/pretty-url.ts +4 -0
- package/package.json +5 -4
- package/plugins.d.ts +1 -0
- package/redux/middlewares/checkout.ts +40 -9
- package/redux/reducers/checkout.ts +9 -3
- 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 +18 -0
- package/types/commerce/misc.ts +2 -0
- package/types/commerce/order.ts +7 -0
- package/types/index.ts +9 -1
- package/utils/app-fetch.ts +1 -1
- package/utils/generate-commerce-search-params.ts +6 -2
- package/utils/index.ts +6 -0
- package/utils/redirection-iframe.ts +85 -0
- package/utils/server-translation.ts +5 -1
- package/with-pz-config.js +11 -1
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { useEffect } from 'react';
|
|
2
|
+
|
|
3
|
+
export const useMessageListener = () => {
|
|
4
|
+
useEffect(() => {
|
|
5
|
+
const handleMessage = (event: MessageEvent) => {
|
|
6
|
+
if (event.origin !== window.location.origin) {
|
|
7
|
+
return;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
if (event.data && typeof event.data === 'string') {
|
|
11
|
+
const messageData = JSON.parse(event.data);
|
|
12
|
+
if (messageData?.url) {
|
|
13
|
+
window.location.href = messageData.url;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
window.addEventListener('message', handleMessage);
|
|
19
|
+
|
|
20
|
+
return () => {
|
|
21
|
+
window.removeEventListener('message', handleMessage);
|
|
22
|
+
};
|
|
23
|
+
}, []);
|
|
24
|
+
};
|
|
@@ -18,7 +18,8 @@ export const usePaymentOptions = () => {
|
|
|
18
18
|
pay_on_delivery: 'pz-pay-on-delivery',
|
|
19
19
|
bkm_express: 'pz-bkm',
|
|
20
20
|
credit_payment: 'pz-credit-payment',
|
|
21
|
-
masterpass: 'pz-masterpass'
|
|
21
|
+
masterpass: 'pz-masterpass',
|
|
22
|
+
gpay: 'pz-gpay'
|
|
22
23
|
};
|
|
23
24
|
|
|
24
25
|
const isInitialTypeIncluded = (type: string) => initialTypes.has(type);
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { CacheHandler } from '@neshca/cache-handler';
|
|
2
|
+
import createLruHandler from '@neshca/cache-handler/local-lru';
|
|
3
|
+
import createRedisHandler from '@neshca/cache-handler/redis-stack';
|
|
4
|
+
import { createClient } from 'redis';
|
|
5
|
+
|
|
6
|
+
CacheHandler.onCreation(async () => {
|
|
7
|
+
const redisUrl = `redis://${process.env.CACHE_HOST}:${
|
|
8
|
+
process.env.CACHE_PORT
|
|
9
|
+
}/${process.env.CACHE_BUCKET ?? '0'}`;
|
|
10
|
+
|
|
11
|
+
const client = createClient({
|
|
12
|
+
url: redisUrl
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
client.on('error', (error) => {
|
|
16
|
+
console.error('Redis client error', { redisUrl, error });
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
await client.connect();
|
|
20
|
+
|
|
21
|
+
const redisHandler = await createRedisHandler({
|
|
22
|
+
client,
|
|
23
|
+
timeoutMs: 5000
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
const localHandler = createLruHandler();
|
|
27
|
+
|
|
28
|
+
return {
|
|
29
|
+
handlers: [redisHandler, localHandler]
|
|
30
|
+
};
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
export default CacheHandler;
|
package/lib/cache.ts
CHANGED
|
@@ -20,13 +20,16 @@ const hashCacheKey = (object?: Record<string, string>) => {
|
|
|
20
20
|
return `_${encodeURIComponent(cacheKey)}`;
|
|
21
21
|
};
|
|
22
22
|
export const CacheKey = {
|
|
23
|
-
List: (
|
|
23
|
+
List: (
|
|
24
|
+
searchParams: { [key: string]: string | string[] | undefined },
|
|
25
|
+
headers?: Record<string, string>
|
|
26
|
+
) =>
|
|
24
27
|
`list_${encodeURIComponent(JSON.stringify(searchParams))}${hashCacheKey(
|
|
25
28
|
headers
|
|
26
29
|
)}`,
|
|
27
30
|
Category: (
|
|
28
31
|
pk: number,
|
|
29
|
-
searchParams?:
|
|
32
|
+
searchParams?: { [key: string]: string | string[] | undefined },
|
|
30
33
|
headers?: Record<string, string>
|
|
31
34
|
) =>
|
|
32
35
|
`category_${pk}_${encodeURIComponent(
|
|
@@ -35,15 +38,20 @@ export const CacheKey = {
|
|
|
35
38
|
CategorySlug: (slug: string) => `category_${slug}`,
|
|
36
39
|
SpecialPage: (
|
|
37
40
|
pk: number,
|
|
38
|
-
searchParams:
|
|
41
|
+
searchParams: { [key: string]: string | string[] | undefined },
|
|
39
42
|
headers?: Record<string, string>
|
|
40
43
|
) =>
|
|
41
44
|
`special_page_${pk}_${encodeURIComponent(
|
|
42
45
|
JSON.stringify(searchParams)
|
|
43
46
|
)}${hashCacheKey(headers)}`,
|
|
44
|
-
Product: (
|
|
45
|
-
|
|
46
|
-
|
|
47
|
+
Product: (
|
|
48
|
+
pk: number,
|
|
49
|
+
searchParams: { [key: string]: string | string[] | undefined }
|
|
50
|
+
) => `product_${pk}_${encodeURIComponent(JSON.stringify(searchParams))}`,
|
|
51
|
+
GroupProduct: (
|
|
52
|
+
pk: number,
|
|
53
|
+
searchParams: { [key: string]: string | string[] | undefined }
|
|
54
|
+
) =>
|
|
47
55
|
`group_product_${pk}_${encodeURIComponent(JSON.stringify(searchParams))}`,
|
|
48
56
|
FlatPage: (pk: number) => `flat_page_${pk}`,
|
|
49
57
|
LandingPage: (pk: number) => `landing_page_${pk}`,
|
|
@@ -158,6 +166,10 @@ export class Cache {
|
|
|
158
166
|
handler: () => Promise<T>,
|
|
159
167
|
options?: CacheOptions
|
|
160
168
|
): Promise<T> {
|
|
169
|
+
if (Settings.usePrettyUrlRoute) {
|
|
170
|
+
return await handler();
|
|
171
|
+
}
|
|
172
|
+
|
|
161
173
|
const requiredVariables = [
|
|
162
174
|
process.env.CACHE_HOST,
|
|
163
175
|
process.env.CACHE_PORT,
|
package/middlewares/default.ts
CHANGED
|
@@ -203,6 +203,15 @@ const withPzDefault =
|
|
|
203
203
|
);
|
|
204
204
|
}
|
|
205
205
|
|
|
206
|
+
if (
|
|
207
|
+
Settings.usePrettyUrlRoute &&
|
|
208
|
+
url.searchParams.toString().length > 0
|
|
209
|
+
) {
|
|
210
|
+
url.pathname =
|
|
211
|
+
url.pathname +
|
|
212
|
+
`searchparams|${url.searchParams.toString()}`;
|
|
213
|
+
}
|
|
214
|
+
|
|
206
215
|
Settings.rewrites.forEach((rewrite) => {
|
|
207
216
|
url.pathname = url.pathname.replace(
|
|
208
217
|
rewrite.source,
|
|
@@ -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
|
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.42.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.0.7",
|
|
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.42.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.41.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,6 +16,7 @@ import {
|
|
|
16
16
|
setPreOrder,
|
|
17
17
|
setRetailStores,
|
|
18
18
|
setShippingOptions,
|
|
19
|
+
setDataSourceShippingOptions,
|
|
19
20
|
setShippingStepCompleted,
|
|
20
21
|
setCreditPaymentOptions
|
|
21
22
|
} from '../../redux/reducers/checkout';
|
|
@@ -26,10 +27,11 @@ import { getCookie, setCookie } from '../../utils';
|
|
|
26
27
|
import settings from 'settings';
|
|
27
28
|
import { LocaleUrlStrategy } from '../../localization';
|
|
28
29
|
import { showMobile3dIframe } from '../../utils/mobile-3d-iframe';
|
|
30
|
+
import { showRedirectionIframe } from '../../utils/redirection-iframe';
|
|
29
31
|
|
|
30
32
|
interface CheckoutResult {
|
|
31
33
|
payload: {
|
|
32
|
-
errors?:
|
|
34
|
+
errors?: Record<string, string[]>;
|
|
33
35
|
pre_order?: PreOrder;
|
|
34
36
|
context_list?: CheckoutContext[];
|
|
35
37
|
};
|
|
@@ -73,6 +75,7 @@ export const preOrderMiddleware: Middleware = ({
|
|
|
73
75
|
deliveryOptions,
|
|
74
76
|
addressList: addresses,
|
|
75
77
|
shippingOptions,
|
|
78
|
+
dataSourceShippingOptions,
|
|
76
79
|
paymentOptions,
|
|
77
80
|
installmentOptions
|
|
78
81
|
} = getState().checkout;
|
|
@@ -125,6 +128,22 @@ export const preOrderMiddleware: Middleware = ({
|
|
|
125
128
|
dispatch(apiEndpoints.setShippingOption.initiate(shippingOptions[0].pk));
|
|
126
129
|
}
|
|
127
130
|
|
|
131
|
+
if (
|
|
132
|
+
dataSourceShippingOptions.length > 0 &&
|
|
133
|
+
!preOrder.data_source_shipping_options
|
|
134
|
+
) {
|
|
135
|
+
const selectedDataSourceShippingOptionsPks =
|
|
136
|
+
dataSourceShippingOptions.map(
|
|
137
|
+
(opt) => opt.data_source_shipping_options[0].pk
|
|
138
|
+
);
|
|
139
|
+
|
|
140
|
+
dispatch(
|
|
141
|
+
apiEndpoints.setDataSourceShippingOptions.initiate(
|
|
142
|
+
selectedDataSourceShippingOptionsPks
|
|
143
|
+
)
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
|
|
128
147
|
if (!preOrder.payment_option && paymentOptions.length > 0) {
|
|
129
148
|
dispatch(apiEndpoints.setPaymentOption.initiate(paymentOptions[0].pk));
|
|
130
149
|
}
|
|
@@ -163,6 +182,7 @@ export const contextListMiddleware: Middleware = ({
|
|
|
163
182
|
if (result?.payload?.context_list) {
|
|
164
183
|
result.payload.context_list.forEach((context) => {
|
|
165
184
|
const redirectUrl = context.page_context.redirect_url;
|
|
185
|
+
const isIframe = context.page_context.is_frame ?? false;
|
|
166
186
|
|
|
167
187
|
if (redirectUrl) {
|
|
168
188
|
const currentLocale = getCookie('pz-locale');
|
|
@@ -181,16 +201,19 @@ export const contextListMiddleware: Middleware = ({
|
|
|
181
201
|
}
|
|
182
202
|
|
|
183
203
|
const urlObj = new URL(url, window.location.origin);
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
/iPad|iPhone|iPod|Android/i.test(navigator.userAgent)) &&
|
|
204
|
+
const isMobileDevice =
|
|
205
|
+
isMobileApp ||
|
|
206
|
+
/iPad|iPhone|iPod|Android/i.test(navigator.userAgent);
|
|
207
|
+
const isIframePaymentOptionExcluded =
|
|
189
208
|
!settings.checkout?.iframeExcludedPaymentOptions?.includes(
|
|
190
209
|
result.payload?.pre_order?.payment_option?.slug
|
|
191
|
-
)
|
|
192
|
-
)
|
|
210
|
+
);
|
|
211
|
+
urlObj.searchParams.set('t', new Date().getTime().toString());
|
|
212
|
+
|
|
213
|
+
if (isMobileDevice && !isIframePaymentOptionExcluded) {
|
|
193
214
|
showMobile3dIframe(urlObj.toString());
|
|
215
|
+
} else if (isIframe && !isIframePaymentOptionExcluded) {
|
|
216
|
+
showRedirectionIframe(urlObj.toString());
|
|
194
217
|
} else {
|
|
195
218
|
window.location.href = urlObj.toString();
|
|
196
219
|
}
|
|
@@ -220,12 +243,20 @@ export const contextListMiddleware: Middleware = ({
|
|
|
220
243
|
dispatch(setShippingOptions(context.page_context.shipping_options));
|
|
221
244
|
}
|
|
222
245
|
|
|
246
|
+
if (context.page_context.data_sources) {
|
|
247
|
+
dispatch(
|
|
248
|
+
setDataSourceShippingOptions(context.page_context.data_sources)
|
|
249
|
+
);
|
|
250
|
+
}
|
|
251
|
+
|
|
223
252
|
if (context.page_context.payment_options) {
|
|
224
253
|
dispatch(setPaymentOptions(context.page_context.payment_options));
|
|
225
254
|
}
|
|
226
255
|
|
|
227
256
|
if (context.page_context.credit_payment_options) {
|
|
228
|
-
dispatch(
|
|
257
|
+
dispatch(
|
|
258
|
+
setCreditPaymentOptions(context.page_context.credit_payment_options)
|
|
259
|
+
);
|
|
229
260
|
}
|
|
230
261
|
|
|
231
262
|
if (context.page_context.payment_choices) {
|
|
@@ -14,12 +14,12 @@ import {
|
|
|
14
14
|
CheckoutCreditPaymentOption,
|
|
15
15
|
PreOrder,
|
|
16
16
|
RetailStore,
|
|
17
|
-
ShippingOption
|
|
17
|
+
ShippingOption,
|
|
18
|
+
DataSource
|
|
18
19
|
} from '../../types';
|
|
19
20
|
|
|
20
21
|
export interface CheckoutState {
|
|
21
|
-
|
|
22
|
-
errors: any;
|
|
22
|
+
errors: Record<string, string[]>;
|
|
23
23
|
hasGiftBox: boolean;
|
|
24
24
|
canGuestPurchase: boolean;
|
|
25
25
|
steps: {
|
|
@@ -37,6 +37,7 @@ export interface CheckoutState {
|
|
|
37
37
|
addressList: Address[];
|
|
38
38
|
deliveryOptions: DeliveryOption[];
|
|
39
39
|
shippingOptions: ShippingOption[];
|
|
40
|
+
dataSourceShippingOptions: DataSource[];
|
|
40
41
|
paymentOptions: PaymentOption[];
|
|
41
42
|
creditPaymentOptions: CheckoutCreditPaymentOption[];
|
|
42
43
|
selectedCreditPaymentPk: number;
|
|
@@ -68,6 +69,7 @@ const initialState: CheckoutState = {
|
|
|
68
69
|
addressList: [],
|
|
69
70
|
deliveryOptions: [],
|
|
70
71
|
shippingOptions: [],
|
|
72
|
+
dataSourceShippingOptions: [],
|
|
71
73
|
paymentOptions: [],
|
|
72
74
|
creditPaymentOptions: [],
|
|
73
75
|
selectedCreditPaymentPk: null,
|
|
@@ -122,6 +124,9 @@ const checkoutSlice = createSlice({
|
|
|
122
124
|
setShippingOptions(state, { payload }) {
|
|
123
125
|
state.shippingOptions = payload;
|
|
124
126
|
},
|
|
127
|
+
setDataSourceShippingOptions(state, { payload }) {
|
|
128
|
+
state.dataSourceShippingOptions = payload;
|
|
129
|
+
},
|
|
125
130
|
setPaymentOptions(state, { payload }) {
|
|
126
131
|
state.paymentOptions = payload;
|
|
127
132
|
},
|
|
@@ -169,6 +174,7 @@ export const {
|
|
|
169
174
|
setAddressList,
|
|
170
175
|
setDeliveryOptions,
|
|
171
176
|
setShippingOptions,
|
|
177
|
+
setDataSourceShippingOptions,
|
|
172
178
|
setPaymentOptions,
|
|
173
179
|
setCreditPaymentOptions,
|
|
174
180
|
setSelectedCreditPaymentPk,
|
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,7 @@ 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;
|
|
81
99
|
}
|
|
82
100
|
|
|
83
101
|
export interface GuestLoginFormParams {
|
package/types/commerce/misc.ts
CHANGED
package/types/commerce/order.ts
CHANGED
|
@@ -52,6 +52,10 @@ export interface OrderItem {
|
|
|
52
52
|
quantity: string;
|
|
53
53
|
unit_price: string;
|
|
54
54
|
total_amount: string;
|
|
55
|
+
attributes: {
|
|
56
|
+
gift_note: string;
|
|
57
|
+
[key: string]: any;
|
|
58
|
+
};
|
|
55
59
|
}
|
|
56
60
|
|
|
57
61
|
export interface Order {
|
|
@@ -105,6 +109,9 @@ export interface Order {
|
|
|
105
109
|
shipping_option: number;
|
|
106
110
|
tracking_number: string;
|
|
107
111
|
tracking_url: string;
|
|
112
|
+
bank: {
|
|
113
|
+
logo: string;
|
|
114
|
+
};
|
|
108
115
|
}
|
|
109
116
|
|
|
110
117
|
export interface Quotations {
|
package/types/index.ts
CHANGED
|
@@ -68,9 +68,17 @@ export interface Currency {
|
|
|
68
68
|
* @see https://en.wikipedia.org/wiki/ISO_4217
|
|
69
69
|
*/
|
|
70
70
|
code: string;
|
|
71
|
+
/**
|
|
72
|
+
* Number of decimal places to display.
|
|
73
|
+
*
|
|
74
|
+
* @example
|
|
75
|
+
* decimalScale: 3
|
|
76
|
+
*/
|
|
77
|
+
decimalScale?: number;
|
|
71
78
|
}
|
|
72
79
|
|
|
73
80
|
export interface Settings {
|
|
81
|
+
usePrettyUrlRoute?: boolean;
|
|
74
82
|
commerceUrl: string;
|
|
75
83
|
redis: {
|
|
76
84
|
defaultExpirationTime: number;
|
|
@@ -216,7 +224,7 @@ export type Translations = { [key: string]: object };
|
|
|
216
224
|
|
|
217
225
|
export interface PageProps<T = any> {
|
|
218
226
|
params: T;
|
|
219
|
-
searchParams:
|
|
227
|
+
searchParams: { [key: string]: string | string[] | undefined };
|
|
220
228
|
}
|
|
221
229
|
|
|
222
230
|
export interface LayoutProps<T = any> extends PageProps<T> {
|