@akinon/pz-masterpass-rest 2.0.17 → 2.0.18-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.
@@ -1,6 +1,7 @@
1
- import React, { useState } from 'react';
1
+ import React, { useMemo, useState } from 'react';
2
2
  import { Input, Icon } from '@akinon/next/components';
3
3
  import { detectCardType, getCardIcon, getCvcLength } from '../utils/card-utils';
4
+ import { getCappedRewardTotal } from '../utils/reward-utils';
4
5
  import type { CardListProps } from '../types/custom-render.types';
5
6
  import MasterpassSecurityInfo from './masterpass-security-info';
6
7
 
@@ -13,6 +14,12 @@ const CardList: React.FC<CardListProps> = ({
13
14
  cvc = '',
14
15
  onCvcChange,
15
16
  cvcRequired = false,
17
+ availableRewards = [],
18
+ selectedRewards = [],
19
+ isLoadingRewards = false,
20
+ onOpenRewardModal,
21
+ rewardCurrency,
22
+ rewardPayableAmount,
16
23
  texts
17
24
  }) => {
18
25
  const [localCvc, setLocalCvc] = useState(cvc);
@@ -23,9 +30,21 @@ const CardList: React.FC<CardListProps> = ({
23
30
  onCvcChange?.(numericValue);
24
31
  };
25
32
 
33
+ const orderedCards = useMemo(() => {
34
+ if (!selectedCard) return cards;
35
+ const idx = cards.findIndex(
36
+ (c) => c.uniqueCardNumber === selectedCard.uniqueCardNumber
37
+ );
38
+ if (idx <= 0) return cards;
39
+ const reordered = [...cards];
40
+ const [picked] = reordered.splice(idx, 1);
41
+ reordered.unshift(picked);
42
+ return reordered;
43
+ }, [cards, selectedCard]);
44
+
26
45
  return (
27
46
  <div className="flex flex-col gap-4">
28
- {cards.map((card) => {
47
+ {orderedCards.map((card) => {
29
48
  const isSelected =
30
49
  selectedCard?.uniqueCardNumber === card.uniqueCardNumber;
31
50
  const expectedCvcLength = getCvcLength(detectCardType(card.cardBin));
@@ -119,6 +138,57 @@ const CardList: React.FC<CardListProps> = ({
119
138
  )}
120
139
  </div>
121
140
 
141
+ {isSelected &&
142
+ (isLoadingRewards || availableRewards.length > 0) && (
143
+ <div
144
+ className="border-t border-[#eeeeee] p-4 bg-[#fafafa] flex items-center justify-between gap-3"
145
+ onClick={(e) => e.stopPropagation()}
146
+ >
147
+ <div className="flex items-center gap-2 min-w-0">
148
+ <Icon name="gift" size={16} className="text-[#000000]" />
149
+ <div className="min-w-0">
150
+ <p className="text-sm font-medium text-[#4a4f54] truncate">
151
+ {texts.rewardOpenButtonText}
152
+ </p>
153
+ {selectedRewards.length > 0 ? (
154
+ <p className="text-xs text-[#00a63d] truncate">
155
+ {(texts.rewardSelectedSummaryText || '').replace(
156
+ '{count}',
157
+ String(selectedRewards.length)
158
+ )}
159
+ {' · '}
160
+ {getCappedRewardTotal(
161
+ selectedRewards,
162
+ rewardPayableAmount
163
+ ).toFixed(2)}{' '}
164
+ {(rewardCurrency || '').toUpperCase()}
165
+ </p>
166
+ ) : (
167
+ <p className="text-xs text-[#9d9d9d] truncate">
168
+ {(texts.rewardAvailableSummaryText || '').replace(
169
+ '{count}',
170
+ String(availableRewards.length)
171
+ )}
172
+ </p>
173
+ )}
174
+ </div>
175
+ </div>
176
+ <button
177
+ type="button"
178
+ onClick={(e) => {
179
+ e.stopPropagation();
180
+ onOpenRewardModal?.();
181
+ }}
182
+ disabled={isLoadingRewards}
183
+ className="px-3 py-1.5 text-xs border border-[#000000] text-[#000000] hover:bg-[#000000] hover:text-white transition-colors disabled:opacity-50 shrink-0"
184
+ >
185
+ {selectedRewards.length > 0
186
+ ? texts.rewardModalConfirmText
187
+ : texts.rewardOpenButtonText}
188
+ </button>
189
+ </div>
190
+ )}
191
+
122
192
  {isSelected && cvcRequired && (
123
193
  <div
124
194
  className="border-t border-[#eeeeee] p-4 bg-[#f7f7f7]"
@@ -184,7 +184,7 @@ const CreditCardForm: React.FC<CreditCardFormProps> = ({
184
184
  setValue('cardNumber', formatted, { shouldValidate: true });
185
185
  }}
186
186
  error={errors.cardNumber}
187
- maxLength={23}
187
+ maxLength={19}
188
188
  className="pr-20"
189
189
  />
190
190
  {cardType !== 'unknown' && (
@@ -118,7 +118,7 @@ const InstallmentList: React.FC<InstallmentListProps> = ({
118
118
  <Button
119
119
  onClick={onProceedToPayment}
120
120
  disabled={isLoading || paymentLoading}
121
- className="w-full cursor-pointer disabled:opacity-50 disabled:cursor-not-allowed"
121
+ className="w-full cursor-pointer bg-[#000000] text-[#ffffff] hover:bg-[#ffffff] hover:text-[#000000] border border-solid border-[#000000] disabled:opacity-50 disabled:cursor-not-allowed"
122
122
  >
123
123
  {paymentLoading ? (
124
124
  <div className="flex items-center justify-center">
@@ -204,15 +204,21 @@ const OTPModal: React.FC<OTPModalProps> = ({
204
204
  >
205
205
  <div className="px-6">
206
206
  {getTitle() && (
207
- <h3 className="text-center mt-4 text-lg font-semibold">{getTitle()}</h3>
207
+ <h3 className="text-center mt-4 text-lg font-semibold">
208
+ {getTitle()}
209
+ </h3>
208
210
  )}
209
- <p className="text-center mt-2 text-sm text-gray-600">{getDescription()}</p>
211
+ <p className="text-center mt-2 text-sm text-gray-600">
212
+ {getDescription()}
213
+ </p>
210
214
  <div className="flex flex-col gap-3 p-5 w-3/4 m-auto">
211
215
  <Input
212
216
  type="text"
213
217
  value={otp}
214
218
  onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
215
- setOtp(e.target.value.replace(/\D/g, '').slice(0, getMaxLength()));
219
+ setOtp(
220
+ e.target.value.replace(/\D/g, '').slice(0, getMaxLength())
221
+ );
216
222
  setError(null);
217
223
  }}
218
224
  maxLength={getMaxLength()}
@@ -222,7 +228,9 @@ const OTPModal: React.FC<OTPModalProps> = ({
222
228
  placeholder={getPlaceholder()}
223
229
  />
224
230
  {getHelperText() && (
225
- <p className="text-xs text-gray-500 text-center">{getHelperText()}</p>
231
+ <p className="text-xs text-gray-500 text-center">
232
+ {getHelperText()}
233
+ </p>
226
234
  )}
227
235
  {error && (
228
236
  <p className="text-[#d72b01] text-xs text-center">{error}</p>
@@ -0,0 +1,194 @@
1
+ import React, { useEffect, useMemo, useState } from 'react';
2
+ import { Modal, Button } from '@akinon/next/components';
3
+ import { RewardSelectionModalProps } from '../types/custom-render.types';
4
+ import type { RewardItem, RewardCategory } from '../types/payment.types';
5
+ import { parseRewardAmount, getCappedRewardAmounts } from '../utils/reward-utils';
6
+
7
+ const formatAmount = (amount: number | string, currency?: string) => {
8
+ const formatted = parseRewardAmount(amount).toFixed(2);
9
+ return currency ? `${formatted} ${currency.toUpperCase()}` : formatted;
10
+ };
11
+
12
+ const isSameReward = (a: RewardItem, b: RewardItem) => a.type === b.type;
13
+
14
+ const RewardSelectionModal: React.FC<RewardSelectionModalProps> = ({
15
+ open,
16
+ onClose,
17
+ onConfirm,
18
+ rewards,
19
+ selectedRewards,
20
+ isLoading = false,
21
+ currency,
22
+ payableAmount,
23
+ texts
24
+ }) => {
25
+ const [draft, setDraft] = useState<RewardItem[]>(selectedRewards);
26
+
27
+ useEffect(() => {
28
+ if (open) {
29
+ setDraft(selectedRewards);
30
+ }
31
+ }, [open, selectedRewards]);
32
+
33
+ const cappedAmounts = useMemo(
34
+ () => getCappedRewardAmounts(draft, payableAmount),
35
+ [draft, payableAmount]
36
+ );
37
+
38
+ const grouped = useMemo(() => {
39
+ const map: Record<RewardCategory, RewardItem[]> = {
40
+ special: [],
41
+ general: []
42
+ };
43
+ rewards.forEach((reward) => {
44
+ if (map[reward.type]) {
45
+ map[reward.type].push(reward);
46
+ }
47
+ });
48
+ return map;
49
+ }, [rewards]);
50
+
51
+ const toggleReward = (reward: RewardItem) => {
52
+ setDraft((current) => {
53
+ const exists = current.some((item) => isSameReward(item, reward));
54
+ if (exists) {
55
+ return current.filter((item) => !isSameReward(item, reward));
56
+ }
57
+ const withoutSameType = current.filter(
58
+ (item) => item.type !== reward.type
59
+ );
60
+ return [...withoutSameType, reward];
61
+ });
62
+ };
63
+
64
+ const isSelected = (reward: RewardItem) =>
65
+ draft.some((item) => isSameReward(item, reward));
66
+
67
+ const categoryLabel = (category: RewardCategory) =>
68
+ category === 'special'
69
+ ? texts.rewardCategorySpecialText
70
+ : texts.rewardCategoryGeneralText;
71
+
72
+ const handleConfirm = async () => {
73
+ await onConfirm(draft);
74
+ };
75
+
76
+ const hasRewards = rewards.length > 0;
77
+
78
+ return (
79
+ <Modal
80
+ portalId="masterpass-reward-modal"
81
+ open={open}
82
+ setOpen={onClose}
83
+ title={texts.rewardModalTitle}
84
+ className="w-full sm:w-[32rem] max-h-[90vh] overflow-y-auto"
85
+ >
86
+ <div className="px-6 pt-4 pb-6">
87
+ {texts.rewardModalDescription && (
88
+ <p className="text-sm text-gray-600 mb-4">
89
+ {texts.rewardModalDescription}
90
+ </p>
91
+ )}
92
+
93
+ {!hasRewards ? (
94
+ <p className="text-center text-gray-500 py-8">
95
+ {texts.rewardModalEmptyMessage}
96
+ </p>
97
+ ) : (
98
+ <div className="space-y-5">
99
+ {(Object.keys(grouped) as RewardCategory[])
100
+ .filter((category) => grouped[category].length > 0)
101
+ .map((category) => (
102
+ <div key={category}>
103
+ <h3 className="text-sm font-semibold text-gray-700 mb-2">
104
+ {categoryLabel(category)}
105
+ </h3>
106
+ <ul className="space-y-2">
107
+ {grouped[category].map((reward) => {
108
+ const selected = isSelected(reward);
109
+ const fullValue = parseRewardAmount(reward.amount);
110
+ const capped = cappedAmounts[reward.type];
111
+ const isCapped = selected && capped < fullValue;
112
+ return (
113
+ <li key={`${reward.type}-${reward.name ?? ''}`}>
114
+ <label
115
+ className={`flex items-center justify-between gap-3 px-3 py-3 border cursor-pointer transition-colors ${
116
+ selected
117
+ ? 'border-primary bg-primary/5'
118
+ : 'border-gray-200 hover:bg-gray-50'
119
+ }`}
120
+ >
121
+ <div className="flex items-center gap-3">
122
+ <input
123
+ type="checkbox"
124
+ className="h-4 w-4"
125
+ checked={selected}
126
+ onChange={() => toggleReward(reward)}
127
+ disabled={isLoading}
128
+ />
129
+ <div>
130
+ <p className="font-medium">
131
+ {reward.name || categoryLabel(reward.type)}
132
+ </p>
133
+ {reward.name && (
134
+ <p className="text-xs text-gray-500">
135
+ {categoryLabel(reward.type)}
136
+ </p>
137
+ )}
138
+ </div>
139
+ </div>
140
+ <div className="text-right">
141
+ <span
142
+ className={`font-semibold ${
143
+ isCapped
144
+ ? 'text-gray-400 line-through text-sm'
145
+ : ''
146
+ }`}
147
+ >
148
+ {formatAmount(reward.amount, currency)}
149
+ </span>
150
+ {isCapped && (
151
+ <p className="text-xs text-[#00a63d] font-medium mt-0.5">
152
+ {(texts.rewardCappedNoticeText || '').replace(
153
+ '{amount}',
154
+ formatAmount(capped, currency)
155
+ )}
156
+ </p>
157
+ )}
158
+ </div>
159
+ </label>
160
+ </li>
161
+ );
162
+ })}
163
+ </ul>
164
+ </div>
165
+ ))}
166
+ </div>
167
+ )}
168
+
169
+ <div className="flex gap-3 justify-end mt-6">
170
+ <Button
171
+ appearance="outlined"
172
+ className="px-5 py-3 h-auto"
173
+ onClick={onClose}
174
+ disabled={isLoading}
175
+ >
176
+ {texts.rewardModalCancelText}
177
+ </Button>
178
+ <Button
179
+ appearance="filled"
180
+ className="px-5 py-3 h-auto"
181
+ onClick={handleConfirm}
182
+ disabled={isLoading || !hasRewards}
183
+ >
184
+ {isLoading
185
+ ? texts.rewardModalLoadingText
186
+ : texts.rewardModalConfirmText}
187
+ </Button>
188
+ </div>
189
+ </div>
190
+ </Modal>
191
+ );
192
+ };
193
+
194
+ export default RewardSelectionModal;
@@ -40,7 +40,16 @@ export const useMasterpassAccount = () => {
40
40
 
41
41
  const initializeAccount = useCallback(
42
42
  async (newTokenData: any, rawToken?: string) => {
43
- if (!newTokenData?.AccountKey) return;
43
+ if (!newTokenData?.AccountKey) {
44
+ dispatch(
45
+ setAccountStatus({
46
+ isAccountNotFound: false,
47
+ isAccountNotLinked: true,
48
+ shouldShowDirectForm: true
49
+ })
50
+ );
51
+ return;
52
+ }
44
53
 
45
54
  const accountService = new AccountService(rawToken || token, newTokenData?.MerchantId);
46
55
 
@@ -126,7 +135,10 @@ export const useMasterpassAccount = () => {
126
135
  dispatch(resetState());
127
136
  }, [dispatch]);
128
137
 
129
- const refreshToken = async (options?: { three_d?: boolean; skipReset?: boolean }) => {
138
+ const refreshToken = async (options?: {
139
+ three_d?: boolean;
140
+ skipReset?: boolean;
141
+ }) => {
130
142
  if (options?.three_d !== false && !options?.skipReset) {
131
143
  resetData();
132
144
  }
@@ -218,8 +230,12 @@ export const useMasterpassAccount = () => {
218
230
  informationModalData: {
219
231
  type: 'warning',
220
232
  title: texts?.sessionExpiredTitle || 'Session Expired',
221
- message: texts?.sessionExpiredMessage || 'Your session has expired due to inactivity. Please restart the process to continue.',
222
- secondaryMessage: texts?.sessionExpiredSecondaryMessage || 'For security reasons, verification codes are only valid for a limited time.',
233
+ message:
234
+ texts?.sessionExpiredMessage ||
235
+ 'Your session has expired due to inactivity. Please restart the process to continue.',
236
+ secondaryMessage:
237
+ texts?.sessionExpiredSecondaryMessage ||
238
+ 'For security reasons, verification codes are only valid for a limited time.',
223
239
  buttonText: texts?.sessionExpiredButton || 'Start Again'
224
240
  }
225
241
  })
@@ -335,7 +351,7 @@ export const useMasterpassAccount = () => {
335
351
  const activeMerchantId = freshResult?.merchantId || tokenData?.MerchantId;
336
352
 
337
353
  if (!activeTokenData?.AccountKey) {
338
- throw new Error('Token data not available');
354
+ return { success: false, message: '' };
339
355
  }
340
356
 
341
357
  const accountService = new AccountService(activeToken, activeMerchantId);
@@ -5,7 +5,9 @@ import {
5
5
  useSetMasterpassRestBinNumberMutation,
6
6
  useCheckoutMasterpassInstallmentMutation,
7
7
  usePrepareMasterpassOrderMutation,
8
- useFinalizeMasterpassOrderMutation
8
+ useFinalizeMasterpassOrderMutation,
9
+ useQueryMasterpassRewardsMutation,
10
+ useSelectMasterpassRewardsMutation
9
11
  } from '../redux/api';
10
12
  import {
11
13
  updatePaymentState,
@@ -14,7 +16,12 @@ import {
14
16
  setInstallments,
15
17
  setCardType,
16
18
  setOrderData,
17
- setOrderCompleted
19
+ setOrderCompleted,
20
+ setAvailableRewards,
21
+ setSelectedRewards,
22
+ setLoadingRewards,
23
+ setShowRewardModal,
24
+ clearRewards
18
25
  } from '../redux/reducer';
19
26
  import { useMasterpassToken } from './useMasterpassToken';
20
27
  import { PaymentService } from '../services/payment';
@@ -24,8 +31,9 @@ import {
24
31
  getTransactionType
25
32
  } from '../utils/payment-utils';
26
33
  import { handleMasterpassResponse } from '../utils/response-handler';
27
- import type { Installment } from '../types/payment.types';
34
+ import type { Installment, RewardItem } from '../types/payment.types';
28
35
  import type { CardModel } from '../types/account.types';
36
+ import { getCappedRewardAmounts } from '../utils/reward-utils';
29
37
 
30
38
  export type PaymentResult = {
31
39
  success: boolean;
@@ -35,7 +43,14 @@ export type PaymentResult = {
35
43
  message?: any;
36
44
  };
37
45
 
38
- export const useMasterpassPayment = () => {
46
+ export interface UseMasterpassPaymentOptions {
47
+ enableRewards?: boolean;
48
+ }
49
+
50
+ export const useMasterpassPayment = (
51
+ options: UseMasterpassPaymentOptions = {}
52
+ ) => {
53
+ const { enableRewards = false } = options;
39
54
  const dispatch = useDispatch();
40
55
  const {
41
56
  paymentState,
@@ -46,6 +61,13 @@ export const useMasterpassPayment = () => {
46
61
  tokenData
47
62
  } = useAppSelector((state) => state.masterpassRest);
48
63
 
64
+ const payableAmount = useAppSelector(
65
+ (state) =>
66
+ state.checkout?.preOrder?.unpaid_amount ??
67
+ state.checkout?.preOrder?.total_amount_with_interest ??
68
+ null
69
+ );
70
+
49
71
  const { refetch: refetchToken } = useMasterpassToken({
50
72
  useThreeD: paymentState.useThreeD
51
73
  });
@@ -62,6 +84,12 @@ export const useMasterpassPayment = () => {
62
84
  const [finalizeMasterpassOrder, { isLoading: isFinalizeLoading }] =
63
85
  useFinalizeMasterpassOrderMutation();
64
86
 
87
+ const [queryMasterpassRewards, { isLoading: isRewardsQueryLoading }] =
88
+ useQueryMasterpassRewardsMutation();
89
+
90
+ const [selectMasterpassRewards, { isLoading: isRewardsSelectLoading }] =
91
+ useSelectMasterpassRewardsMutation();
92
+
65
93
  const refreshTokenForPayment = useCallback(async () => {
66
94
  const result = await refetchToken({ skipReset: true });
67
95
  if (result?.data?.token) {
@@ -97,12 +125,38 @@ export const useMasterpassPayment = () => {
97
125
  [checkoutMasterpassInstallment, dispatch]
98
126
  );
99
127
 
128
+ const fetchRewardsForCard = useCallback(
129
+ async (card: CardModel) => {
130
+ if (!card?.cardAlias) return;
131
+
132
+ dispatch(setLoadingRewards(true));
133
+
134
+ try {
135
+ const result = await queryMasterpassRewards({
136
+ card_alias: card.cardAlias
137
+ }).unwrap();
138
+
139
+ const rewards =
140
+ result.context_list?.[0]?.page_context?.rewards || [];
141
+ dispatch(setAvailableRewards(rewards));
142
+ } catch (error) {
143
+ dispatch(setAvailableRewards([]));
144
+ } finally {
145
+ dispatch(setLoadingRewards(false));
146
+ }
147
+ },
148
+ [queryMasterpassRewards, dispatch]
149
+ );
150
+
100
151
  const handleCardSelect = useCallback(
101
152
  async (card: CardModel) => {
102
153
  dispatch(setSelectedCard(card));
103
154
  dispatch(setInstallments([]));
104
155
  dispatch(setSelectedInstallment(null));
105
156
  dispatch(setCardType(null));
157
+ if (enableRewards) {
158
+ dispatch(clearRewards());
159
+ }
106
160
 
107
161
  try {
108
162
  const result = await setMasterpassRestBinNumber({
@@ -119,11 +173,53 @@ export const useMasterpassPayment = () => {
119
173
  await handleInstallmentSelect(pageContext.installments[0]);
120
174
  }
121
175
  }
176
+
177
+ if (enableRewards) {
178
+ void fetchRewardsForCard(card);
179
+ }
122
180
  } catch (error) {
123
181
  // Silently handle errors (e.g., mutation aborted due to rapid selection)
124
182
  }
125
183
  },
126
- [setMasterpassRestBinNumber, handleInstallmentSelect, dispatch]
184
+ [
185
+ enableRewards,
186
+ setMasterpassRestBinNumber,
187
+ handleInstallmentSelect,
188
+ fetchRewardsForCard,
189
+ dispatch
190
+ ]
191
+ );
192
+
193
+ const openRewardModal = useCallback(() => {
194
+ dispatch(setShowRewardModal(true));
195
+ }, [dispatch]);
196
+
197
+ const closeRewardModal = useCallback(() => {
198
+ dispatch(setShowRewardModal(false));
199
+ }, [dispatch]);
200
+
201
+ const confirmRewards = useCallback(
202
+ async (selected: RewardItem[]) => {
203
+ const capped = getCappedRewardAmounts(selected, payableAmount);
204
+ const special = capped.special.toFixed(2);
205
+ const general = capped.general.toFixed(2);
206
+
207
+ try {
208
+ await selectMasterpassRewards({ special, general }).unwrap();
209
+ dispatch(setSelectedRewards(selected));
210
+ dispatch(setShowRewardModal(false));
211
+ return { success: true };
212
+ } catch (error) {
213
+ return {
214
+ success: false,
215
+ message:
216
+ error instanceof Error
217
+ ? error.message
218
+ : 'Failed to apply rewards'
219
+ };
220
+ }
221
+ },
222
+ [selectMasterpassRewards, payableAmount, dispatch]
127
223
  );
128
224
 
129
225
  const processPayment = useCallback(async (): Promise<PaymentResult> => {
@@ -251,10 +347,6 @@ export const useMasterpassPayment = () => {
251
347
  const activeToken = freshResult?.token;
252
348
  const activeMerchantId = freshResult?.merchantId || tokenData?.MerchantId;
253
349
 
254
- if (!activeTokenData?.AccountKey) {
255
- return { success: false, message: 'Token data not available' };
256
- }
257
-
258
350
  const prepareResult = await prepareMasterpassOrder({
259
351
  use_three_d: paymentState.useThreeD
260
352
  }).unwrap();
@@ -268,13 +360,13 @@ export const useMasterpassPayment = () => {
268
360
  cardHolderName: newCardFormData.cardholderName || '',
269
361
  cardAlias: newCardFormData.cardAlias || '',
270
362
  expiryDate: newCardFormData.expiryDate,
271
- accountKey: activeTokenData.AccountKey,
363
+ accountKey: activeTokenData?.AccountKey || '',
272
364
  amount: prepareResult.pre_order?.total_amount_with_interest,
273
365
  orderNo: prepareResult.context_list?.[0]?.page_context?.order_no,
274
366
  currencyCode: currency,
275
367
  installmentCount: selectedInstallment.installment_count,
276
- authenticationMethod: activeTokenData.AuthenticationMethod,
277
- secure3DModel: activeTokenData.Secure3dType,
368
+ authenticationMethod: activeTokenData?.AuthenticationMethod,
369
+ secure3DModel: activeTokenData?.Secure3dType,
278
370
  terminalGroupId,
279
371
  acquirerIcaNumber: bankIca,
280
372
  additionalFields:
@@ -346,11 +438,18 @@ export const useMasterpassPayment = () => {
346
438
  isInstallmentLoading,
347
439
  isPrepareLoading,
348
440
  isFinalizeLoading,
441
+ isRewardsQueryLoading,
442
+ isRewardsSelectLoading,
443
+ payableAmount,
349
444
 
350
445
  updatePaymentState: updatePaymentStateAction,
351
446
  handleCardSelect,
352
447
  handleInstallmentSelect,
353
448
  processPayment,
354
- processDirectPayment
449
+ processDirectPayment,
450
+ fetchRewardsForCard,
451
+ openRewardModal,
452
+ closeRewardModal,
453
+ confirmRewards
355
454
  };
356
455
  };
package/src/index.ts CHANGED
@@ -4,6 +4,7 @@ export { default as MasterpassRestOption } from './views/masterpass-rest-option'
4
4
 
5
5
  export { default as CreditCardForm } from './components/credit-card-form';
6
6
  export { default as PaymentMethodSelector } from './components/payment-method-selector';
7
+ export { default as RewardSelectionModal } from './components/reward-selection-modal';
7
8
 
8
9
  export { default as masterpassRestReducer } from './redux/reducer';
9
10
 
@@ -14,6 +15,7 @@ export { useMasterpassScript } from './hooks/useMasterpassScript';
14
15
 
15
16
  export * from './utils/payment-constants';
16
17
  export * from './utils/payment-utils';
18
+ export * from './utils/reward-utils';
17
19
  export * from './utils/card-utils';
18
20
  export * from './utils/validation-schemas';
19
21
  export * from './utils/masterpass-sdk';