@akinon/next 2.0.0-beta.9 → 2.0.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 +434 -23
- package/__tests__/next-config.test.ts +83 -0
- package/__tests__/tsconfig.json +23 -0
- package/api/auth.ts +367 -63
- 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/components/accordion.tsx +21 -6
- package/components/client-root.tsx +119 -3
- package/components/file-input.tsx +65 -3
- package/components/index.ts +1 -0
- package/components/input.tsx +2 -2
- 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 +3 -3
- package/components/selected-payment-option-view.tsx +21 -0
- package/data/client/account.ts +17 -2
- package/data/client/basket.ts +39 -0
- package/data/client/checkout.ts +336 -99
- package/data/client/misc.ts +13 -1
- 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 +71 -1
- package/data/urls.ts +6 -3
- package/hocs/client/with-segment-defaults.tsx +2 -2
- package/hocs/server/with-segment-defaults.tsx +81 -20
- package/hooks/index.ts +3 -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 +53 -19
- package/instrumentation/index.ts +0 -1
- package/instrumentation/node.ts +2 -20
- package/jest.config.js +25 -0
- package/lib/cache-handler.mjs +534 -16
- package/lib/cache.ts +269 -34
- 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 +357 -203
- package/middlewares/index.ts +10 -2
- package/middlewares/locale.ts +5 -3
- 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 +9 -15
- package/middlewares/wallet-complete-redirection.ts +206 -0
- package/package.json +24 -10
- package/plugins.d.ts +19 -4
- package/plugins.js +9 -1
- package/redux/actions.ts +47 -0
- package/redux/middlewares/checkout.ts +61 -8
- package/redux/middlewares/index.ts +14 -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 +15 -1
- package/redux/reducers/index.ts +7 -1
- package/redux/reducers/widget.ts +80 -0
- package/sentry/index.ts +54 -17
- package/tailwind/content.js +16 -0
- package/types/commerce/checkout.ts +26 -1
- package/types/commerce/widget.ts +33 -0
- package/types/index.ts +114 -5
- 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 +69 -18
- package/utils/mobile-3d-iframe.ts +8 -2
- 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/utils/redirection-iframe.ts +8 -2
- package/utils/widget-styles.ts +107 -0
- package/with-pz-config.js +20 -7
package/redux/reducers/index.ts
CHANGED
|
@@ -2,12 +2,15 @@ import rootReducer from './root';
|
|
|
2
2
|
import checkoutReducer from './checkout';
|
|
3
3
|
import configReducer from './config';
|
|
4
4
|
import headerReducer from './header';
|
|
5
|
+
import widgetReducer from './widget';
|
|
5
6
|
import { api } from '../../data/client/api';
|
|
6
7
|
|
|
7
8
|
// Plugin reducers
|
|
8
9
|
import { masterpassReducer } from '@akinon/pz-masterpass';
|
|
9
10
|
import { otpReducer } from '@akinon/pz-otp';
|
|
10
11
|
import { savedCardReducer } from '@akinon/pz-saved-card';
|
|
12
|
+
import cyberSourceUcReducer from '@akinon/pz-cybersource-uc/src/redux/reducer';
|
|
13
|
+
import { masterpassRestReducer } from '@akinon/pz-masterpass-rest';
|
|
11
14
|
|
|
12
15
|
const fallbackReducer = (state = {}) => state;
|
|
13
16
|
|
|
@@ -17,9 +20,12 @@ const reducers = {
|
|
|
17
20
|
checkout: checkoutReducer,
|
|
18
21
|
config: configReducer,
|
|
19
22
|
header: headerReducer,
|
|
23
|
+
widget: widgetReducer,
|
|
20
24
|
masterpass: masterpassReducer || fallbackReducer,
|
|
21
25
|
otp: otpReducer || fallbackReducer,
|
|
22
|
-
savedCard: savedCardReducer || fallbackReducer
|
|
26
|
+
savedCard: savedCardReducer || fallbackReducer,
|
|
27
|
+
cybersource_uc: cyberSourceUcReducer || fallbackReducer,
|
|
28
|
+
masterpassRest: masterpassRestReducer || fallbackReducer
|
|
23
29
|
};
|
|
24
30
|
|
|
25
31
|
export default reducers;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { createSlice, PayloadAction } from '@reduxjs/toolkit';
|
|
2
|
+
import { WidgetComponentData, WidgetDataSource } from '../../types/widget';
|
|
3
|
+
|
|
4
|
+
export interface WidgetState {
|
|
5
|
+
designMode: boolean;
|
|
6
|
+
responsive: string;
|
|
7
|
+
components: WidgetComponentData[];
|
|
8
|
+
placeholders: {
|
|
9
|
+
slug: string;
|
|
10
|
+
widgetSlugs: string[];
|
|
11
|
+
}[];
|
|
12
|
+
selectedPlaceholder?: string;
|
|
13
|
+
selectedWidget?: string;
|
|
14
|
+
selectedComponentId?: string;
|
|
15
|
+
draggingActive?: boolean;
|
|
16
|
+
dataSources: WidgetDataSource[];
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const initialState: WidgetState = {
|
|
20
|
+
designMode: true,
|
|
21
|
+
responsive: 'mobile',
|
|
22
|
+
components: [],
|
|
23
|
+
placeholders: [],
|
|
24
|
+
selectedPlaceholder: undefined,
|
|
25
|
+
selectedWidget: undefined,
|
|
26
|
+
selectedComponentId: undefined,
|
|
27
|
+
draggingActive: false,
|
|
28
|
+
dataSources: []
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const widgetSlice = createSlice({
|
|
32
|
+
name: 'widget',
|
|
33
|
+
initialState,
|
|
34
|
+
reducers: {
|
|
35
|
+
setDesignMode(state, { payload }: PayloadAction<boolean>) {
|
|
36
|
+
state.designMode = payload;
|
|
37
|
+
},
|
|
38
|
+
setResponsive(state, { payload }: PayloadAction<string>) {
|
|
39
|
+
state.responsive = payload;
|
|
40
|
+
},
|
|
41
|
+
setComponents(state, { payload }: PayloadAction<WidgetComponentData[]>) {
|
|
42
|
+
state.components = payload;
|
|
43
|
+
},
|
|
44
|
+
setPlaceholders(
|
|
45
|
+
state,
|
|
46
|
+
{ payload }: PayloadAction<WidgetState['placeholders']>
|
|
47
|
+
) {
|
|
48
|
+
state.placeholders = payload;
|
|
49
|
+
},
|
|
50
|
+
setSelectedPlaceholder(state, { payload }: PayloadAction<string>) {
|
|
51
|
+
state.selectedPlaceholder = payload;
|
|
52
|
+
},
|
|
53
|
+
setSelectedWidget(state, { payload }: PayloadAction<string>) {
|
|
54
|
+
state.selectedWidget = payload;
|
|
55
|
+
},
|
|
56
|
+
setSelectedComponentId(state, { payload }: PayloadAction<string>) {
|
|
57
|
+
state.selectedComponentId = payload;
|
|
58
|
+
},
|
|
59
|
+
setDraggingActive(state, { payload }: PayloadAction<boolean>) {
|
|
60
|
+
state.draggingActive = payload;
|
|
61
|
+
},
|
|
62
|
+
setDataSources(state, { payload }: PayloadAction<WidgetDataSource[]>) {
|
|
63
|
+
state.dataSources = payload;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
export const {
|
|
69
|
+
setDesignMode,
|
|
70
|
+
setResponsive,
|
|
71
|
+
setComponents,
|
|
72
|
+
setPlaceholders,
|
|
73
|
+
setSelectedPlaceholder,
|
|
74
|
+
setSelectedWidget,
|
|
75
|
+
setSelectedComponentId,
|
|
76
|
+
setDraggingActive,
|
|
77
|
+
setDataSources
|
|
78
|
+
} = widgetSlice.actions;
|
|
79
|
+
|
|
80
|
+
export default widgetSlice.reducer;
|
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
|
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
const defaultPlugins = require('../plugins');
|
|
2
|
+
|
|
3
|
+
const getAkinonNextContent = (plugins = defaultPlugins) => {
|
|
4
|
+
return [
|
|
5
|
+
`./node_modules/@akinon/next/components/**/*.{js,ts,jsx,tsx}`,
|
|
6
|
+
`../../node_modules/@akinon/next/components/**/*.{js,ts,jsx,tsx}`,
|
|
7
|
+
...plugins
|
|
8
|
+
.map((plugin) => [
|
|
9
|
+
`./node_modules/@akinon/${plugin}/**/*.{js,ts,jsx,tsx}`,
|
|
10
|
+
`../../node_modules/@akinon/${plugin}/**/*.{js,ts,jsx,tsx}`
|
|
11
|
+
])
|
|
12
|
+
.flat()
|
|
13
|
+
];
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
module.exports = getAkinonNextContent;
|
|
@@ -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 {
|
|
@@ -68,6 +68,18 @@ export interface CheckoutPaymentOption {
|
|
|
68
68
|
viewProps?: any;
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
+
export interface LoyaltyBalanceItem {
|
|
72
|
+
label_id: number | null;
|
|
73
|
+
label: string | null;
|
|
74
|
+
balance: string;
|
|
75
|
+
currency?: string;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export interface AccountUsage {
|
|
79
|
+
label_id: number | null;
|
|
80
|
+
amount: number;
|
|
81
|
+
}
|
|
82
|
+
|
|
71
83
|
export interface GiftBox {
|
|
72
84
|
note: string;
|
|
73
85
|
gift_video: boolean;
|
|
@@ -91,6 +103,7 @@ export interface PreOrder {
|
|
|
91
103
|
notes?: string;
|
|
92
104
|
user_phone_number?: string;
|
|
93
105
|
loyalty_money?: string;
|
|
106
|
+
loyalty_account_usages?: AccountUsage[];
|
|
94
107
|
currency_type_label?: string;
|
|
95
108
|
is_guest?: boolean;
|
|
96
109
|
is_post_order?: boolean;
|
|
@@ -109,6 +122,7 @@ export interface PreOrder {
|
|
|
109
122
|
token?: string;
|
|
110
123
|
agreement_confirmed?: boolean;
|
|
111
124
|
phone_number?: string;
|
|
125
|
+
number?: string;
|
|
112
126
|
}
|
|
113
127
|
|
|
114
128
|
export type ExtraField = Record<string, any>;
|
|
@@ -150,6 +164,8 @@ export interface CheckoutContext {
|
|
|
150
164
|
redirect_url?: string;
|
|
151
165
|
context_data?: any;
|
|
152
166
|
balance?: string;
|
|
167
|
+
balances?: LoyaltyBalanceItem[];
|
|
168
|
+
accounts?: LoyaltyBalanceItem[];
|
|
153
169
|
attribute_based_shipping_options?: AttributeBasedShippingOption[];
|
|
154
170
|
paymentData?: any;
|
|
155
171
|
paymentMethod?: string;
|
|
@@ -202,6 +218,15 @@ export interface MiddlewareParams {
|
|
|
202
218
|
dispatch: TypedDispatch;
|
|
203
219
|
}
|
|
204
220
|
|
|
221
|
+
export interface MiddlewareAction {
|
|
222
|
+
type: string;
|
|
223
|
+
payload?: { status?: number; [key: string]: unknown };
|
|
224
|
+
meta?: {
|
|
225
|
+
arg?: { endpointName?: string };
|
|
226
|
+
baseQueryMeta?: { request?: { url?: string } };
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
|
|
205
230
|
export type SendSmsType = {
|
|
206
231
|
phone_number: string;
|
|
207
232
|
};
|
package/types/commerce/widget.ts
CHANGED
|
@@ -26,3 +26,36 @@ export type WidgetResultType<T> = {
|
|
|
26
26
|
slug?: string;
|
|
27
27
|
template?: string;
|
|
28
28
|
};
|
|
29
|
+
|
|
30
|
+
export type WidgetSchemaType<T> = {
|
|
31
|
+
pk?: number;
|
|
32
|
+
name?: string;
|
|
33
|
+
schema?: T;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export type DynamicWidgetResultType = WidgetResultType<{
|
|
37
|
+
[key: string]: {
|
|
38
|
+
value: string;
|
|
39
|
+
kwargs: {
|
|
40
|
+
data_type: string;
|
|
41
|
+
value?: string;
|
|
42
|
+
url?: string;
|
|
43
|
+
};
|
|
44
|
+
};
|
|
45
|
+
}>;
|
|
46
|
+
|
|
47
|
+
export type DynamicWidgetSchemaType = WidgetSchemaType<{
|
|
48
|
+
[key: string]: {
|
|
49
|
+
key: string;
|
|
50
|
+
data_type: string;
|
|
51
|
+
label: string;
|
|
52
|
+
properties: {
|
|
53
|
+
parent_id?: string;
|
|
54
|
+
style?: {
|
|
55
|
+
[key: string]: any;
|
|
56
|
+
};
|
|
57
|
+
tag?: string;
|
|
58
|
+
type?: string;
|
|
59
|
+
};
|
|
60
|
+
};
|
|
61
|
+
}>;
|
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,12 +212,26 @@ export interface Settings {
|
|
|
209
212
|
*/
|
|
210
213
|
resetBasketOnCurrencyChange?: boolean;
|
|
211
214
|
frontendIds?: Record<string, number>;
|
|
215
|
+
usePzSegment?: boolean;
|
|
216
|
+
pzSegments?: {
|
|
217
|
+
separator?: string;
|
|
218
|
+
segments: PzSegmentDefinition[];
|
|
219
|
+
};
|
|
212
220
|
}
|
|
213
221
|
|
|
214
222
|
export interface CacheOptions {
|
|
215
223
|
cache?: boolean;
|
|
216
224
|
expire?: number;
|
|
217
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';
|
|
218
235
|
}
|
|
219
236
|
|
|
220
237
|
export interface ClientRequestOptions {
|
|
@@ -239,22 +256,87 @@ export type ImageOptions = CDNOptions & {
|
|
|
239
256
|
|
|
240
257
|
export type Translations = { [key: string]: object };
|
|
241
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
|
+
// Search params type compatible with both Next.js resolved searchParams and URLSearchParams
|
|
279
|
+
export type SearchParams = Record<string, string | string[] | undefined> | URLSearchParams;
|
|
280
|
+
|
|
281
|
+
// Raw Next 16 server prop shape, used at the middleware/HOC boundary before normalization
|
|
282
|
+
export type RawSearchParams = Record<string, string | string[] | undefined>;
|
|
283
|
+
|
|
284
|
+
// Page/Layout props — sync params for backward compatibility with v1 brands.
|
|
285
|
+
// `searchParams` is always exposed as `URLSearchParams` (matching v1 behavior).
|
|
286
|
+
// The server HOC normalizes Next 16's raw Record into a URLSearchParams instance.
|
|
242
287
|
export interface PageProps<T = any> {
|
|
243
|
-
params:
|
|
244
|
-
|
|
288
|
+
params: T & {
|
|
289
|
+
pz?: string;
|
|
290
|
+
commerce?: string;
|
|
291
|
+
locale?: string;
|
|
292
|
+
currency?: string;
|
|
293
|
+
url?: string;
|
|
294
|
+
[key: string]: any;
|
|
295
|
+
};
|
|
296
|
+
searchParams: URLSearchParams;
|
|
245
297
|
}
|
|
246
298
|
|
|
247
299
|
export interface LayoutProps<T = any> extends PageProps<T> {
|
|
248
300
|
children: React.ReactNode;
|
|
249
301
|
}
|
|
250
302
|
|
|
251
|
-
export interface RootLayoutProps<
|
|
303
|
+
export interface RootLayoutProps<T = any> extends LayoutProps<T> {
|
|
304
|
+
translations: Translations;
|
|
305
|
+
locale: Locale & {
|
|
306
|
+
isoCode: string;
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
// Async versions for Next.js 16 generateMetadata and internal use
|
|
311
|
+
export interface AsyncPageProps<T = any> {
|
|
312
|
+
params: Promise<T & {
|
|
313
|
+
pz?: string;
|
|
314
|
+
commerce?: string;
|
|
315
|
+
locale?: string;
|
|
316
|
+
currency?: string;
|
|
317
|
+
url?: string;
|
|
318
|
+
[key: string]: any;
|
|
319
|
+
}>;
|
|
320
|
+
searchParams: Promise<{ [key: string]: string | string[] | undefined }>;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// Resolved (sync) versions for inner components after withSegmentDefaults resolves props
|
|
324
|
+
export interface ResolvedPageProps<T = any> {
|
|
325
|
+
params: T & { locale: string; currency: string };
|
|
326
|
+
searchParams: URLSearchParams;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
export interface ResolvedLayoutProps<T = any> extends ResolvedPageProps<T> {
|
|
330
|
+
children: React.ReactNode;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
export interface ResolvedRootLayoutProps<
|
|
252
334
|
T = {
|
|
253
335
|
commerce: string;
|
|
254
336
|
locale: string;
|
|
255
337
|
currency: string;
|
|
256
338
|
}
|
|
257
|
-
> extends
|
|
339
|
+
> extends ResolvedLayoutProps<T> {
|
|
258
340
|
translations: Translations;
|
|
259
341
|
locale: Locale & {
|
|
260
342
|
isoCode: string;
|
|
@@ -282,7 +364,13 @@ export interface ButtonProps
|
|
|
282
364
|
target?: '_blank' | '_self' | '_parent' | '_top';
|
|
283
365
|
}
|
|
284
366
|
|
|
285
|
-
export
|
|
367
|
+
export interface FileInputProps extends React.HTMLProps<HTMLInputElement> {
|
|
368
|
+
fileClassName?: string;
|
|
369
|
+
fileNameWrapperClassName?: string;
|
|
370
|
+
fileInputClassName?: string;
|
|
371
|
+
onChange?: (event: React.ChangeEvent<HTMLInputElement>) => void;
|
|
372
|
+
buttonClassName?: string;
|
|
373
|
+
}
|
|
286
374
|
|
|
287
375
|
export interface PriceProps {
|
|
288
376
|
currencyCode?: string;
|
|
@@ -303,15 +391,19 @@ export interface InputProps extends React.HTMLProps<HTMLInputElement> {
|
|
|
303
391
|
|
|
304
392
|
export interface AccordionProps {
|
|
305
393
|
isCollapse?: boolean;
|
|
394
|
+
collapseClassName?: string;
|
|
306
395
|
title?: string;
|
|
307
396
|
subTitle?: string;
|
|
308
397
|
icons?: string[];
|
|
309
398
|
iconSize?: number;
|
|
310
399
|
iconColor?: string;
|
|
311
400
|
children?: ReactNode;
|
|
401
|
+
headerClassName?: string;
|
|
312
402
|
className?: string;
|
|
313
403
|
titleClassName?: string;
|
|
404
|
+
subTitleClassName?: string;
|
|
314
405
|
dataTestId?: string;
|
|
406
|
+
contentClassName?: string;
|
|
315
407
|
}
|
|
316
408
|
|
|
317
409
|
export interface PluginModuleComponentProps {
|
|
@@ -336,3 +428,20 @@ export interface PaginationProps {
|
|
|
336
428
|
direction?: 'next' | 'prev';
|
|
337
429
|
isLoading?: boolean;
|
|
338
430
|
}
|
|
431
|
+
|
|
432
|
+
export interface ModalProps {
|
|
433
|
+
portalId: string;
|
|
434
|
+
children?: React.ReactNode;
|
|
435
|
+
open?: boolean;
|
|
436
|
+
setOpen?: (open: boolean) => void;
|
|
437
|
+
title?: React.ReactNode;
|
|
438
|
+
showCloseButton?: React.ReactNode;
|
|
439
|
+
className?: string;
|
|
440
|
+
overlayClassName?: string;
|
|
441
|
+
headerWrapperClassName?: string;
|
|
442
|
+
titleClassName?: string;
|
|
443
|
+
closeButtonClassName?: string;
|
|
444
|
+
iconName?: string;
|
|
445
|
+
iconSize?: number;
|
|
446
|
+
iconClassName?: string;
|
|
447
|
+
}
|
package/types/next-auth.d.ts
CHANGED
package/types/widget.ts
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
export type WidgetStyle = {
|
|
2
|
+
[breakpoint: string]: Record<string, string>;
|
|
3
|
+
};
|
|
4
|
+
|
|
5
|
+
export enum WidgetDataSourceType {
|
|
6
|
+
COLLECTION = 'collection',
|
|
7
|
+
API = 'api',
|
|
8
|
+
STATIC = 'static'
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface WidgetDataSource {
|
|
12
|
+
type: WidgetDataSourceType;
|
|
13
|
+
id: string;
|
|
14
|
+
widgetSlug?: string;
|
|
15
|
+
details: {
|
|
16
|
+
collection?: {
|
|
17
|
+
pk: number;
|
|
18
|
+
productLimit: number;
|
|
19
|
+
};
|
|
20
|
+
api?: {
|
|
21
|
+
url: string;
|
|
22
|
+
method: string;
|
|
23
|
+
headers: Record<string, string>;
|
|
24
|
+
body: Record<string, string>;
|
|
25
|
+
};
|
|
26
|
+
static?: {
|
|
27
|
+
name: string;
|
|
28
|
+
data: Record<string, any>;
|
|
29
|
+
};
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export type ImageSrc = {
|
|
34
|
+
[key: string]: {
|
|
35
|
+
src: string;
|
|
36
|
+
dimensions: { width: number; height: number };
|
|
37
|
+
};
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
export type WidgetComponentData = {
|
|
41
|
+
id: string;
|
|
42
|
+
widgetSlug: string;
|
|
43
|
+
type: string;
|
|
44
|
+
tag: string;
|
|
45
|
+
style: WidgetStyle;
|
|
46
|
+
value: {
|
|
47
|
+
text?: string;
|
|
48
|
+
src?: string;
|
|
49
|
+
alt?: string;
|
|
50
|
+
title?: string;
|
|
51
|
+
url?: string;
|
|
52
|
+
type?: string;
|
|
53
|
+
width?: string;
|
|
54
|
+
height?: string;
|
|
55
|
+
autoplay?: boolean;
|
|
56
|
+
controls?: boolean;
|
|
57
|
+
muted?: boolean;
|
|
58
|
+
loop?: boolean;
|
|
59
|
+
[key: string]: any;
|
|
60
|
+
};
|
|
61
|
+
parentId: string | null;
|
|
62
|
+
iteratingNode: string;
|
|
63
|
+
iteratorValue: string;
|
|
64
|
+
iteratingValue: string;
|
|
65
|
+
selectedDataSourceId: string;
|
|
66
|
+
dataSources: WidgetDataSource[];
|
|
67
|
+
imageSrc?: ImageSrc;
|
|
68
|
+
href?: string;
|
|
69
|
+
target?: string;
|
|
70
|
+
slider?: {
|
|
71
|
+
items?: number;
|
|
72
|
+
slidesToSlide?: number;
|
|
73
|
+
autoPlay?: boolean;
|
|
74
|
+
autoPlaySpeed?: number;
|
|
75
|
+
infinite?: boolean;
|
|
76
|
+
showDots?: boolean;
|
|
77
|
+
arrows?: boolean;
|
|
78
|
+
itemsToShow?: number;
|
|
79
|
+
};
|
|
80
|
+
};
|
package/utils/app-fetch.ts
CHANGED
|
@@ -2,6 +2,7 @@ import Settings from 'settings';
|
|
|
2
2
|
import logger from '../utils/log';
|
|
3
3
|
import { headers, cookies } from 'next/headers';
|
|
4
4
|
import { ServerVariables } from './server-variables';
|
|
5
|
+
import { notFound } from 'next/navigation';
|
|
5
6
|
|
|
6
7
|
export enum FetchResponseType {
|
|
7
8
|
JSON = 'json',
|
|
@@ -43,12 +44,12 @@ const appFetch = async <T>({
|
|
|
43
44
|
const requestURL = `${decodeURIComponent(commerceUrl)}${url}`;
|
|
44
45
|
|
|
45
46
|
init.headers = {
|
|
47
|
+
cookie: nextCookies.toString(),
|
|
46
48
|
...(init.headers ?? {}),
|
|
47
49
|
...(ServerVariables.globalHeaders ?? {}),
|
|
48
50
|
'Accept-Language': currentLocale.apiValue,
|
|
49
51
|
'x-currency': currency,
|
|
50
|
-
'x-forwarded-for': ip
|
|
51
|
-
cookie: nextCookies.toString()
|
|
52
|
+
'x-forwarded-for': ip
|
|
52
53
|
};
|
|
53
54
|
|
|
54
55
|
init.next = {
|
|
@@ -75,6 +76,10 @@ const appFetch = async <T>({
|
|
|
75
76
|
}
|
|
76
77
|
}
|
|
77
78
|
|
|
79
|
+
if (status === 422) {
|
|
80
|
+
notFound();
|
|
81
|
+
}
|
|
82
|
+
|
|
78
83
|
return response;
|
|
79
84
|
};
|
|
80
85
|
|
|
@@ -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') {
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import Settings from 'settings';
|
|
2
|
+
|
|
3
|
+
export default function getRootHostname(
|
|
4
|
+
url: string | undefined
|
|
5
|
+
): string | null {
|
|
6
|
+
if (!url) return null;
|
|
7
|
+
|
|
8
|
+
try {
|
|
9
|
+
const urlObj = new URL(url);
|
|
10
|
+
const hostname = urlObj.hostname;
|
|
11
|
+
const parts = hostname.split('.');
|
|
12
|
+
|
|
13
|
+
const firstPart = parts[0];
|
|
14
|
+
|
|
15
|
+
const isLocale = Settings.localization.locales.some(
|
|
16
|
+
(locale) => locale.value === firstPart
|
|
17
|
+
);
|
|
18
|
+
|
|
19
|
+
if (isLocale) {
|
|
20
|
+
const hostnameAfterLocale = parts.slice(1).join('.');
|
|
21
|
+
return `.${hostnameAfterLocale}`;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return `.${hostname}`;
|
|
25
|
+
} catch {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
}
|