@akinon/next 1.59.0 → 1.60.0-rc.6

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.
Files changed (64) hide show
  1. package/CHANGELOG.md +657 -0
  2. package/api/client.ts +23 -2
  3. package/assets/styles/index.css +49 -0
  4. package/assets/styles/index.css.map +1 -0
  5. package/assets/styles/index.scss +50 -26
  6. package/bin/pz-generate-translations.js +41 -0
  7. package/bin/pz-prebuild.js +1 -0
  8. package/bin/pz-predev.js +1 -0
  9. package/components/file-input.tsx +8 -0
  10. package/components/index.ts +1 -0
  11. package/components/input.tsx +21 -7
  12. package/components/link.tsx +17 -13
  13. package/components/plugin-module.tsx +8 -3
  14. package/components/price.tsx +11 -4
  15. package/components/pz-root.tsx +15 -3
  16. package/components/selected-payment-option-view.tsx +2 -1
  17. package/data/client/api.ts +1 -1
  18. package/data/client/b2b.ts +35 -2
  19. package/data/client/basket.ts +6 -5
  20. package/data/client/checkout.ts +55 -10
  21. package/data/client/user.ts +3 -2
  22. package/data/server/category.ts +43 -19
  23. package/data/server/flatpage.ts +29 -7
  24. package/data/server/form.ts +29 -11
  25. package/data/server/landingpage.ts +26 -7
  26. package/data/server/list.ts +16 -6
  27. package/data/server/menu.ts +15 -2
  28. package/data/server/product.ts +33 -13
  29. package/data/server/seo.ts +17 -24
  30. package/data/server/special-page.ts +15 -5
  31. package/data/server/widget.ts +14 -7
  32. package/data/urls.ts +8 -1
  33. package/hocs/server/with-segment-defaults.tsx +4 -1
  34. package/hooks/index.ts +2 -1
  35. package/hooks/use-message-listener.ts +24 -0
  36. package/hooks/use-pagination.ts +2 -2
  37. package/hooks/use-payment-options.ts +2 -1
  38. package/lib/cache-handler.mjs +33 -0
  39. package/lib/cache.ts +8 -6
  40. package/middlewares/currency.ts +2 -1
  41. package/middlewares/default.ts +226 -152
  42. package/middlewares/index.ts +3 -1
  43. package/middlewares/oauth-login.ts +3 -1
  44. package/middlewares/pretty-url.ts +11 -1
  45. package/middlewares/saved-card-redirection.ts +179 -0
  46. package/middlewares/url-redirection.ts +4 -0
  47. package/package.json +4 -3
  48. package/plugins.d.ts +6 -0
  49. package/plugins.js +2 -1
  50. package/redux/middlewares/checkout.ts +78 -14
  51. package/redux/reducers/checkout.ts +23 -3
  52. package/redux/reducers/index.ts +3 -1
  53. package/routes/pretty-url.tsx +192 -0
  54. package/types/commerce/address.ts +1 -1
  55. package/types/commerce/b2b.ts +12 -2
  56. package/types/commerce/checkout.ts +30 -0
  57. package/types/commerce/order.ts +1 -0
  58. package/types/index.ts +17 -2
  59. package/utils/app-fetch.ts +16 -8
  60. package/utils/generate-commerce-search-params.ts +3 -1
  61. package/utils/index.ts +27 -6
  62. package/utils/redirection-iframe.ts +85 -0
  63. package/utils/server-translation.ts +11 -1
  64. package/with-pz-config.js +13 -2
@@ -9,6 +9,7 @@ import {
9
9
  withOauthLogin,
10
10
  withPrettyUrl,
11
11
  withRedirectionPayment,
12
+ withSavedCardRedirection,
12
13
  withThreeDRedirection,
13
14
  withUrlRedirection
14
15
  } from '.';
@@ -88,14 +89,44 @@ const withPzDefault =
88
89
  req.nextUrl.pathname.includes('/orders/hooks/') ||
89
90
  req.nextUrl.pathname.includes('/orders/checkout-with-token/')
