@akinon/pz-masterpass-rest 2.0.0-beta.12 → 2.0.0-beta.13
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 +21 -0
- package/README.md +11 -1
- package/assets/masterpass-javascript-sdk-web.min.js +1 -0
- package/docs/USAGE.md +1176 -0
- package/package.json +3 -3
- package/src/components/credit-card-form.tsx +1 -1
- package/src/components/information-modal.tsx +139 -0
- package/src/components/otp-modal.tsx +94 -12
- package/src/hooks/useMasterpassAccount.ts +77 -37
- package/src/hooks/useMasterpassPayment.ts +248 -123
- package/src/hooks/useMasterpassToken.ts +61 -16
- package/src/redux/api.ts +16 -7
- package/src/redux/reducer.ts +14 -0
- package/src/services/account.ts +73 -64
- package/src/services/payment.ts +131 -93
- package/src/services/verify.ts +44 -44
- package/src/types/custom-render.types.ts +22 -2
- package/src/types/payment.types.ts +14 -0
- package/src/utils/payment-constants.ts +3 -3
- package/src/utils/payment-utils.ts +20 -4
- package/src/utils/response-handler.ts +35 -6
- package/src/utils/session-handler.ts +60 -0
- package/src/utils/validation-schemas.ts +1 -1
- package/src/views/masterpass-rest-option.tsx +55 -30
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
setOrderData,
|
|
17
17
|
setOrderCompleted
|
|
18
18
|
} from '../redux/reducer';
|
|
19
|
+
import { useMasterpassToken } from './useMasterpassToken';
|
|
19
20
|
import { PaymentService } from '../services/payment';
|
|
20
21
|
import {
|
|
21
22
|
createPaymentRequest,
|
|
@@ -26,10 +27,28 @@ import { handleMasterpassResponse } from '../utils/response-handler';
|
|
|
26
27
|
import type { Installment } from '../types/payment.types';
|
|
27
28
|
import type { CardModel } from '../types/account.types';
|
|
28
29
|
|
|
30
|
+
export type PaymentResult = {
|
|
31
|
+
success: boolean;
|
|
32
|
+
requiresRedirect?: boolean;
|
|
33
|
+
requiresOTP?: boolean;
|
|
34
|
+
otpType?: 'OTP' | 'RTA' | 'CVV';
|
|
35
|
+
message?: any;
|
|
36
|
+
};
|
|
37
|
+
|
|
29
38
|
export const useMasterpassPayment = () => {
|
|
30
39
|
const dispatch = useDispatch();
|
|
31
|
-
const {
|
|
32
|
-
|
|
40
|
+
const {
|
|
41
|
+
paymentState,
|
|
42
|
+
newCardFormData,
|
|
43
|
+
currency,
|
|
44
|
+
terminalGroupId,
|
|
45
|
+
bankIca,
|
|
46
|
+
tokenData
|
|
47
|
+
} = useAppSelector((state) => state.masterpassRest);
|
|
48
|
+
|
|
49
|
+
const { refetch: refetchToken } = useMasterpassToken({
|
|
50
|
+
useThreeD: paymentState.useThreeD
|
|
51
|
+
});
|
|
33
52
|
|
|
34
53
|
const [setMasterpassRestBinNumber, { isLoading: isCheckoutLoading }] =
|
|
35
54
|
useSetMasterpassRestBinNumberMutation();
|
|
@@ -43,6 +62,19 @@ export const useMasterpassPayment = () => {
|
|
|
43
62
|
const [finalizeMasterpassOrder, { isLoading: isFinalizeLoading }] =
|
|
44
63
|
useFinalizeMasterpassOrderMutation();
|
|
45
64
|
|
|
65
|
+
const refreshTokenForPayment = useCallback(async () => {
|
|
66
|
+
const result = await refetchToken({ skipReset: true });
|
|
67
|
+
if (result?.data?.token) {
|
|
68
|
+
const decodedToken = window.Utils.decodeJwt(result.data.token);
|
|
69
|
+
return {
|
|
70
|
+
tokenData: decodedToken,
|
|
71
|
+
token: result.data.token,
|
|
72
|
+
merchantId: decodedToken?.MerchantId
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
return null;
|
|
76
|
+
}, [refetchToken]);
|
|
77
|
+
|
|
46
78
|
const updatePaymentStateAction = useCallback(
|
|
47
79
|
(updates: Partial<typeof paymentState>) => {
|
|
48
80
|
dispatch(updatePaymentState(updates));
|
|
@@ -50,6 +82,21 @@ export const useMasterpassPayment = () => {
|
|
|
50
82
|
[dispatch]
|
|
51
83
|
);
|
|
52
84
|
|
|
85
|
+
const handleInstallmentSelect = useCallback(
|
|
86
|
+
async (installment: Installment) => {
|
|
87
|
+
dispatch(setSelectedInstallment(installment));
|
|
88
|
+
|
|
89
|
+
try {
|
|
90
|
+
await checkoutMasterpassInstallment({
|
|
91
|
+
installment: installment.pk
|
|
92
|
+
}).unwrap();
|
|
93
|
+
} catch (error) {
|
|
94
|
+
// Silently handle errors (e.g., mutation aborted due to rapid selection)
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
[checkoutMasterpassInstallment, dispatch]
|
|
98
|
+
);
|
|
99
|
+
|
|
53
100
|
const handleCardSelect = useCallback(
|
|
54
101
|
async (card: CardModel) => {
|
|
55
102
|
dispatch(setSelectedCard(card));
|
|
@@ -67,152 +114,230 @@ export const useMasterpassPayment = () => {
|
|
|
67
114
|
const pageContext = result.context_list[0].page_context;
|
|
68
115
|
dispatch(setInstallments(pageContext.installments));
|
|
69
116
|
dispatch(setCardType(pageContext.card_type));
|
|
117
|
+
|
|
118
|
+
if (pageContext.installments?.length > 0) {
|
|
119
|
+
await handleInstallmentSelect(pageContext.installments[0]);
|
|
120
|
+
}
|
|
70
121
|
}
|
|
71
122
|
} catch (error) {
|
|
72
|
-
|
|
123
|
+
// Silently handle errors (e.g., mutation aborted due to rapid selection)
|
|
73
124
|
}
|
|
74
125
|
},
|
|
75
|
-
[setMasterpassRestBinNumber, dispatch]
|
|
126
|
+
[setMasterpassRestBinNumber, handleInstallmentSelect, dispatch]
|
|
76
127
|
);
|
|
77
128
|
|
|
78
|
-
const
|
|
79
|
-
|
|
80
|
-
dispatch(setSelectedInstallment(installment));
|
|
129
|
+
const processPayment = useCallback(async (): Promise<PaymentResult> => {
|
|
130
|
+
const { selectedCard, selectedInstallment, cvc, useThreeD } = paymentState;
|
|
81
131
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
132
|
+
if (!selectedCard || !selectedInstallment) {
|
|
133
|
+
return {
|
|
134
|
+
success: false,
|
|
135
|
+
message: 'Please complete all required steps before payment'
|
|
136
|
+
};
|
|
137
|
+
}
|
|
86
138
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
139
|
+
try {
|
|
140
|
+
const freshResult = await refreshTokenForPayment();
|
|
141
|
+
const activeTokenData = freshResult?.tokenData || tokenData;
|
|
142
|
+
const activeToken = freshResult?.token;
|
|
143
|
+
const activeMerchantId = freshResult?.merchantId || tokenData?.MerchantId;
|
|
90
144
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
throw new Error('Failed to prepare order');
|
|
145
|
+
if (!activeTokenData?.AccountKey) {
|
|
146
|
+
return { success: false, message: 'Token data not available' };
|
|
94
147
|
}
|
|
95
|
-
},
|
|
96
|
-
[
|
|
97
|
-
checkoutMasterpassInstallment,
|
|
98
|
-
prepareMasterpassOrder,
|
|
99
|
-
paymentState.useThreeD,
|
|
100
|
-
dispatch
|
|
101
|
-
]
|
|
102
|
-
);
|
|
103
148
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
paymentState;
|
|
108
|
-
|
|
109
|
-
if (
|
|
110
|
-
!selectedCard ||
|
|
111
|
-
!tokenData?.AccountKey ||
|
|
112
|
-
!selectedInstallment ||
|
|
113
|
-
!orderData
|
|
114
|
-
) {
|
|
115
|
-
throw new Error('Please complete all required steps before payment');
|
|
116
|
-
}
|
|
149
|
+
const prepareResult = await prepareMasterpassOrder({
|
|
150
|
+
use_three_d: useThreeD
|
|
151
|
+
}).unwrap();
|
|
117
152
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
return { requiresRedirect: true };
|
|
141
|
-
}
|
|
153
|
+
dispatch(setOrderData(prepareResult));
|
|
154
|
+
|
|
155
|
+
const paymentService = new PaymentService(activeToken, activeMerchantId);
|
|
156
|
+
const paymentRequest = createPaymentRequest({
|
|
157
|
+
cvc,
|
|
158
|
+
cardAlias: selectedCard.cardAlias,
|
|
159
|
+
accountKey: activeTokenData.AccountKey,
|
|
160
|
+
amount: prepareResult.pre_order?.total_amount_with_interest,
|
|
161
|
+
orderNo: prepareResult.context_list?.[0]?.page_context?.order_no,
|
|
162
|
+
currencyCode: currency,
|
|
163
|
+
installmentCount: selectedInstallment.installment_count,
|
|
164
|
+
authenticationMethod: activeTokenData.AuthenticationMethod,
|
|
165
|
+
secure3DModel: activeTokenData.Secure3dType,
|
|
166
|
+
terminalGroupId,
|
|
167
|
+
acquirerIcaNumber: bankIca,
|
|
168
|
+
additionalFields:
|
|
169
|
+
prepareResult.context_list?.[0]?.page_context?.extras
|
|
170
|
+
?.additional_fields || {}
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
const paymentResult = await paymentService.processPayment(paymentRequest);
|
|
174
|
+
const response = await handleMasterpassResponse(paymentResult);
|
|
142
175
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
176
|
+
if (response.requires3D && response.redirectUrl) {
|
|
177
|
+
window.location.href = response.redirectUrl;
|
|
178
|
+
return { success: false, requiresRedirect: true };
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
if (response.success) {
|
|
182
|
+
const transactionType = getTransactionType(useThreeD);
|
|
183
|
+
const finalizeResult = await finalizeMasterpassOrder({
|
|
184
|
+
responseCode: paymentResult.data?.result?.responseCode,
|
|
185
|
+
token: paymentResult.data?.result?.token,
|
|
186
|
+
three_d_secure: useThreeD,
|
|
187
|
+
transactionType
|
|
188
|
+
}).unwrap();
|
|
151
189
|
|
|
152
|
-
|
|
153
|
-
dispatch(setOrderData(finalizeResult));
|
|
190
|
+
dispatch(setOrderData(finalizeResult));
|
|
154
191
|
|
|
155
|
-
|
|
192
|
+
if (finalizeResult.errors) {
|
|
193
|
+
return { success: false, message: finalizeResult.errors };
|
|
156
194
|
}
|
|
157
195
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
throw error;
|
|
196
|
+
dispatch(setOrderCompleted(true));
|
|
197
|
+
return { success: true };
|
|
161
198
|
}
|
|
162
|
-
},
|
|
163
|
-
[paymentState, currency, finalizeMasterpassOrder, dispatch]
|
|
164
|
-
);
|
|
165
199
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
200
|
+
return {
|
|
201
|
+
success: response.success,
|
|
202
|
+
requiresOTP: response.requiresOTP,
|
|
203
|
+
otpType: response.otpType,
|
|
204
|
+
message: response.message
|
|
205
|
+
};
|
|
206
|
+
} catch (error) {
|
|
207
|
+
return {
|
|
208
|
+
success: false,
|
|
209
|
+
message:
|
|
210
|
+
error instanceof Error
|
|
211
|
+
? error.message
|
|
212
|
+
: 'An unexpected error occurred'
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
}, [
|
|
216
|
+
paymentState,
|
|
217
|
+
tokenData,
|
|
218
|
+
currency,
|
|
219
|
+
bankIca,
|
|
220
|
+
terminalGroupId,
|
|
221
|
+
prepareMasterpassOrder,
|
|
222
|
+
finalizeMasterpassOrder,
|
|
223
|
+
refreshTokenForPayment,
|
|
224
|
+
dispatch
|
|
225
|
+
]);
|
|
226
|
+
|
|
227
|
+
const processDirectPayment = useCallback(async (): Promise<PaymentResult> => {
|
|
228
|
+
const { selectedInstallment } = paymentState;
|
|
229
|
+
|
|
230
|
+
if (!selectedInstallment) {
|
|
231
|
+
return {
|
|
232
|
+
success: false,
|
|
233
|
+
message: 'Please complete all required steps before payment'
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
if (
|
|
238
|
+
!newCardFormData.cardNumber ||
|
|
239
|
+
!newCardFormData.expiryDate ||
|
|
240
|
+
!newCardFormData.cvv
|
|
241
|
+
) {
|
|
242
|
+
return {
|
|
243
|
+
success: false,
|
|
244
|
+
message: 'Please complete all card details before payment'
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
try {
|
|
249
|
+
const freshResult = await refreshTokenForPayment();
|
|
250
|
+
const activeTokenData = freshResult?.tokenData || tokenData;
|
|
251
|
+
const activeToken = freshResult?.token;
|
|
252
|
+
const activeMerchantId = freshResult?.merchantId || tokenData?.MerchantId;
|
|
169
253
|
|
|
170
|
-
if (!
|
|
171
|
-
|
|
254
|
+
if (!activeTokenData?.AccountKey) {
|
|
255
|
+
return { success: false, message: 'Token data not available' };
|
|
172
256
|
}
|
|
173
257
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
)
|
|
179
|
-
|
|
258
|
+
const prepareResult = await prepareMasterpassOrder({
|
|
259
|
+
use_three_d: paymentState.useThreeD
|
|
260
|
+
}).unwrap();
|
|
261
|
+
|
|
262
|
+
dispatch(setOrderData(prepareResult));
|
|
263
|
+
|
|
264
|
+
const paymentService = new PaymentService(activeToken, activeMerchantId);
|
|
265
|
+
const directPaymentRequest = createDirectPaymentRequest({
|
|
266
|
+
cvc: newCardFormData.cvv,
|
|
267
|
+
cardNumber: newCardFormData.cardNumber.replace(/\D/g, ''),
|
|
268
|
+
cardHolderName: newCardFormData.cardholderName || '',
|
|
269
|
+
cardAlias: newCardFormData.cardAlias || '',
|
|
270
|
+
expiryDate: newCardFormData.expiryDate,
|
|
271
|
+
accountKey: activeTokenData.AccountKey,
|
|
272
|
+
amount: prepareResult.pre_order?.total_amount_with_interest,
|
|
273
|
+
orderNo: prepareResult.context_list?.[0]?.page_context?.order_no,
|
|
274
|
+
currencyCode: currency,
|
|
275
|
+
installmentCount: selectedInstallment.installment_count,
|
|
276
|
+
authenticationMethod: activeTokenData.AuthenticationMethod,
|
|
277
|
+
secure3DModel: activeTokenData.Secure3dType,
|
|
278
|
+
terminalGroupId,
|
|
279
|
+
acquirerIcaNumber: bankIca,
|
|
280
|
+
additionalFields:
|
|
281
|
+
prepareResult.context_list?.[0]?.page_context?.extras
|
|
282
|
+
?.additional_fields || {}
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
const paymentResult = await paymentService.directPayment(
|
|
286
|
+
directPaymentRequest
|
|
287
|
+
);
|
|
288
|
+
const response = await handleMasterpassResponse(paymentResult);
|
|
289
|
+
|
|
290
|
+
if (response.requires3D && response.redirectUrl) {
|
|
291
|
+
window.location.href = response.redirectUrl;
|
|
292
|
+
return { success: false, requiresRedirect: true };
|
|
180
293
|
}
|
|
181
294
|
|
|
182
|
-
|
|
183
|
-
const
|
|
184
|
-
const
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
const paymentResult = await paymentService.directPayment(
|
|
201
|
-
directPaymentRequest
|
|
202
|
-
);
|
|
203
|
-
return handleMasterpassResponse(paymentResult);
|
|
204
|
-
} catch (error) {
|
|
205
|
-
return {
|
|
206
|
-
success: false,
|
|
207
|
-
message:
|
|
208
|
-
error instanceof Error
|
|
209
|
-
? error.message
|
|
210
|
-
: 'An unexpected error occurred'
|
|
211
|
-
};
|
|
295
|
+
if (response.success) {
|
|
296
|
+
const transactionType = getTransactionType(paymentState.useThreeD);
|
|
297
|
+
const finalizeResult = await finalizeMasterpassOrder({
|
|
298
|
+
responseCode: paymentResult.data?.result?.responseCode,
|
|
299
|
+
token: paymentResult.data?.result?.token,
|
|
300
|
+
three_d_secure: paymentState.useThreeD,
|
|
301
|
+
transactionType
|
|
302
|
+
}).unwrap();
|
|
303
|
+
|
|
304
|
+
dispatch(setOrderData(finalizeResult));
|
|
305
|
+
|
|
306
|
+
if (finalizeResult.errors) {
|
|
307
|
+
return { success: false, message: finalizeResult.errors };
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
dispatch(setOrderCompleted(true));
|
|
311
|
+
return { success: true };
|
|
212
312
|
}
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
313
|
+
|
|
314
|
+
return {
|
|
315
|
+
success: response.success,
|
|
316
|
+
requiresOTP: response.requiresOTP,
|
|
317
|
+
otpType: response.otpType,
|
|
318
|
+
message: response.message
|
|
319
|
+
};
|
|
320
|
+
} catch (error) {
|
|
321
|
+
return {
|
|
322
|
+
success: false,
|
|
323
|
+
message:
|
|
324
|
+
error instanceof Error
|
|
325
|
+
? error.message
|
|
326
|
+
: 'An unexpected error occurred'
|
|
327
|
+
};
|
|
328
|
+
}
|
|
329
|
+
}, [
|
|
330
|
+
paymentState,
|
|
331
|
+
tokenData,
|
|
332
|
+
newCardFormData,
|
|
333
|
+
currency,
|
|
334
|
+
bankIca,
|
|
335
|
+
terminalGroupId,
|
|
336
|
+
prepareMasterpassOrder,
|
|
337
|
+
finalizeMasterpassOrder,
|
|
338
|
+
refreshTokenForPayment,
|
|
339
|
+
dispatch
|
|
340
|
+
]);
|
|
216
341
|
|
|
217
342
|
return {
|
|
218
343
|
paymentState,
|
|
@@ -1,13 +1,19 @@
|
|
|
1
|
-
import { useEffect, useCallback, useMemo } from 'react';
|
|
1
|
+
import { useEffect, useCallback, useMemo, useRef } from 'react';
|
|
2
2
|
import { useDispatch } from 'react-redux';
|
|
3
3
|
import { useAppSelector } from '@akinon/next/redux/hooks';
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
useGetMasterpassRestTokenQuery,
|
|
6
|
+
useLazyGetMasterpassRestTokenQuery
|
|
7
|
+
} from '../redux/api';
|
|
5
8
|
import {
|
|
6
9
|
setMasterpassRestToken,
|
|
7
10
|
setMasterpassRestTokenData,
|
|
8
11
|
setMasterpassTerminalGroupId,
|
|
9
|
-
|
|
12
|
+
setMasterpassBankIca,
|
|
13
|
+
setTokenLoading,
|
|
14
|
+
updatePaymentState
|
|
10
15
|
} from '../redux/reducer';
|
|
16
|
+
import { isTokenExpired } from '../utils/payment-utils';
|
|
11
17
|
|
|
12
18
|
interface UseMasterpassTokenProps {
|
|
13
19
|
useThreeD: boolean;
|
|
@@ -21,23 +27,25 @@ export const useMasterpassToken = ({
|
|
|
21
27
|
onTokenReady
|
|
22
28
|
}: UseMasterpassTokenProps) => {
|
|
23
29
|
const dispatch = useDispatch();
|
|
30
|
+
const skipTokenSyncRef = useRef(false);
|
|
31
|
+
const onTokenReadyRef = useRef(onTokenReady);
|
|
32
|
+
onTokenReadyRef.current = onTokenReady;
|
|
33
|
+
|
|
24
34
|
const {
|
|
25
35
|
token: reduxToken,
|
|
26
36
|
tokenData,
|
|
27
37
|
isTokenLoading
|
|
28
38
|
} = useAppSelector((state) => state.masterpassRest);
|
|
29
39
|
|
|
30
|
-
const
|
|
31
|
-
(tokenData
|
|
32
|
-
|
|
33
|
-
},
|
|
34
|
-
[onTokenReady]
|
|
35
|
-
);
|
|
40
|
+
const stableOnTokenReady = useCallback((tokenData: any) => {
|
|
41
|
+
onTokenReadyRef.current?.(tokenData);
|
|
42
|
+
}, []);
|
|
36
43
|
|
|
37
44
|
const shouldSkip = useMemo(() => {
|
|
38
45
|
const hasToken = !!(token || reduxToken);
|
|
39
|
-
|
|
40
|
-
|
|
46
|
+
const isExpired = isTokenExpired(tokenData);
|
|
47
|
+
return hasToken && !isExpired;
|
|
48
|
+
}, [token, reduxToken, tokenData]);
|
|
41
49
|
|
|
42
50
|
const { data, refetch, isLoading, error } = useGetMasterpassRestTokenQuery(
|
|
43
51
|
{},
|
|
@@ -46,25 +54,62 @@ export const useMasterpassToken = ({
|
|
|
46
54
|
}
|
|
47
55
|
);
|
|
48
56
|
|
|
57
|
+
const [fetchToken] = useLazyGetMasterpassRestTokenQuery();
|
|
58
|
+
|
|
49
59
|
useEffect(() => {
|
|
50
60
|
dispatch(setTokenLoading(isLoading));
|
|
51
61
|
}, [isLoading, dispatch]);
|
|
52
62
|
|
|
53
63
|
useEffect(() => {
|
|
64
|
+
if (skipTokenSyncRef.current) {
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
|
|
54
68
|
if (data?.token && data.token !== reduxToken) {
|
|
55
69
|
dispatch(setMasterpassRestToken(data.token));
|
|
56
70
|
dispatch(setMasterpassTerminalGroupId(data.extras.terminal_group_id));
|
|
71
|
+
dispatch(setMasterpassBankIca(data.extras.bank_ica));
|
|
57
72
|
|
|
58
73
|
const decodedToken = window.Utils.decodeJwt(data.token);
|
|
59
74
|
dispatch(setMasterpassRestTokenData(decodedToken));
|
|
60
75
|
|
|
61
|
-
|
|
76
|
+
if (decodedToken?.AuthenticationMethod?.toLowerCase() === 'none') {
|
|
77
|
+
dispatch(updatePaymentState({ useThreeD: false }));
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
stableOnTokenReady(decodedToken);
|
|
62
81
|
}
|
|
63
|
-
}, [data?.token, reduxToken, dispatch,
|
|
82
|
+
}, [data?.token, reduxToken, dispatch, stableOnTokenReady]);
|
|
64
83
|
|
|
65
|
-
const refetchToken = useCallback(
|
|
66
|
-
|
|
67
|
-
|
|
84
|
+
const refetchToken = useCallback(
|
|
85
|
+
async (options?: { three_d?: boolean; skipReset?: boolean }) => {
|
|
86
|
+
skipTokenSyncRef.current = true;
|
|
87
|
+
|
|
88
|
+
const result = await fetchToken(options?.three_d === false ? { three_d: false } : {});
|
|
89
|
+
|
|
90
|
+
if (result.data?.token) {
|
|
91
|
+
dispatch(setMasterpassRestToken(result.data.token));
|
|
92
|
+
dispatch(
|
|
93
|
+
setMasterpassTerminalGroupId(result.data.extras.terminal_group_id)
|
|
94
|
+
);
|
|
95
|
+
dispatch(setMasterpassBankIca(result.data.extras.bank_ica));
|
|
96
|
+
|
|
97
|
+
const decodedToken = window.Utils.decodeJwt(result.data.token);
|
|
98
|
+
dispatch(setMasterpassRestTokenData(decodedToken));
|
|
99
|
+
|
|
100
|
+
if (decodedToken?.AuthenticationMethod?.toLowerCase() === 'none') {
|
|
101
|
+
dispatch(updatePaymentState({ useThreeD: false }));
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (options?.three_d !== false && !options?.skipReset) {
|
|
105
|
+
stableOnTokenReady(decodedToken);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return result;
|
|
110
|
+
},
|
|
111
|
+
[fetchToken, dispatch, stableOnTokenReady]
|
|
112
|
+
);
|
|
68
113
|
|
|
69
114
|
return {
|
|
70
115
|
token: reduxToken || token,
|
package/src/redux/api.ts
CHANGED
|
@@ -2,7 +2,9 @@ import { api } from '@akinon/next/data/client/api';
|
|
|
2
2
|
import { buildClientRequestUrl } from '@akinon/next/utils';
|
|
3
3
|
import { setPaymentStepBusy } from '@akinon/next/redux/reducers/checkout';
|
|
4
4
|
|
|
5
|
-
export interface MasterpassRestTokenRequest {
|
|
5
|
+
export interface MasterpassRestTokenRequest {
|
|
6
|
+
three_d?: boolean;
|
|
7
|
+
}
|
|
6
8
|
|
|
7
9
|
export interface MasterpassRestTokenResponse {
|
|
8
10
|
msisdn: string;
|
|
@@ -59,6 +61,7 @@ export interface PrepareMasterpassOrderResponse {
|
|
|
59
61
|
extras: {
|
|
60
62
|
user_id: string;
|
|
61
63
|
bank_ica: string | null;
|
|
64
|
+
additional_fields?: any;
|
|
62
65
|
};
|
|
63
66
|
};
|
|
64
67
|
page_name: string;
|
|
@@ -115,11 +118,16 @@ export const masterpassRestApi = api.injectEndpoints({
|
|
|
115
118
|
MasterpassRestTokenResponse,
|
|
116
119
|
MasterpassRestTokenRequest
|
|
117
120
|
>({
|
|
118
|
-
query: () =>
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
121
|
+
query: (arg) => {
|
|
122
|
+
const baseUrl = '/orders/masterpass-rest-token/';
|
|
123
|
+
const url =
|
|
124
|
+
arg?.three_d === false ? `${baseUrl}?three_d=false` : baseUrl;
|
|
125
|
+
return {
|
|
126
|
+
url: buildClientRequestUrl(url, {
|
|
127
|
+
useFormData: true
|
|
128
|
+
})
|
|
129
|
+
};
|
|
130
|
+
},
|
|
123
131
|
keepUnusedDataFor: 60,
|
|
124
132
|
async onQueryStarted(_, { dispatch, queryFulfilled }) {
|
|
125
133
|
dispatch(setPaymentStepBusy(true));
|
|
@@ -137,7 +145,7 @@ export const masterpassRestApi = api.injectEndpoints({
|
|
|
137
145
|
}),
|
|
138
146
|
method: 'POST',
|
|
139
147
|
params: {
|
|
140
|
-
page: '
|
|
148
|
+
page: 'MasterpassRestBinNumberPage'
|
|
141
149
|
},
|
|
142
150
|
body: {
|
|
143
151
|
is_masterpass_stored_card: arg.is_masterpass_stored_card,
|
|
@@ -227,6 +235,7 @@ export const masterpassRestApi = api.injectEndpoints({
|
|
|
227
235
|
|
|
228
236
|
export const {
|
|
229
237
|
useGetMasterpassRestTokenQuery,
|
|
238
|
+
useLazyGetMasterpassRestTokenQuery,
|
|
230
239
|
useSetMasterpassRestBinNumberMutation,
|
|
231
240
|
useCheckoutMasterpassInstallmentMutation,
|
|
232
241
|
usePrepareMasterpassOrderMutation,
|
package/src/redux/reducer.ts
CHANGED
|
@@ -34,6 +34,7 @@ export interface AccountStatus {
|
|
|
34
34
|
export interface MasterpassRestState {
|
|
35
35
|
token: string | null;
|
|
36
36
|
terminalGroupId: string | null;
|
|
37
|
+
bankIca: string | null;
|
|
37
38
|
tokenData: MasterpassRestTokenData | null;
|
|
38
39
|
accountData: AccountAccessSuccessResponse | null;
|
|
39
40
|
accountStatus: AccountStatus;
|
|
@@ -51,6 +52,7 @@ export interface MasterpassRestState {
|
|
|
51
52
|
const initialState: MasterpassRestState = {
|
|
52
53
|
token: null,
|
|
53
54
|
terminalGroupId: null,
|
|
55
|
+
bankIca: null,
|
|
54
56
|
tokenData: null,
|
|
55
57
|
accountData: null,
|
|
56
58
|
accountStatus: {
|
|
@@ -72,6 +74,8 @@ const initialState: MasterpassRestState = {
|
|
|
72
74
|
showLinkModal: false,
|
|
73
75
|
showOTPModal: false,
|
|
74
76
|
show3DSecureModal: false,
|
|
77
|
+
showInformationModal: false,
|
|
78
|
+
informationModalData: null,
|
|
75
79
|
otpType: 'OTP',
|
|
76
80
|
verificationData: null,
|
|
77
81
|
cardToDelete: null,
|
|
@@ -96,6 +100,12 @@ const masterpassRestSlice = createSlice({
|
|
|
96
100
|
setMasterpassTerminalGroupId: (state, action: PayloadAction<string>) => {
|
|
97
101
|
state.terminalGroupId = action.payload;
|
|
98
102
|
},
|
|
103
|
+
setMasterpassBankIca: (
|
|
104
|
+
state,
|
|
105
|
+
action: PayloadAction<string | null>
|
|
106
|
+
) => {
|
|
107
|
+
state.bankIca = action.payload;
|
|
108
|
+
},
|
|
99
109
|
setMasterpassRestTokenData: (
|
|
100
110
|
state,
|
|
101
111
|
action: PayloadAction<MasterpassRestTokenData>
|
|
@@ -208,6 +218,7 @@ const masterpassRestSlice = createSlice({
|
|
|
208
218
|
|
|
209
219
|
state.token = null;
|
|
210
220
|
state.terminalGroupId = null;
|
|
221
|
+
state.bankIca = null;
|
|
211
222
|
state.tokenData = null;
|
|
212
223
|
state.accountData = null;
|
|
213
224
|
state.accountStatus = {
|
|
@@ -229,6 +240,8 @@ const masterpassRestSlice = createSlice({
|
|
|
229
240
|
showLinkModal: false,
|
|
230
241
|
showOTPModal: false,
|
|
231
242
|
show3DSecureModal: false,
|
|
243
|
+
showInformationModal: false,
|
|
244
|
+
informationModalData: null,
|
|
232
245
|
otpType: 'OTP',
|
|
233
246
|
verificationData: null,
|
|
234
247
|
cardToDelete: null,
|
|
@@ -246,6 +259,7 @@ const masterpassRestSlice = createSlice({
|
|
|
246
259
|
export const {
|
|
247
260
|
setMasterpassRestToken,
|
|
248
261
|
setMasterpassTerminalGroupId,
|
|
262
|
+
setMasterpassBankIca,
|
|
249
263
|
setMasterpassRestTokenData,
|
|
250
264
|
setTokenLoading,
|
|
251
265
|
setScriptLoaded,
|