@akinon/pz-masterpass-rest 2.0.14 → 2.0.15-rc.0

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/src/redux/api.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  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
+ import type { RewardItem } from '../types/payment.types';
4
5
 
5
6
  export interface MasterpassRestTokenRequest {
6
7
  three_d?: boolean;
@@ -97,6 +98,39 @@ interface CardType {
97
98
  logo: string;
98
99
  }
99
100
 
101
+ export interface QueryMasterpassRewardsRequest {
102
+ card_alias: string;
103
+ }
104
+
105
+ export interface QueryMasterpassRewardsResponse {
106
+ context_list: Array<{
107
+ page_context: {
108
+ rewards: RewardItem[];
109
+ };
110
+ page_name: string;
111
+ page_slug: string;
112
+ }>;
113
+ template_name: string;
114
+ errors: any;
115
+ pre_order: any;
116
+ }
117
+
118
+ export interface SelectMasterpassRewardsRequest {
119
+ special: string;
120
+ general: string;
121
+ }
122
+
123
+ export interface SelectMasterpassRewardsResponse {
124
+ context_list: Array<{
125
+ page_context: any;
126
+ page_name: string;
127
+ page_slug: string;
128
+ }>;
129
+ template_name: string;
130
+ errors: any;
131
+ pre_order: any;
132
+ }
133
+
100
134
  export interface SetMasterpassRestBinNumberResponse {
101
135
  context_list: Array<{
102
136
  page_context: {
@@ -202,6 +236,51 @@ export const masterpassRestApi = api.injectEndpoints({
202
236
  dispatch(setPaymentStepBusy(false));
203
237
  }
204
238
  }),
239
+ queryMasterpassRewards: build.mutation<
240
+ QueryMasterpassRewardsResponse,
241
+ QueryMasterpassRewardsRequest
242
+ >({
243
+ query: (arg) => ({
244
+ url: buildClientRequestUrl('/orders/checkout/', {
245
+ useFormData: true
246
+ }),
247
+ method: 'POST',
248
+ params: {
249
+ page: 'MasterpassRestRewardListPage'
250
+ },
251
+ body: {
252
+ card_alias: arg.card_alias
253
+ }
254
+ }),
255
+ async onQueryStarted(_, { dispatch, queryFulfilled }) {
256
+ dispatch(setPaymentStepBusy(true));
257
+ await queryFulfilled;
258
+ dispatch(setPaymentStepBusy(false));
259
+ }
260
+ }),
261
+ selectMasterpassRewards: build.mutation<
262
+ SelectMasterpassRewardsResponse,
263
+ SelectMasterpassRewardsRequest
264
+ >({
265
+ query: (arg) => ({
266
+ url: buildClientRequestUrl('/orders/checkout/', {
267
+ useFormData: true
268
+ }),
269
+ method: 'POST',
270
+ params: {
271
+ page: 'MasterpassRestRewardSelectionPage'
272
+ },
273
+ body: {
274
+ special: arg.special,
275
+ general: arg.general
276
+ }
277
+ }),
278
+ async onQueryStarted(_, { dispatch, queryFulfilled }) {
279
+ dispatch(setPaymentStepBusy(true));
280
+ await queryFulfilled;
281
+ dispatch(setPaymentStepBusy(false));
282
+ }
283
+ }),
205
284
  finalizeMasterpassOrder: build.mutation<
206
285
  FinalizeMasterpassOrderResponse,
207
286
  FinalizeMasterpassOrderRequest
@@ -239,5 +318,7 @@ export const {
239
318
  useSetMasterpassRestBinNumberMutation,
240
319
  useCheckoutMasterpassInstallmentMutation,
241
320
  usePrepareMasterpassOrderMutation,
242
- useFinalizeMasterpassOrderMutation
321
+ useFinalizeMasterpassOrderMutation,
322
+ useQueryMasterpassRewardsMutation,
323
+ useSelectMasterpassRewardsMutation
243
324
  } = masterpassRestApi;
@@ -5,7 +5,8 @@ import {
5
5
  ModalState,
6
6
  Installment,
7
7
  CardType,
8
- OrderData
8
+ OrderData,
9
+ RewardItem
9
10
  } from '../types/payment.types';
10
11
  import { CreditCardFormData } from '../utils/validation-schemas';
11
12
 
@@ -68,13 +69,17 @@ const initialState: MasterpassRestState = {
68
69
  orderData: null,
69
70
  orderCompleted: false,
70
71
  cvc: '',
71
- useThreeD: true
72
+ useThreeD: true,
73
+ availableRewards: [],
74
+ selectedRewards: [],
75
+ isLoadingRewards: false
72
76
  },
73
77
  modalState: {
74
78
  showLinkModal: false,
75
79
  showOTPModal: false,
76
80
  show3DSecureModal: false,
77
81
  showInformationModal: false,
82
+ showRewardModal: false,
78
83
  informationModalData: null,
79
84
  otpType: 'OTP',
80
85
  verificationData: null,
@@ -169,6 +174,24 @@ const masterpassRestSlice = createSlice({
169
174
  setOrderCompleted: (state, action: PayloadAction<boolean>) => {
170
175
  state.paymentState.orderCompleted = action.payload;
171
176
  },
177
+ setAvailableRewards: (state, action: PayloadAction<RewardItem[]>) => {
178
+ state.paymentState.availableRewards = action.payload;
179
+ },
180
+ setSelectedRewards: (state, action: PayloadAction<RewardItem[]>) => {
181
+ state.paymentState.selectedRewards = action.payload;
182
+ },
183
+ setLoadingRewards: (state, action: PayloadAction<boolean>) => {
184
+ state.paymentState.isLoadingRewards = action.payload;
185
+ },
186
+ setShowRewardModal: (state, action: PayloadAction<boolean>) => {
187
+ state.modalState.showRewardModal = action.payload;
188
+ },
189
+ clearRewards: (state) => {
190
+ state.paymentState.availableRewards = [];
191
+ state.paymentState.selectedRewards = [];
192
+ state.paymentState.isLoadingRewards = false;
193
+ state.modalState.showRewardModal = false;
194
+ },
172
195
  updateModalState: (state, action: PayloadAction<Partial<ModalState>>) => {
173
196
  state.modalState = { ...state.modalState, ...action.payload };
174
197
  },
@@ -234,13 +257,17 @@ const masterpassRestSlice = createSlice({
234
257
  orderData: null,
235
258
  orderCompleted: false,
236
259
  cvc: '',
237
- useThreeD: true
260
+ useThreeD: true,
261
+ availableRewards: [],
262
+ selectedRewards: [],
263
+ isLoadingRewards: false
238
264
  };
239
265
  state.modalState = {
240
266
  showLinkModal: false,
241
267
  showOTPModal: false,
242
268
  show3DSecureModal: false,
243
269
  showInformationModal: false,
270
+ showRewardModal: false,
244
271
  informationModalData: null,
245
272
  otpType: 'OTP',
246
273
  verificationData: null,
@@ -276,6 +303,11 @@ export const {
276
303
  setOrderData,
277
304
  setCvc,
278
305
  setOrderCompleted,
306
+ setAvailableRewards,
307
+ setSelectedRewards,
308
+ setLoadingRewards,
309
+ setShowRewardModal,
310
+ clearRewards,
279
311
  updateModalState,
280
312
  setShowLinkModal,
281
313
  setShowOTPModal,
@@ -1,6 +1,6 @@
1
1
  import { ReactElement } from 'react';
2
2
  import type { CreditCardFormData } from '../utils/validation-schemas';
3
- import { CardType, Installment } from './payment.types';
3
+ import { CardType, Installment, RewardItem } from './payment.types';
4
4
 
5
5
  export type PaymentMethodSelectorProps = {
6
6
  cards: any[];
@@ -18,6 +18,14 @@ export type CardListProps = {
18
18
  cvc?: string;
19
19
  onCvcChange?: (cvc: string) => void;
20
20
  cvcRequired?: boolean;
21
+ availableRewards?: RewardItem[];
22
+ selectedRewards?: RewardItem[];
23
+ isLoadingRewards?: boolean;
24
+ isConfirmingRewards?: boolean;
25
+ onOpenRewardModal?: () => void;
26
+ onConfirmRewards?: (selected: RewardItem[]) => Promise<void> | void;
27
+ rewardCurrency?: string;
28
+ rewardPayableAmount?: string | number | null;
21
29
  texts: MasterpassRestOptionTexts;
22
30
  };
23
31
 
@@ -58,6 +66,18 @@ export type OTPModalProps = {
58
66
  texts: MasterpassRestOptionTexts;
59
67
  };
60
68
 
69
+ export type RewardSelectionModalProps = {
70
+ open: boolean;
71
+ onClose: () => void;
72
+ onConfirm: (selected: RewardItem[]) => Promise<void> | void;
73
+ rewards: RewardItem[];
74
+ selectedRewards: RewardItem[];
75
+ isLoading?: boolean;
76
+ currency?: string;
77
+ payableAmount?: string | number | null;
78
+ texts: MasterpassRestOptionTexts;
79
+ };
80
+
61
81
  export type ConfirmationModalProps = {
62
82
  open: boolean;
63
83
  onClose: () => void;
@@ -119,6 +139,14 @@ export type MasterpassRestOptionRenderProps = {
119
139
  isInstallmentLoading: boolean;
120
140
  isPrepareLoading: boolean;
121
141
  isFinalizeLoading: boolean;
142
+ isProcessingPayment: boolean;
143
+ isRewardsQueryLoading: boolean;
144
+ isRewardsSelectLoading: boolean;
145
+
146
+ openRewardModal: () => void;
147
+ closeRewardModal: () => void;
148
+ handleConfirmRewards: (selected: RewardItem[]) => Promise<void>;
149
+ payableAmount: string | null;
122
150
 
123
151
  texts: MasterpassRestOptionTexts;
124
152
 
@@ -130,6 +158,7 @@ export type MasterpassRestOptionRenderProps = {
130
158
  LinkModal: React.ComponentType<LinkModalProps>;
131
159
  OTPModal: React.ComponentType<OTPModalProps>;
132
160
  ConfirmationModal: React.ComponentType<ConfirmationModalProps>;
161
+ RewardSelectionModal: React.ComponentType<RewardSelectionModalProps>;
133
162
  };
134
163
  };
135
164
 
@@ -141,6 +170,7 @@ export type MasterpassRestOptionCustomRender = {
141
170
  linkModal?: (props: LinkModalProps) => ReactElement;
142
171
  otpModal?: (props: OTPModalProps) => ReactElement;
143
172
  confirmationModal?: (props: ConfirmationModalProps) => ReactElement;
173
+ rewardSelectionModal?: (props: RewardSelectionModalProps) => ReactElement;
144
174
  errorDisplay?: (props: ErrorDisplayProps) => ReactElement;
145
175
  loadingState?: (props: LoadingStateProps) => ReactElement;
146
176
  emptyState?: (props: EmptyStateProps) => ReactElement;
@@ -277,4 +307,20 @@ export type MasterpassRestOptionTexts = {
277
307
  sessionExpiredMessage?: string;
278
308
  sessionExpiredSecondaryMessage?: string;
279
309
  sessionExpiredButton?: string;
310
+
311
+ rewardModalTitle?: string;
312
+ rewardModalDescription?: string;
313
+ rewardModalEmptyMessage?: string;
314
+ rewardModalConfirmText?: string;
315
+ rewardModalCancelText?: string;
316
+ rewardModalLoadingText?: string;
317
+ rewardOpenButtonText?: string;
318
+ rewardSelectedSummaryText?: string;
319
+ rewardAvailableSummaryText?: string;
320
+ rewardClearText?: string;
321
+ rewardCategorySpecialText?: string;
322
+ rewardCategoryGeneralText?: string;
323
+ rewardFailedToLoadText?: string;
324
+ rewardFailedToSelectText?: string;
325
+ rewardCappedNoticeText?: string;
280
326
  };
@@ -69,6 +69,15 @@ export type TransactionType =
69
69
  | 'DIRECT_PURCHASE'
70
70
  | 'DIRECT_PURCHASE_3D';
71
71
 
72
+ export type RewardName = 'FBB' | 'BNS';
73
+ export type RewardCategory = 'special' | 'general';
74
+
75
+ export interface RewardItem {
76
+ type: RewardCategory;
77
+ amount: number | string;
78
+ name?: RewardName;
79
+ }
80
+
72
81
  export interface PaymentState {
73
82
  selectedCard: any | null;
74
83
  selectedInstallment: Installment | null;
@@ -78,6 +87,9 @@ export interface PaymentState {
78
87
  orderCompleted: boolean;
79
88
  cvc: string;
80
89
  useThreeD: boolean;
90
+ availableRewards: RewardItem[];
91
+ selectedRewards: RewardItem[];
92
+ isLoadingRewards: boolean;
81
93
  }
82
94
 
83
95
  export type InformationModalType = 'warning' | 'error' | 'success' | 'info';
@@ -95,6 +107,7 @@ export interface ModalState {
95
107
  showOTPModal: boolean;
96
108
  show3DSecureModal: boolean;
97
109
  showInformationModal: boolean;
110
+ showRewardModal: boolean;
98
111
  informationModalData: InformationModalData | null;
99
112
  otpType: OTPType;
100
113
  verificationData: any | null;
@@ -9,7 +9,7 @@ export const formatCardNumber = (value: string): string => {
9
9
 
10
10
  const formatted = cleanValue.replace(/(\d{4})(?=\d)/g, '$1 ');
11
11
 
12
- return formatted.substring(0, 23);
12
+ return formatted.substring(0, 19);
13
13
  };
14
14
 
15
15
  export const formatExpiryDate = (value: string): string => {
@@ -0,0 +1,41 @@
1
+ import type { RewardItem, RewardCategory } from '../types/payment.types';
2
+
3
+ export const REWARD_PRIORITY: RewardCategory[] = ['special', 'general'];
4
+
5
+ export const parseRewardAmount = (amount: number | string): number => {
6
+ const value = typeof amount === 'string' ? parseFloat(amount) : amount;
7
+ return Number.isFinite(value) ? value : 0;
8
+ };
9
+
10
+ export const getCappedRewardAmounts = (
11
+ selected: RewardItem[],
12
+ payableAmount?: string | number | null
13
+ ): Record<RewardCategory, number> => {
14
+ const parsedPayable =
15
+ payableAmount != null ? parseRewardAmount(payableAmount) : NaN;
16
+ let remaining = Number.isFinite(parsedPayable) ? parsedPayable : Infinity;
17
+
18
+ const result: Record<RewardCategory, number> = { special: 0, general: 0 };
19
+
20
+ REWARD_PRIORITY.forEach((type) => {
21
+ const picked = selected.find((item) => item.type === type);
22
+ if (!picked) return;
23
+
24
+ const value = parseRewardAmount(picked.amount);
25
+ if (value <= 0) return;
26
+
27
+ const used = Math.min(value, remaining);
28
+ remaining = Math.max(remaining - used, 0);
29
+ result[type] = used;
30
+ });
31
+
32
+ return result;
33
+ };
34
+
35
+ export const getCappedRewardTotal = (
36
+ selected: RewardItem[],
37
+ payableAmount?: string | number | null
38
+ ): number => {
39
+ const amounts = getCappedRewardAmounts(selected, payableAmount);
40
+ return REWARD_PRIORITY.reduce((sum, type) => sum + amounts[type], 0);
41
+ };
@@ -29,6 +29,8 @@ import InstallmentList from '../components/installment-list';
29
29
  import CreditCardForm from '../components/credit-card-form';
30
30
  import PaymentMethodSelector from '../components/payment-method-selector';
31
31
  import InformationModal from '../components/information-modal';
32
+ import RewardSelectionModal from '../components/reward-selection-modal';
33
+ import type { RewardItem } from '../types/payment.types';
32
34
  import mpBlackLogo from '../assets/img/masterpass-black-logo.png';
33
35
 
34
36
  interface MasterpassRestOptionProps {
@@ -38,6 +40,7 @@ interface MasterpassRestOptionProps {
38
40
  environment?: MasterpassEnvironment;
39
41
  texts?: MasterpassRestOptionTexts;
40
42
  customRender?: MasterpassRestOptionCustomRender;
43
+ enableRewards?: boolean;
41
44
  }
42
45
 
43
46
  const defaultTexts: MasterpassRestOptionTexts = {
@@ -158,7 +161,23 @@ const defaultTexts: MasterpassRestOptionTexts = {
158
161
  sessionExpiredTitle: 'Session Expired',
159
162
  sessionExpiredMessage: 'Your session has expired due to inactivity. Please restart the process to continue.',
160
163
  sessionExpiredSecondaryMessage: 'For security reasons, sessions are only valid for a limited time.',
161
- sessionExpiredButton: 'Start Again'
164
+ sessionExpiredButton: 'Start Again',
165
+
166
+ rewardModalTitle: 'Use Card Rewards',
167
+ rewardModalDescription: 'Select the rewards you want to apply to this order.',
168
+ rewardModalEmptyMessage: 'No rewards available for this card.',
169
+ rewardModalConfirmText: 'Apply',
170
+ rewardModalCancelText: 'Cancel',
171
+ rewardModalLoadingText: 'Applying...',
172
+ rewardOpenButtonText: 'Use Rewards',
173
+ rewardSelectedSummaryText: '{count} reward(s) applied',
174
+ rewardAvailableSummaryText: '{count} reward(s) available',
175
+ rewardClearText: 'Clear',
176
+ rewardCategorySpecialText: 'Special Rewards',
177
+ rewardCategoryGeneralText: 'General Rewards',
178
+ rewardFailedToLoadText: 'Failed to load rewards',
179
+ rewardFailedToSelectText: 'Failed to apply rewards',
180
+ rewardCappedNoticeText: '{amount} will be applied'
162
181
  };
163
182
 
164
183
  const mergeTexts = (
@@ -177,7 +196,8 @@ const MasterpassRestOption: React.FC<MasterpassRestOptionProps> = ({
177
196
  sdkUrl,
178
197
  environment,
179
198
  texts = defaultTexts,
180
- customRender
199
+ customRender,
200
+ enableRewards = false
181
201
  }) => {
182
202
  const mergedTexts = React.useMemo(
183
203
  () => mergeTexts(texts, defaultTexts),
@@ -201,6 +221,7 @@ const MasterpassRestOption: React.FC<MasterpassRestOptionProps> = ({
201
221
  'stored_card' | 'new_card'
202
222
  >('stored_card');
203
223
  const [cvc, setCvc] = useState<string>('');
224
+ const [isProcessingPayment, setIsProcessingPayment] = useState(false);
204
225
 
205
226
  const [setMasterpassRestBinNumber] = useSetMasterpassRestBinNumberMutation();
206
227
 
@@ -209,12 +230,18 @@ const MasterpassRestOption: React.FC<MasterpassRestOptionProps> = ({
209
230
  isInstallmentLoading,
210
231
  isPrepareLoading,
211
232
  isFinalizeLoading,
233
+ isRewardsQueryLoading,
234
+ isRewardsSelectLoading,
212
235
  updatePaymentState,
213
236
  handleCardSelect,
214
237
  handleInstallmentSelect,
215
238
  processPayment,
216
- processDirectPayment
217
- } = useMasterpassPayment();
239
+ processDirectPayment,
240
+ openRewardModal,
241
+ closeRewardModal,
242
+ confirmRewards,
243
+ payableAmount
244
+ } = useMasterpassPayment({ enableRewards });
218
245
 
219
246
  const {
220
247
  accountData,
@@ -382,6 +409,10 @@ const MasterpassRestOption: React.FC<MasterpassRestOptionProps> = ({
382
409
  }, [dispatch, handleAddCard, mergedTexts.failedToSaveCardText]);
383
410
 
384
411
  const handleProceedToPayment = useCallback(async () => {
412
+ if (isProcessingPayment) return;
413
+
414
+ setIsProcessingPayment(true);
415
+
385
416
  try {
386
417
  dispatch(clearAllErrors());
387
418
 
@@ -408,8 +439,10 @@ const MasterpassRestOption: React.FC<MasterpassRestOptionProps> = ({
408
439
  const errorMessage =
409
440
  error instanceof Error ? error.message : mergedTexts.paymentFailedText;
410
441
  dispatch(setError(errorMessage));
442
+ } finally {
443
+ setIsProcessingPayment(false);
411
444
  }
412
- }, [dispatch, paymentMethod, processDirectPayment, processPayment, updateModalState, mergedTexts.paymentFailedText]);
445
+ }, [isProcessingPayment, dispatch, paymentMethod, processDirectPayment, processPayment, updateModalState, mergedTexts.paymentFailedText]);
413
446
 
414
447
  const handleOTPSubmitWithErrorHandling = useCallback(async (otp: string) => {
415
448
  if (!handleOTPSubmit)
@@ -449,6 +482,18 @@ const MasterpassRestOption: React.FC<MasterpassRestOptionProps> = ({
449
482
  }
450
483
  }, [dispatch, handleInstallmentSelect, mergedTexts.failedToSelectInstallmentText]);
451
484
 
485
+ const handleConfirmRewards = useCallback(
486
+ async (selected: RewardItem[]) => {
487
+ const result = await confirmRewards(selected);
488
+ if (!result.success) {
489
+ dispatch(
490
+ setError(result.message || mergedTexts.rewardFailedToSelectText)
491
+ );
492
+ }
493
+ },
494
+ [confirmRewards, dispatch, mergedTexts.rewardFailedToSelectText]
495
+ );
496
+
452
497
  const handleCvcChange = useCallback((newCvc: string) => {
453
498
  setCvc(newCvc);
454
499
  updatePaymentState({ cvc: newCvc });
@@ -486,7 +531,8 @@ const MasterpassRestOption: React.FC<MasterpassRestOptionProps> = ({
486
531
  InstallmentList: wrapRenderFunction(customRenderRef.current?.installmentList) || InstallmentList,
487
532
  LinkModal: wrapRenderFunction(customRenderRef.current?.linkModal) || LinkModal,
488
533
  OTPModal: wrapRenderFunction(customRenderRef.current?.otpModal) || OTPModal,
489
- ConfirmationModal: wrapRenderFunction(customRenderRef.current?.confirmationModal) || ConfirmationModal
534
+ ConfirmationModal: wrapRenderFunction(customRenderRef.current?.confirmationModal) || ConfirmationModal,
535
+ RewardSelectionModal: wrapRenderFunction(customRenderRef.current?.rewardSelectionModal) || RewardSelectionModal
490
536
  };
491
537
  }, [
492
538
  customRender?.paymentMethodSelector,
@@ -495,7 +541,8 @@ const MasterpassRestOption: React.FC<MasterpassRestOptionProps> = ({
495
541
  customRender?.installmentList,
496
542
  customRender?.linkModal,
497
543
  customRender?.otpModal,
498
- customRender?.confirmationModal
544
+ customRender?.confirmationModal,
545
+ customRender?.rewardSelectionModal
499
546
  ]);
500
547
 
501
548
  const hasStoredCards =
@@ -541,6 +588,14 @@ const MasterpassRestOption: React.FC<MasterpassRestOptionProps> = ({
541
588
  isInstallmentLoading,
542
589
  isPrepareLoading,
543
590
  isFinalizeLoading,
591
+ isProcessingPayment,
592
+ isRewardsQueryLoading,
593
+ isRewardsSelectLoading,
594
+
595
+ openRewardModal,
596
+ closeRewardModal,
597
+ handleConfirmRewards,
598
+ payableAmount,
544
599
 
545
600
  texts: mergedTexts,
546
601
 
@@ -573,6 +628,13 @@ const MasterpassRestOption: React.FC<MasterpassRestOptionProps> = ({
573
628
  isInstallmentLoading,
574
629
  isPrepareLoading,
575
630
  isFinalizeLoading,
631
+ isProcessingPayment,
632
+ isRewardsQueryLoading,
633
+ isRewardsSelectLoading,
634
+ openRewardModal,
635
+ closeRewardModal,
636
+ handleConfirmRewards,
637
+ payableAmount,
576
638
  mergedTexts,
577
639
  memoizedComponents
578
640
  ]);
@@ -651,6 +713,20 @@ const MasterpassRestOption: React.FC<MasterpassRestOptionProps> = ({
651
713
  removingCardId: modalState?.removingCardId,
652
714
  cvc: cvc,
653
715
  onCvcChange: handleCvcChange,
716
+ ...(enableRewards
717
+ ? {
718
+ availableRewards: paymentState.availableRewards,
719
+ selectedRewards: paymentState.selectedRewards,
720
+ isLoadingRewards:
721
+ paymentState.isLoadingRewards ||
722
+ isRewardsQueryLoading,
723
+ isConfirmingRewards: isRewardsSelectLoading,
724
+ onOpenRewardModal: openRewardModal,
725
+ onConfirmRewards: handleConfirmRewards,
726
+ rewardCurrency: stateCurrency || currency,
727
+ rewardPayableAmount: payableAmount
728
+ }
729
+ : {}),
654
730
  texts: mergedTexts
655
731
  })
656
732
  ) : (
@@ -662,6 +738,20 @@ const MasterpassRestOption: React.FC<MasterpassRestOptionProps> = ({
662
738
  removingCardId={modalState?.removingCardId}
663
739
  cvc={cvc}
664
740
  onCvcChange={handleCvcChange}
741
+ {...(enableRewards
742
+ ? {
743
+ availableRewards: paymentState.availableRewards,
744
+ selectedRewards: paymentState.selectedRewards,
745
+ isLoadingRewards:
746
+ paymentState.isLoadingRewards ||
747
+ isRewardsQueryLoading,
748
+ isConfirmingRewards: isRewardsSelectLoading,
749
+ onOpenRewardModal: openRewardModal,
750
+ onConfirmRewards: handleConfirmRewards,
751
+ rewardCurrency: stateCurrency || currency,
752
+ rewardPayableAmount: payableAmount
753
+ }
754
+ : {})}
665
755
  texts={mergedTexts}
666
756
  />
667
757
  )}
@@ -707,7 +797,10 @@ const MasterpassRestOption: React.FC<MasterpassRestOptionProps> = ({
707
797
  selectedInstallment: paymentState.selectedInstallment,
708
798
  isLoading: isInstallmentLoading || isPrepareLoading,
709
799
  onProceedToPayment: handleProceedToPayment,
710
- paymentLoading: isFinalizeLoading,
800
+ paymentLoading:
801
+ isProcessingPayment ||
802
+ isPrepareLoading ||
803
+ isFinalizeLoading,
711
804
  texts: mergedTexts
712
805
  })
713
806
  ) : (
@@ -718,7 +811,11 @@ const MasterpassRestOption: React.FC<MasterpassRestOptionProps> = ({
718
811
  selectedInstallment={paymentState.selectedInstallment}
719
812
  isLoading={isInstallmentLoading || isPrepareLoading}
720
813
  onProceedToPayment={handleProceedToPayment}
721
- paymentLoading={isFinalizeLoading}
814
+ paymentLoading={
815
+ isProcessingPayment ||
816
+ isPrepareLoading ||
817
+ isFinalizeLoading
818
+ }
722
819
  texts={mergedTexts}
723
820
  />
724
821
  )
@@ -894,6 +991,33 @@ const MasterpassRestOption: React.FC<MasterpassRestOptionProps> = ({
894
991
  onClose={() => updateModalState({ showInformationModal: false, informationModalData: null })}
895
992
  data={modalState?.informationModalData}
896
993
  />
994
+
995
+ {enableRewards &&
996
+ (customRender?.rewardSelectionModal ? (
997
+ customRender.rewardSelectionModal({
998
+ open: modalState?.showRewardModal ?? false,
999
+ onClose: closeRewardModal,
1000
+ onConfirm: handleConfirmRewards,
1001
+ rewards: paymentState.availableRewards,
1002
+ selectedRewards: paymentState.selectedRewards,
1003
+ isLoading: isRewardsSelectLoading,
1004
+ currency: stateCurrency || currency,
1005
+ payableAmount,
1006
+ texts: mergedTexts
1007
+ })
1008
+ ) : (
1009
+ <RewardSelectionModal
1010
+ open={modalState?.showRewardModal ?? false}
1011
+ onClose={closeRewardModal}
1012
+ onConfirm={handleConfirmRewards}
1013
+ rewards={paymentState.availableRewards}
1014
+ selectedRewards={paymentState.selectedRewards}
1015
+ isLoading={isRewardsSelectLoading}
1016
+ currency={stateCurrency || currency}
1017
+ payableAmount={payableAmount}
1018
+ texts={mergedTexts}
1019
+ />
1020
+ ))}
897
1021
  </div>
898
1022
  );
899
1023
  };