@akinon/next 1.18.0 → 1.19.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/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # @akinon/next
2
2
 
3
+ ## 1.19.1
4
+
5
+ ## 1.19.0
6
+
7
+ ### Minor Changes
8
+
9
+ - 846e3200: ZERO-2287: Add pz-masterpass plugin
10
+
3
11
  ## 1.18.0
4
12
 
5
13
  ### Minor Changes
@@ -15,6 +15,7 @@ enum Plugin {
15
15
  Otp = 'pz-otp',
16
16
  BKMExpress = 'pz-bkm',
17
17
  CreditPayment = 'pz-credit-payment',
18
+ Masterpass = 'pz-masterpass',
18
19
  B2B = 'pz-b2b'
19
20
  }
20
21
 
@@ -28,6 +29,12 @@ export enum Component {
28
29
  Otp = 'Otp',
29
30
  BKMExpress = 'BKMOption',
30
31
  CreditPayment = 'CreditPayment',
32
+ MasterpassProvider = 'MasterpassProvider',
33
+ MasterpassCardList = 'MasterpassCardList',
34
+ MasterpassCardRegistration = 'MasterpassCardRegistration',
35
+ MasterpassDeleteConfirmationModal = 'MasterpassDeleteConfirmationModal',
36
+ MasterpassOtpModal = 'MasterpassOtpModal',
37
+ MasterpassLinkModal = 'MasterpassLinkModal',
31
38
  MyQuotationsB2B = 'AccountMyQuotations',
32
39
  BasketB2B = 'BasketB2b'
33
40
  }
@@ -42,7 +49,18 @@ const PluginComponents = new Map([
42
49
  [Plugin.Otp, [Component.Otp]],
43
50
  [Plugin.BKMExpress, [Component.BKMExpress]],
44
51
  [Plugin.CreditPayment, [Component.CreditPayment]],
45
- [Plugin.B2B, [Component.MyQuotationsB2B, Component.BasketB2B]],
52
+ [
53
+ Plugin.Masterpass,
54
+ [
55
+ Component.MasterpassCardList,
56
+ Component.MasterpassProvider,
57
+ Component.MasterpassCardRegistration,
58
+ Component.MasterpassDeleteConfirmationModal,
59
+ Component.MasterpassOtpModal,
60
+ Component.MasterpassLinkModal
61
+ ]
62
+ ],
63
+ [Plugin.B2B, [Component.MyQuotationsB2B, Component.BasketB2B]]
46
64
  ]);
47
65
 
