@akinon/next 1.60.0 → 1.61.0-rc.23

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