90
91
  ) {
91
- return NextResponse.rewrite(
92
+ const segment = url.searchParams.get('segment');
93
+ const currency = url.searchParams.get('currency')?.toLowerCase();
94
+
95
+ const headers = {};
96
+
97
+ if (segment) {
98
+ headers['X-Segment-Id'] = segment;
99
+ }
100
+
101
+ if (currency) {
102
+ headers['x-currency'] = currency;
103
+ }
104
+
105
+ const response = NextResponse.rewrite(
92
106
  new URL(
93
107
  `${Settings.commerceUrl}${req.nextUrl.pathname.replace(
94
108
  urlLocaleMatcherRegex,
95
109
  ''
96
110
  )}`
97
- )
111
+ ),
112
+ {
113
+ headers
114
+ }
98
115
  );
116
+
117
+ if (segment) {
118
+ response.cookies.set('pz-segment', segment);
119
+ }
120
+
121
+ if (currency) {
122
+ response.cookies.set('pz-currency', currency, {
123
+ sameSite: 'none',
124
+ secure: true,
125
+ expires: new Date(Date.now() + 1000 * 60 * 60 * 24 * 7) // 7 days
126
+ });
127
+ }
128
+
129
+ return response;
99
130
  }
100
131
 
101
132
  if (req.nextUrl.pathname.startsWith('/orders/redirection/')) {
@@ -110,6 +141,14 @@ const withPzDefault =
110
141
  );
111
142
  }
112
143
 
144
+ if (req.nextUrl.pathname.includes('/orders/saved-card-redirect')) {
145
+ return NextResponse.rewrite(
146
+ new URL(
147
+ `${encodeURI(Settings.commerceUrl)}/orders/saved-card-redirect/`
148
+ )
149
+ );
150
+ }
151
+
113
152
  // If commerce redirects to /orders/checkout/ without locale
114
153
  if (
115
154
  req.nextUrl.pathname.match(new RegExp('^/orders/checkout/$')) &&
@@ -127,6 +166,25 @@ const withPzDefault =
127
166
  return NextResponse.redirect(redirectUrlWithLocale, 303);
128
167
  }
129
168
 