48
66
  const getPlugin = (component: Component) => {
@@ -55,10 +73,12 @@ const getPlugin = (component: Component) => {
55
73
 
56
74
  export default function PluginModule({
57
75
  component,
58
- props
76
+ props,
77
+ children
59
78
  }: {
60
79
  component: Component;
61
80
  props?: any;
81
+ children?: React.ReactNode;
62
82
  }) {
63
83
  const plugin = getPlugin(component);
64
84
 
@@ -87,6 +107,8 @@ export default function PluginModule({
87
107
  promise = import(`${'@akinon/pz-bkm'}`);
88
108
  } else if (plugin === Plugin.CreditPayment) {
89
109
  promise = import(`${'@akinon/pz-credit-payment'}`);
110
+ } else if (plugin === Plugin.Masterpass) {
111
+ promise = import(`${'@akinon/pz-masterpass'}`);
90
112
  } else if (plugin === Plugin.B2B) {
91
113
  promise = import(`${'@akinon/pz-b2b'}`);
92
114
  }
@@ -100,11 +122,15 @@ export default function PluginModule({
100
122
  },
101
123
  { ssr: false }
102
124
  ),
103
- [plugin]
125
+ [plugin, component]
104
126
  );
105
127
 
106
128
  if (!(plugins as string[]).includes(plugin)) {
107
- return null;
129
+ return <>{children}</>;
130
+ }
131
+
132
+ if (children) {
133
+ return <Component {...props}>{children}</Component>;
108
134
  }
109
135
 
110
136
  return <Component {...props} />;
@@ -50,6 +50,10 @@ export default function SelectedPaymentOptionView() {
50
50
  );
51
51
  } else if (payment_option.payment_type === 'loyalty_money') {
52
52
  promise = import(`views/checkout/steps/payment/options/loyalty`);
53
+ } else if (payment_option.payment_type === 'masterpass') {
54
+ promise = import(
55
+ `views/checkout/steps/payment/options/credit-card`
56
+ );
53
57
  }
54
58
  // else if (payment_option.payment_type === 'credit_payment') {
55
59
  // promise = import(`views/checkout/steps/payment/options/credit-payment`);
@@ -16,7 +16,17 @@ import {
16
16
  import { buildClientRequestUrl } from '../../utils';
17
17
  import { api } from './api';
18
18
  import { checkout } from '../urls';
19
- import { store } from 'redux/store';
19
+ import { AppDispatch, AppStore, store } from 'redux/store';
20
+ import settings from 'settings';
21
+ import { showMobile3dIframe } from '../../utils/mobile-3d-iframe';
22
+ import {
23
+ setError,
24
+ setOtpModalVisible
25
+ } from '@akinon/pz-masterpass/src/redux/reducer';
26
+ import {
27
+ buildDirectPurchaseForm,
28
+ buildPurchaseForm
29
+ } from '@akinon/pz-masterpass/src/utils';
20
30
 
21
31
  interface CheckoutResponse {
22
32
  pre_order?: PreOrder;
@@ -38,7 +48,7 @@ interface SetRetailStoreParams {
38
48
  billingAddressPk: number;
39
49
  }
40
50
 
41
- interface CompleteCreditCardParams {
51
+ export interface CompleteCreditCardParams {
42
52
  card_holder: string;
43
53
  card_cvv: string;
44
54
  card_number: string;
@@ -66,6 +76,83 @@ export interface PayOnDeliveryParams {
66
76
  paymentType: string;
67
77
  }
68
78
 
79
+ const completeMasterpassPayment = async (
80
+ params: CompleteCreditCardParams,
81
+ dispatch: AppDispatch,
82
+ context: CheckoutContext,
83
+ reduxStore: AppStore
84
+ ) => {
85
+ const state = reduxStore.getState();
86
+ const { token, order_no } = context.page_context;
87
+ const { endpoints: apiEndpoints } = checkoutApi;
88
+ const { preOrder } = state.checkout ?? {};
89
+
90
+ const { isDirectPurchase, referenceNo, credentials, msisdn, selectedCard } =
91
+ state.masterpass ?? {};
92
+
93
+ const commonFormValues = {
94
+ token,
95
+ orderNo: order_no,
96
+ referenceNo,
97
+ merchantId: credentials?.merchant_id ?? null,
98
+ msisdn,
99
+ amount: preOrder?.unpaid_amount?.replace('.', '') ?? ''
100
+ };
101
+
102
+ const form = isDirectPurchase
103
+ ? await buildDirectPurchaseForm(commonFormValues, params)
104
+ : await buildPurchaseForm({ ...commonFormValues, selectedCard });
105
+
106
+ window.MFS?.[
107
+ state.masterpass.isDirectPurchase ? 'directPurchase' : 'purchase'
108
+ ]($(form), async (statusCode, response) => {
109
+ if (response.responseCode == '5009') {
110
+ // TODO: Handle Digital Loan
111
+ }
112
+
113
+ if (response.responseCode == '5010') {
114
+ const { isMobileApp } = state.root;
115
+ const returnUrl = state.masterpass.credentials?.s3d_return_url;
116
+ const url =
117
+ response.url3D + '&returnUrl=' + encodeURIComponent(returnUrl);
118
+ const urlObj = new URL(url, window.location.origin);
119
+ urlObj.searchParams.set('t', new Date().getTime().toString());
120
+
121
+ if (
122
+ (isMobileApp ||
123
+ /iPad|iPhone|iPod|Android/i.test(navigator.userAgent)) &&
124
+ !settings.checkout?.iframeExcludedPaymentOptions?.includes(
125
+ preOrder?.payment_option?.slug
126
+ )
127
+ ) {
128
+ showMobile3dIframe(urlObj.toString());
129
+ } else {
130
+ window.location.href = urlObj.toString();
131
+ }
132
+
133
+ return;
134
+ }
135
+
136
+ if (response.responseCode == '5001') {
137
+ dispatch(setOtpModalVisible(true));
138
+ return;
139
+ }
140
+
141
+ if (
142
+ response.token &&
143
+ (response.responseCode == '0000' || response.responseCode == '')
144
+ ) {
145
+ dispatch(
146
+ apiEndpoints.completeMasterpassPayment.initiate({ token }) as any
147
+ );
148
+ }
149
+
150
+ if (response.responseDescription.length) {
151
+ dispatch(setError(response.responseDescription));
152
+ }
153
+ });
154
+ };
155
+
69
156
  export const checkoutApi = api.injectEndpoints({
70
157
  endpoints: (build) => ({
71
158
  fetchCheckout: build.query<CheckoutResponse, void>({
@@ -101,19 +188,69 @@ export const checkoutApi = api.injectEndpoints({
101
188
  card_month,
102
189
  card_year,
103
190
  use_three_d = true
104
- }) => ({
105
- url: buildClientRequestUrl(checkout.completeCreditCardPayment, {
191
+ }) => {
192
+ const paymentOption =
193
+ store.getState().checkout?.preOrder?.payment_option;
194
+
195
+ if (paymentOption?.payment_type === 'masterpass') {
196
+ return {
197
+ url: buildClientRequestUrl(checkout.getMasterpassOrderNo, {
198
+ useFormData: true
199
+ }),
200
+ method: 'POST'
201
+ };
202
+ }
203
+
204
+ return {
205
+ url: buildClientRequestUrl(checkout.completeCreditCardPayment, {
206
+ useFormData: true
207
+ }),
208
+ method: 'POST',
209
+ body: {
210
+ agreement: '1',
211
+ use_three_d: use_three_d ? '1' : '0',
212
+ card_cvv,
213
+ card_holder,
214
+ card_month,
215
+ card_number,
216
+ card_year
217
+ }
218
+ };
219
+ },
220
+ async onQueryStarted(args, { dispatch, queryFulfilled }) {
221
+ dispatch(setPaymentStepBusy(true));
222
+ const { data } = await queryFulfilled;
223
+ const reduxStore = (await import('redux/store')).store;
224
+ const completePaymentContext = data?.context_list?.find(
225
+ (context) => context?.page_name === 'MasterpassCompletePage'
226
+ );
227
+
228
+ if (completePaymentContext) {
229
+ await completeMasterpassPayment(
230
+ args,
231
+ dispatch,
232
+ completePaymentContext,
233
+ reduxStore
234
+ );
235
+ }
236
+
237
+ dispatch(setPaymentStepBusy(false));
238
+ },
239
+ invalidatesTags: ['Basket']
240
+ }),
241
+ completeMasterpassPayment: build.mutation<
242
+ CheckoutResponse,
243
+ {
244
+ token: string;
245
+ }
246
+ >({
247
+ query: ({ token }) => ({
248
+ url: buildClientRequestUrl(checkout.completeMasterpassPayment, {
106
249
  useFormData: true
107
250
  }),
108
251
  method: 'POST',
109
252
  body: {
110
- agreement: '1',
111
- use_three_d: use_three_d ? '1' : '0',
112
- card_cvv,
113
- card_holder,
114
- card_month,
115
- card_number,
116
- card_year
253
+ token
117
254
  }
118
255
  }),
119
256
  async onQueryStarted(arg, { dispatch, queryFulfilled }) {
@@ -328,7 +465,7 @@ export const checkoutApi = api.injectEndpoints({
328
465
  }),
329
466
  method: 'POST',
330
467
  body: {
331
- agreement: true,
468
+ agreement: true
332
469
  }
333
470
  }),
334
471
  async onQueryStarted(arg, { dispatch, queryFulfilled }) {
package/data/urls.ts CHANGED
@@ -79,6 +79,8 @@ export const checkout = {
79
79
  setPaymentOption: '/orders/checkout/?page=PaymentOptionSelectionPage',
80
80
  setBinNumber: '/orders/checkout/?page=BinNumberPage',
81
81
  setMasterpassBinNumber: '/orders/checkout/?page=MasterpassBinNumberPage',
82
+ getMasterpassOrderNo: '/orders/checkout/?page=MasterpassOrderNoPage',
83
+ completeMasterpassPayment: '/orders/checkout/?page=MasterpassCompletePage',
82
84
  setInstallmentOption: '/orders/checkout/?page=InstallmentSelectionPage',
83
85
  setMasterPassInstallmentOption:
84
86
  '/orders/checkout/?page=MasterpassInstallmentPage',
@@ -18,6 +18,7 @@ export const usePaymentOptions = () => {
18
18
  pay_on_delivery: 'pz-pay-on-delivery',
19
19
  bkm_express: 'pz-bkm',
20
20
  credit_payment: 'pz-credit-payment',
21
+ masterpass: 'pz-masterpass'
21
22
  };
22
23
 
23
24
  const isInitialTypeIncluded = (type: string) => initialTypes.has(type);
@@ -0,0 +1,159 @@
1
+ import { NextFetchEvent, NextMiddleware, NextResponse } from 'next/server';
2
+ import Settings from 'settings';
3
+ import { Buffer } from 'buffer';
4
+ import logger from '../utils/log';
5
+ import { getUrlPathWithLocale } from '../utils/localization';
6
+ import { PzNextRequest } from '.';
7
+
8
+ const streamToString = async (stream: ReadableStream<Uint8Array> | null) => {
9
+ if (stream) {
10
+ const chunks = [];
11
+ let result = '';
12
+
13
+ try {
14
+ for await (const chunk of stream as any) {
15
+ chunks.push(Buffer.from(chunk));
16
+ }
17
+
18
+ result = Buffer.concat(chunks).toString('utf-8');
19
+ } catch (error) {
20
+ logger.error('Error while reading body stream', {
21
+ middleware: 'complete-masterpass',
22
+ error
23
+ });
24
+ }
25
+
26
+ return result;
27
+ }
28
+ return null;
29
+ };
30
+
31
+ const withCompleteMasterpass =
32
+ (middleware: NextMiddleware) =>
33
+ async (req: PzNextRequest, event: NextFetchEvent) => {
34
+ const url = req.nextUrl.clone();
35
+ const ip = req.headers.get('x-forwarded-for') ?? '';
36
+
37
+ if (url.search.indexOf('MasterpassCompletePage') === -1) {
38
+ return middleware(req, event);
39
+ }
40
+
41
+ const requestUrl = `${Settings.commerceUrl}/orders/checkout/${url.search}`;
42
+ const requestHeaders = {
43
+ 'X-Requested-With': 'XMLHttpRequest',
44
+ 'Content-Type': 'application/x-www-form-urlencoded',
45
+ Cookie: `osessionid=${req.cookies.get('osessionid')?.value ?? ''}`,
46
+ 'x-currency': req.cookies.get('pz-currency')?.value ?? ''
47
+ };
48
+
49
+ try {
50
+ const body = await streamToString(req.body);
51
+
52
+ const request = await fetch(requestUrl, {
53
+ method: 'POST',
54
+ headers: requestHeaders,
55
+ body
56
+ });
57
+
58
+ logger.info('Complete Masterpass payment request', {
59
+ requestUrl,
60
+ status: request.status,
61
+ requestHeaders,
62
+ ip
63
+ });
64
+
65
+ const response = await request.json();
66
+
67
+ const { context_list: contextList, errors } = response;
68
+ const redirectionContext = contextList?.find(
69
+ (context) => context.page_context?.redirect_url
70
+ );
71
+ const redirectUrl = redirectionContext?.page_context?.redirect_url;
72
+
73
+ if (errors && Object.keys(errors).length) {
74
+ logger.error('Error while completing Masterpass payment', {
75
+ middleware: 'complete-masterpass',
76
+ errors,
77
+ requestHeaders,
78
+ ip
79
+ });
80
+
81
+ return NextResponse.redirect(
82
+ `${url.origin}${getUrlPathWithLocale(
83
+ '/orders/checkout/',
84
+ req.cookies.get('pz-locale')?.value
85
+ )}`,
86
+ {
87
+ status: 303,
88
+ headers: {
89
+ 'Set-Cookie': `pz-pos-error=${JSON.stringify(errors)}; path=/;`
90
+ }
91
+ }
92
+ );
93
+ }
94
+
95
+ logger.info('Order success page context list', {
96
+ middleware: 'complete-masterpass',
97
+ contextList,
98
+ ip
99
+ });
100
+
101
+ if (!redirectUrl) {
102
+ logger.warn(
103
+ 'No redirection url for order success page found in page_context. Redirecting to checkout page.',
104
+ {
105
+ middleware: 'complete-masterpass',
106
+ requestHeaders,
107
+ response: JSON.stringify(response),
108
+ ip
109
+ }
110
+ );
111
+
112
+ const redirectUrlWithLocale = `${url.origin}${getUrlPathWithLocale(
113
+ '/orders/checkout/',
114
+ req.cookies.get('pz-locale')?.value
115
+ )}`;
116
+
117
+ return NextResponse.redirect(redirectUrlWithLocale, 303);
118
+ }
119
+
120
+ const redirectUrlWithLocale = `${url.origin}${getUrlPathWithLocale(
121
+ redirectUrl,
122
+ req.cookies.get('pz-locale')?.value
123
+ )}`;
124
+
125
+ logger.info('Redirecting to order success page', {
126
+ middleware: 'complete-masterpass',
127
+ redirectUrlWithLocale,
128
+ ip
129
+ });
130
+
131
+ // Using POST method while redirecting causes an error,
132
+ // So we use 303 status code to change the method to GET
133
+ const nextResponse = NextResponse.redirect(redirectUrlWithLocale, 303);
134
+
135
+ nextResponse.headers.set(
136
+ 'Set-Cookie',
137
+ request.headers.get('set-cookie') ?? ''
138
+ );
139
+
140
+ return nextResponse;
141
+ } catch (error) {
142
+ logger.error('Error while completing Masterpass payment', {
143
+ middleware: 'complete-masterpass',
144
+ error,
145
+ requestHeaders,
146
+ ip
147
+ });
148
+
149
+ return NextResponse.redirect(
150
+ `${url.origin}${getUrlPathWithLocale(
151
+ '/orders/checkout/',
152
+ req.cookies.get('pz-locale')?.value
153
+ )}`,
154
+ 303
155
+ );
156
+ }
157
+ };
158
+
159
+ export default withCompleteMasterpass;
@@ -3,6 +3,7 @@ import Settings from 'settings';
3
3
  import {
4
4
  PzNextRequest,
5
5
  withCompleteGpay,
6
+ withCompleteMasterpass,
6
7
  withOauthLogin,
7
8
  withPrettyUrl,
8
9
  withRedirectionPayment,
@@ -124,61 +125,74 @@ const withPzDefault =
124
125
  withThreeDRedirection(
125
126
  withUrlRedirection(
126
127
  withCompleteGpay(
127
- async (req: PzNextRequest, event: NextFetchEvent) => {
128
- let middlewareResult: NextResponse | void =
129
- NextResponse.next();
128
+ withCompleteMasterpass(
129
+ async (req: PzNextRequest, event: NextFetchEvent) => {
130
+ let middlewareResult: NextResponse | void =
131
+ NextResponse.next();
130
132
 
131
- try {
132
- const { locale, prettyUrl, currency } =
133
- req.middlewareParams.rewrites;
134
- const { defaultLocaleValue } = Settings.localization;
135
- const url = req.nextUrl.clone();
136
- const pathnameWithoutLocale = url.pathname.replace(
137
- urlLocaleMatcherRegex,
138
- ''
139
- );
140
-
141
- url.basePath = `/${commerceUrl}`;
142
- url.pathname = `/${
143
- locale.length ? `${locale}/` : ''
144
- }${currency}${prettyUrl ?? pathnameWithoutLocale}`;
145
-
146
- Settings.rewrites.forEach((rewrite) => {
147
- url.pathname = url.pathname.replace(
148
- rewrite.source,
149
- rewrite.destination
133
+ try {
134
+ const { locale, prettyUrl, currency } =
135
+ req.middlewareParams.rewrites;
136
+ const { defaultLocaleValue } = Settings.localization;
137
+ const url = req.nextUrl.clone();
138
+ const pathnameWithoutLocale = url.pathname.replace(
139
+ urlLocaleMatcherRegex,
140
+ ''
150
141
  );
151
- });
152
142
 
153
- middlewareResult = (await middleware(
154
- req,
155
- event
156
- )) as NextResponse | void;
143
+ url.basePath = `/${commerceUrl}`;
144
+ url.pathname = `/${
145
+ locale.length ? `${locale}/` : ''
146
+ }${currency}${prettyUrl ?? pathnameWithoutLocale}`;
157
147
 
158
- // if middleware.ts has a return value for current url
159
- if (middlewareResult instanceof NextResponse) {
160
- // pz-override-response header is used to prevent 404 page for custom responses.
161
- if (
162
- middlewareResult.headers.get(
163
- 'pz-override-response'
164
- ) !== 'true'
165
- ) {
166
- middlewareResult.headers.set(
167
- 'x-middleware-rewrite',
168
- url.href
148
+ Settings.rewrites.forEach((rewrite) => {
149
+ url.pathname = url.pathname.replace(
150
+ rewrite.source,
151
+ rewrite.destination
169
152
  );
170
- }
171
- } else {
172
- // if middleware.ts doesn't have a return value.
173
- // e.g. NextResponse.next() doesn't exist in middleware.ts
153
+ });
174
154
 
175
- middlewareResult = NextResponse.rewrite(url);
176
- }
155
+ middlewareResult = (await middleware(
156
+ req,
157
+ event
158
+ )) as NextResponse | void;
177
159
 
178
- if (!url.pathname.startsWith(`/${currency}/orders`)) {
160
+ // if middleware.ts has a return value for current url
161
+ if (middlewareResult instanceof NextResponse) {
162
+ // pz-override-response header is used to prevent 404 page for custom responses.
163
+ if (
164
+ middlewareResult.headers.get(
165
+ 'pz-override-response'
166
+ ) !== 'true'
167
+ ) {
168
+ middlewareResult.headers.set(
169
+ 'x-middleware-rewrite',
170
+ url.href
171
+ );
172
+ }
173
+ } else {
174
+ // if middleware.ts doesn't have a return value.
175
+ // e.g. NextResponse.next() doesn't exist in middleware.ts
176
+
177
+ middlewareResult = NextResponse.rewrite(url);
178
+ }
179
+
180
+ if (!url.pathname.startsWith(`/${currency}/orders`)) {
181
+ middlewareResult.cookies.set(
182
+ 'pz-locale',
183
+ locale?.length > 0 ? locale : defaultLocaleValue,
184
+ {
185
+ sameSite: 'none',
186
+ secure: true,
187
+ expires: new Date(
188
+ Date.now() + 1000 * 60 * 60 * 24 * 7
189
+ ) // 7 days
190
+ }
191
+ );
192
+ }
179
193
  middlewareResult.cookies.set(
180
- 'pz-locale',
181
- locale?.length > 0 ? locale : defaultLocaleValue,
194
+ 'pz-currency',
195
+ currency,
182
196
  {
183
197
  sameSite: 'none',
184
198
  secure: true,
@@ -187,65 +201,63 @@ const withPzDefault =
187
201
  ) // 7 days
188
202
  }
189
203
  );
190
- }
191
- middlewareResult.cookies.set('pz-currency', currency, {
192
- sameSite: 'none',
193
- secure: true,
194
- expires: new Date(Date.now() + 1000 * 60 * 60 * 24 * 7) // 7 days
195
- });
196
-
197
- if (
198
- req.cookies.get('pz-locale') &&
199
- req.cookies.get('pz-locale').value !== locale
200
- ) {
201
- logger.debug('Locale changed', {
202
- locale,
203
- oldLocale: req.cookies.get('pz-locale')?.value,
204
- ip
205
- });
206
- }
207
-
208
- middlewareResult.headers.set(
209
- 'pz-url',
210
- req.nextUrl.toString()
211
- );
212
204
 
213
- if (req.cookies.get('pz-set-currency')) {
214
- middlewareResult.cookies.delete('pz-set-currency');
215
- }
205
+ if (
206
+ req.cookies.get('pz-locale') &&
207
+ req.cookies.get('pz-locale').value !== locale
208
+ ) {
209
+ logger.debug('Locale changed', {
210
+ locale,
211
+ oldLocale: req.cookies.get('pz-locale')?.value,
212
+ ip
213
+ });
214
+ }
216
215
 
217
- if (process.env.ACC_APP_VERSION) {
218
216
  middlewareResult.headers.set(
219
- 'acc-app-version',
220
- process.env.ACC_APP_VERSION
217
+ 'pz-url',
218
+ req.nextUrl.toString()
221
219
  );
222
- }
223
220
 
224
- // Set CSRF token if not set
225
- try {
226
- const url = `${Settings.commerceUrl}${user.csrfToken}`;
221
+ if (req.cookies.get('pz-set-currency')) {
222
+ middlewareResult.cookies.delete('pz-set-currency');
223
+ }
227
224
 
228
- if (!req.cookies.get('csrftoken')) {
229
- const { csrf_token } = await (
230
- await fetch(url)
231
- ).json();
232
- middlewareResult.cookies.set('csrftoken', csrf_token);
225
+ if (process.env.ACC_APP_VERSION) {
226
+ middlewareResult.headers.set(
227
+ 'acc-app-version',
228
+ process.env.ACC_APP_VERSION
229
+ );
230
+ }
231
+
232
+ // Set CSRF token if not set
233
+ try {
234
+ const url = `${Settings.commerceUrl}${user.csrfToken}`;
235
+
236
+ if (!req.cookies.get('csrftoken')) {
237
+ const { csrf_token } = await (
238
+ await fetch(url)
239
+ ).json();
240
+ middlewareResult.cookies.set(
241
+ 'csrftoken',
242
+ csrf_token
243
+ );
244
+ }
245
+ } catch (error) {
246
+ logger.error('CSRF Error', {
247
+ error,
248
+ ip
249
+ });
233
250
  }
234
251
  } catch (error) {
235
- logger.error('CSRF Error', {
252
+ logger.error('withPzDefault Error', {
236
253
  error,
237
254
  ip
238
255
  });
239
256
  }
240
- } catch (error) {
241
- logger.error('withPzDefault Error', {
242
- error,
243
- ip
244
- });
245
- }
246
257
 
247
- return middlewareResult;
248
- }
258
+ return middlewareResult;
259
+ }
260
+ )
249
261
  )
250
262
  )
251
263
  )
@@ -6,6 +6,7 @@ import withLocale from './locale';
6
6
  import withOauthLogin from './oauth-login';
7
7
  import withUrlRedirection from './url-redirection';
8
8
  import withCompleteGpay from './complete-gpay';
9
+ import withCompleteMasterpass from './complete-masterpass';
9
10
  import { NextRequest } from 'next/server';
10
11
 
11
12
  export {
@@ -16,7 +17,8 @@ export {
16
17
  withLocale,
17
18
  withOauthLogin,
18
19
  withUrlRedirection,
19
- withCompleteGpay
20
+ withCompleteGpay,
21
+ withCompleteMasterpass
20
22
  };
21
23
 
22
24
  export interface PzNextRequest extends NextRequest {
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.18.0",
4
+ "version": "1.19.1",
5
5
  "private": false,
6
6
  "license": "MIT",
7
7
  "bin": {
@@ -31,7 +31,7 @@
31
31
  "@typescript-eslint/eslint-plugin": "6.7.4",
32
32
  "@typescript-eslint/parser": "6.7.4",
33
33
  "eslint": "^8.14.0",
34
- "@akinon/eslint-plugin-projectzero": "1.18.0",
34
+ "@akinon/eslint-plugin-projectzero": "1.19.1",
35
35
  "eslint-config-prettier": "8.5.0"
36
36
  }
37
37
  }
package/plugins.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ declare module '@akinon/pz-masterpass' {
2
+ export const masterpassReducer: unknown;
3
+ }
package/plugins.js CHANGED
@@ -8,5 +8,6 @@ module.exports = [
8
8
  'pz-otp',
9
9
  'pz-bkm',
10
10
  'pz-credit-payment',
11
+ 'pz-masterpass',
11
12
  'pz-b2b'
12
13
  ];
@@ -4,12 +4,16 @@ import configReducer from './config';
4
4
  import headerReducer from './header';
5
5
  import { api } from '../../data/client/api';
6
6
 
7
+ // Plugin reducers
8
+ import { masterpassReducer } from '@akinon/pz-masterpass';
9
+
7
10
  const reducers = {
8
11
  [api.reducerPath]: api.reducer,
9
12
  root: rootReducer,
10
13
  checkout: checkoutReducer,
11
14
  config: configReducer,
12
- header: headerReducer
15
+ header: headerReducer,
16
+ masterpass: masterpassReducer
13
17
  };
14
18
 
15
- export default reducers;
19
+ export default reducers;
@@ -117,6 +117,7 @@ export interface CheckoutContext {
117
117
  redirect_url?: string;
118
118
  context_data?: any;
119
119
  balance?: string;
120
+ [key: string]: any;
120
121
  };
121
122
  }
122
123