@akinon/next 2.0.0-beta.12 → 2.0.0-beta.13
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 +282 -29
- package/api/auth.ts +99 -77
- package/api/cache.ts +41 -5
- package/api/client.ts +3 -3
- 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/bin/pz-generate-routes.js +105 -0
- package/bin/pz-prebuild.js +1 -1
- package/bin/pz-predev.js +1 -0
- package/components/accordion.tsx +21 -6
- package/components/button.tsx +1 -1
- package/components/file-input.tsx +65 -3
- package/components/input.tsx +2 -2
- package/components/modal.tsx +32 -16
- package/components/plugin-module.tsx +61 -3
- package/components/select.tsx +2 -2
- package/components/selected-payment-option-view.tsx +21 -0
- package/data/client/checkout.ts +130 -74
- package/data/server/category.ts +11 -9
- package/data/server/flatpage.ts +4 -1
- package/data/server/form.ts +4 -1
- package/data/server/landingpage.ts +4 -1
- package/data/server/list.ts +5 -4
- package/data/server/menu.ts +4 -1
- package/data/server/product.ts +97 -52
- package/data/server/seo.ts +4 -1
- package/data/server/special-page.ts +5 -4
- package/data/server/widget.ts +4 -1
- package/data/urls.ts +3 -2
- package/hocs/client/with-segment-defaults.tsx +2 -2
- package/hocs/server/with-segment-defaults.tsx +65 -20
- package/hooks/index.ts +1 -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/instrumentation/index.ts +0 -1
- package/instrumentation/node.ts +2 -20
- package/jest.config.js +7 -1
- package/lib/cache-handler.mjs +527 -15
- package/lib/cache.ts +260 -31
- package/localization/provider.tsx +2 -5
- package/middlewares/checkout-provider.ts +1 -1
- package/middlewares/complete-gpay.ts +33 -26
- package/middlewares/complete-masterpass.ts +34 -26
- package/middlewares/complete-wallet.ts +183 -0
- package/middlewares/default.ts +346 -235
- package/middlewares/index.ts +8 -2
- package/middlewares/locale.ts +0 -1
- package/middlewares/masterpass-rest-callback.ts +220 -0
- package/middlewares/pretty-url.ts +21 -8
- package/middlewares/redirection-payment.ts +33 -26
- package/middlewares/saved-card-redirection.ts +34 -26
- package/middlewares/three-d-redirection.ts +33 -26
- package/middlewares/url-redirection.ts +9 -15
- package/middlewares/wallet-complete-redirection.ts +207 -0
- package/package.json +20 -11
- package/plugins.d.ts +19 -4
- package/plugins.js +9 -1
- package/redux/actions.ts +47 -0
- package/redux/middlewares/checkout.ts +20 -8
- package/redux/middlewares/index.ts +12 -10
- package/redux/middlewares/pre-order/address.ts +1 -1
- package/redux/middlewares/pre-order/attribute-based-shipping-option.ts +1 -1
- package/redux/middlewares/pre-order/data-source-shipping-option.ts +1 -1
- package/redux/middlewares/pre-order/delivery-option.ts +1 -1
- package/redux/middlewares/pre-order/index.ts +3 -1
- package/redux/middlewares/pre-order/installment-option.ts +2 -1
- package/redux/middlewares/pre-order/payment-option-reset.ts +37 -0
- package/redux/middlewares/pre-order/payment-option.ts +1 -1
- package/redux/middlewares/pre-order/pre-order-validation.ts +4 -3
- package/redux/middlewares/pre-order/redirection.ts +2 -2
- package/redux/middlewares/pre-order/set-pre-order.ts +2 -2
- package/redux/middlewares/pre-order/shipping-option.ts +1 -1
- package/redux/middlewares/pre-order/shipping-step.ts +1 -1
- package/redux/reducers/checkout.ts +9 -1
- package/redux/reducers/index.ts +5 -1
- package/sentry/index.ts +54 -17
- package/types/commerce/checkout.ts +11 -1
- package/types/index.ts +96 -6
- package/types/next-auth.d.ts +2 -2
- package/utils/app-fetch.ts +2 -2
- package/utils/generate-commerce-search-params.ts +3 -2
- package/utils/get-checkout-path.ts +3 -0
- package/utils/index.ts +38 -11
- package/utils/override-middleware.ts +1 -0
- package/utils/pz-segments.ts +92 -0
- package/utils/redirect-ignore.ts +35 -0
- package/utils/redirect.ts +9 -3
- package/with-pz-config.js +10 -4
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
import { Middleware } from '@reduxjs/toolkit';
|
|
2
|
-
import { CheckoutResult } from '../../../types';
|
|
2
|
+
import { CheckoutResult, MiddlewareAction } from '../../../types';
|
|
3
3
|
|
|
4
4
|
export const preOrderValidationMiddleware: Middleware = () => {
|
|
5
5
|
return (next) => (action) => {
|
|
6
|
-
const result
|
|
6
|
+
const result = next(action) as CheckoutResult;
|
|
7
7
|
const preOrder = result?.payload?.pre_order;
|
|
8
|
+
const act = action as MiddlewareAction;
|
|
8
9
|
|
|
9
10
|
if (
|
|
10
11
|
!preOrder ||
|
|
11
12
|
['guestLogin', 'getCheckoutLoyaltyBalance'].includes(
|
|
12
|
-
|
|
13
|
+
act?.meta?.arg?.endpointName
|
|
13
14
|
)
|
|
14
15
|
) {
|
|
15
16
|
return result;
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { Middleware } from '@reduxjs/toolkit';
|
|
2
|
-
import { MiddlewareParams } from '../../../types';
|
|
2
|
+
import { CheckoutResult, MiddlewareParams } from '../../../types';
|
|
3
3
|
import { checkoutApi } from '../../../data/client/checkout';
|
|
4
4
|
|
|
5
5
|
export const redirectionMiddleware: Middleware = ({
|
|
6
6
|
dispatch
|
|
7
7
|
}: MiddlewareParams) => {
|
|
8
8
|
return (next) => (action) => {
|
|
9
|
-
const result = next(action);
|
|
9
|
+
const result = next(action) as CheckoutResult;
|
|
10
10
|
const preOrder = result?.payload?.pre_order;
|
|
11
11
|
|
|
12
12
|
if (!preOrder) {
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { Middleware } from '@reduxjs/toolkit';
|
|
2
|
-
import { MiddlewareParams } from '../../../types';
|
|
2
|
+
import { CheckoutResult, MiddlewareParams } from '../../../types';
|
|
3
3
|
import { setPreOrder } from '../../../redux/reducers/checkout';
|
|
4
4
|
|
|
5
5
|
export const setPreOrderMiddleware: Middleware = ({
|
|
6
6
|
dispatch
|
|
7
7
|
}: MiddlewareParams) => {
|
|
8
8
|
return (next) => (action) => {
|
|
9
|
-
const result = next(action);
|
|
9
|
+
const result = next(action) as CheckoutResult;
|
|
10
10
|
const preOrder = result?.payload?.pre_order;
|
|
11
11
|
|
|
12
12
|
if (preOrder) {
|
|
@@ -7,7 +7,7 @@ export const shippingOptionMiddleware: Middleware = ({
|
|
|
7
7
|
dispatch
|
|
8
8
|
}: MiddlewareParams) => {
|
|
9
9
|
return (next) => (action) => {
|
|
10
|
-
const result
|
|
10
|
+
const result = next(action) as CheckoutResult;
|
|
11
11
|
const preOrder = result?.payload?.pre_order;
|
|
12
12
|
|
|
13
13
|
if (!preOrder) {
|
|
@@ -7,7 +7,7 @@ export const shippingStepMiddleware: Middleware = ({
|
|
|
7
7
|
dispatch
|
|
8
8
|
}: MiddlewareParams) => {
|
|
9
9
|
return (next) => (action) => {
|
|
10
|
-
const result
|
|
10
|
+
const result = next(action) as CheckoutResult;
|
|
11
11
|
const preOrder = result?.payload?.pre_order;
|
|
12
12
|
|
|
13
13
|
if (!preOrder) {
|
|
@@ -40,6 +40,7 @@ export interface CheckoutState {
|
|
|
40
40
|
shippingOptions: ShippingOption[];
|
|
41
41
|
dataSourceShippingOptions: DataSource[];
|
|
42
42
|
paymentOptions: PaymentOption[];
|
|
43
|
+
unavailablePaymentOptions: PaymentOption[];
|
|
43
44
|
creditPaymentOptions: CheckoutCreditPaymentOption[];
|
|
44
45
|
selectedCreditPaymentPk: number;
|
|
45
46
|
paymentChoices: PaymentChoice[];
|
|
@@ -60,6 +61,8 @@ export interface CheckoutState {
|
|
|
60
61
|
countryCode: string;
|
|
61
62
|
currencyCode: string;
|
|
62
63
|
version: string;
|
|
64
|
+
public_key: string;
|
|
65
|
+
[key: string]: any;
|
|
63
66
|
};
|
|
64
67
|
detail: {
|
|
65
68
|
label: string;
|
|
@@ -94,6 +97,7 @@ const initialState: CheckoutState = {
|
|
|
94
97
|
shippingOptions: [],
|
|
95
98
|
dataSourceShippingOptions: [],
|
|
96
99
|
paymentOptions: [],
|
|
100
|
+
unavailablePaymentOptions: [],
|
|
97
101
|
creditPaymentOptions: [],
|
|
98
102
|
selectedCreditPaymentPk: null,
|
|
99
103
|
paymentChoices: [],
|
|
@@ -157,6 +161,9 @@ const checkoutSlice = createSlice({
|
|
|
157
161
|
setPaymentOptions(state, { payload }) {
|
|
158
162
|
state.paymentOptions = payload;
|
|
159
163
|
},
|
|
164
|
+
setUnavailablePaymentOptions(state, { payload }) {
|
|
165
|
+
state.unavailablePaymentOptions = payload;
|
|
166
|
+
},
|
|
160
167
|
setPaymentChoices(state, { payload }) {
|
|
161
168
|
state.paymentChoices = payload;
|
|
162
169
|
},
|
|
@@ -218,9 +225,10 @@ export const {
|
|
|
218
225
|
setShippingOptions,
|
|
219
226
|
setDataSourceShippingOptions,
|
|
220
227
|
setPaymentOptions,
|
|
228
|
+
setUnavailablePaymentOptions,
|
|
229
|
+
setPaymentChoices,
|
|
221
230
|
setCreditPaymentOptions,
|
|
222
231
|
setSelectedCreditPaymentPk,
|
|
223
|
-
setPaymentChoices,
|
|
224
232
|
setCardType,
|
|
225
233
|
setInstallmentOptions,
|
|
226
234
|
setBankAccounts,
|
package/redux/reducers/index.ts
CHANGED
|
@@ -8,6 +8,8 @@ import { api } from '../../data/client/api';
|
|
|
8
8
|
import { masterpassReducer } from '@akinon/pz-masterpass';
|
|
9
9
|
import { otpReducer } from '@akinon/pz-otp';
|
|
10
10
|
import { savedCardReducer } from '@akinon/pz-saved-card';
|
|
11
|
+
import cyberSourceUcReducer from '@akinon/pz-cybersource-uc/src/redux/reducer';
|
|
12
|
+
import { masterpassRestReducer } from '@akinon/pz-masterpass-rest';
|
|
11
13
|
|
|
12
14
|
const fallbackReducer = (state = {}) => state;
|
|
13
15
|
|
|
@@ -19,7 +21,9 @@ const reducers = {
|
|
|
19
21
|
header: headerReducer,
|
|
20
22
|
masterpass: masterpassReducer || fallbackReducer,
|
|
21
23
|
otp: otpReducer || fallbackReducer,
|
|
22
|
-
savedCard: savedCardReducer || fallbackReducer
|
|
24
|
+
savedCard: savedCardReducer || fallbackReducer,
|
|
25
|
+
cybersource_uc: cyberSourceUcReducer || fallbackReducer,
|
|
26
|
+
masterpassRest: masterpassRestReducer || fallbackReducer
|
|
23
27
|
};
|
|
24
28
|
|
|
25
29
|
export default reducers;
|
package/sentry/index.ts
CHANGED
|
@@ -13,36 +13,73 @@ const ALLOWED_CLIENT_LOG_TYPES: ClientLogType[] = [
|
|
|
13
13
|
ClientLogType.CHECKOUT
|
|
14
14
|
];
|
|
15
15
|
|
|
16
|
+
const isNetworkError = (exception: unknown): boolean => {
|
|
17
|
+
if (!(exception instanceof Error)) return false;
|
|
18
|
+
|
|
19
|
+
const networkErrorPatterns = [
|
|
20
|
+
'networkerror',
|
|
21
|
+
'failed to fetch',
|
|
22
|
+
'network request failed',
|
|
23
|
+
'network error',
|
|
24
|
+
'loading chunk',
|
|
25
|
+
'chunk load failed'
|
|
26
|
+
];
|
|
27
|
+
|
|
28
|
+
if (exception.name === 'NetworkError') return true;
|
|
29
|
+
|
|
30
|
+
if (exception.name === 'TypeError') {
|
|
31
|
+
return networkErrorPatterns.some((pattern) =>
|
|
32
|
+
exception.message.toLowerCase().includes(pattern)
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return networkErrorPatterns.some((pattern) =>
|
|
37
|
+
exception.message.toLowerCase().includes(pattern)
|
|
38
|
+
);
|
|
39
|
+
};
|
|
40
|
+
|
|
16
41
|
export const initSentry = (
|
|
17
42
|
type: 'Server' | 'Client' | 'Edge',
|
|
18
43
|
options: Sentry.BrowserOptions | Sentry.NodeOptions | Sentry.EdgeOptions = {}
|
|
19
44
|
) => {
|
|
20
|
-
// TODO:
|
|
45
|
+
// TODO: Remove Zero Project DSN
|
|
21
46
|
|
|
22
|
-
|
|
47
|
+
const baseConfig = {
|
|
23
48
|
dsn:
|
|
24
|
-
options.dsn ||
|
|
25
49
|
SENTRY_DSN ||
|
|
50
|
+
options.dsn ||
|
|
26
51
|
'https://d8558ef8997543deacf376c7d8d7cf4b@o64293.ingest.sentry.io/4504338423742464',
|
|
27
52
|
initialScope: {
|
|
28
53
|
tags: {
|
|
29
54
|
APP_TYPE: 'ProjectZeroNext',
|
|
30
|
-
TYPE: type
|
|
55
|
+
TYPE: type,
|
|
56
|
+
...((options.initialScope as any)?.tags || {})
|
|
31
57
|
}
|
|
32
58
|
},
|
|
33
59
|
tracesSampleRate: 0,
|
|
34
|
-
integrations: []
|
|
35
|
-
|
|
36
|
-
if (
|
|
37
|
-
type === 'Client' &&
|
|
38
|
-
!ALLOWED_CLIENT_LOG_TYPES.includes(
|
|
39
|
-
event.tags?.LOG_TYPE as ClientLogType
|
|
40
|
-
)
|
|
41
|
-
) {
|
|
42
|
-
return null;
|
|
43
|
-
}
|
|
60
|
+
integrations: []
|
|
61
|
+
};
|
|
44
62
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
})
|
|
63
|
+
if (type === 'Server' || type === 'Edge') {
|
|
64
|
+
Sentry.init(baseConfig);
|
|
65
|
+
} else if (type === 'Client') {
|
|
66
|
+
Sentry.init({
|
|
67
|
+
...baseConfig,
|
|
68
|
+
beforeSend: (event, hint) => {
|
|
69
|
+
if (
|
|
70
|
+
!ALLOWED_CLIENT_LOG_TYPES.includes(
|
|
71
|
+
event.tags?.LOG_TYPE as ClientLogType
|
|
72
|
+
)
|
|
73
|
+
) {
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (isNetworkError(hint?.originalException)) {
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return event;
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
}
|
|
48
85
|
};
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
+
import type { JSX } from 'react';
|
|
1
2
|
import { Address } from './address';
|
|
2
3
|
import { Basket } from './basket';
|
|
3
4
|
import { RetailStore } from './misc';
|
|
4
5
|
import { PaymentOption } from './order';
|
|
5
6
|
import { Product } from './product';
|
|
6
|
-
import { JSX } from 'react';
|
|
7
7
|
import { RootState, TypedDispatch } from 'redux/store';
|
|
8
8
|
|
|
9
9
|
export enum CheckoutStep {
|
|
@@ -109,6 +109,7 @@ export interface PreOrder {
|
|
|
109
109
|
token?: string;
|
|
110
110
|
agreement_confirmed?: boolean;
|
|
111
111
|
phone_number?: string;
|
|
112
|
+
number?: string;
|
|
112
113
|
}
|
|
113
114
|
|
|
114
115
|
export type ExtraField = Record<string, any>;
|
|
@@ -202,6 +203,15 @@ export interface MiddlewareParams {
|
|
|
202
203
|
dispatch: TypedDispatch;
|
|
203
204
|
}
|
|
204
205
|
|
|
206
|
+
export interface MiddlewareAction {
|
|
207
|
+
type: string;
|
|
208
|
+
payload?: { status?: number; [key: string]: unknown };
|
|
209
|
+
meta?: {
|
|
210
|
+
arg?: { endpointName?: string };
|
|
211
|
+
baseQueryMeta?: { request?: { url?: string } };
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
|
|
205
215
|
export type SendSmsType = {
|
|
206
216
|
phone_number: string;
|
|
207
217
|
};
|
package/types/index.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { LocaleUrlStrategy } from '../localization';
|
|
2
2
|
import { PzNextRequest } from '../middlewares';
|
|
3
|
+
import { NextFetchEvent } from 'next/server';
|
|
4
|
+
import { NextURL } from 'next/dist/server/web/next-url';
|
|
3
5
|
import { Control, FieldError } from 'react-hook-form';
|
|
4
6
|
import { ReactNode } from 'react';
|
|
5
7
|
import { UsePaginationType } from '../hooks/use-pagination';
|
|
@@ -199,6 +201,7 @@ export interface Settings {
|
|
|
199
201
|
extraPaymentTypes?: string[];
|
|
200
202
|
masterpassJsUrl?: string;
|
|
201
203
|
};
|
|
204
|
+
customNotFoundEnabled: boolean;
|
|
202
205
|
useOptimizedTranslations?: boolean;
|
|
203
206
|
plugins?: Record<string, Record<string, any>>;
|
|
204
207
|
includedProxyHeaders?: string[];
|
|
@@ -209,13 +212,26 @@ export interface Settings {
|
|
|
209
212
|
*/
|
|
210
213
|
resetBasketOnCurrencyChange?: boolean;
|
|
211
214
|
frontendIds?: Record<string, number>;
|
|
212
|
-
|
|
215
|
+
usePzSegment?: boolean;
|
|
216
|
+
pzSegments?: {
|
|
217
|
+
separator?: string;
|
|
218
|
+
segments: PzSegmentDefinition[];
|
|
219
|
+
};
|
|
213
220
|
}
|
|
214
221
|
|
|
215
222
|
export interface CacheOptions {
|
|
216
223
|
cache?: boolean;
|
|
217
224
|
expire?: number;
|
|
218
225
|
useProxy?: boolean;
|
|
226
|
+
compressed?: boolean;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
export interface SetCookieOptions {
|
|
230
|
+
expires?: number; // days
|
|
231
|
+
path?: string;
|
|
232
|
+
domain?: string;
|
|
233
|
+
secure?: boolean;
|
|
234
|
+
sameSite?: 'strict' | 'lax' | 'none';
|
|
219
235
|
}
|
|
220
236
|
|
|
221
237
|
export interface ClientRequestOptions {
|
|
@@ -240,22 +256,69 @@ export type ImageOptions = CDNOptions & {
|
|
|
240
256
|
|
|
241
257
|
export type Translations = { [key: string]: object };
|
|
242
258
|
|
|
259
|
+
export interface PzSegmentResolveContext {
|
|
260
|
+
req: PzNextRequest;
|
|
261
|
+
event: NextFetchEvent;
|
|
262
|
+
url: NextURL;
|
|
263
|
+
locale: string;
|
|
264
|
+
currency: string;
|
|
265
|
+
pathname: string;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
export interface PzSegmentDefinition {
|
|
269
|
+
name: string;
|
|
270
|
+
resolve?: (context: PzSegmentResolveContext) => string;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
export interface PzSegmentsConfig {
|
|
274
|
+
separator: string;
|
|
275
|
+
segments: PzSegmentDefinition[];
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
// Next.js 16 async page/layout props (for exported page components and generateMetadata)
|
|
243
279
|
export interface PageProps<T = any> {
|
|
244
|
-
params: Promise<T & {
|
|
245
|
-
|
|
280
|
+
params: Promise<T & {
|
|
281
|
+
pz?: string;
|
|
282
|
+
commerce?: string;
|
|
283
|
+
locale?: string;
|
|
284
|
+
currency?: string;
|
|
285
|
+
url?: string;
|
|
286
|
+
[key: string]: any;
|
|
287
|
+
}>;
|
|
288
|
+
searchParams: Promise<{ [key: string]: string | string[] | undefined }>;
|
|
246
289
|
}
|
|
247
290
|
|
|
248
291
|
export interface LayoutProps<T = any> extends PageProps<T> {
|
|
249
292
|
children: React.ReactNode;
|
|
250
293
|
}
|
|
251
294
|
|
|
252
|
-
export interface RootLayoutProps<
|
|
295
|
+
export interface RootLayoutProps<T = any> extends LayoutProps<T> {
|
|
296
|
+
translations: Translations;
|
|
297
|
+
locale: Locale & {
|
|
298
|
+
isoCode: string;
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
// Search params type compatible with both Next.js resolved searchParams and URLSearchParams
|
|
303
|
+
export type SearchParams = Record<string, string | string[] | undefined> | URLSearchParams;
|
|
304
|
+
|
|
305
|
+
// Resolved (sync) versions for inner components after withSegmentDefaults resolves props
|
|
306
|
+
export interface ResolvedPageProps<T = any> {
|
|
307
|
+
params: T & { locale: string; currency: string };
|
|
308
|
+
searchParams: SearchParams;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
export interface ResolvedLayoutProps<T = any> extends ResolvedPageProps<T> {
|
|
312
|
+
children: React.ReactNode;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
export interface ResolvedRootLayoutProps<
|
|
253
316
|
T = {
|
|
254
317
|
commerce: string;
|
|
255
318
|
locale: string;
|
|
256
319
|
currency: string;
|
|
257
320
|
}
|
|
258
|
-
> extends
|
|
321
|
+
> extends ResolvedLayoutProps<T> {
|
|
259
322
|
translations: Translations;
|
|
260
323
|
locale: Locale & {
|
|
261
324
|
isoCode: string;
|
|
@@ -283,7 +346,13 @@ export interface ButtonProps
|
|
|
283
346
|
target?: '_blank' | '_self' | '_parent' | '_top';
|
|
284
347
|
}
|
|
285
348
|
|
|
286
|
-
export
|
|
349
|
+
export interface FileInputProps extends React.HTMLProps<HTMLInputElement> {
|
|
350
|
+
fileClassName?: string;
|
|
351
|
+
fileNameWrapperClassName?: string;
|
|
352
|
+
fileInputClassName?: string;
|
|
353
|
+
onChange?: (event: React.ChangeEvent<HTMLInputElement>) => void;
|
|
354
|
+
buttonClassName?: string;
|
|
355
|
+
}
|
|
287
356
|
|
|
288
357
|
export interface PriceProps {
|
|
289
358
|
currencyCode?: string;
|
|
@@ -304,15 +373,19 @@ export interface InputProps extends React.HTMLProps<HTMLInputElement> {
|
|
|
304
373
|
|
|
305
374
|
export interface AccordionProps {
|
|
306
375
|
isCollapse?: boolean;
|
|
376
|
+
collapseClassName?: string;
|
|
307
377
|
title?: string;
|
|
308
378
|
subTitle?: string;
|
|
309
379
|
icons?: string[];
|
|
310
380
|
iconSize?: number;
|
|
311
381
|
iconColor?: string;
|
|
312
382
|
children?: ReactNode;
|
|
383
|
+
headerClassName?: string;
|
|
313
384
|
className?: string;
|
|
314
385
|
titleClassName?: string;
|
|
386
|
+
subTitleClassName?: string;
|
|
315
387
|
dataTestId?: string;
|
|
388
|
+
contentClassName?: string;
|
|
316
389
|
}
|
|
317
390
|
|
|
318
391
|
export interface PluginModuleComponentProps {
|
|
@@ -337,3 +410,20 @@ export interface PaginationProps {
|
|
|
337
410
|
direction?: 'next' | 'prev';
|
|
338
411
|
isLoading?: boolean;
|
|
339
412
|
}
|
|
413
|
+
|
|
414
|
+
export interface ModalProps {
|
|
415
|
+
portalId: string;
|
|
416
|
+
children?: React.ReactNode;
|
|
417
|
+
open?: boolean;
|
|
418
|
+
setOpen?: (open: boolean) => void;
|
|
419
|
+
title?: React.ReactNode;
|
|
420
|
+
showCloseButton?: React.ReactNode;
|
|
421
|
+
className?: string;
|
|
422
|
+
overlayClassName?: string;
|
|
423
|
+
headerWrapperClassName?: string;
|
|
424
|
+
titleClassName?: string;
|
|
425
|
+
closeButtonClassName?: string;
|
|
426
|
+
iconName?: string;
|
|
427
|
+
iconSize?: number;
|
|
428
|
+
iconClassName?: string;
|
|
429
|
+
}
|
package/types/next-auth.d.ts
CHANGED
package/utils/app-fetch.ts
CHANGED
|
@@ -43,12 +43,12 @@ const appFetch = async <T>({
|
|
|
43
43
|
const requestURL = `${decodeURIComponent(commerceUrl)}${url}`;
|
|
44
44
|
|
|
45
45
|
init.headers = {
|
|
46
|
+
cookie: nextCookies.toString(),
|
|
46
47
|
...(init.headers ?? {}),
|
|
47
48
|
...(ServerVariables.globalHeaders ?? {}),
|
|
48
49
|
'Accept-Language': currentLocale.apiValue,
|
|
49
50
|
'x-currency': currency,
|
|
50
|
-
'x-forwarded-for': ip
|
|
51
|
-
cookie: nextCookies.toString()
|
|
51
|
+
'x-forwarded-for': ip
|
|
52
52
|
};
|
|
53
53
|
|
|
54
54
|
init.next = {
|
|
@@ -1,13 +1,14 @@
|
|
|
1
|
+
import { SearchParams } from '../types';
|
|
1
2
|
import logger from './log';
|
|
2
3
|
|
|
3
4
|
export const generateCommerceSearchParams = (
|
|
4
|
-
searchParams?:
|
|
5
|
+
searchParams?: SearchParams
|
|
5
6
|
) => {
|
|
6
7
|
if (!searchParams) {
|
|
7
8
|
return null;
|
|
8
9
|
}
|
|
9
10
|
|
|
10
|
-
const urlSerchParams = new URLSearchParams(searchParams);
|
|
11
|
+
const urlSerchParams = new URLSearchParams(searchParams as any);
|
|
11
12
|
|
|
12
13
|
Object.entries(searchParams).forEach(([key, value]) => {
|
|
13
14
|
if (typeof value === 'object') {
|
package/utils/index.ts
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import settings from 'settings';
|
|
2
2
|
import { LocaleUrlStrategy } from '../localization';
|
|
3
|
-
import { CDNOptions, ClientRequestOptions } from '../types';
|
|
3
|
+
import { CDNOptions, ClientRequestOptions, SetCookieOptions } from '../types';
|
|
4
|
+
import getRootHostname from './get-root-hostname';
|
|
4
5
|
|
|
5
6
|
export * from './get-currency';
|
|
6
7
|
export * from './menu-generator';
|
|
7
8
|
export * from './generate-commerce-search-params';
|
|
8
9
|
export * from './get-currency-label';
|
|
10
|
+
export * from './pz-segments';
|
|
11
|
+
export * from './get-checkout-path';
|
|
9
12
|
|
|
10
13
|
export function getCookie(name: string) {
|
|
11
14
|
if (typeof document === 'undefined') {
|
|
@@ -20,14 +23,40 @@ export function getCookie(name: string) {
|
|
|
20
23
|
}
|
|
21
24
|
}
|
|
22
25
|
|
|
23
|
-
export function setCookie(
|
|
24
|
-
|
|
25
|
-
|
|
26
|
+
export function setCookie(
|
|
27
|
+
name: string,
|
|
28
|
+
value: string,
|
|
29
|
+
options: SetCookieOptions = {}
|
|
30
|
+
) {
|
|
31
|
+
const cookieParts = [`${name}=${value}`];
|
|
32
|
+
|
|
33
|
+
if (options.expires) {
|
|
34
|
+
const date = new Date();
|
|
35
|
+
date.setTime(date.getTime() + options.expires * 24 * 60 * 60 * 1000);
|
|
36
|
+
cookieParts.push(`expires=${date.toUTCString()}`);
|
|
37
|
+
}
|
|
26
38
|
|
|
27
|
-
|
|
39
|
+
cookieParts.push(`path=${options.path ?? '/'}`);
|
|
28
40
|
|
|
29
|
-
|
|
30
|
-
|
|
41
|
+
if (options.secure) {
|
|
42
|
+
cookieParts.push('secure');
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (options.sameSite) {
|
|
46
|
+
cookieParts.push(`sameSite=${options.sameSite}`);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const domain =
|
|
50
|
+
options.domain ??
|
|
51
|
+
(settings.localization.localeUrlStrategy === LocaleUrlStrategy.Subdomain
|
|
52
|
+
? getRootHostname(document.location.href)
|
|
53
|
+
: null);
|
|
54
|
+
|
|
55
|
+
if (domain) {
|
|
56
|
+
cookieParts.push(`domain=${domain}`);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
document.cookie = cookieParts.join('; ');
|
|
31
60
|
}
|
|
32
61
|
|
|
33
62
|
export function removeCookie(name: string) {
|
|
@@ -152,9 +181,6 @@ export function buildCDNUrl(url: string, config?: CDNOptions) {
|
|
|
152
181
|
return `${rootWithoutOptions}${options}${fileExtension}`;
|
|
153
182
|
}
|
|
154
183
|
|
|
155
|
-
const { locales, localeUrlStrategy, defaultLocaleValue } =
|
|
156
|
-
settings.localization;
|
|
157
|
-
|
|
158
184
|
export const urlLocaleMatcherRegex = new RegExp(
|
|
159
185
|
`^/(${settings.localization.locales
|
|
160
186
|
.filter((l) =>
|
|
@@ -169,7 +195,8 @@ export const urlLocaleMatcherRegex = new RegExp(
|
|
|
169
195
|
);
|
|
170
196
|
|
|
171
197
|
export const getPosError = () => {
|
|
172
|
-
const
|
|
198
|
+
const cookieValue = getCookie('pz-pos-error');
|
|
199
|
+
const error = JSON.parse(cookieValue ? decodeURIComponent(cookieValue) : '{}');
|
|
173
200
|
|
|
174
201
|
// delete 'pz-pos-error' cookie when refreshing or closing page
|
|
175
202
|
window.addEventListener('beforeunload', () => {
|
|
@@ -10,6 +10,7 @@ export enum MiddlewareNames {
|
|
|
10
10
|
DataSourceShippingOptionMiddleware = 'dataSourceShippingOptionMiddleware',
|
|
11
11
|
AttributeBasedShippingOptionMiddleware = 'attributeBasedShippingOptionMiddleware',
|
|
12
12
|
PaymentOptionMiddleware = 'paymentOptionMiddleware',
|
|
13
|
+
PaymentOptionResetMiddleware = 'paymentOptionResetMiddleware',
|
|
13
14
|
InstallmentOptionMiddleware = 'installmentOptionMiddleware',
|
|
14
15
|
ShippingStepMiddleware = 'shippingStepMiddleware'
|
|
15
16
|
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import type { PzSegmentDefinition, PzSegmentsConfig } from '../types';
|
|
2
|
+
|
|
3
|
+
export function isLegacyMode(settings: any): boolean {
|
|
4
|
+
return !settings.usePzSegment;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
const DEFAULT_SEPARATOR = '--';
|
|
8
|
+
|
|
9
|
+
const DEFAULT_SEGMENTS: PzSegmentDefinition[] = [
|
|
10
|
+
{ name: 'locale' },
|
|
11
|
+
{ name: 'currency' },
|
|
12
|
+
{ name: 'url' }
|
|
13
|
+
];
|
|
14
|
+
|
|
15
|
+
export function getPzSegmentsConfig(settings: any): PzSegmentsConfig {
|
|
16
|
+
if (settings.pzSegments) {
|
|
17
|
+
const customSegments = (settings.pzSegments.segments ?? []).filter(
|
|
18
|
+
(seg: PzSegmentDefinition) =>
|
|
19
|
+
!DEFAULT_SEGMENTS.some((d) => d.name === seg.name)
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
return {
|
|
23
|
+
separator: settings.pzSegments.separator ?? DEFAULT_SEPARATOR,
|
|
24
|
+
segments: [...DEFAULT_SEGMENTS, ...customSegments]
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return {
|
|
29
|
+
separator: DEFAULT_SEPARATOR,
|
|
30
|
+
segments: DEFAULT_SEGMENTS
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function encodePzValue(
|
|
35
|
+
values: Record<string, string>,
|
|
36
|
+
config: PzSegmentsConfig
|
|
37
|
+
): string {
|
|
38
|
+
return config.segments
|
|
39
|
+
.map((seg) => values[seg.name] ?? '')
|
|
40
|
+
.join(config.separator);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function decodePzValue(
|
|
44
|
+
pzValue: string,
|
|
45
|
+
config: PzSegmentsConfig
|
|
46
|
+
): Record<string, string> {
|
|
47
|
+
const parts = pzValue.split(config.separator);
|
|
48
|
+
const result: Record<string, string> = {};
|
|
49
|
+
|
|
50
|
+
config.segments.forEach((seg, index) => {
|
|
51
|
+
result[seg.name] = parts[index] ?? '';
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
return result;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function getBuiltInSegments(
|
|
58
|
+
parsed: Record<string, string>,
|
|
59
|
+
settings: any
|
|
60
|
+
): { locale: string; currency: string; url: string } {
|
|
61
|
+
const { defaultLocaleValue, defaultCurrencyCode } = settings.localization;
|
|
62
|
+
|
|
63
|
+
return {
|
|
64
|
+
locale: parsed.locale || defaultLocaleValue,
|
|
65
|
+
currency: parsed.currency || defaultCurrencyCode,
|
|
66
|
+
url: parsed.url ? decodeURIComponent(parsed.url) : ''
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export function parsePzParams(
|
|
71
|
+
params: { pz?: string; locale?: string; currency?: string; url?: string },
|
|
72
|
+
settings: any
|
|
73
|
+
): { locale: string; currency: string; url: string; [key: string]: string } {
|
|
74
|
+
if (isLegacyMode(settings)) {
|
|
75
|
+
return {
|
|
76
|
+
locale:
|
|
77
|
+
params.locale ?? settings.localization.defaultLocaleValue,
|
|
78
|
+
currency:
|
|
79
|
+
params.currency ?? settings.localization.defaultCurrencyCode,
|
|
80
|
+
url: params.url ? decodeURIComponent(params.url) : ''
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const config = getPzSegmentsConfig(settings);
|
|
85
|
+
const parsed = decodePzValue(params.pz ?? '', config);
|
|
86
|
+
const builtIn = getBuiltInSegments(parsed, settings);
|
|
87
|
+
|
|
88
|
+
return {
|
|
89
|
+
...parsed,
|
|
90
|
+
...builtIn
|
|
91
|
+
};
|
|
92
|
+
}
|