@akinon/next 1.118.0 → 1.119.0-rc.1

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/data/urls.ts CHANGED
@@ -183,7 +183,11 @@ export const product = {
183
183
  breadcrumbUrl: (menuitemmodel: string) =>
184
184
  `/menus/generate_breadcrumb/?item=${menuitemmodel}&generator_name=menu_item`,
185
185
  bundleProduct: (productPk: string, queryString: string) =>
186
- `/bundle-product/${productPk}/?${queryString}`
186
+ `/bundle-product/${productPk}/?${queryString}`,
187
+ similarProducts: (params?: string) =>
188
+ `/similar-products${params ? `?${params}` : ''}`,
189
+ similarProductsList: (params?: string) =>
190
+ `/similar-product-list${params ? `?${params}` : ''}`
187
191
  };
188
192
 
189
193
  export const wishlist = {
@@ -364,11 +364,17 @@ CacheHandler.onCreation(async () => {
364
364
  };
365
365
  }
366
366
 
367
- const redisHandler = createRedisHandler({
367
+ const redisOptions = {
368
368
  client,
369
369
  timeoutMs: CACHE_CONFIG.redis.timeoutMs,
370
370
  keyExpirationStrategy: 'EXPIREAT'
371
- });
371
+ };
372
+
373
+ if (process.env.CACHE_PASSWORD) {
374
+ redisOptions.password = process.env.CACHE_PASSWORD;
375
+ }
376
+
377
+ const redisHandler = createRedisHandler(redisOptions);
372
378
 
373
379
  const localHandler = createLruHandler(CACHE_CONFIG.lru);
374
380
 
package/lib/cache.ts CHANGED
@@ -155,9 +155,14 @@ export class Cache {
155
155
  process.env.CACHE_PORT
156
156
  }/${process.env.CACHE_BUCKET ?? '0'}`;
157
157
 
158
- const client: RedisClientType = createClient({
159
- url: redisUrl
160
- });
158
+ const options = {
159
+ url: redisUrl,
160
+ ...(process.env.CACHE_PASSWORD && {
161
+ password: process.env.CACHE_PASSWORD
162
+ })
163
+ };
164
+
165
+ const client: RedisClientType = createClient(options);
161
166
 
162
167
  client.on('error', (error) => {
163
168
  logger.error('Redis client error', { redisUrl, error });
@@ -0,0 +1,18 @@
1
+ import { NextMiddleware } from 'next/server';
2
+
3
+ const withBfcacheHeaders = (middleware: NextMiddleware): NextMiddleware => {
4
+ return async (req, event) => {
5
+ const response = await middleware(req, event);
6
+
7
+ if (process.env.BF_CACHE === 'true' && response) {
8
+ response.headers.set(
9
+ 'Cache-Control',
10
+ 'private, no-cache, max-age=0, must-revalidate'
11
+ );
12
+ }
13
+
14
+ return response;
15
+ };
16
+ };
17
+
18
+ export default withBfcacheHeaders;
@@ -4,6 +4,7 @@ import { Buffer } from 'buffer';
4
4
  import logger from '../utils/log';
5
5
  import { getUrlPathWithLocale } from '../utils/localization';
6
6
  import { PzNextRequest } from '.';
7
+ import { getCheckoutPath } from '../utils';
7
8
 
8
9
  const streamToString = async (stream: ReadableStream<Uint8Array> | null) => {
9
10
  if (stream) {
@@ -40,7 +41,8 @@ const withCompleteGpay =
40
41
  return middleware(req, event);
41
42
  }
42
43
 
43
- const requestUrl = `${Settings.commerceUrl}/orders/checkout/${url.search}`;
44
+ const isPostCheckout = req.cookies.get('pz-post-checkout-flow')?.value === 'true';
45
+ const requestUrl = `${Settings.commerceUrl}${getCheckoutPath(isPostCheckout)}${url.search}`;
44
46
  const requestHeaders = {
45
47
  'X-Requested-With': 'XMLHttpRequest',
46
48
  'Content-Type': 'application/x-www-form-urlencoded',
@@ -108,10 +110,9 @@ const withCompleteGpay =
108
110
  });
109
111
 
110
112
  // Add error cookie
111
- errorResponse.headers.append(
112
- 'Set-Cookie',
113
- `pz-pos-error=${JSON.stringify(errors)}; path=/;`
114
- );
113
+ errorResponse.cookies.set('pz-pos-error', JSON.stringify(errors), {
114
+ path: '/'
115
+ });
115
116
 
116
117
  return errorResponse;
117
118
  }
@@ -5,6 +5,7 @@ import logger from '../utils/log';
5
5
  import { getUrlPathWithLocale } from '../utils/localization';
6
6
  import { PzNextRequest } from '.';
7
7
  import { ServerVariables } from '../utils/server-variables';
8
+ import { getCheckoutPath } from '../utils';
8
9
 
9
10
  const streamToString = async (stream: ReadableStream<Uint8Array> | null) => {
10
11
  if (stream) {
@@ -41,7 +42,8 @@ const withCompleteMasterpass =
41
42
  return middleware(req, event);
42
43
  }
43
44
 
44
- const requestUrl = `${Settings.commerceUrl}/orders/checkout/${url.search}`;
45
+ const isPostCheckout = req.cookies.get('pz-post-checkout-flow')?.value === 'true';
46
+ const requestUrl = `${Settings.commerceUrl}${getCheckoutPath(isPostCheckout)}${url.search}`;
45
47
  const requestHeaders = {
46
48
  'X-Requested-With': 'XMLHttpRequest',
47
49
  'Content-Type': 'application/x-www-form-urlencoded',
@@ -109,10 +111,9 @@ const withCompleteMasterpass =
109
111
  });
110
112
 
111
113
  // Add error cookie
112
- errorResponse.headers.append(
113
- 'Set-Cookie',
114
- `pz-pos-error=${JSON.stringify(errors)}; path=/;`
115
- );
114
+ errorResponse.cookies.set('pz-pos-error', JSON.stringify(errors), {
115
+ path: '/'
116
+ });
116
117
 
117
118
  return errorResponse;
118
119
  }
@@ -4,6 +4,7 @@ import { Buffer } from 'buffer';
4
4
  import logger from '../utils/log';
5
5
  import { getUrlPathWithLocale } from '../utils/localization';
6
6
  import { PzNextRequest } from '.';
7
+ import { getCheckoutPath } from '../utils';
7
8
 
8
9
  const streamToString = async (stream: ReadableStream<Uint8Array> | null) => {
9
10
  if (stream) {
@@ -39,7 +40,8 @@ const withCompleteWallet =
39
40
  return middleware(req, event);
40
41
  }
41
42
 
42
- const requestUrl = `${Settings.commerceUrl}/orders/checkout/${url.search}`;
43
+ const isPostCheckout = req.cookies.get('pz-post-checkout-flow')?.value === 'true';
44
+ const requestUrl = `${Settings.commerceUrl}${getCheckoutPath(isPostCheckout)}${url.search}`;
43
45
  const requestHeaders = {
44
46
  'X-Requested-With': 'XMLHttpRequest',
45
47
  'Content-Type': 'application/x-www-form-urlencoded',
@@ -105,10 +107,9 @@ const withCompleteWallet =
105
107
  });
106
108
 
107
109
  // Add error cookie
108
- errorResponse.headers.append(
109
- 'Set-Cookie',
110
- `pz-pos-error=${JSON.stringify(errors)}; path=/;`
111
- );
110
+ errorResponse.cookies.set('pz-pos-error', JSON.stringify(errors), {
111
+ path: '/'
112
+ });
112
113
 
113
114
  return errorResponse;
114
115
  }
@@ -14,7 +14,8 @@ import {
14
14
  withUrlRedirection,
15
15
  withCompleteWallet,
16
16
  withWalletCompleteRedirection,
17
- withMasterpassRestCallback
17
+ withMasterpassRestCallback,
18
+ withBfcacheHeaders
18
19
  } from '.';
19
20
  import { urlLocaleMatcherRegex } from '../utils';
20
21
  import withCurrency from './currency';
@@ -25,6 +26,8 @@ import { getUrlPathWithLocale } from '../utils/localization';
25
26
  import getRootHostname from '../utils/get-root-hostname';
26
27
  import { LocaleUrlStrategy } from '../localization';
27
28
 
29
+ const POST_CHECKOUT_COOKIE_MAX_AGE_MS = 1000 * 60 * 30; // 30 minutes
30
+
28
31
  const withPzDefault =
29
32
  (middleware: NextMiddleware) =>
30
33
  async (req: PzNextRequest, event: NextFetchEvent) => {
@@ -101,6 +104,7 @@ const withPzDefault =
101
104
  if (
102
105
  req.nextUrl.pathname.includes('/orders/hooks/') ||
103
106
  req.nextUrl.pathname.includes('/orders/checkout-with-token/') ||
107
+ req.nextUrl.pathname.includes('/orders/post-checkout-redirect/') ||
104
108
  req.nextUrl.pathname.includes('/hooks/cash_register/complete/') ||
105
109
  req.nextUrl.pathname.includes('/hooks/cash_register/pre_order/')
106
110
  ) {
@@ -128,8 +132,13 @@ const withPzDefault =
128
132
  }
129
133
 
130
134
  if (req.nextUrl.pathname.startsWith('/orders/redirection/')) {
135
+ const queryString = searchParams.toString();
131
136
  return NextResponse.rewrite(
132
- new URL(`${encodeURI(Settings.commerceUrl)}/orders/redirection/`)
137
+ new URL(
138
+ `${encodeURI(Settings.commerceUrl)}/orders/redirection/${
139
+ queryString ? `?${queryString}` : ''
140
+ }`
141
+ )
133
142
  );
134
143
  }
135
144
 
@@ -147,21 +156,35 @@ const withPzDefault =
147
156
  );
148
157
  }
149
158
 
150
- // If commerce redirects to /orders/checkout/ without locale
159
+ // If commerce redirects to /orders/checkout/ or /orders/post-checkout/ without locale
160
+ const isPostCheckout = !!req.nextUrl.pathname.match(
161
+ new RegExp('^/orders/post-checkout/$')
162
+ );
163
+ const checkoutLocalePath = getUrlPathWithLocale(
164
+ '/orders/checkout/',
165
+ req.cookies.get('pz-locale')?.value
166
+ );
151
167
  if (
152
- req.nextUrl.pathname.match(new RegExp('^/orders/checkout/$')) &&
153
- req.nextUrl.searchParams.size === 0 &&
154
- getUrlPathWithLocale(
155
- '/orders/checkout/',
156
- req.cookies.get('pz-locale')?.value
157
- ) !== req.nextUrl.pathname
168
+ (isPostCheckout && req.nextUrl.searchParams.size === 0) ||
169
+ (req.nextUrl.pathname.match(new RegExp('^/orders/checkout/$')) &&
170
+ req.nextUrl.searchParams.size === 0 &&
171
+ checkoutLocalePath !== req.nextUrl.pathname)
158
172
  ) {
159
- const redirectUrlWithLocale = `${url.origin}${getUrlPathWithLocale(
160
- '/orders/checkout/',
161
- req.cookies.get('pz-locale')?.value
162
- )}`;
173
+ const response = NextResponse.redirect(
174
+ `${url.origin}${checkoutLocalePath}`,
175
+ 303
176
+ );
177
+
178
+ if (isPostCheckout) {
179
+ response.cookies.set('pz-post-checkout-flow', 'true', {
180
+ path: '/',
181
+ sameSite: 'none',
182
+ secure: true,
183
+ expires: new Date(Date.now() + POST_CHECKOUT_COOKIE_MAX_AGE_MS)
184
+ });
185
+ }
163
186
 
164
- return NextResponse.redirect(redirectUrlWithLocale, 303);
187
+ return response;
165
188
  }
166
189
 
167
190
  // Dynamically handle any payment gateway without specifying names
@@ -233,10 +256,11 @@ const withPzDefault =
233
256
  withCompleteWallet(
234
257
  withWalletCompleteRedirection(
235
258
  withMasterpassRestCallback(
236
- async (
237
- req: PzNextRequest,
238
- event: NextFetchEvent
239
- ) => {
259
+ withBfcacheHeaders(
260
+ async (
261
+ req: PzNextRequest,
262
+ event: NextFetchEvent
263
+ ) => {
240
264
  let middlewareResult: NextResponse | void =
241
265
  NextResponse.next();
242
266
 
@@ -420,6 +444,25 @@ const withPzDefault =
420
444
  );
421
445
  }
422
446
 
447
+ if (
448
+ req.cookies.get(
449
+ 'pz-post-checkout-flow'
450
+ )
451
+ ) {
452
+ if (
453
+ pathnameWithoutLocale.startsWith(
454
+ '/orders/completed/'
455
+ ) ||
456
+ pathnameWithoutLocale.startsWith(
457
+ '/basket'
458
+ )
459
+ ) {
460
+ middlewareResult.cookies.delete(
461
+ 'pz-post-checkout-flow'
462
+ );
463
+ }
464
+ }
465
+
423
466
  if (process.env.ACC_APP_VERSION) {
424
467
  middlewareResult.headers.set(
425
468
  'acc-app-version',
@@ -457,7 +500,7 @@ const withPzDefault =
457
500
  }
458
501
 
459
502
  return middlewareResult;
460
- }
503
+ })
461
504
  )
462
505
  )
463
506
  )
@@ -12,6 +12,7 @@ import withSavedCardRedirection from './saved-card-redirection';
12
12
  import withCompleteWallet from './complete-wallet';
13
13
  import withWalletCompleteRedirection from './wallet-complete-redirection';
14
14
  import withMasterpassRestCallback from './masterpass-rest-callback';
15
+ import withBfcacheHeaders from './bfcache-headers';
15
16
  import { NextRequest } from 'next/server';
16
17
 
17
18
  export {
@@ -28,7 +29,8 @@ export {
28
29
  withSavedCardRedirection,
29
30
  withCompleteWallet,
30
31
  withWalletCompleteRedirection,
31
- withMasterpassRestCallback
32
+ withMasterpassRestCallback,
33
+ withBfcacheHeaders
32
34
  };
33
35
 
34
36
  export interface PzNextRequest extends NextRequest {
@@ -3,6 +3,7 @@ import Settings from 'settings';
3
3
  import logger from '../utils/log';
4
4
  import { getUrlPathWithLocale } from '../utils/localization';
5
5
  import { PzNextRequest } from '.';
6
+ import { getCheckoutPath } from '../utils';
6
7
 
7
8
  const withMasterpassRestCallback =
8
9
  (middleware: NextMiddleware) =>
@@ -19,7 +20,9 @@ const withMasterpassRestCallback =
19
20
  }
20
21
 
21
22
  try {
22
- const requestUrl = new URL('/orders/checkout/', Settings.commerceUrl);
23
+ const isPostCheckout = req.cookies.get('pz-post-checkout-flow')?.value === 'true';
24
+ const requestUrl = new URL(getCheckoutPath(isPostCheckout), Settings.commerceUrl);
25
+
23
26
  url.searchParams.forEach((value, key) => {
24
27
  requestUrl.searchParams.set(key, value);
25
28
  });
@@ -56,18 +59,20 @@ const withMasterpassRestCallback =
56
59
  ip
57
60
  });
58
61
 
59
- return NextResponse.redirect(
62
+ const errorResponse = NextResponse.redirect(
60
63
  `${url.origin}${getUrlPathWithLocale(
61
64
  '/orders/checkout/',
62
65
  req.cookies.get('pz-locale')?.value
63
66
  )}`,
64
- {
65
- status: 303,
66
- headers: {
67
- 'Set-Cookie': `pz-pos-error=${encodeURIComponent(JSON.stringify(errors))}; path=/;`
68
- }
69
- }
67
+ 303
70
68
  );
69
+
70
+ // Add error cookie
71
+ errorResponse.cookies.set('pz-pos-error', JSON.stringify(errors), {
72
+ path: '/'
73
+ });
74
+
75
+ return errorResponse;
71
76
  }
72
77
 
73
78
  const redirectUrl =
@@ -4,6 +4,7 @@ import Settings from 'settings';
4
4
  import logger from '../utils/log';
5
5
  import { PzNextRequest } from '.';
6
6
  import { getUrlPathWithLocale } from '../utils/localization';
7
+ import { getCheckoutPath } from '../utils';
7
8
 
8
9
  const streamToString = async (stream: ReadableStream<Uint8Array> | null) => {
9
10
  if (stream) {
@@ -41,7 +42,8 @@ const withRedirectionPayment =
41
42
  return middleware(req, event);
42
43
  }
43
44
 
44
- const requestUrl = `${Settings.commerceUrl}/orders/checkout/${url.search}`;
45
+ const isPostCheckout = req.cookies.get('pz-post-checkout-flow')?.value === 'true';
46
+ const requestUrl = `${Settings.commerceUrl}${getCheckoutPath(isPostCheckout)}${url.search}`;
45
47
  const requestHeaders = {
46
48
  'X-Requested-With': 'XMLHttpRequest',
47
49
  'Content-Type': 'application/x-www-form-urlencoded',
@@ -109,10 +111,9 @@ const withRedirectionPayment =
109
111
  });
110
112
 
111
113
  // Add error cookie
112
- errorResponse.headers.append(
113
- 'Set-Cookie',
114
- `pz-pos-error=${JSON.stringify(errors)}; path=/;`
115
- );
114
+ errorResponse.cookies.set('pz-pos-error', JSON.stringify(errors), {
115
+ path: '/'
116
+ });
116
117
 
117
118
  return errorResponse;
118
119
  }
@@ -5,6 +5,7 @@ import logger from '../utils/log';
5
5
  import { getUrlPathWithLocale } from '../utils/localization';
6
6
  import { PzNextRequest } from '.';
7
7
  import { ServerVariables } from '../utils/server-variables';
8
+ import { getCheckoutPath } from '../utils';
8
9
 
9
10
  const streamToString = async (stream: ReadableStream<Uint8Array> | null) => {
10
11
  if (stream) {
@@ -41,7 +42,8 @@ const withSavedCardRedirection =
41
42
  return middleware(req, event);
42
43
  }
43
44
 
44
- const requestUrl = `${Settings.commerceUrl}/orders/checkout/${url.search}`;
45
+ const isPostCheckout = req.cookies.get('pz-post-checkout-flow')?.value === 'true';
46
+ const requestUrl = `${Settings.commerceUrl}${getCheckoutPath(isPostCheckout)}${url.search}`;
45
47
  const requestHeaders = {
46
48
  'X-Requested-With': 'XMLHttpRequest',
47
49
  'Content-Type': 'application/x-www-form-urlencoded',
@@ -109,10 +111,9 @@ const withSavedCardRedirection =
109
111
  });
110
112
 
111
113
  // Add error cookie
112
- errorResponse.headers.append(
113
- 'Set-Cookie',
114
- `pz-pos-error=${JSON.stringify(errors)}; path=/;`
115
- );
114
+ errorResponse.cookies.set('pz-pos-error', JSON.stringify(errors), {
115
+ path: '/'
116
+ });
116
117
 
117
118
  return errorResponse;
118
119
  }
@@ -4,6 +4,7 @@ import { Buffer } from 'buffer';
4
4
  import logger from '../utils/log';
5
5
  import { getUrlPathWithLocale } from '../utils/localization';
6
6
  import { PzNextRequest } from '.';
7
+ import { getCheckoutPath } from '../utils';
7
8
 
8
9
  const streamToString = async (stream: ReadableStream<Uint8Array> | null) => {
9
10
  if (stream) {
@@ -40,7 +41,8 @@ const withThreeDRedirection =
40
41
  return middleware(req, event);
41
42
  }
42
43
 
43
- const requestUrl = `${Settings.commerceUrl}/orders/checkout/${url.search}`;
44
+ const isPostCheckout = req.cookies.get('pz-post-checkout-flow')?.value === 'true';
45
+ const requestUrl = `${Settings.commerceUrl}${getCheckoutPath(isPostCheckout)}${url.search}`;
44
46
  const requestHeaders = {
45
47
  'X-Requested-With': 'XMLHttpRequest',
46
48
  'Content-Type': 'application/x-www-form-urlencoded',
@@ -108,10 +110,9 @@ const withThreeDRedirection =
108
110
  });
109
111
 
110
112
  // Add error cookie
111
- errorResponse.headers.append(
112
- 'Set-Cookie',
113
- `pz-pos-error=${JSON.stringify(errors)}; path=/;`
114
- );
113
+ errorResponse.cookies.set('pz-pos-error', JSON.stringify(errors), {
114
+ path: '/'
115
+ });
115
116
 
116
117
  return errorResponse;
117
118
  }
@@ -4,6 +4,7 @@ import { Buffer } from 'buffer';
4
4
  import logger from '../utils/log';
5
5
  import { getUrlPathWithLocale } from '../utils/localization';
6
6
  import { PzNextRequest } from '.';
7
+ import { getCheckoutPath } from '../utils';
7
8
 
8
9
  const streamToString = async (stream: ReadableStream<Uint8Array> | null) => {
9
10
  if (stream) {
@@ -39,7 +40,8 @@ const withWalletCompleteRedirection =
39
40
  return middleware(req, event);
40
41
  }
41
42
 
42
- const requestUrl = `${Settings.commerceUrl}/orders/checkout/${url.search}`;
43
+ const isPostCheckout = req.cookies.get('pz-post-checkout-flow')?.value === 'true';
44
+ const requestUrl = `${Settings.commerceUrl}${getCheckoutPath(isPostCheckout)}${url.search}`;
43
45
  const requestHeaders = {
44
46
  'X-Requested-With': 'XMLHttpRequest',
45
47
  'Content-Type': 'application/x-www-form-urlencoded',
@@ -129,10 +131,9 @@ const withWalletCompleteRedirection =
129
131
  });
130
132
 
131
133
  // Add error cookie
132
- errorResponse.headers.append(
133
- 'Set-Cookie',
134
- `pz-pos-error=${JSON.stringify(errors)}; path=/;`
135
- );
134
+ errorResponse.cookies.set('pz-pos-error', JSON.stringify(errors), {
135
+ path: '/'
136
+ });
136
137
 
137
138
  return errorResponse;
138
139
  }
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.118.0",
4
+ "version": "1.119.0-rc.1",
5
5
  "private": false,
6
6
  "license": "MIT",
7
7
  "bin": {
@@ -35,7 +35,7 @@
35
35
  "set-cookie-parser": "2.6.0"
36
36
  },
37
37
  "devDependencies": {
38
- "@akinon/eslint-plugin-projectzero": "1.118.0",
38
+ "@akinon/eslint-plugin-projectzero": "1.119.0-rc.1",
39
39
  "@babel/core": "7.26.10",
40
40
  "@babel/preset-env": "7.26.9",
41
41
  "@babel/preset-typescript": "7.27.0",
package/plugins.d.ts CHANGED
@@ -37,6 +37,16 @@ declare module '@akinon/pz-cybersource-uc/src/redux/middleware' {
37
37
  export default middleware as any;
38
38
  }
39
39
 
40
+ declare module '@akinon/pz-apple-pay' {}
41
+
42
+ declare module '@akinon/pz-similar-products' {
43
+ export const SimilarProductsModal: any;
44
+ export const SimilarProductsFilterSidebar: any;
45
+ export const SimilarProductsResultsGrid: any;
46
+ export const SimilarProductsPlugin: any;
47
+ export const SimilarProductsButtonPlugin: any;
48
+ }
49
+
40
50
  declare module '@akinon/pz-cybersource-uc/src/redux/reducer' {
41
51
  export default reducer as any;
42
52
  }
package/plugins.js CHANGED
@@ -16,6 +16,7 @@ module.exports = [
16
16
  'pz-tabby-extension',
17
17
  'pz-apple-pay',
18
18
  'pz-tamara-extension',
19
+ 'pz-similar-products',
19
20
  'pz-cybersource-uc',
20
21
  'pz-hepsipay',
21
22
  'pz-flow-payment',
@@ -204,15 +204,25 @@ export const contextListMiddleware: Middleware = ({
204
204
  (ctx) => ctx.page_name === 'DeliveryOptionSelectionPage'
205
205
  )
206
206
  ) {
207
+ const isCreditCardPayment =
208
+ preOrder?.payment_option?.payment_type === 'credit_card' ||
209
+ preOrder?.payment_option?.payment_type === 'masterpass';
210
+
207
211
  if (context.page_context.card_type) {
208
212
  dispatch(setCardType(context.page_context.card_type));
213
+ } else if (isCreditCardPayment) {
214
+ dispatch(setCardType(null));
209
215
  }
210
216
 
211
217
  if (
212
218
  context.page_context.installments &&
213
219
  preOrder?.payment_option?.payment_type !== 'masterpass_rest'
214
220
  ) {
215
- dispatch(setInstallmentOptions(context.page_context.installments));
221
+ if (!isCreditCardPayment || context.page_context.card_type) {
222
+ dispatch(
223
+ setInstallmentOptions(context.page_context.installments)
224
+ );
225
+ }
216
226
  }
217
227
  }
218
228
 
@@ -14,9 +14,17 @@ export const installmentOptionMiddleware: Middleware = ({
14
14
  return result;
15
15
  }
16
16
 
17
- const { installmentOptions } = getState().checkout;
17
+ const { installmentOptions, cardType } = getState().checkout;
18
18
  const { endpoints: apiEndpoints } = checkoutApi;
19
19
 
20
+ const isCreditCardPayment =
21
+ preOrder?.payment_option?.payment_type === 'credit_card' ||
22
+ preOrder?.payment_option?.payment_type === 'masterpass';
23
+
24
+ if (isCreditCardPayment && !cardType) {
25
+ return result;
26
+ }
27
+
20
28
  if (
21
29
  !preOrder?.installment &&
22
30
  preOrder?.payment_option?.payment_type !== 'saved_card' &&
package/types/index.ts CHANGED
@@ -83,6 +83,12 @@ export interface Settings {
83
83
  };
84
84
  usePrettyUrlRoute?: boolean;
85
85
  commerceUrl: string;
86
+ /**
87
+ * This option allows you to track Sentry events on the client side, in addition to server and edge environments.
88
+ *
89
+ * It overrides process.env.NEXT_PUBLIC_SENTRY_DSN and process.env.SENTRY_DSN.
90
+ */
91
+ sentryDsn?: string;
86
92
  redis: {
87
93
  defaultExpirationTime: number;
88
94
  };
@@ -0,0 +1,3 @@
1
+ export const getCheckoutPath = (isPostCheckout: boolean): string => {
2
+ return isPostCheckout ? '/orders/post-checkout/' : '/orders/checkout/';
3
+ };
package/utils/index.ts CHANGED
@@ -7,6 +7,7 @@ export * from './get-currency';
7
7
  export * from './menu-generator';
8
8
  export * from './generate-commerce-search-params';
9
9
  export * from './get-currency-label';
10
+ export * from './get-checkout-path';
10
11
 
11
12
  export function getCookie(name: string) {
12
13
  if (typeof document === 'undefined') {
@@ -194,7 +195,9 @@ export const urlLocaleMatcherRegex = new RegExp(
194
195
 
195
196
  export const getPosError = () => {
196
197
  const cookieValue = getCookie('pz-pos-error');
197
- const error = JSON.parse(cookieValue ? decodeURIComponent(cookieValue) : '{}');
198
+ const error = JSON.parse(
199
+ cookieValue ? decodeURIComponent(cookieValue) : '{}'
200
+ );
198
201
 
199
202
  // delete 'pz-pos-error' cookie when refreshing or closing page
200
203
  window.addEventListener('beforeunload', () => {
@@ -204,6 +207,23 @@ export const getPosError = () => {
204
207
  return error;
205
208
  };
206
209
 
210
+ export const checkPaymentWillRedirect = (response: {
211
+ context_list?: Array<{
212
+ page_name: string;
213
+ page_context?: { context_data?: { redirect_url?: string } };
214
+ }>;
215
+ redirect_url?: string;
216
+ errors?: unknown;
217
+ }): boolean => {
218
+ if (!response) return false;
219
+
220
+ const hasThankYouPage = response.context_list?.some(
221
+ (c) => c.page_name === 'ThankYouPage'
222
+ );
223
+
224
+ return Boolean(hasThankYouPage || response.redirect_url);
225
+ };
226
+
207
227
  export const urlSchemes = [
208
228
  'http',
209
229
  'tel:',