169
+ // Dynamically handle any payment gateway without specifying names
170
+ const paymentGatewayRegex = new RegExp('^/payment-gateway/([^/]+)/$');
171
+ const gatewayMatch = req.nextUrl.pathname.match(paymentGatewayRegex);
172
+
173
+ if (
174
+ gatewayMatch && // Check if the URL matches the /payment-gateway/<gateway> pattern
175
+ getUrlPathWithLocale(
176
+ `/payment-gateway/${gatewayMatch[1]}/`,
177
+ req.cookies.get('pz-locale')?.value
178
+ ) !== req.nextUrl.pathname
179
+ ) {
180
+ const redirectUrlWithLocale = `${url.origin}${getUrlPathWithLocale(
181
+ `/payment-gateway/${gatewayMatch[1]}/`,
182
+ req.cookies.get('pz-locale')?.value
183
+ )}?${req.nextUrl.searchParams.toString()}`;
184
+
185
+ return NextResponse.redirect(redirectUrlWithLocale);
186
+ }
187
+
130
188
  if (req.nextUrl.pathname.startsWith('/orders/checkout-provider/')) {
131
189
  try {
132
190
  const data = await req.json();
@@ -174,114 +232,141 @@ const withPzDefault =
174
232
  withUrlRedirection(
175
233
  withCompleteGpay(
176
234
  withCompleteMasterpass(
177
- async (req: PzNextRequest, event: NextFetchEvent) => {
178
- let middlewareResult: NextResponse | void =
179
- NextResponse.next();
180
-
181
- try {
182
- const { locale, prettyUrl, currency } =
183
- req.middlewareParams.rewrites;
184
- const { defaultLocaleValue } =
185
- Settings.localization;
186
- const url = req.nextUrl.clone();
187
- const pathnameWithoutLocale = url.pathname.replace(
188
- urlLocaleMatcherRegex,
189
- ''
190
- );
191
-
192
- middlewareResult = (await middleware(
193
- req,
194
- event
195
- )) as NextResponse | void;
196
-
197
- let customRewriteUrlDiff = '';
198
-
199
- if (
200
- middlewareResult instanceof NextResponse &&
201
- middlewareResult.headers.get(
202
- 'pz-override-response'
203
- ) &&
204
- middlewareResult.headers.get(
205
- 'x-middleware-rewrite'
206
- )
207
- ) {
208
- const rewriteUrl = new URL(
209
- middlewareResult.headers.get(
210
- 'x-middleware-rewrite'
211
- )
212
- );
213
- const originalUrl = new URL(req.url);
214
- customRewriteUrlDiff =
215
- rewriteUrl.pathname.replace(
216
- originalUrl.pathname,
217
- ''
218
- );
219
- }
235
+ withSavedCardRedirection(
236
+ async (req: PzNextRequest, event: NextFetchEvent) => {
237
+ let middlewareResult: NextResponse | void =
238
+ NextResponse.next();
220
239
 
221
- url.basePath = `/${commerceUrl}`;
222
- url.pathname = `/${
223
- locale.length ? `${locale}/` : ''
224
- }${currency}/${customRewriteUrlDiff}${
225
- prettyUrl ?? pathnameWithoutLocale
226
- }`.replace(/\/+/g, '/');
227
-
228
- if (
229
- !req.middlewareParams.found &&
230
- Settings.customNotFoundEnabled
231
- ) {
232
- let pathname = url.pathname
233
- .replace(/\/+$/, '')
234
- .split('/');
235
- url.pathname = url.pathname.replace(
236
- pathname.pop(),
237
- 'pz-not-found'
240
+ try {
241
+ const { locale, prettyUrl, currency } =
242
+ req.middlewareParams.rewrites;
243
+ const { defaultLocaleValue } =
244
+ Settings.localization;
245
+ const url = req.nextUrl.clone();
246
+ const pathnameWithoutLocale = url.pathname.replace(
247
+ urlLocaleMatcherRegex,
248
+ ''
238
249
  );
239
- }
240
250
 
241
- Settings.rewrites.forEach((rewrite) => {
242
- url.pathname = url.pathname.replace(
243
- rewrite.source,
244
- rewrite.destination
245
- );
246
- });
251
+ middlewareResult = (await middleware(
252
+ req,
253
+ event
254
+ )) as NextResponse | void;
255
+
256
+ let customRewriteUrlDiff = '';
247
257
 
248
- // if middleware.ts has a return value for current url
249
- if (middlewareResult instanceof NextResponse) {
250
- // pz-override-response header is used to prevent 404 page for custom responses.
251
258
  if (
259
+ middlewareResult instanceof NextResponse &&
252
260
  middlewareResult.headers.get(
253
261
  'pz-override-response'
254
- ) !== 'true'
255
- ) {
256
- middlewareResult.headers.set(
257
- 'x-middleware-rewrite',
258
- url.href
259
- );
260
- } else if (
261
- middlewareResult.headers.get(
262
- 'x-middleware-rewrite'
263
262
  ) &&
264
263
  middlewareResult.headers.get(
265
- 'pz-override-response'
266
- ) === 'true'
264
+ 'x-middleware-rewrite'
265
+ )
267
266
  ) {
268
- middlewareResult = NextResponse.rewrite(url);
267
+ const rewriteUrl = new URL(
268
+ middlewareResult.headers.get(
269
+ 'x-middleware-rewrite'
270
+ )
271
+ );
272
+ const originalUrl = new URL(req.url);
273
+ customRewriteUrlDiff =
274
+ rewriteUrl.pathname.replace(
275
+ originalUrl.pathname,
276
+ ''
277
+ );
269
278
  }
270
- } else {
271
- // if middleware.ts doesn't have a return value.
272
- // e.g. NextResponse.next() doesn't exist in middleware.ts
273
279
 
274
- middlewareResult = NextResponse.rewrite(url);
275
- }
280
+ url.basePath = `/${commerceUrl}`;
281
+ url.pathname = `/${
282
+ locale.length ? `${locale}/` : ''
283
+ }${currency}/${customRewriteUrlDiff}${
284
+ prettyUrl ?? pathnameWithoutLocale
285
+ }`.replace(/\/+/g, '/');
286
+
287
+ if (
288
+ !req.middlewareParams.found &&
289
+ Settings.customNotFoundEnabled
290
+ ) {
291
+ let pathname = url.pathname
292
+ .replace(/\/+$/, '')
293
+ .split('/');
294
+ url.pathname = url.pathname.replace(
295
+ pathname.pop(),
296
+ 'pz-not-found'
297
+ );
298
+ }
299
+
300
+ if (
301
+ Settings.usePrettyUrlRoute &&
302
+ url.searchParams.toString().length > 0 &&
303
+ !Object.entries(ROUTES).find(([, value]) =>
304
+ new RegExp(`^${value}/?$`).test(
305
+ pathnameWithoutLocale
306
+ )
307
+ )
308
+ ) {
309
+ url.pathname =
310
+ url.pathname +
311
+ `searchparams|${url.searchParams.toString()}`;
312
+ }
313
+
314
+ Settings.rewrites.forEach((rewrite) => {
315
+ url.pathname = url.pathname.replace(
316
+ rewrite.source,
317
+ rewrite.destination
318
+ );
319
+ });
320
+
321
+ // if middleware.ts has a return value for current url
322
+ if (middlewareResult instanceof NextResponse) {
323
+ // pz-override-response header is used to prevent 404 page for custom responses.
324
+ if (
325
+ middlewareResult.headers.get(
326
+ 'pz-override-response'
327
+ ) !== 'true'
328
+ ) {
329
+ middlewareResult.headers.set(
330
+ 'x-middleware-rewrite',
331
+ url.href
332
+ );
333
+ } else if (
334
+ middlewareResult.headers.get(
335
+ 'x-middleware-rewrite'
336
+ ) &&
337
+ middlewareResult.headers.get(
338
+ 'pz-override-response'
339
+ ) === 'true'
340
+ ) {
341
+ middlewareResult = NextResponse.rewrite(url);
342
+ }
343
+ } else {
344
+ // if middleware.ts doesn't have a return value.
345
+ // e.g. NextResponse.next() doesn't exist in middleware.ts
276
346
 
277
- if (
278
- !url.pathname.startsWith(`/${currency}/orders`)
279
- ) {
347
+ middlewareResult = NextResponse.rewrite(url);
348
+ }
349
+
350
+ if (
351
+ !url.pathname.startsWith(`/${currency}/orders`)
352
+ ) {
353
+ middlewareResult.cookies.set(
354
+ 'pz-locale',
355
+ locale?.length > 0
356
+ ? locale
357
+ : defaultLocaleValue,
358
+ {
359
+ sameSite: 'none',
360
+ secure: true,
361
+ expires: new Date(
362
+ Date.now() + 1000 * 60 * 60 * 24 * 7
363
+ ) // 7 days
364
+ }
365
+ );
366
+ }
280
367
  middlewareResult.cookies.set(
281
- 'pz-locale',
282
- locale?.length > 0
283
- ? locale
284
- : defaultLocaleValue,
368
+ 'pz-currency',
369
+ currency,
285
370
  {
286
371
  sameSite: 'none',
287
372
  secure: true,
@@ -290,76 +375,65 @@ const withPzDefault =
290
375
  ) // 7 days
291
376
  }
292
377
  );
293
- }
294
- middlewareResult.cookies.set(
295
- 'pz-currency',
296
- currency,
297
- {
298
- sameSite: 'none',
299
- secure: true,
300
- expires: new Date(
301
- Date.now() + 1000 * 60 * 60 * 24 * 7
302
- ) // 7 days
303
- }
304
- );
305
-
306
- if (
307
- req.cookies.get('pz-locale') &&
308
- req.cookies.get('pz-locale').value !== locale
309
- ) {
310
- logger.debug('Locale changed', {
311
- locale,
312
- oldLocale: req.cookies.get('pz-locale')?.value,
313
- ip
314
- });
315
- }
316
-
317
- middlewareResult.headers.set(
318
- 'pz-url',
319
- req.nextUrl.toString()
320
- );
321
378
 
322
- if (req.cookies.get('pz-set-currency')) {
323
- middlewareResult.cookies.delete(
324
- 'pz-set-currency'
325
- );
326
- }
379
+ if (
380
+ req.cookies.get('pz-locale') &&
381
+ req.cookies.get('pz-locale').value !== locale
382
+ ) {
383
+ logger.debug('Locale changed', {
384
+ locale,
385
+ oldLocale: req.cookies.get('pz-locale')?.value,
386
+ ip
387
+ });
388
+ }
327
389
 
328
- if (process.env.ACC_APP_VERSION) {
329
390
  middlewareResult.headers.set(
330
- 'acc-app-version',
331
- process.env.ACC_APP_VERSION
391
+ 'pz-url',
392
+ req.nextUrl.toString()
332
393
  );
333
- }
334
394
 
335
- // Set CSRF token if not set
336
- try {
337
- const url = `${Settings.commerceUrl}${user.csrfToken}`;
395
+ if (req.cookies.get('pz-set-currency')) {
396
+ middlewareResult.cookies.delete(
397
+ 'pz-set-currency'
398
+ );
399
+ }
338
400
 
339
- if (!req.cookies.get('csrftoken')) {
340
- const { csrf_token } = await (
341
- await fetch(url)
342
- ).json();
343
- middlewareResult.cookies.set(
344
- 'csrftoken',
345
- csrf_token
401
+ if (process.env.ACC_APP_VERSION) {
402
+ middlewareResult.headers.set(
403
+ 'acc-app-version',
404
+ process.env.ACC_APP_VERSION
346
405
  );
347
406
  }
407
+
408
+ // Set CSRF token if not set
409
+ try {
410
+ const url = `${Settings.commerceUrl}${user.csrfToken}`;
411
+
412
+ if (!req.cookies.get('csrftoken')) {
413
+ const { csrf_token } = await (
414
+ await fetch(url)
415
+ ).json();
416
+ middlewareResult.cookies.set(
417
+ 'csrftoken',
418
+ csrf_token
419
+ );
420
+ }
421
+ } catch (error) {
422
+ logger.error('CSRF Error', {
423
+ error,
424
+ ip
425
+ });
426
+ }
348
427
  } catch (error) {
349
- logger.error('CSRF Error', {
428
+ logger.error('withPzDefault Error', {
350
429
  error,
351
430
  ip
352
431
  });
353
432
  }
354
- } catch (error) {
355
- logger.error('withPzDefault Error', {
356
- error,
357
- ip
358
- });
359
- }
360
433
 
361
- return middlewareResult;
362
- }
434
+ return middlewareResult;
435
+ }
436
+ )
363
437
  )
364
438
  )
365
439
  )
@@ -8,6 +8,7 @@ import withUrlRedirection from './url-redirection';
8
8
  import withCompleteGpay from './complete-gpay';
9
9
  import withCompleteMasterpass from './complete-masterpass';
10
10
  import withCheckoutProvider from './checkout-provider';
11
+ import withSavedCardRedirection from './saved-card-redirection';
11
12
  import { NextRequest } from 'next/server';
12
13
 
13
14
  export {
@@ -20,7 +21,8 @@ export {
20
21
  withUrlRedirection,
21
22
  withCompleteGpay,
22
23
  withCompleteMasterpass,
23
- withCheckoutProvider
24
+ withCheckoutProvider,
25
+ withSavedCardRedirection
24
26
  };
25
27
 
26
28
  export interface PzNextRequest extends NextRequest {
@@ -58,7 +58,9 @@ const withOauthLogin =
58
58
  return middleware(req, event);
59
59
  }
60
60
 
61
- if (req.cookies.get('messages')?.value.includes('Successfully signed in')) {
61
+ const currentSessionId = req.cookies.get('osessionid');
62
+
63
+ if (req.cookies.get('messages')?.value.includes('Successfully signed in') || currentSessionId) {
62
64
  let redirectUrlWithLocale = `${url.origin}${getUrlPathWithLocale(
63
65
  '/auth/oauth-login',
64
66
  req.cookies.get('pz-locale')?.value
@@ -43,9 +43,14 @@ const resolvePrettyUrlHandler =
43
43
  return prettyUrlResult;
44
44
  };
45
45
 
46
- const resolvePrettyUrl = async (pathname: string, ip: string | null) => {
46
+ const resolvePrettyUrl = async (
47
+ pathname: string,
48
+ locale: string,
49
+ ip: string | null
50
+ ) => {
47
51
  return Cache.wrap(
48
52
  CacheKey.PrettyUrl(pathname),
53
+ locale,
49
54
  resolvePrettyUrlHandler(pathname, ip),
50
55
  {
51
56
  useProxy: true
@@ -56,6 +61,10 @@ const resolvePrettyUrl = async (pathname: string, ip: string | null) => {
56
61
  const withPrettyUrl =
57
62
  (middleware: NextMiddleware) =>
58
63
  async (req: PzNextRequest, event: NextFetchEvent) => {
64
+ if (Settings.usePrettyUrlRoute) {
65
+ return middleware(req, event);
66
+ }
67
+
59
68
  const url = req.nextUrl.clone();
60
69
  const matchedLanguagePrefix = url.pathname.match(
61
70
  urlLocaleMatcherRegex
@@ -84,6 +93,7 @@ const withPrettyUrl =
84
93
  )
85
94
  ? url.pathname
86
95
  : prettyUrlPathname,
96
+ matchedLanguagePrefix,
87
97
  ip
88
98
  );
89
99