@akinon/next 1.82.0-rc.2 → 1.82.0-rc.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.js +12 -0
- package/CHANGELOG.md +136 -0
- package/api/auth.ts +15 -0
- package/components/client-root.tsx +20 -0
- package/data/client/basket.ts +60 -16
- package/data/client/misc.ts +25 -1
- package/data/client/product.ts +17 -1
- package/data/urls.ts +8 -2
- package/hooks/index.ts +1 -0
- package/hooks/use-router.ts +5 -2
- package/hooks/use-sentry-uncaught-errors.ts +24 -0
- package/instrumentation/index.ts +3 -0
- package/instrumentation/node.ts +15 -13
- package/localization/index.ts +2 -1
- package/middlewares/locale.ts +31 -10
- package/package.json +3 -2
- package/redux/middlewares/checkout.ts +0 -142
- package/redux/middlewares/pre-order/address.ts +2 -0
- package/redux/middlewares/pre-order/attribute-based-shipping-option.ts +2 -0
- package/redux/middlewares/pre-order/data-source-shipping-option.ts +2 -0
- package/redux/middlewares/pre-order/delivery-option.ts +2 -0
- package/redux/middlewares/pre-order/index.ts +14 -10
- package/redux/middlewares/pre-order/installment-option.ts +2 -0
- package/redux/middlewares/pre-order/payment-option.ts +2 -0
- package/redux/middlewares/pre-order/redirection.ts +2 -0
- package/redux/middlewares/pre-order/shipping-option.ts +2 -0
- package/sentry/index.ts +36 -17
- package/utils/index.ts +11 -8
- package/utils/localization.ts +4 -0
- package/views/error-page.tsx +92 -0
package/.eslintrc.js
CHANGED
|
@@ -24,6 +24,18 @@ module.exports = {
|
|
|
24
24
|
parserOptions: {
|
|
25
25
|
sourceType: 'script'
|
|
26
26
|
}
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
env: {
|
|
30
|
+
node: true
|
|
31
|
+
},
|
|
32
|
+
files: ['redux/middlewares/pre-order/index.ts'],
|
|
33
|
+
rules: {
|
|
34
|
+
'@akinon/projectzero/check-pre-order-middleware-order': 'error'
|
|
35
|
+
},
|
|
36
|
+
parserOptions: {
|
|
37
|
+
sourceType: 'script'
|
|
38
|
+
}
|
|
27
39
|
}
|
|
28
40
|
],
|
|
29
41
|
parser: '@typescript-eslint/parser',
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,141 @@
|
|
|
1
1
|
# @akinon/next
|
|
2
2
|
|
|
3
|
+
## 1.82.0-rc.20
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- e5529cd: ZERO-3267: Update error-page component to use root path for links instead of ROUTES
|
|
8
|
+
|
|
9
|
+
## 1.82.0-rc.19
|
|
10
|
+
|
|
11
|
+
### Minor Changes
|
|
12
|
+
|
|
13
|
+
- 33377cf: ZERO-3267: Refactor import statement for ROUTES in error-page component
|
|
14
|
+
|
|
15
|
+
## 1.82.0-rc.18
|
|
16
|
+
|
|
17
|
+
### Minor Changes
|
|
18
|
+
|
|
19
|
+
- e4761d2: Refactor import statement for ROUTES in error-page component
|
|
20
|
+
|
|
21
|
+
## 1.82.0-rc.17
|
|
22
|
+
|
|
23
|
+
### Minor Changes
|
|
24
|
+
|
|
25
|
+
- e2c6d426: ZERO-2935: Add @sentry/nextjs dependency to akinon-next and remove from projectzeronext
|
|
26
|
+
- 70bc0aed: ZERO-3284: Set tracesSampleRate in Sentry configuration
|
|
27
|
+
|
|
28
|
+
## 1.82.0-rc.16
|
|
29
|
+
|
|
30
|
+
### Minor Changes
|
|
31
|
+
|
|
32
|
+
- 757ee539: ZERO-3207: Add SMS send & verify endpoints with state management
|
|
33
|
+
- 6f506af: ZERO-3229: Implement mini basket query for basket total quantity
|
|
34
|
+
- 5dfeea04: ZERO-2801: Revert ZERO-2801
|
|
35
|
+
- 2d9b2b2c: ZERO-2816: Add segment to headers
|
|
36
|
+
- 5e1feca: Revert "ZERO-3286: Add notFound handling for chunk URLs starting with \_next"
|
|
37
|
+
- c0c1962: ZERO-3258: Add new API endpoints for fetching Bukalemun image URL and bundle product data
|
|
38
|
+
- 40a46853: ZERO-3182: Optimize basket update mutation with optimistic update
|
|
39
|
+
- f49bb74f: ZERO-3097: Add setCookie to logging in payment redirection middlewares
|
|
40
|
+
- 0e05135: ZERO-3244: Encode URL search parameters
|
|
41
|
+
- e9541a13: ZERO-2816: Add headers to url
|
|
42
|
+
- 4d3deb4f: ZERO-2935: sentry 8 upgrade
|
|
43
|
+
- 72fd4d67: ZERO-3084: Fix URL search parameters encoding in default middleware
|
|
44
|
+
- c53ef7b9: ZERO-2668: The Link component has been updated to improve the logic for handling href values. Previously, if the href was not a string or started with 'http', it would return the href as is. Now, if the href is not provided, it will default to '#' to prevent any potential errors. Additionally, if the href is a string and does not start with 'http', it will be formatted with the locale and pathname, based on the localeUrlStrategy and defaultLocaleValue. This ensures that the correct href is generated based on the localization settings.
|
|
45
|
+
- 64699d3f: ZERO-2761: Fix invalid import for plugin module
|
|
46
|
+
- 9abd011: ZERO-3267: Refactor error handling in ErrorPage component to set error details in Sentry scope
|
|
47
|
+
- 7727ae55: ZERO-3073: Refactor basket page to use server-side data fetching and simplify component structure
|
|
48
|
+
- d552629: ZERO-3182: Refactor basketApi to use invalidatesTags and comment out onQueryStarted logic
|
|
49
|
+
- c3b2f3f: ZERO-3267: Enable sentry client errors and filter them by log type
|
|
50
|
+
- 17f87524: ZERO-2816: Make the incoming currency lowercase
|
|
51
|
+
- 65d3b862: ZERO-3054: Update headers in appFetch
|
|
52
|
+
- bbe18b9f: ZERO-2575: Fix build error
|
|
53
|
+
- 17bfadc: ZERO-3275: Disable OpenTelemetry monitoring in production environment
|
|
54
|
+
- 4920742c: Disable getCachedTranslations
|
|
55
|
+
- b6e5b62: ZERO-3257: Enhance locale middleware to redirect using existing or default locale and support 303 status for POST requests
|
|
56
|
+
- ac65ca9: ZERO-3269: Enhance locale handling by adding Subdomain strategy and updating related functions
|
|
57
|
+
- 7e56d6b6: ZERO-2841: Update api tagTypes
|
|
58
|
+
- 43c182ee: ZERO-3054: Update Redis variable checks to conditionally include CACHE_SECRET
|
|
59
|
+
- 2d305aaf: ZERO-2935: Update Sentry configuration: remove hideSourceMaps option and add it to withPzConfig
|
|
60
|
+
- eeb20bea: Revert "ZERO-3054: Refactor cache handler to use custom Redis handler and implement key hashing"
|
|
61
|
+
- 3bf63c8: ZERO-3286: Add notFound handling for chunk URLs starting with \_next
|
|
62
|
+
- 9be2c08: ZERO-3243: Improve basket update query handling with optimistic updates
|
|
63
|
+
- f2c92d5c: ZERO-2816: Update cookie name
|
|
64
|
+
- 2f3588f: ZERO-3287: Add user session handling in authentication flow
|
|
65
|
+
- 7bd3d992: ZERO-2801: Refactor locale middleware to handle single locale configuration
|
|
66
|
+
- fdd255ee: ZERO-3054: Refactor cache handler to use custom Redis handler and implement key hashing
|
|
67
|
+
- 0b1bd07: ZERO-3240: Remove unused preOrderMiddleware
|
|
68
|
+
- 49eeebfa: ZERO-2909: Add deleteCollectionItem query to wishlistApi
|
|
69
|
+
- 3f9b8d7e: ZERO-2761: Update plugins.js for akinon-next
|
|
70
|
+
|
|
71
|
+
## 1.82.0-rc.15
|
|
72
|
+
|
|
73
|
+
### Minor Changes
|
|
74
|
+
|
|
75
|
+
- 2f3588fb: ZERO-3287: Add user session handling in authentication flow
|
|
76
|
+
|
|
77
|
+
## 1.82.0-rc.14
|
|
78
|
+
|
|
79
|
+
### Minor Changes
|
|
80
|
+
|
|
81
|
+
- 5e1feca: Revert "ZERO-3286: Add notFound handling for chunk URLs starting with \_next"
|
|
82
|
+
|
|
83
|
+
## 1.82.0-rc.13
|
|
84
|
+
|
|
85
|
+
### Minor Changes
|
|
86
|
+
|
|
87
|
+
- 3bf63c8: ZERO-3286: Add notFound handling for chunk URLs starting with \_next
|
|
88
|
+
|
|
89
|
+
## 1.82.0-rc.12
|
|
90
|
+
|
|
91
|
+
### Minor Changes
|
|
92
|
+
|
|
93
|
+
- ac65ca9: ZERO-3269: Enhance locale handling by adding Subdomain strategy and updating related functions
|
|
94
|
+
|
|
95
|
+
## 1.82.0-rc.11
|
|
96
|
+
|
|
97
|
+
## 1.82.0-rc.10
|
|
98
|
+
|
|
99
|
+
## 1.82.0-rc.9
|
|
100
|
+
|
|
101
|
+
### Minor Changes
|
|
102
|
+
|
|
103
|
+
- 9abd011: ZERO-3267: Refactor error handling in ErrorPage component to set error details in Sentry scope
|
|
104
|
+
|
|
105
|
+
## 1.82.0-rc.8
|
|
106
|
+
|
|
107
|
+
### Minor Changes
|
|
108
|
+
|
|
109
|
+
- 17bfadc: ZERO-3275: Disable OpenTelemetry monitoring in production environment
|
|
110
|
+
|
|
111
|
+
## 1.82.0-rc.7
|
|
112
|
+
|
|
113
|
+
### Minor Changes
|
|
114
|
+
|
|
115
|
+
- c3b2f3f: ZERO-3267: Enable sentry client errors and filter them by log type
|
|
116
|
+
|
|
117
|
+
## 1.82.0-rc.6
|
|
118
|
+
|
|
119
|
+
### Minor Changes
|
|
120
|
+
|
|
121
|
+
- 0b1bd07f: ZERO-3240: Remove unused preOrderMiddleware
|
|
122
|
+
|
|
123
|
+
## 1.82.0-rc.5
|
|
124
|
+
|
|
125
|
+
### Minor Changes
|
|
126
|
+
|
|
127
|
+
- 6f506afc: ZERO-3229: Implement mini basket query for basket total quantity
|
|
128
|
+
- c0c19629: ZERO-3258: Add new API endpoints for fetching Bukalemun image URL and bundle product data
|
|
129
|
+
- 9be2c081: ZERO-3243: Improve basket update query handling with optimistic updates
|
|
130
|
+
|
|
131
|
+
## 1.82.0-rc.4
|
|
132
|
+
|
|
133
|
+
### Minor Changes
|
|
134
|
+
|
|
135
|
+
- b6e5b624: ZERO-3257: Enhance locale middleware to redirect using existing or default locale and support 303 status for POST requests
|
|
136
|
+
|
|
137
|
+
## 1.82.0-rc.3
|
|
138
|
+
|
|
3
139
|
## 1.82.0-rc.2
|
|
4
140
|
|
|
5
141
|
### Minor Changes
|
package/api/auth.ts
CHANGED
|
@@ -99,6 +99,21 @@ const nextAuthOptions = (req: NextApiRequest, res: NextApiResponse) => {
|
|
|
99
99
|
userIp
|
|
100
100
|
});
|
|
101
101
|
|
|
102
|
+
const checkCurrentUser = await getCurrentUser(
|
|
103
|
+
req.cookies['osessionid'] ?? '',
|
|
104
|
+
req.cookies['pz-currency'] ?? ''
|
|
105
|
+
);
|
|
106
|
+
|
|
107
|
+
if (checkCurrentUser?.pk) {
|
|
108
|
+
const sessionCookie = headers
|
|
109
|
+
.get('cookie')
|
|
110
|
+
?.match(/osessionid=\w+/)?.[0]
|
|
111
|
+
.replace(/osessionid=/, '');
|
|
112
|
+
if (sessionCookie) {
|
|
113
|
+
headers.set('cookie', sessionCookie);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
102
117
|
const apiRequest = await fetch(
|
|
103
118
|
`${Settings.commerceUrl}${user[credentials.formType]}`,
|
|
104
119
|
{
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
3
|
import { useMobileIframeHandler } from '../hooks';
|
|
4
|
+
import * as Sentry from '@sentry/nextjs';
|
|
5
|
+
import { initSentry } from '../sentry';
|
|
6
|
+
import { useEffect } from 'react';
|
|
4
7
|
|
|
5
8
|
export default function ClientRoot({
|
|
6
9
|
children,
|
|
@@ -11,6 +14,23 @@ export default function ClientRoot({
|
|
|
11
14
|
}) {
|
|
12
15
|
const { preventPageRender } = useMobileIframeHandler({ sessionId });
|
|
13
16
|
|
|
17
|
+
const initializeSentry = async () => {
|
|
18
|
+
const response = await fetch('/api/sentry', { next: { revalidate: 0 } });
|
|
19
|
+
const data = await response.json();
|
|
20
|
+
|
|
21
|
+
const options = {
|
|
22
|
+
dsn: data.dsn
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
initSentry('Client', options);
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
useEffect(() => {
|
|
29
|
+
if (!Sentry.isInitialized()) {
|
|
30
|
+
initializeSentry();
|
|
31
|
+
}
|
|
32
|
+
}, []);
|
|
33
|
+
|
|
14
34
|
if (preventPageRender) {
|
|
15
35
|
return null;
|
|
16
36
|
}
|
package/data/client/basket.ts
CHANGED
|
@@ -24,6 +24,26 @@ export const basketApi = api.injectEndpoints({
|
|
|
24
24
|
transformResponse: (response: { basket: Basket }) => response.basket,
|
|
25
25
|
providesTags: ['Basket']
|
|
26
26
|
}),
|
|
27
|
+
getMiniBasket: build.query<
|
|
28
|
+
{ pk: number | null; total_quantity: number },
|
|
29
|
+
void
|
|
30
|
+
>({
|
|
31
|
+
query: () =>
|
|
32
|
+
buildClientRequestUrl(basket.getMiniBasket, {
|
|
33
|
+
contentType: 'application/json'
|
|
34
|
+
}),
|
|
35
|
+
providesTags: ['Basket']
|
|
36
|
+
}),
|
|
37
|
+
getMiniBasketDetail: build.query<
|
|
38
|
+
{ pk: number | null; total_quantity: number },
|
|
39
|
+
{ namespace: string }
|
|
40
|
+
>({
|
|
41
|
+
query: ({ namespace }) =>
|
|
42
|
+
buildClientRequestUrl(basket.getMiniBasketDetail(namespace), {
|
|
43
|
+
contentType: 'application/json'
|
|
44
|
+
}),
|
|
45
|
+
providesTags: ['MultiBasket']
|
|
46
|
+
}),
|
|
27
47
|
getBasketDetail: build.query<Basket, { namespace: string }>({
|
|
28
48
|
query: ({ namespace }) =>
|
|
29
49
|
buildClientRequestUrl(basket.getBasketDetail(namespace)),
|
|
@@ -84,23 +104,45 @@ export const basketApi = api.injectEndpoints({
|
|
|
84
104
|
method: 'PUT',
|
|
85
105
|
body
|
|
86
106
|
}),
|
|
87
|
-
|
|
88
|
-
|
|
107
|
+
async onQueryStarted(_, { dispatch, queryFulfilled }) {
|
|
108
|
+
try {
|
|
109
|
+
const { data } = await queryFulfilled;
|
|
110
|
+
|
|
111
|
+
dispatch(
|
|
112
|
+
basketApi.util.updateQueryData(
|
|
113
|
+
'getBasket',
|
|
114
|
+
undefined,
|
|
115
|
+
() => data.basket
|
|
116
|
+
)
|
|
117
|
+
);
|
|
89
118
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
119
|
+
if (data.basket.namespace) {
|
|
120
|
+
dispatch(
|
|
121
|
+
basketApi.util.updateQueryData(
|
|
122
|
+
'getBasketDetail',
|
|
123
|
+
{ namespace: data.basket.namespace },
|
|
124
|
+
() => data.basket
|
|
125
|
+
)
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
dispatch(
|
|
130
|
+
basketApi.util.updateQueryData(
|
|
131
|
+
'getAllBaskets',
|
|
132
|
+
undefined,
|
|
133
|
+
(baskets) => {
|
|
134
|
+
if (!baskets) return baskets;
|
|
135
|
+
|
|
136
|
+
return baskets.map((basket) =>
|
|
137
|
+
basket.pk === data.basket.pk ? data.basket : basket
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
)
|
|
141
|
+
);
|
|
142
|
+
} catch (error) {
|
|
143
|
+
console.error('Error updating quantity:', error);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
104
146
|
}),
|
|
105
147
|
clearBasket: build.mutation<Basket, void>({
|
|
106
148
|
query: (body) => ({
|
|
@@ -141,6 +183,8 @@ export const basketApi = api.injectEndpoints({
|
|
|
141
183
|
|
|
142
184
|
export const {
|
|
143
185
|
useGetBasketQuery,
|
|
186
|
+
useGetMiniBasketQuery,
|
|
187
|
+
useGetMiniBasketDetailQuery,
|
|
144
188
|
useLazyGetBasketDetailQuery,
|
|
145
189
|
useGetAllBasketsQuery,
|
|
146
190
|
useRemoveBasketMutation,
|
package/data/client/misc.ts
CHANGED
|
@@ -92,6 +92,29 @@ export const miscApi = api.injectEndpoints({
|
|
|
92
92
|
transformResponse: (response: { menu: MenuItemType[] }) => {
|
|
93
93
|
return response.menu;
|
|
94
94
|
}
|
|
95
|
+
}),
|
|
96
|
+
getBukalemunImageUrl: builder.query<
|
|
97
|
+
any,
|
|
98
|
+
{ current_chapter: string; sku: string; selected_attributes: any }
|
|
99
|
+
>({
|
|
100
|
+
query: ({ current_chapter, sku, selected_attributes }) => {
|
|
101
|
+
const data = {
|
|
102
|
+
...selected_attributes,
|
|
103
|
+
current_chapter,
|
|
104
|
+
sku
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
const params = new URLSearchParams(data);
|
|
108
|
+
|
|
109
|
+
return {
|
|
110
|
+
url: buildClientRequestUrl(
|
|
111
|
+
misc.bukalemunImageUrl(params.toString()),
|
|
112
|
+
{
|
|
113
|
+
responseType: 'json'
|
|
114
|
+
}
|
|
115
|
+
)
|
|
116
|
+
};
|
|
117
|
+
}
|
|
95
118
|
})
|
|
96
119
|
}),
|
|
97
120
|
overrideExisting: true
|
|
@@ -102,5 +125,6 @@ export const {
|
|
|
102
125
|
useEmailSubscriptionMutation,
|
|
103
126
|
useSetLanguageMutation,
|
|
104
127
|
useGetWidgetQuery,
|
|
105
|
-
useGetMenuQuery
|
|
128
|
+
useGetMenuQuery,
|
|
129
|
+
useGetBukalemunImageUrlQuery
|
|
106
130
|
} = miscApi;
|
package/data/client/product.ts
CHANGED
|
@@ -75,6 +75,21 @@ export const productApi = api.injectEndpoints({
|
|
|
75
75
|
query: (productPk) => ({
|
|
76
76
|
url: buildClientRequestUrl(product.installments(productPk))
|
|
77
77
|
})
|
|
78
|
+
}),
|
|
79
|
+
getBundleProductData: build.query<
|
|
80
|
+
any,
|
|
81
|
+
{ productPk: string; queryString: string }
|
|
82
|
+
>({
|
|
83
|
+
query: ({ productPk, queryString }) => {
|
|
84
|
+
return {
|
|
85
|
+
url: buildClientRequestUrl(
|
|
86
|
+
product.bundleProduct(productPk, queryString),
|
|
87
|
+
{
|
|
88
|
+
responseType: 'json'
|
|
89
|
+
}
|
|
90
|
+
)
|
|
91
|
+
};
|
|
92
|
+
}
|
|
78
93
|
})
|
|
79
94
|
}),
|
|
80
95
|
overrideExisting: true
|
|
@@ -85,5 +100,6 @@ export const {
|
|
|
85
100
|
useGetProductByPkQuery,
|
|
86
101
|
useGetRetailStoreStockMutation,
|
|
87
102
|
useGetInstallmentsQuery,
|
|
88
|
-
useGetProductByParamsQuery
|
|
103
|
+
useGetProductByParamsQuery,
|
|
104
|
+
useGetBundleProductDataQuery
|
|
89
105
|
} = productApi;
|
package/data/urls.ts
CHANGED
|
@@ -74,7 +74,10 @@ export const address = {
|
|
|
74
74
|
|
|
75
75
|
export const basket = {
|
|
76
76
|
getBasket: '/baskets/basket/',
|
|
77
|
+
getMiniBasket: '/baskets/basket/mini/',
|
|
77
78
|
getBasketDetail: (namespace: string) => `/baskets/basket/${namespace}/`,
|
|
79
|
+
getMiniBasketDetail: (namespace: string) =>
|
|
80
|
+
`/baskets/basket/${namespace}/mini/`,
|
|
78
81
|
getAllBaskets: '/baskets/basket-list/',
|
|
79
82
|
removeBasket: (pk: number) => `/baskets/basket-list/${pk}/`,
|
|
80
83
|
selectMainBasket: (pk: number) => `/baskets/basket-list/id/${pk}/main/`,
|
|
@@ -162,7 +165,8 @@ export const misc = {
|
|
|
162
165
|
parent ? `&parent=${parent}` : ''
|
|
163
166
|
}`,
|
|
164
167
|
cmsSeo: (slug: string | string[]) => `/cms/seo/?url=${slug ? slug : '/'}`,
|
|
165
|
-
setCurrency: '/users/activate-currency/'
|
|
168
|
+
setCurrency: '/users/activate-currency/',
|
|
169
|
+
bukalemunImageUrl: (params: string) => `/bukalemun/?${params}`
|
|
166
170
|
};
|
|
167
171
|
|
|
168
172
|
export const product = {
|
|
@@ -176,7 +180,9 @@ export const product = {
|
|
|
176
180
|
slug: (slug: string) => `/${slug}/`,
|
|
177
181
|
categoryUrl: (pk: number) => `/products/${pk}/category_nodes/?limit=1`,
|
|
178
182
|
breadcrumbUrl: (menuitemmodel: string) =>
|
|
179
|
-
`/menus/generate_breadcrumb/?item=${menuitemmodel}&generator_name=menu_item
|
|
183
|
+
`/menus/generate_breadcrumb/?item=${menuitemmodel}&generator_name=menu_item`,
|
|
184
|
+
bundleProduct: (productPk: string, queryString: string) =>
|
|
185
|
+
`/bundle-product/${productPk}/?${queryString}`
|
|
180
186
|
};
|
|
181
187
|
|
|
182
188
|
export const wishlist = {
|
package/hooks/index.ts
CHANGED
package/hooks/use-router.ts
CHANGED
|
@@ -27,8 +27,11 @@ export const useRouter = () => {
|
|
|
27
27
|
);
|
|
28
28
|
|
|
29
29
|
url.pathname = `${
|
|
30
|
-
|
|
31
|
-
|
|
30
|
+
localeUrlStrategy === LocaleUrlStrategy.Subdomain ||
|
|
31
|
+
(locale === defaultLocale?.value &&
|
|
32
|
+
[LocaleUrlStrategy.HideDefaultLocale].includes(
|
|
33
|
+
localeUrlStrategy as LocaleUrlStrategy
|
|
34
|
+
))
|
|
32
35
|
? ''
|
|
33
36
|
: `/${locale}`
|
|
34
37
|
}${pathnameWithoutLocale}`;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { useEffect } from 'react';
|
|
2
|
+
import * as Sentry from '@sentry/nextjs';
|
|
3
|
+
import { ClientLogType } from '@akinon/next/sentry';
|
|
4
|
+
|
|
5
|
+
export const useSentryUncaughtErrors = (error: Error & { digest?: string }) => {
|
|
6
|
+
useEffect(() => {
|
|
7
|
+
Sentry.withScope(function (scope) {
|
|
8
|
+
scope.setLevel('fatal');
|
|
9
|
+
scope.setTags({
|
|
10
|
+
APP_TYPE: 'ProjectZeroNext',
|
|
11
|
+
TYPE: 'Client',
|
|
12
|
+
LOG_TYPE: ClientLogType.UNCAUGHT_ERROR_PAGE
|
|
13
|
+
});
|
|
14
|
+
scope.setExtra('error', error);
|
|
15
|
+
|
|
16
|
+
const error_ = new Error('FATAL: Uncaught client error');
|
|
17
|
+
error_.name = 'UNCAUGHT_ERROR_PAGE';
|
|
18
|
+
|
|
19
|
+
Sentry.captureException(error_, {
|
|
20
|
+
fingerprint: ['UNCAUGHT_ERROR_PAGE', error.digest]
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
}, [error]);
|
|
24
|
+
};
|
package/instrumentation/index.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { initSentry } from '../sentry';
|
|
2
|
+
import * as Sentry from '@sentry/nextjs';
|
|
2
3
|
|
|
3
4
|
export async function register() {
|
|
4
5
|
if (process.env.NEXT_RUNTIME === 'nodejs') {
|
|
@@ -10,3 +11,5 @@ export async function register() {
|
|
|
10
11
|
initSentry('Edge');
|
|
11
12
|
}
|
|
12
13
|
}
|
|
14
|
+
|
|
15
|
+
export const onRequestError = Sentry.captureRequestError;
|
package/instrumentation/node.ts
CHANGED
|
@@ -4,17 +4,19 @@ import { Resource } from '@opentelemetry/resources';
|
|
|
4
4
|
import { SemanticResourceAttributes } from '@opentelemetry/semantic-conventions';
|
|
5
5
|
import { SimpleSpanProcessor } from '@opentelemetry/sdk-trace-node';
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
new
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
7
|
+
if (process.env.NODE_ENV === 'development') {
|
|
8
|
+
const sdk = new NodeSDK({
|
|
9
|
+
resource: new Resource({
|
|
10
|
+
[SemanticResourceAttributes.SERVICE_NAME]: 'pz-next-app'
|
|
11
|
+
}),
|
|
12
|
+
spanProcessor: new SimpleSpanProcessor(
|
|
13
|
+
new OTLPTraceExporter({
|
|
14
|
+
url: `${
|
|
15
|
+
process.env.PZ_DASHBOARD_URL ?? 'http://localhost:3005'
|
|
16
|
+
}/api/traces`
|
|
17
|
+
})
|
|
18
|
+
)
|
|
19
|
+
});
|
|
19
20
|
|
|
20
|
-
sdk.start();
|
|
21
|
+
sdk.start();
|
|
22
|
+
}
|
package/localization/index.ts
CHANGED
package/middlewares/locale.ts
CHANGED
|
@@ -4,17 +4,32 @@ import { PzNextRequest } from '.';
|
|
|
4
4
|
import { LocaleUrlStrategy } from '../localization';
|
|
5
5
|
import { urlLocaleMatcherRegex } from '../utils';
|
|
6
6
|
import logger from '../utils/log';
|
|
7
|
+
import { getUrlPathWithLocale } from '../utils/localization';
|
|
7
8
|
|
|
8
|
-
const getMatchedLocale = (pathname: string) => {
|
|
9
|
+
const getMatchedLocale = (pathname: string, req: PzNextRequest) => {
|
|
9
10
|
let matchedLocale = pathname.match(urlLocaleMatcherRegex)?.[0] ?? '';
|
|
10
11
|
matchedLocale = matchedLocale.replace('/', '');
|
|
11
12
|
|
|
13
|
+
const { localeUrlStrategy, defaultLocaleValue } = settings.localization;
|
|
14
|
+
|
|
15
|
+
if (localeUrlStrategy === LocaleUrlStrategy.Subdomain) {
|
|
16
|
+
const host = req.headers.get('x-forwarded-host');
|
|
17
|
+
|
|
18
|
+
if (host) {
|
|
19
|
+
const subDomain = host.split('.')[0] || '';
|
|
20
|
+
const subDomainLocaleMatched = `/${subDomain}`.match(
|
|
21
|
+
urlLocaleMatcherRegex
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
if (subDomainLocaleMatched && subDomainLocaleMatched[0]) {
|
|
25
|
+
matchedLocale = subDomainLocaleMatched[0].slice(1);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
12
30
|
if (!matchedLocale.length) {
|
|
13
|
-
if (
|
|
14
|
-
|
|
15
|
-
LocaleUrlStrategy.ShowAllLocales
|
|
16
|
-
) {
|
|
17
|
-
matchedLocale = settings.localization.defaultLocaleValue;
|
|
31
|
+
if (localeUrlStrategy !== LocaleUrlStrategy.ShowAllLocales) {
|
|
32
|
+
matchedLocale = defaultLocaleValue;
|
|
18
33
|
}
|
|
19
34
|
}
|
|
20
35
|
|
|
@@ -28,7 +43,7 @@ const withLocale =
|
|
|
28
43
|
|
|
29
44
|
try {
|
|
30
45
|
const url = req.nextUrl.clone();
|
|
31
|
-
const matchedLocale = getMatchedLocale(url.pathname);
|
|
46
|
+
const matchedLocale = getMatchedLocale(url.pathname, req);
|
|
32
47
|
let { localeUrlStrategy, defaultLocaleValue, redirectToDefaultLocale } =
|
|
33
48
|
settings.localization;
|
|
34
49
|
|
|
@@ -50,8 +65,15 @@ const withLocale =
|
|
|
50
65
|
redirectToDefaultLocale &&
|
|
51
66
|
req.method === 'GET'
|
|
52
67
|
) {
|
|
53
|
-
|
|
54
|
-
|
|
68
|
+
// Redirect to existing or default locale
|
|
69
|
+
|
|
70
|
+
url.pathname = getUrlPathWithLocale(
|
|
71
|
+
url.pathname,
|
|
72
|
+
req.cookies.get('pz-locale')?.value
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
// Use 303 for POST requests
|
|
76
|
+
return NextResponse.redirect(url, 303);
|
|
55
77
|
}
|
|
56
78
|
|
|
57
79
|
req.middlewareParams.rewrites.locale = matchedLocale;
|
|
@@ -61,7 +83,6 @@ const withLocale =
|
|
|
61
83
|
ip
|
|
62
84
|
});
|
|
63
85
|
}
|
|
64
|
-
|
|
65
86
|
return middleware(req, event);
|
|
66
87
|
};
|
|
67
88
|
|
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.82.0-rc.
|
|
4
|
+
"version": "1.82.0-rc.20",
|
|
5
5
|
"private": false,
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"bin": {
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
"@opentelemetry/semantic-conventions": "1.19.0",
|
|
22
22
|
"@reduxjs/toolkit": "1.9.7",
|
|
23
23
|
"@neshca/cache-handler": "1.9.0",
|
|
24
|
+
"@sentry/nextjs": "9.5.0",
|
|
24
25
|
"cross-spawn": "7.0.3",
|
|
25
26
|
"generic-pool": "3.9.0",
|
|
26
27
|
"react-redux": "8.1.3",
|
|
@@ -30,7 +31,7 @@
|
|
|
30
31
|
"set-cookie-parser": "2.6.0"
|
|
31
32
|
},
|
|
32
33
|
"devDependencies": {
|
|
33
|
-
"@akinon/eslint-plugin-projectzero": "1.82.0-rc.
|
|
34
|
+
"@akinon/eslint-plugin-projectzero": "1.82.0-rc.20",
|
|
34
35
|
"@types/react-redux": "7.1.30",
|
|
35
36
|
"@types/set-cookie-parser": "2.4.7",
|
|
36
37
|
"@typescript-eslint/eslint-plugin": "6.7.4",
|
|
@@ -16,10 +16,8 @@ import {
|
|
|
16
16
|
setLoyaltyBalance,
|
|
17
17
|
setPaymentChoices,
|
|
18
18
|
setPaymentOptions,
|
|
19
|
-
setPreOrder,
|
|
20
19
|
setRetailStores,
|
|
21
20
|
setShippingOptions,
|
|
22
|
-
setShippingStepCompleted,
|
|
23
21
|
setHepsipayAvailability,
|
|
24
22
|
setWalletPaymentData,
|
|
25
23
|
setPayOnDeliveryOtpModalActive
|
|
@@ -59,146 +57,6 @@ export const errorMiddleware: Middleware = ({ dispatch }: MiddlewareParams) => {
|
|
|
59
57
|
};
|
|
60
58
|
};
|
|
61
59
|
|
|
62
|
-
export const preOrderMiddleware: Middleware = ({
|
|
63
|
-
getState,
|
|
64
|
-
dispatch
|
|
65
|
-
}: MiddlewareParams) => {
|
|
66
|
-
return (next) => (action) => {
|
|
67
|
-
const result: CheckoutResult = next(action);
|
|
68
|
-
const preOrder = result?.payload?.pre_order;
|
|
69
|
-
|
|
70
|
-
if (
|
|
71
|
-
!preOrder ||
|
|
72
|
-
action?.meta?.arg?.endpointName === 'guestLogin' ||
|
|
73
|
-
action?.meta?.arg?.endpointName === 'getCheckoutLoyaltyBalance'
|
|
74
|
-
) {
|
|
75
|
-
return result;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
const {
|
|
79
|
-
deliveryOptions,
|
|
80
|
-
addressList: addresses,
|
|
81
|
-
shippingOptions,
|
|
82
|
-
dataSourceShippingOptions,
|
|
83
|
-
paymentOptions,
|
|
84
|
-
installmentOptions,
|
|
85
|
-
attributeBasedShippingOptions
|
|
86
|
-
} = getState().checkout;
|
|
87
|
-
const { endpoints: apiEndpoints } = checkoutApi;
|
|
88
|
-
|
|
89
|
-
if (preOrder.is_redirected) {
|
|
90
|
-
const contextList = result?.payload?.context_list;
|
|
91
|
-
|
|
92
|
-
if (
|
|
93
|
-
contextList.find(
|
|
94
|
-
(ctx) => ctx.page_name === 'RedirectionPaymentSelectedPage'
|
|
95
|
-
)
|
|
96
|
-
) {
|
|
97
|
-
dispatch(
|
|
98
|
-
apiEndpoints.setPaymentOption.initiate(preOrder.payment_option?.pk)
|
|
99
|
-
);
|
|
100
|
-
return;
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
dispatch(setPreOrder(preOrder));
|
|
105
|
-
|
|
106
|
-
if (!preOrder.delivery_option && deliveryOptions.length > 0) {
|
|
107
|
-
dispatch(
|
|
108
|
-
apiEndpoints.setDeliveryOption.initiate(
|
|
109
|
-
deliveryOptions.find((opt) => opt.delivery_option_type === 'customer')
|
|
110
|
-
?.pk
|
|
111
|
-
)
|
|
112
|
-
);
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
if (
|
|
116
|
-
(!preOrder.shipping_address || !preOrder.billing_address) &&
|
|
117
|
-
addresses.length > 0 &&
|
|
118
|
-
(!preOrder.delivery_option ||
|
|
119
|
-
preOrder.delivery_option.delivery_option_type === 'customer')
|
|
120
|
-
) {
|
|
121
|
-
dispatch(
|
|
122
|
-
apiEndpoints.setAddresses.initiate({
|
|
123
|
-
shippingAddressPk: addresses[0].pk,
|
|
124
|
-
billingAddressPk: addresses[0].pk
|
|
125
|
-
})
|
|
126
|
-
);
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
if (
|
|
130
|
-
shippingOptions.length > 0 &&
|
|
131
|
-
(!preOrder.shipping_option ||
|
|
132
|
-
!shippingOptions.find((opt) => opt.pk === preOrder.shipping_option?.pk))
|
|
133
|
-
) {
|
|
134
|
-
dispatch(apiEndpoints.setShippingOption.initiate(shippingOptions[0].pk));
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
if (
|
|
138
|
-
dataSourceShippingOptions.length > 0 &&
|
|
139
|
-
!preOrder.data_source_shipping_options
|
|
140
|
-
) {
|
|
141
|
-
const selectedDataSourceShippingOptionsPks =
|
|
142
|
-
dataSourceShippingOptions.map(
|
|
143
|
-
(opt) => opt.data_source_shipping_options[0].pk
|
|
144
|
-
);
|
|
145
|
-
|
|
146
|
-
dispatch(
|
|
147
|
-
apiEndpoints.setDataSourceShippingOptions.initiate(
|
|
148
|
-
selectedDataSourceShippingOptionsPks
|
|
149
|
-
)
|
|
150
|
-
);
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
if (
|
|
154
|
-
Object.keys(attributeBasedShippingOptions).length > 0 &&
|
|
155
|
-
!preOrder.attribute_based_shipping_options
|
|
156
|
-
) {
|
|
157
|
-
const initialSelectedOptions: Record<string, number> = Object.fromEntries(
|
|
158
|
-
Object.entries(attributeBasedShippingOptions).map(([key, options]) => [
|
|
159
|
-
key,
|
|
160
|
-
options.attribute_based_shipping_options[0].pk
|
|
161
|
-
])
|
|
162
|
-
);
|
|
163
|
-
|
|
164
|
-
dispatch(
|
|
165
|
-
apiEndpoints.setAttributeBasedShippingOptions.initiate(
|
|
166
|
-
initialSelectedOptions
|
|
167
|
-
)
|
|
168
|
-
);
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
if (!preOrder.payment_option && paymentOptions.length > 0) {
|
|
172
|
-
dispatch(apiEndpoints.setPaymentOption.initiate(paymentOptions[0].pk));
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
if (
|
|
176
|
-
!preOrder.installment &&
|
|
177
|
-
preOrder.payment_option?.payment_type !== 'saved_card' &&
|
|
178
|
-
installmentOptions.length > 0
|
|
179
|
-
) {
|
|
180
|
-
dispatch(
|
|
181
|
-
apiEndpoints.setInstallmentOption.initiate(installmentOptions[0].pk)
|
|
182
|
-
);
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
dispatch(
|
|
186
|
-
setShippingStepCompleted(
|
|
187
|
-
[
|
|
188
|
-
preOrder.delivery_option?.delivery_option_type === 'retail_store'
|
|
189
|
-
? true
|
|
190
|
-
: preOrder.shipping_address?.pk,
|
|
191
|
-
preOrder.billing_address?.pk,
|
|
192
|
-
preOrder.shipping_option?.pk,
|
|
193
|
-
addresses.length > 0
|
|
194
|
-
].every(Boolean)
|
|
195
|
-
)
|
|
196
|
-
);
|
|
197
|
-
|
|
198
|
-
return result;
|
|
199
|
-
};
|
|
200
|
-
};
|
|
201
|
-
|
|
202
60
|
export const contextListMiddleware: Middleware = ({
|
|
203
61
|
dispatch,
|
|
204
62
|
getState
|
|
@@ -10,16 +10,20 @@ import { paymentOptionMiddleware } from './payment-option';
|
|
|
10
10
|
import { installmentOptionMiddleware } from './installment-option';
|
|
11
11
|
import { shippingStepMiddleware } from './shipping-step';
|
|
12
12
|
|
|
13
|
+
// ⚠️ WARNING: Redux Toolkit applies middlewares in reverse order (from last to first).
|
|
14
|
+
// This list is written **in reverse execution order** to ensure they run in the correct sequence.
|
|
15
|
+
// If you add a new middleware, make sure to insert it **in reverse order** based on execution priority.
|
|
16
|
+
|
|
13
17
|
export const preOrderMiddlewares = [
|
|
14
|
-
|
|
15
|
-
redirectionMiddleware,
|
|
16
|
-
setPreOrderMiddleware,
|
|
17
|
-
deliveryOptionMiddleware,
|
|
18
|
-
setAddressMiddleware,
|
|
19
|
-
shippingOptionMiddleware,
|
|
20
|
-
dataSourceShippingOptionMiddleware,
|
|
21
|
-
attributeBasedShippingOptionMiddleware,
|
|
22
|
-
paymentOptionMiddleware,
|
|
18
|
+
shippingStepMiddleware,
|
|
23
19
|
installmentOptionMiddleware,
|
|
24
|
-
|
|
20
|
+
paymentOptionMiddleware,
|
|
21
|
+
attributeBasedShippingOptionMiddleware,
|
|
22
|
+
dataSourceShippingOptionMiddleware,
|
|
23
|
+
shippingOptionMiddleware,
|
|
24
|
+
setAddressMiddleware,
|
|
25
|
+
deliveryOptionMiddleware,
|
|
26
|
+
setPreOrderMiddleware,
|
|
27
|
+
redirectionMiddleware,
|
|
28
|
+
preOrderValidationMiddleware
|
|
25
29
|
];
|
package/sentry/index.ts
CHANGED
|
@@ -1,29 +1,48 @@
|
|
|
1
1
|
import * as Sentry from '@sentry/nextjs';
|
|
2
2
|
|
|
3
|
-
const SENTRY_DSN: string =
|
|
3
|
+
const SENTRY_DSN: string | undefined =
|
|
4
4
|
process.env.SENTRY_DSN || process.env.NEXT_PUBLIC_SENTRY_DSN;
|
|
5
5
|
|
|
6
|
+
export enum ClientLogType {
|
|
7
|
+
UNCAUGHT_ERROR_PAGE = 'UNCAUGHT_ERROR_PAGE',
|
|
8
|
+
CHECKOUT = 'CHECKOUT'
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const ALLOWED_CLIENT_LOG_TYPES: ClientLogType[] = [
|
|
12
|
+
ClientLogType.UNCAUGHT_ERROR_PAGE,
|
|
13
|
+
ClientLogType.CHECKOUT
|
|
14
|
+
];
|
|
15
|
+
|
|
6
16
|
export const initSentry = (
|
|
7
17
|
type: 'Server' | 'Client' | 'Edge',
|
|
8
18
|
options: Sentry.BrowserOptions | Sentry.NodeOptions | Sentry.EdgeOptions = {}
|
|
9
19
|
) => {
|
|
10
20
|
// TODO: Handle options with ESLint rules
|
|
11
21
|
|
|
12
|
-
|
|
22
|
+
Sentry.init({
|
|
23
|
+
dsn:
|
|
24
|
+
options.dsn ||
|
|
25
|
+
SENTRY_DSN ||
|
|
26
|
+
'https://d8558ef8997543deacf376c7d8d7cf4b@o64293.ingest.sentry.io/4504338423742464',
|
|
27
|
+
initialScope: {
|
|
28
|
+
tags: {
|
|
29
|
+
APP_TYPE: 'ProjectZeroNext',
|
|
30
|
+
TYPE: type
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
tracesSampleRate: 0,
|
|
34
|
+
integrations: [],
|
|
35
|
+
beforeSend: (event, hint) => {
|
|
36
|
+
if (
|
|
37
|
+
type === 'Client' &&
|
|
38
|
+
!ALLOWED_CLIENT_LOG_TYPES.includes(
|
|
39
|
+
event.tags?.LOG_TYPE as ClientLogType
|
|
40
|
+
)
|
|
41
|
+
) {
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
13
44
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
SENTRY_DSN ||
|
|
18
|
-
'https://d8558ef8997543deacf376c7d8d7cf4b@o64293.ingest.sentry.io/4504338423742464',
|
|
19
|
-
initialScope: {
|
|
20
|
-
tags: {
|
|
21
|
-
APP_TYPE: 'ProjectZeroNext',
|
|
22
|
-
TYPE: type
|
|
23
|
-
}
|
|
24
|
-
},
|
|
25
|
-
tracesSampleRate: 1.0,
|
|
26
|
-
integrations: []
|
|
27
|
-
});
|
|
28
|
-
}
|
|
45
|
+
return event;
|
|
46
|
+
}
|
|
47
|
+
});
|
|
29
48
|
};
|
package/utils/index.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import settings from 'settings';
|
|
2
2
|
import { LocaleUrlStrategy } from '../localization';
|
|
3
|
-
import { CDNOptions, ClientRequestOptions } from '../types';
|
|
3
|
+
import { CDNOptions, ClientRequestOptions, Locale } from '../types';
|
|
4
4
|
|
|
5
5
|
export * from './get-currency';
|
|
6
6
|
export * from './menu-generator';
|
|
@@ -152,14 +152,17 @@ export function buildCDNUrl(url: string, config?: CDNOptions) {
|
|
|
152
152
|
return `${rootWithoutOptions}${options}${fileExtension}`;
|
|
153
153
|
}
|
|
154
154
|
|
|
155
|
+
const { locales, localeUrlStrategy, defaultLocaleValue } =
|
|
156
|
+
settings.localization;
|
|
157
|
+
|
|
158
|
+
const isLocaleExcluded = (locale: Locale) =>
|
|
159
|
+
![LocaleUrlStrategy.ShowAllLocales, LocaleUrlStrategy.Subdomain].includes(
|
|
160
|
+
localeUrlStrategy
|
|
161
|
+
) && locale.value !== defaultLocaleValue;
|
|
162
|
+
|
|
155
163
|
export const urlLocaleMatcherRegex = new RegExp(
|
|
156
|
-
`^/(${
|
|
157
|
-
.filter((l) =>
|
|
158
|
-
settings.localization.localeUrlStrategy !==
|
|
159
|
-
LocaleUrlStrategy.ShowAllLocales
|
|
160
|
-
? l.value !== settings.localization.defaultLocaleValue
|
|
161
|
-
: l
|
|
162
|
-
)
|
|
164
|
+
`^/(${locales
|
|
165
|
+
.filter((l) => !isLocaleExcluded(l))
|
|
163
166
|
.map((l) => l.value)
|
|
164
167
|
.join('|')})(?=/|$)`
|
|
165
168
|
);
|
package/utils/localization.ts
CHANGED
|
@@ -11,6 +11,10 @@ export const getUrlPathWithLocale = (
|
|
|
11
11
|
currentLocale = defaultLocaleValue;
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
+
if (localeUrlStrategy === LocaleUrlStrategy.Subdomain) {
|
|
15
|
+
return pathname;
|
|
16
|
+
}
|
|
17
|
+
|
|
14
18
|
if (localeUrlStrategy === LocaleUrlStrategy.HideAllLocales) {
|
|
15
19
|
return pathname;
|
|
16
20
|
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { useEffect, useState } from 'react';
|
|
2
|
+
import { useLocalization } from '../hooks';
|
|
3
|
+
import { Button, Link } from '../components';
|
|
4
|
+
|
|
5
|
+
export default function PzErrorPage({
|
|
6
|
+
error,
|
|
7
|
+
reset
|
|
8
|
+
}: {
|
|
9
|
+
error: Error & { digest?: string; isServerError?: boolean };
|
|
10
|
+
reset: () => void;
|
|
11
|
+
}) {
|
|
12
|
+
const [isServerError, setIsServerError] = useState(false);
|
|
13
|
+
|
|
14
|
+
useEffect(() => {
|
|
15
|
+
if ('isServerError' in error) {
|
|
16
|
+
setIsServerError(true);
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
setIsServerError(!!error.digest);
|
|
21
|
+
}, [error]);
|
|
22
|
+
|
|
23
|
+
return isServerError ? (
|
|
24
|
+
<ServerErrorUI />
|
|
25
|
+
) : (
|
|
26
|
+
<ClientErrorUI error={error} reset={reset} />
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function ClientErrorUI({
|
|
31
|
+
error,
|
|
32
|
+
reset
|
|
33
|
+
}: {
|
|
34
|
+
error: Error & { digest?: string };
|
|
35
|
+
reset: () => void;
|
|
36
|
+
}) {
|
|
37
|
+
const { t } = useLocalization();
|
|
38
|
+
|
|
39
|
+
const errorMessage = error?.message || 'Unknown error';
|
|
40
|
+
|
|
41
|
+
return (
|
|
42
|
+
<section className="text-center px-6 my-14 md:px-0 md:m-14">
|
|
43
|
+
<div className="text-4xl font-bold md:text-6xl text-red-500">Oops!</div>
|
|
44
|
+
<h1 className="text-lg md:text-xl mt-4">
|
|
45
|
+
{t('common.client_error.title')}
|
|
46
|
+
</h1>
|
|
47
|
+
<p className="text-lg md:text-xl mt-2">
|
|
48
|
+
{t('common.client_error.description')}
|
|
49
|
+
</p>
|
|
50
|
+
|
|
51
|
+
<div className="mt-4 mx-auto max-w-lg">
|
|
52
|
+
<p className="text-xs text-gray-600 font-mono bg-gray-100 p-3 rounded overflow-auto text-left">
|
|
53
|
+
<span className="font-semibold">Error:</span> {errorMessage}
|
|
54
|
+
</p>
|
|
55
|
+
</div>
|
|
56
|
+
|
|
57
|
+
<div className="mt-6 flex flex-col gap-4 items-center justify-center">
|
|
58
|
+
<Link href="/" className="text-lg underline">
|
|
59
|
+
{t('common.client_error.link_text')}
|
|
60
|
+
</Link>
|
|
61
|
+
<Button onClick={reset} className="text-lg w-28">
|
|
62
|
+
{t('common.try_again')}
|
|
63
|
+
</Button>
|
|
64
|
+
</div>
|
|
65
|
+
</section>
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function ServerErrorUI() {
|
|
70
|
+
const { t } = useLocalization();
|
|
71
|
+
|
|
72
|
+
const reloadPage = () => {
|
|
73
|
+
window.location.reload();
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
return (
|
|
77
|
+
<section className="text-center px-6 my-14 md:px-0 md:m-14">
|
|
78
|
+
<div className="text-7xl font-bold md:text-8xl">500</div>
|
|
79
|
+
<h1 className="text-lg md:text-xl"> {t('common.page_500.title')} </h1>
|
|
80
|
+
<p className="text-lg md:text-xl"> {t('common.page_500.description')} </p>
|
|
81
|
+
|
|
82
|
+
<div className="mt-6 flex flex-col gap-4 items-center justify-center">
|
|
83
|
+
<Link href="/" className="text-lg underline">
|
|
84
|
+
{t('common.page_500.link_text')}
|
|
85
|
+
</Link>
|
|
86
|
+
<Button onClick={reloadPage} className="text-lg w-28">
|
|
87
|
+
{t('common.try_again')}
|
|
88
|
+
</Button>
|
|
89
|
+
</div>
|
|
90
|
+
</section>
|
|
91
|
+
);
|
|
92
|
+
}
|