@akinon/pz-masterpass 1.102.0-rc.78 → 1.102.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/CHANGELOG.md +1 -20
- package/README.md +2 -462
- package/package.json +1 -1
- package/src/hooks/use-delete-card.tsx +5 -16
- package/src/views/card-list/index.tsx +79 -124
- package/src/views/card-registration/index.tsx +6 -67
- package/src/views/delete-confirmation-modal/index.tsx +1 -25
- package/src/views/link-modal/index.tsx +1 -23
- package/src/views/otp-modal/index.tsx +1 -38
package/CHANGELOG.md
CHANGED
|
@@ -1,23 +1,6 @@
|
|
|
1
1
|
# @akinon/pz-masterpass
|
|
2
2
|
|
|
3
|
-
## 1.102.0
|
|
4
|
-
|
|
5
|
-
## 1.102.0-rc.77
|
|
6
|
-
|
|
7
|
-
### Minor Changes
|
|
8
|
-
|
|
9
|
-
- d8be48fb: ZERO-3422: Update fetch method to use dynamic request method in wallet complete redirection middleware
|
|
10
|
-
- ad0bec92: ZERO-3364 :Update readme file for masterpass
|
|
11
|
-
- 16aff543: ZERO-3431: Add test script for redirect utility in package.json
|
|
12
|
-
- 64699d3ff: ZERO-2761: Fix invalid import for plugin module
|
|
13
|
-
- e974d8e8: ZERO-3406: Fix rc build
|
|
14
|
-
- b31333ed: ZERO-3357 :Add components with renderer properties for customizable UI elements in pz-masterpass
|
|
15
|
-
- 7eb51ca9: ZERO-3424 :Update package versions
|
|
16
|
-
- 7727ae55f: ZERO-3073: Refactor basket page to use server-side data fetching and simplify component structure
|
|
17
|
-
- 8b1d24eb: ZERO-3422: Update fetch method to use dynamic request method in wallet complete redirection middleware
|
|
18
|
-
- 33377cfd: ZERO-3267: Refactor import statement for ROUTES in error-page component
|
|
19
|
-
- 08c3caec: ZERO-3607 :Enhance the DeleteButton component with additional features and improve the OTP modal functionality by adding minutes and seconds
|
|
20
|
-
- e9af4e2: ZERO-3607 :Enhance the DeleteButton component with additional features and improve the OTP modal functionality by adding minutes and seconds
|
|
3
|
+
## 1.102.0
|
|
21
4
|
|
|
22
5
|
## 1.101.0
|
|
23
6
|
|
|
@@ -49,8 +32,6 @@
|
|
|
49
32
|
|
|
50
33
|
## 1.91.0
|
|
51
34
|
|
|
52
|
-
> > > > > > > origin/ZERO-3418
|
|
53
|
-
|
|
54
35
|
## 1.90.0
|
|
55
36
|
|
|
56
37
|
## 1.89.0
|
package/README.md
CHANGED
|
@@ -12,14 +12,10 @@ npx @akinon/projectzero@latest --plugins
|
|
|
12
12
|
|
|
13
13
|
## Available Props
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
### Masterpass Provider
|
|
16
16
|
|
|
17
17
|
##### File Path: src/app/[commerce]/[locale]/[currency]/orders/checkout/page.tsx
|
|
18
18
|
|
|
19
|
-
### Usage Examples
|
|
20
|
-
|
|
21
|
-
##### Default Usage
|
|
22
|
-
|
|
23
19
|
```javascript
|
|
24
20
|
<PluginModule
|
|
25
21
|
component={Component.MasterpassProvider}
|
|
@@ -33,7 +29,7 @@ npx @akinon/projectzero@latest --plugins
|
|
|
33
29
|
</PluginModule>
|
|
34
30
|
```
|
|
35
31
|
|
|
36
|
-
|
|
32
|
+
### Additional Params
|
|
37
33
|
|
|
38
34
|
##### To add extra parameters, it can be added by passing additional Params property to the Masterpass Provider.
|
|
39
35
|
|
|
@@ -55,30 +51,8 @@ npx @akinon/projectzero@latest --plugins
|
|
|
55
51
|
|
|
56
52
|
### Delete Confirmation Modal
|
|
57
53
|
|
|
58
|
-
#### Props
|
|
59
|
-
|
|
60
|
-
| Props | Type | Required | Description |
|
|
61
|
-
| --- | --- | --- | --- |
|
|
62
|
-
| translations | typeof defaultTranslations | Optional | Used to customize the default texts. |
|
|
63
|
-
| renderer | RendererProps | Optional | Renderer functions that can be used to customize all subcomponents. |
|
|
64
|
-
|
|
65
|
-
#### RendererProps
|
|
66
|
-
|
|
67
|
-
| Props | Type | Description |
|
|
68
|
-
| --- | --- | --- |
|
|
69
|
-
| open | boolean | It is information whether the modal is open or not. |
|
|
70
|
-
| setOpen | (open: boolean) => void | Used to manage modal on/off operation. |
|
|
71
|
-
| onConfirm | () => void | This is the function that will perform the deletion operation. |
|
|
72
|
-
| onCancel | () => void | This is the function that will be run if the user cancels the deletion process. |
|
|
73
|
-
| loading | boolean | Indicates the loading status during the deletion process. |
|
|
74
|
-
| error | string / null | Error message to be displayed if an error occurs during deletion. |
|
|
75
|
-
|
|
76
54
|
##### File Path: src/app/[commerce]/[locale]/[currency]/orders/checkout/page.tsx
|
|
77
55
|
|
|
78
|
-
### Usage Examples
|
|
79
|
-
|
|
80
|
-
##### Default Usage
|
|
81
|
-
|
|
82
56
|
```javascript
|
|
83
57
|
<PluginModule
|
|
84
58
|
component={Component.MasterpassDeleteConfirmationModal}
|
|
@@ -92,70 +66,10 @@ npx @akinon/projectzero@latest --plugins
|
|
|
92
66
|
/>
|
|
93
67
|
```
|
|
94
68
|
|
|
95
|
-
##### Customized Usage with Renderer
|
|
96
|
-
|
|
97
|
-
```javascript
|
|
98
|
-
<PluginModule
|
|
99
|
-
component={Component.MasterpassDeleteConfirmationModal}
|
|
100
|
-
props={{
|
|
101
|
-
renderer: {
|
|
102
|
-
Content: ({ open, setOpen, onConfirm, onCancel, loading, error }) => (
|
|
103
|
-
<Modal
|
|
104
|
-
open={open}
|
|
105
|
-
setOpen={setOpen}
|
|
106
|
-
className="w-full sm:w-[28rem]"
|
|
107
|
-
portalId="masterpass-remove-card-modal"
|
|
108
|
-
>
|
|
109
|
-
<div className="flex flex-col items-center p-5">
|
|
110
|
-
<div className="text-xs mb-3">
|
|
111
|
-
Are you sure you want to delete your card?
|
|
112
|
-
</div>
|
|
113
|
-
<Button onClick={onConfirm} className="bg-red-600 text-black">
|
|
114
|
-
{loading ? 'Deletion...' : 'Delete'}
|
|
115
|
-
</Button>
|
|
116
|
-
<Button appearance="outlined" onClick={onCancel}>
|
|
117
|
-
Cancel
|
|
118
|
-
</Button>
|
|
119
|
-
{error && (
|
|
120
|
-
<p className="text-red-500 text-sm mt-2 text-center">
|
|
121
|
-
🚨 {error}
|
|
122
|
-
</p>
|
|
123
|
-
)}
|
|
124
|
-
</div>
|
|
125
|
-
</Modal>
|
|
126
|
-
)
|
|
127
|
-
}
|
|
128
|
-
}}
|
|
129
|
-
/>
|
|
130
|
-
```
|
|
131
|
-
|
|
132
69
|
### OTP Modal
|
|
133
70
|
|
|
134
|
-
#### Props
|
|
135
|
-
|
|
136
|
-
| Props | Type | Required | Description |
|
|
137
|
-
| --- | --- | --- | --- |
|
|
138
|
-
| translations | { [key: string]: string } | Optional | Translation object to customize all texts. Overrides default texts. |
|
|
139
|
-
| renderer | RendererProps | Optional | Renderer functions that can be used to customize all subcomponents. |
|
|
140
|
-
|
|
141
|
-
#### RendererProps
|
|
142
|
-
|
|
143
|
-
| Props | Type | Description |
|
|
144
|
-
| --- | --- | --- |
|
|
145
|
-
| open | boolean | It is information whether the modal is open or not. |
|
|
146
|
-
| setOpen | (open: boolean) => void | Used to manage modal on/off operation. |
|
|
147
|
-
| onSubmit | (data: { otp_code: string }) => void | Sends the OTP code entered by the user. |
|
|
148
|
-
| loading | boolean | Indicates the loading status during validation. |
|
|
149
|
-
| error | string / null | Error message to be displayed if there is an error. |
|
|
150
|
-
| resendSms | () => void | Function triggered when the user requests SMS again. |
|
|
151
|
-
| resendSmsFetching | boolean | Indicates the loading status during the resending process. |
|
|
152
|
-
| targetDate | number | When the countdown will end (as a timestamp). |
|
|
153
|
-
| otpRef | string / null | Transaction reference number, if applicable. |
|
|
154
|
-
|
|
155
71
|
##### File Path: src/app/[commerce]/[locale]/[currency]/orders/checkout/page.tsx
|
|
156
72
|
|
|
157
|
-
##### Default Usage
|
|
158
|
-
|
|
159
73
|
```javascript
|
|
160
74
|
<PluginModule
|
|
161
75
|
component={Component.MasterpassOtpModal}
|
|
@@ -172,123 +86,10 @@ npx @akinon/projectzero@latest --plugins
|
|
|
172
86
|
/>
|
|
173
87
|
```
|
|
174
88
|
|
|
175
|
-
##### Customized Usage with Renderer
|
|
176
|
-
|
|
177
|
-
```javascript
|
|
178
|
-
<PluginModule
|
|
179
|
-
component={Component.MasterpassOtpModal}
|
|
180
|
-
props={{
|
|
181
|
-
renderer: {
|
|
182
|
-
Content: ({
|
|
183
|
-
open,
|
|
184
|
-
setOpen,
|
|
185
|
-
onSubmit,
|
|
186
|
-
loading,
|
|
187
|
-
error,
|
|
188
|
-
resendSms,
|
|
189
|
-
resendSmsFetching,
|
|
190
|
-
targetDate,
|
|
191
|
-
otpRef,
|
|
192
|
-
minutes,
|
|
193
|
-
seconds,
|
|
194
|
-
control,
|
|
195
|
-
formError
|
|
196
|
-
}) => {
|
|
197
|
-
const [code, setCode] = useState('');
|
|
198
|
-
return (
|
|
199
|
-
<Modal
|
|
200
|
-
portalId="otp-masterpass"
|
|
201
|
-
open={open}
|
|
202
|
-
setOpen={setOpen}
|
|
203
|
-
className="w-[330px] bottom-auto top-1/4 mx-auto px-0 pb-0 md:pb-0 md:rounded-none md:pt-0 md:px-0 md:bottom-auto"
|
|
204
|
-
iconSize={20}
|
|
205
|
-
>
|
|
206
|
-
<div className="py-4 px-14 pt-12 pb-9 flex flex-col justify-center items-center">
|
|
207
|
-
<div className="text-lg leading-5 font-semibold text-secondary text-center pb-7">
|
|
208
|
-
Telefon doğrulama kodunu gir
|
|
209
|
-
</div>
|
|
210
|
-
<form
|
|
211
|
-
onSubmit={(e) => {
|
|
212
|
-
e.preventDefault();
|
|
213
|
-
onSubmit({ otp_code: code });
|
|
214
|
-
}}
|
|
215
|
-
>
|
|
216
|
-
<div className="mt-2 flex flex-col items-center justify-between">
|
|
217
|
-
<div>
|
|
218
|
-
<label className="text-xs leading-[14px] font-normal text-secondary">
|
|
219
|
-
SMS kodu
|
|
220
|
-
</label>
|
|
221
|
-
<Input
|
|
222
|
-
id="otp_code"
|
|
223
|
-
autoComplete="off"
|
|
224
|
-
minLength={6}
|
|
225
|
-
maxLength={6}
|
|
226
|
-
max="999999"
|
|
227
|
-
min="000000"
|
|
228
|
-
control={control}
|
|
229
|
-
className="h-9 rounded-full border-gray-620 mt-2"
|
|
230
|
-
onChange={(e) =>
|
|
231
|
-
setCode((e.target as HTMLInputElement).value)
|
|
232
|
-
}
|
|
233
|
-
/>
|
|
234
|
-
</div>
|
|
235
|
-
<Button className="w-full capitalize bg-secondary rounded-full text-base h-auto py-1.5 mt-2 border-none">
|
|
236
|
-
Doğrula
|
|
237
|
-
</Button>
|
|
238
|
-
{formError && (
|
|
239
|
-
<p className="mt-2 text-error text-xs text-center">
|
|
240
|
-
{formError}
|
|
241
|
-
</p>
|
|
242
|
-
)}
|
|
243
|
-
</div>
|
|
244
|
-
</form>
|
|
245
|
-
{minutes + seconds > 0 ? (
|
|
246
|
-
<div className="flex mt-2 flex justify-center">
|
|
247
|
-
{`0${minutes}`} :{' '}
|
|
248
|
-
{`${seconds < 10 ? '0' : ''}${seconds}`}
|
|
249
|
-
</div>
|
|
250
|
-
) : (
|
|
251
|
-
<Button
|
|
252
|
-
onClick={() => resendSms()}
|
|
253
|
-
className="w-full capitalize bg-secondary rounded-full text-base h-auto py-1.5 mt-2 border-none text-white"
|
|
254
|
-
>
|
|
255
|
-
{!resendSmsFetching ? 'resend code' : <LoaderSpinner />}
|
|
256
|
-
</Button>
|
|
257
|
-
)}
|
|
258
|
-
</div>
|
|
259
|
-
</Modal>
|
|
260
|
-
);
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
}}
|
|
264
|
-
/>
|
|
265
|
-
```
|
|
266
|
-
|
|
267
89
|
### Link Modal
|
|
268
90
|
|
|
269
|
-
#### Props
|
|
270
|
-
|
|
271
|
-
| Props | Type | Required | Description |
|
|
272
|
-
| --- | --- | --- | --- |
|
|
273
|
-
| translations | { [key: string]: string } | Optional | Translation object to customize all texts. Overrides default texts. |
|
|
274
|
-
| renderer | RendererProps | Optional | Renderer functions that can be used to customize all subcomponents. |
|
|
275
|
-
|
|
276
|
-
#### RendererProps
|
|
277
|
-
|
|
278
|
-
| Props | Type | Description |
|
|
279
|
-
| --- | --- | --- |
|
|
280
|
-
| open | boolean | It is information whether the modal is open or not. |
|
|
281
|
-
| setOpen | (open: boolean) => void | Used to manage modal on/off operation. |
|
|
282
|
-
| onClick | () => void | It is the function that is called when the user clicks the "Use" button. |
|
|
283
|
-
| loading | boolean | This is the loading status that will be displayed during the API request. |
|
|
284
|
-
| error | string | If there is an error in the API response, a message is displayed in this field. |
|
|
285
|
-
|
|
286
91
|
##### File Path: src/app/[commerce]/[locale]/[currency]/orders/checkout/page.tsx
|
|
287
92
|
|
|
288
|
-
### Usage Examples
|
|
289
|
-
|
|
290
|
-
##### Default Usage
|
|
291
|
-
|
|
292
93
|
```javascript
|
|
293
94
|
<PluginModule
|
|
294
95
|
component={Component.MasterpassLinkModal}
|
|
@@ -302,67 +103,10 @@ npx @akinon/projectzero@latest --plugins
|
|
|
302
103
|
/>
|
|
303
104
|
```
|
|
304
105
|
|
|
305
|
-
##### Customized Usage with Renderer
|
|
306
|
-
|
|
307
|
-
```javascript
|
|
308
|
-
<PluginModule
|
|
309
|
-
component={Component.MasterpassLinkModal}
|
|
310
|
-
props={{
|
|
311
|
-
renderer: {
|
|
312
|
-
Content: ({ open, setOpen, onClick, loading, error }) => (
|
|
313
|
-
<Modal
|
|
314
|
-
open={open}
|
|
315
|
-
setOpen={setOpen}
|
|
316
|
-
className="w-full sm:w-[28rem]"
|
|
317
|
-
portalId="masterpass-check-user"
|
|
318
|
-
>
|
|
319
|
-
<div className="p-10">
|
|
320
|
-
<p className="text-sm text-center">
|
|
321
|
-
You have cards registered to your Masterpass account. Do you want
|
|
322
|
-
to use your cards?
|
|
323
|
-
</p>
|
|
324
|
-
<Button
|
|
325
|
-
onClick={onClick}
|
|
326
|
-
disabled={loading}
|
|
327
|
-
className="bg-green-600 text-error w-full py-2 mt-4"
|
|
328
|
-
>
|
|
329
|
-
{loading ? 'Loading...' : 'Use'}
|
|
330
|
-
</Button>
|
|
331
|
-
{error && <p className="text-error text-sm">{error}</p>}
|
|
332
|
-
</div>
|
|
333
|
-
</Modal>
|
|
334
|
-
)
|
|
335
|
-
}
|
|
336
|
-
}}
|
|
337
|
-
/>
|
|
338
|
-
```
|
|
339
|
-
|
|
340
106
|
### Card List
|
|
341
107
|
|
|
342
|
-
#### Props
|
|
343
|
-
|
|
344
|
-
| Props | Type | Required | Description |
|
|
345
|
-
| --- | --- | --- | --- |
|
|
346
|
-
| className | string | Optional | Gives an additional style class to the component's outer container. |
|
|
347
|
-
| translations | { [key: string]: string } | Optional | Translation object to customize all texts. Overrides default texts. |
|
|
348
|
-
| renderer | RendererProps | Optional | Renderer functions that can be used to customize all subcomponents. |
|
|
349
|
-
|
|
350
|
-
#### RendererProps
|
|
351
|
-
|
|
352
|
-
| Props | Type | Description |
|
|
353
|
-
| --- | --- | --- |
|
|
354
|
-
| Header | JSX.Element | Used to customize the title area at the top of the card list. |
|
|
355
|
-
| CardItem | (params: { card, selectedCard, onSelect, DeleteButton }) => JSX.Element | It allows you to fully customize the card element. |
|
|
356
|
-
| Loader | () => JSX.Element | Used to define a custom loader component to be displayed when loading cards. |
|
|
357
|
-
| ErrorFallback | (params: { error: string; onRetry: () => void }) => JSX.Element | Custom widget to be shown if an error occurs while loading cards. |
|
|
358
|
-
| SwitchPaymentButton | (props: { onClick: () => void; label: string }) => JSX.Element | Used to customize the "Pay with a new card" option. |
|
|
359
|
-
|
|
360
108
|
##### File Path: src/views/checkout/steps/payment/options/credit-card/index.tsx
|
|
361
109
|
|
|
362
|
-
### Usage Examples
|
|
363
|
-
|
|
364
|
-
##### Default Usage
|
|
365
|
-
|
|
366
110
|
```javascript
|
|
367
111
|
<PluginModule
|
|
368
112
|
component={Component.MasterpassCardList}
|
|
@@ -377,131 +121,10 @@ npx @akinon/projectzero@latest --plugins
|
|
|
377
121
|
/>
|
|
378
122
|
```
|
|
379
123
|
|
|
380
|
-
##### Customized Usage with Renderer
|
|
381
|
-
|
|
382
|
-
```javascript
|
|
383
|
-
<PluginModule
|
|
384
|
-
component={Component.MasterpassCardList}
|
|
385
|
-
props={{
|
|
386
|
-
className: 'px-10',
|
|
387
|
-
form: {
|
|
388
|
-
control,
|
|
389
|
-
register,
|
|
390
|
-
errors,
|
|
391
|
-
setFormValue,
|
|
392
|
-
clearErrors
|
|
393
|
-
},
|
|
394
|
-
renderer: {
|
|
395
|
-
Header: () => (
|
|
396
|
-
<div className="flex items-center gap-2 mt-4 px-10 text-success">
|
|
397
|
-
Select a card to pay
|
|
398
|
-
</div>
|
|
399
|
-
),
|
|
400
|
-
Loader: () => (
|
|
401
|
-
<div className="flex justify-center items-center p-10">
|
|
402
|
-
<span className="text-lg font-bold text-error">
|
|
403
|
-
Loading your cards...
|
|
404
|
-
</span>
|
|
405
|
-
</div>
|
|
406
|
-
),
|
|
407
|
-
ErrorFallback: ({ error, onRetry }) => (
|
|
408
|
-
<div className="text-center p-8">
|
|
409
|
-
<h2 className="text-red-500 text-xl mb-4">Oops! {error}</h2>
|
|
410
|
-
<Button onClick={onRetry}>Try Again</Button>
|
|
411
|
-
</div>
|
|
412
|
-
),
|
|
413
|
-
CardItem: ({ card, onSelect, DeleteButton, selectedCard }) => (
|
|
414
|
-
<li
|
|
415
|
-
key={card.UniqueId}
|
|
416
|
-
className="p-4 cursor-pointer rounded-[10px] border-gray border space-x-5 pl-5 mb-6 md:mb-2.5"
|
|
417
|
-
onClick={() => onSelect(card)}
|
|
418
|
-
>
|
|
419
|
-
<div className="flex justify-between items-center">
|
|
420
|
-
<div className="flex items-center">
|
|
421
|
-
<Checkbox
|
|
422
|
-
key={
|
|
423
|
-
selectedCard?.UniqueId === card.UniqueId
|
|
424
|
-
? 'selected'
|
|
425
|
-
: 'not-selected'
|
|
426
|
-
}
|
|
427
|
-
checked={selectedCard?.UniqueId === card.UniqueId}
|
|
428
|
-
onChange={() => onSelect(card)}
|
|
429
|
-
className="mr-2"
|
|
430
|
-
/>
|
|
431
|
-
<div>
|
|
432
|
-
<h3 className="font-semibold">{card.Name}</h3>
|
|
433
|
-
<p className="text-xs text-gray-500">{card.Value1}</p>
|
|
434
|
-
</div>
|
|
435
|
-
</div>
|
|
436
|
-
<DeleteButton
|
|
437
|
-
cardAliasName={card.Name}
|
|
438
|
-
content={<Icon name="close" size={12} />}
|
|
439
|
-
className="mb-8"
|
|
440
|
-
/>
|
|
441
|
-
</div>
|
|
442
|
-
</li>
|
|
443
|
-
),
|
|
444
|
-
SwitchPaymentButton: ({ onClick, label }) => (
|
|
445
|
-
<div className="px-10">
|
|
446
|
-
<button
|
|
447
|
-
onClick={onClick}
|
|
448
|
-
className="p-4 w-full text-left cursor-pointer rounded-[10px] border-gray border space-x-5 pl-5 mb-6 md:mb-2.5"
|
|
449
|
-
>
|
|
450
|
-
{label}
|
|
451
|
-
</button>
|
|
452
|
-
</div>
|
|
453
|
-
)
|
|
454
|
-
}
|
|
455
|
-
}}
|
|
456
|
-
/>
|
|
457
|
-
```
|
|
458
|
-
|
|
459
124
|
### Card Registration
|
|
460
125
|
|
|
461
|
-
#### Props
|
|
462
|
-
|
|
463
|
-
| Props | Type | Required | Description |
|
|
464
|
-
| --- | --- | --- | --- |
|
|
465
|
-
| getValues | () => Record<string, string> | Required | Returns the values of form fields. |
|
|
466
|
-
| className | string | Optional | Gives an additional CSS class to the outer container. |
|
|
467
|
-
| infoModalContent | React.ReactNode | Optional | Body content for the informational modal. |
|
|
468
|
-
| infoModalIcon | React.ReactNode | Optional | Used to override the notification icon. |
|
|
469
|
-
| translations | typeof defaultTranslations | Optional | Can be used to override default texts. |
|
|
470
|
-
| renderer | RendererProps | Optional | Renderer functions that can be used to customize all subcomponents. |
|
|
471
|
-
|
|
472
|
-
#### RendererProps
|
|
473
|
-
|
|
474
|
-
| Props | Type | Description |
|
|
475
|
-
| --- | --- | --- |
|
|
476
|
-
| Content | (props: { isChecked, toggle, setIsInfoModalOpen, onChange, onSubmit, loading, error, showGoBackLink?, onClickGoBackLink? }) => JSX.Element | Used to render the main content. |
|
|
477
|
-
| InfoModal | (props: { open: boolean; setOpen: (value: boolean) => void }) => JSX.Element | Can be used to override the notification modal. |
|
|
478
|
-
|
|
479
126
|
##### File Path: src/views/checkout/steps/payment/options/credit-card/index.tsx
|
|
480
127
|
|
|
481
|
-
### Usage Examples
|
|
482
|
-
|
|
483
|
-
##### Default Usage
|
|
484
|
-
|
|
485
|
-
```javascript
|
|
486
|
-
<PluginModule
|
|
487
|
-
component={Component.MasterpassCardRegistration}
|
|
488
|
-
props={{
|
|
489
|
-
// Do not remove getValues, it is used to get the form values
|
|
490
|
-
getValues,
|
|
491
|
-
translations: {
|
|
492
|
-
enter_card_name: 'Enter card name',
|
|
493
|
-
continue: 'Continue',
|
|
494
|
-
pay_with_my_masterpass_card: 'Pay with my Masterpass card',
|
|
495
|
-
terms_and_conditions: 'Masterpass terms and conditions',
|
|
496
|
-
card_registration_consent:
|
|
497
|
-
'I want to store my card information in the Mastercard infrastructure and use it again in my next purchase.'
|
|
498
|
-
}
|
|
499
|
-
}}
|
|
500
|
-
/>
|
|
501
|
-
```
|
|
502
|
-
|
|
503
|
-
##### Customized Usage with className, infoModalContent, infoModalIcon
|
|
504
|
-
|
|
505
128
|
```javascript
|
|
506
129
|
<PluginModule
|
|
507
130
|
component={Component.MasterpassCardRegistration}
|
|
@@ -522,86 +145,3 @@ npx @akinon/projectzero@latest --plugins
|
|
|
522
145
|
}}
|
|
523
146
|
/>
|
|
524
147
|
```
|
|
525
|
-
|
|
526
|
-
##### Customized Usage with Renderer
|
|
527
|
-
|
|
528
|
-
```javascript
|
|
529
|
-
<PluginModule
|
|
530
|
-
component={Component.MasterpassCardRegistration}
|
|
531
|
-
props={{
|
|
532
|
-
// Do not remove getValues, it is used to get the form values
|
|
533
|
-
getValues,
|
|
534
|
-
renderer: {
|
|
535
|
-
InfoModal: ({ open, setOpen }) => (
|
|
536
|
-
<Modal
|
|
537
|
-
open={open}
|
|
538
|
-
setOpen={setOpen}
|
|
539
|
-
portalId="masterpass-info-modal"
|
|
540
|
-
>
|
|
541
|
-
masterpass information
|
|
542
|
-
</Modal>
|
|
543
|
-
),
|
|
544
|
-
Content: ({
|
|
545
|
-
isChecked,
|
|
546
|
-
toggle,
|
|
547
|
-
setIsInfoModalOpen,
|
|
548
|
-
onChange,
|
|
549
|
-
onSubmit,
|
|
550
|
-
loading,
|
|
551
|
-
error,
|
|
552
|
-
showGoBackLink,
|
|
553
|
-
onClickGoBackLink
|
|
554
|
-
}) => (
|
|
555
|
-
<div className="bg-[#F8F8F8] mx-10 mb-5 px-2 py-1">
|
|
556
|
-
<div className="flex items-center gap-2 pb-4 mb-4">
|
|
557
|
-
<Checkbox checked={isChecked} onChange={toggle} />
|
|
558
|
-
<h1>Masterpass</h1>
|
|
559
|
-
<div>
|
|
560
|
-
<Icon
|
|
561
|
-
name="info"
|
|
562
|
-
size={15}
|
|
563
|
-
className="fill-[#000000] cursor-pointer"
|
|
564
|
-
onClick={() => {
|
|
565
|
-
setIsInfoModalOpen(true);
|
|
566
|
-
}}
|
|
567
|
-
/>
|
|
568
|
-
</div>
|
|
569
|
-
</div>
|
|
570
|
-
<p className="text-xs">
|
|
571
|
-
I want to store my card information in the Mastercard infrastructure and use it again in my next purchase.
|
|
572
|
-
</p>
|
|
573
|
-
{isChecked && (
|
|
574
|
-
<>
|
|
575
|
-
<Input
|
|
576
|
-
label="Give your card a name"
|
|
577
|
-
onChange={(e) =>
|
|
578
|
-
onChange((e.target as HTMLInputElement).value)
|
|
579
|
-
}
|
|
580
|
-
className="mt-2"
|
|
581
|
-
/>
|
|
582
|
-
<Button
|
|
583
|
-
onClick={onSubmit}
|
|
584
|
-
className="bg-green-600 text-black w-full mt-3"
|
|
585
|
-
>
|
|
586
|
-
{loading ? 'Loading...' : 'Save'}
|
|
587
|
-
</Button>
|
|
588
|
-
{error && (
|
|
589
|
-
<p className="text-xs text-red-600 mt-2">🚨 {error}</p>
|
|
590
|
-
)}
|
|
591
|
-
</>
|
|
592
|
-
)}
|
|
593
|
-
{showGoBackLink && (
|
|
594
|
-
<div>
|
|
595
|
-
<button
|
|
596
|
-
onClick={onClickGoBackLink}
|
|
597
|
-
className="text-xs text-red-600 underline mt-3"
|
|
598
|
-
>
|
|
599
|
-
I want to pay with my card registered to Masterpass.
|
|
600
|
-
</button>
|
|
601
|
-
</div>
|
|
602
|
-
)}
|
|
603
|
-
</div>
|
|
604
|
-
)
|
|
605
|
-
}
|
|
606
|
-
}}
|
|
607
|
-
```
|
package/package.json
CHANGED
|
@@ -3,20 +3,14 @@
|
|
|
3
3
|
import { useAppDispatch, useAppSelector } from '@akinon/next/redux/hooks';
|
|
4
4
|
import { Icon } from 'components';
|
|
5
5
|
import { useCallback, useEffect, useMemo, useState } from 'react';
|
|
6
|
-
import { twMerge } from 'tailwind-merge';
|
|
7
6
|
import {
|
|
8
7
|
setDeletionCardAliasName,
|
|
9
8
|
setDeletionModalVisible
|
|
10
9
|
} from '../redux/reducer';
|
|
10
|
+
import { CheckMasterpassResponse } from '../types';
|
|
11
11
|
import { formCreator } from '../utils';
|
|
12
12
|
import { useCards } from './use-cards';
|
|
13
13
|
|
|
14
|
-
export type DeleteButtonProps = {
|
|
15
|
-
cardAliasName: string;
|
|
16
|
-
content?: JSX.Element;
|
|
17
|
-
className?: string;
|
|
18
|
-
};
|
|
19
|
-
|
|
20
14
|
export const useDeleteCard = () => {
|
|
21
15
|
const { msisdn, token, language, deletion } = useAppSelector(
|
|
22
16
|
(state: any) => state.masterpass
|
|
@@ -73,27 +67,22 @@ export const useDeleteCard = () => {
|
|
|
73
67
|
|
|
74
68
|
const DeleteButton = useMemo(
|
|
75
69
|
() =>
|
|
76
|
-
({ cardAliasName
|
|
70
|
+
({ cardAliasName }: { cardAliasName: string }) => {
|
|
77
71
|
return (
|
|
78
72
|
<span
|
|
79
|
-
className=
|
|
73
|
+
className="cursor-pointer p-1"
|
|
80
74
|
onClick={(event: React.MouseEvent<HTMLElement>) => {
|
|
81
75
|
event.stopPropagation();
|
|
82
76
|
dispatch(setDeletionModalVisible(true));
|
|
83
77
|
dispatch(setDeletionCardAliasName(cardAliasName));
|
|
84
78
|
}}
|
|
85
79
|
>
|
|
86
|
-
|
|
80
|
+
<Icon name="close" size={12} />
|
|
87
81
|
</span>
|
|
88
82
|
);
|
|
89
83
|
},
|
|
90
84
|
[]
|
|
91
85
|
);
|
|
92
86
|
|
|
93
|
-
return {
|
|
94
|
-
DeleteButton,
|
|
95
|
-
deleteCard,
|
|
96
|
-
isLoading,
|
|
97
|
-
error
|
|
98
|
-
};
|
|
87
|
+
return { DeleteButton, deleteCard, isLoading, error };
|
|
99
88
|
};
|
|
@@ -48,30 +48,6 @@ const defaultTranslations = {
|
|
|
48
48
|
security_code_info: 'What’s CVC?'
|
|
49
49
|
};
|
|
50
50
|
|
|
51
|
-
interface RendererProps {
|
|
52
|
-
Header?: () => JSX.Element;
|
|
53
|
-
CardItem?: (params: {
|
|
54
|
-
card: any;
|
|
55
|
-
selectedCard: any;
|
|
56
|
-
onSelect: (card: any) => Promise<void>;
|
|
57
|
-
DeleteButton?: React.FC<{
|
|
58
|
-
cardAliasName: string;
|
|
59
|
-
onDelete: () => void;
|
|
60
|
-
className?: string;
|
|
61
|
-
content?: JSX.Element;
|
|
62
|
-
}>;
|
|
63
|
-
}) => JSX.Element;
|
|
64
|
-
Loader?: () => JSX.Element;
|
|
65
|
-
ErrorFallback?: (params: {
|
|
66
|
-
error: string;
|
|
67
|
-
onRetry: () => void;
|
|
68
|
-
}) => JSX.Element;
|
|
69
|
-
SwitchPaymentButton?: (props: {
|
|
70
|
-
onClick: () => void;
|
|
71
|
-
label: string;
|
|
72
|
-
}) => JSX.Element;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
51
|
export interface MasterpassCardListProps {
|
|
76
52
|
className?: string;
|
|
77
53
|
translations?: typeof defaultTranslations;
|
|
@@ -82,14 +58,12 @@ export interface MasterpassCardListProps {
|
|
|
82
58
|
register: UseFormRegister<any>;
|
|
83
59
|
setFormValue: UseFormSetValue<any>;
|
|
84
60
|
};
|
|
85
|
-
renderer?: RendererProps;
|
|
86
61
|
}
|
|
87
62
|
|
|
88
63
|
export const MasterpassCardList = ({
|
|
89
64
|
className,
|
|
90
65
|
translations,
|
|
91
|
-
form
|
|
92
|
-
renderer
|
|
66
|
+
form
|
|
93
67
|
}: MasterpassCardListProps) => {
|
|
94
68
|
const { preOrder } = useAppSelector((state) => state.checkout);
|
|
95
69
|
const { accountStatus, isDirectPurchase, selectedCard, cvcRequired } =
|
|
@@ -99,28 +73,7 @@ export const MasterpassCardList = ({
|
|
|
99
73
|
const { DeleteButton } = useDeleteCard();
|
|
100
74
|
const dispatch = useAppDispatch();
|
|
101
75
|
|
|
102
|
-
const
|
|
103
|
-
if (selectedCard?.UniqueId !== card.UniqueId) {
|
|
104
|
-
await setMasterpassBinNumber(card.Value1.substring(0, 6)).unwrap();
|
|
105
|
-
dispatch(setSelectedCard(card));
|
|
106
|
-
dispatch(setCvcRequired(false));
|
|
107
|
-
if (form) {
|
|
108
|
-
form.setFormValue('card_cvv', '');
|
|
109
|
-
form.clearErrors('card_cvv');
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
};
|
|
113
|
-
|
|
114
|
-
const switchPaymentButton = renderer?.SwitchPaymentButton ? (
|
|
115
|
-
renderer.SwitchPaymentButton({
|
|
116
|
-
onClick: () => {
|
|
117
|
-
dispatch(setIsDirectPurchase(true));
|
|
118
|
-
dispatch(setInstallmentOptions([]));
|
|
119
|
-
},
|
|
120
|
-
label:
|
|
121
|
-
translations?.pay_with_new_card ?? defaultTranslations.pay_with_new_card
|
|
122
|
-
})
|
|
123
|
-
) : (
|
|
76
|
+
const switchPaymentButton = (
|
|
124
77
|
<a
|
|
125
78
|
href="#"
|
|
126
79
|
className="text-xs underline"
|
|
@@ -139,9 +92,7 @@ export const MasterpassCardList = ({
|
|
|
139
92
|
}
|
|
140
93
|
|
|
141
94
|
if (loading) {
|
|
142
|
-
return
|
|
143
|
-
renderer.Loader()
|
|
144
|
-
) : (
|
|
95
|
+
return (
|
|
145
96
|
<div className="p-5">
|
|
146
97
|
<LoaderSpinner className="w-8 h-8" />
|
|
147
98
|
</div>
|
|
@@ -149,14 +100,18 @@ export const MasterpassCardList = ({
|
|
|
149
100
|
}
|
|
150
101
|
|
|
151
102
|
if (error && !isDirectPurchase) {
|
|
152
|
-
return
|
|
153
|
-
renderer.ErrorFallback({ error, onRetry: refreshCards })
|
|
154
|
-
) : (
|
|
103
|
+
return (
|
|
155
104
|
<div className="flex flex-col items-center">
|
|
156
105
|
<div className="p-5">{error}</div>
|
|
157
|
-
<Button
|
|
106
|
+
<Button
|
|
107
|
+
className="w-48 mb-5"
|
|
108
|
+
onClick={() => {
|
|
109
|
+
refreshCards();
|
|
110
|
+
}}
|
|
111
|
+
>
|
|
158
112
|
{translations?.retryFetchCards ?? defaultTranslations.retryFetchCards}
|
|
159
113
|
</Button>
|
|
114
|
+
|
|
160
115
|
{switchPaymentButton}
|
|
161
116
|
</div>
|
|
162
117
|
);
|
|
@@ -171,75 +126,38 @@ export const MasterpassCardList = ({
|
|
|
171
126
|
}
|
|
172
127
|
|
|
173
128
|
return (
|
|
174
|
-
<div className=
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
<p className="text-xs">
|
|
187
|
-
{translations?.title ?? defaultTranslations.title}
|
|
188
|
-
</p>
|
|
189
|
-
</>
|
|
190
|
-
)}
|
|
191
|
-
|
|
192
|
-
<ul className={twMerge('mt-4 text-xs', className)}>
|
|
129
|
+
<div className={twMerge('w-full', className)}>
|
|
130
|
+
<Image
|
|
131
|
+
className="mb-4"
|
|
132
|
+
width={140}
|
|
133
|
+
height={25}
|
|
134
|
+
src={masterpassLogo.src}
|
|
135
|
+
alt="Masterpass Logo"
|
|
136
|
+
/>
|
|
137
|
+
<p className="text-xs">
|
|
138
|
+
{translations?.title ?? defaultTranslations.title}
|
|
139
|
+
</p>
|
|
140
|
+
<ul className="mt-4 text-xs">
|
|
193
141
|
{cards?.map((card) => {
|
|
194
|
-
|
|
195
|
-
selectedCard?.UniqueId === card.UniqueId && form && cvcRequired ? (
|
|
196
|
-
<div
|
|
197
|
-
className={twMerge(
|
|
198
|
-
clsx('flex items-center justify-start mt-2', {
|
|
199
|
-
'items-baseline': form.errors.card_cvv
|
|
200
|
-
})
|
|
201
|
-
)}
|
|
202
|
-
>
|
|
203
|
-
<label
|
|
204
|
-
className="text-xs text-black-400 mr-1.5"
|
|
205
|
-
htmlFor="card_cvv"
|
|
206
|
-
>
|
|
207
|
-
{translations?.security_code ??
|
|
208
|
-
defaultTranslations.security_code}
|
|
209
|
-
</label>
|
|
210
|
-
<Input
|
|
211
|
-
format="###"
|
|
212
|
-
mask="_"
|
|
213
|
-
control={form.control}
|
|
214
|
-
allowEmptyFormatting={true}
|
|
215
|
-
{...form.register('card_cvv')}
|
|
216
|
-
error={form.errors.card_cvv}
|
|
217
|
-
/>
|
|
218
|
-
<div className="group relative flex items-center justify-start text-gray-600 cursor-pointer ml-2 transition-all hover:text-secondary">
|
|
219
|
-
<span className="text-xs underline">
|
|
220
|
-
{translations?.security_code_info ??
|
|
221
|
-
defaultTranslations.security_code_info}
|
|
222
|
-
</span>
|
|
223
|
-
<Icon name="cvc" size={16} className="leading-none ml-2" />
|
|
224
|
-
<div className="hidden group-hover:block absolute right-0 bottom-5 w-[11rem] lg:w-[21rem] lg:left-auto lg:right-auto border-2">
|
|
225
|
-
<Image src="/cvv.jpg" alt="Cvv" width={385} height={262} />
|
|
226
|
-
</div>
|
|
227
|
-
</div>
|
|
228
|
-
</div>
|
|
229
|
-
) : null;
|
|
230
|
-
|
|
231
|
-
return renderer?.CardItem ? (
|
|
232
|
-
renderer.CardItem({
|
|
233
|
-
card,
|
|
234
|
-
selectedCard,
|
|
235
|
-
onSelect: onSelectCard,
|
|
236
|
-
DeleteButton
|
|
237
|
-
})
|
|
238
|
-
) : (
|
|
142
|
+
return (
|
|
239
143
|
<li
|
|
240
144
|
key={card.UniqueId}
|
|
241
145
|
className="p-4 mb-2 border-2 border-gray-200 flex flex-col space-x-2 cursor-pointer"
|
|
242
|
-
onClick={() =>
|
|
146
|
+
onClick={async () => {
|
|
147
|
+
if (selectedCard?.UniqueId !== card.UniqueId) {
|
|
148
|
+
await setMasterpassBinNumber(
|
|
149
|
+
card.Value1.substring(0, 6)
|
|
150
|
+
).unwrap();
|
|
151
|
+
|
|
152
|
+
dispatch(setSelectedCard(card));
|
|
153
|
+
dispatch(setCvcRequired(false));
|
|
154
|
+
|
|
155
|
+
if (form) {
|
|
156
|
+
form.setFormValue('card_cvv', '');
|
|
157
|
+
form.clearErrors('card_cvv');
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}}
|
|
243
161
|
>
|
|
244
162
|
<div className="flex justify-between items-center">
|
|
245
163
|
<input
|
|
@@ -251,14 +169,12 @@ export const MasterpassCardList = ({
|
|
|
251
169
|
className="mr-2"
|
|
252
170
|
onChange={(e) => e.preventDefault()}
|
|
253
171
|
/>
|
|
254
|
-
|
|
255
172
|
<label
|
|
256
173
|
htmlFor={card.UniqueId}
|
|
257
174
|
className="flex flex-col w-full cursor-pointer md:flex-row md:items-center md:justify-between"
|
|
258
175
|
>
|
|
259
176
|
<p className="w-full lg:w-1/3">{card.Name}</p>
|
|
260
177
|
<p className="w-full text-[10px] lg:w-1/3">{card.Value1}</p>
|
|
261
|
-
|
|
262
178
|
<Image
|
|
263
179
|
className="w-8 h-6 object-contain flex items-center justify-center mr-4"
|
|
264
180
|
width={50}
|
|
@@ -270,7 +186,46 @@ export const MasterpassCardList = ({
|
|
|
270
186
|
|
|
271
187
|
<DeleteButton cardAliasName={card.Name} />
|
|
272
188
|
</div>
|
|
273
|
-
{
|
|
189
|
+
{selectedCard?.UniqueId === card.UniqueId && form && cvcRequired && (
|
|
190
|
+
<div
|
|
191
|
+
className={twMerge(
|
|
192
|
+
clsx('flex items-center justify-start mt-2', {
|
|
193
|
+
'items-baseline': form.errors.card_cvv
|
|
194
|
+
})
|
|
195
|
+
)}
|
|
196
|
+
>
|
|
197
|
+
<label
|
|
198
|
+
className="text-xs text-black-400 mr-1.5"
|
|
199
|
+
htmlFor="card_cvv"
|
|
200
|
+
>
|
|
201
|
+
{translations?.security_code ??
|
|
202
|
+
defaultTranslations.security_code}
|
|
203
|
+
</label>
|
|
204
|
+
<Input
|
|
205
|
+
format="###"
|
|
206
|
+
mask="_"
|
|
207
|
+
control={form.control}
|
|
208
|
+
allowEmptyFormatting={true}
|
|
209
|
+
{...form.register('card_cvv')}
|
|
210
|
+
error={form.errors.card_cvv}
|
|
211
|
+
/>
|
|
212
|
+
<div className="group relative flex items-center justify-start text-gray-600 cursor-pointer ml-2 transition-all hover:text-secondary">
|
|
213
|
+
<span className="text-xs underline">
|
|
214
|
+
{translations?.security_code_info ??
|
|
215
|
+
defaultTranslations.security_code_info}
|
|
216
|
+
</span>
|
|
217
|
+
<Icon name="cvc" size={16} className="leading-none ml-2" />
|
|
218
|
+
<div className="hidden group-hover:block absolute right-0 bottom-5 w-[11rem] lg:w-[21rem] lg:left-auto lg:right-auto border-2">
|
|
219
|
+
<Image
|
|
220
|
+
src="/cvv.jpg"
|
|
221
|
+
alt="Cvv"
|
|
222
|
+
width={385}
|
|
223
|
+
height={262}
|
|
224
|
+
/>
|
|
225
|
+
</div>
|
|
226
|
+
</div>
|
|
227
|
+
</div>
|
|
228
|
+
)}
|
|
274
229
|
</li>
|
|
275
230
|
);
|
|
276
231
|
})}
|
|
@@ -32,31 +32,13 @@ export const MasterpassCardRegistration = ({
|
|
|
32
32
|
className,
|
|
33
33
|
infoModalContent,
|
|
34
34
|
infoModalIcon,
|
|
35
|
-
translations
|
|
36
|
-
renderer = {}
|
|
35
|
+
translations
|
|
37
36
|
}: {
|
|
38
37
|
getValues: () => Record<string, string | number | boolean>;
|
|
39
38
|
className?: string;
|
|
40
39
|
infoModalContent?: React.ReactNode;
|
|
41
40
|
infoModalIcon?: React.ReactNode;
|
|
42
41
|
translations?: typeof defaultTranslations;
|
|
43
|
-
renderer?: {
|
|
44
|
-
Content?: (props: {
|
|
45
|
-
isChecked: boolean;
|
|
46
|
-
toggle: () => void;
|
|
47
|
-
setIsInfoModalOpen: (value: boolean) => void;
|
|
48
|
-
onChange: (value: string) => void;
|
|
49
|
-
onSubmit: () => void;
|
|
50
|
-
loading: boolean;
|
|
51
|
-
error: string | null;
|
|
52
|
-
showGoBackLink?: boolean;
|
|
53
|
-
onClickGoBackLink?: () => void;
|
|
54
|
-
}) => JSX.Element;
|
|
55
|
-
InfoModal?: (props: {
|
|
56
|
-
open: boolean;
|
|
57
|
-
setOpen: (value: boolean) => void;
|
|
58
|
-
}) => JSX.Element;
|
|
59
|
-
};
|
|
60
42
|
}) => {
|
|
61
43
|
const { preOrder } = useAppSelector((state: RootState) => state.checkout);
|
|
62
44
|
const { msisdn, token, language, otp, isDirectPurchase, accountStatus } =
|
|
@@ -186,56 +168,13 @@ export const MasterpassCardRegistration = ({
|
|
|
186
168
|
return null;
|
|
187
169
|
}
|
|
188
170
|
|
|
189
|
-
if (renderer.Content) {
|
|
190
|
-
return (
|
|
191
|
-
<>
|
|
192
|
-
{renderer.InfoModal ? (
|
|
193
|
-
<renderer.InfoModal
|
|
194
|
-
open={isInfoModalOpen}
|
|
195
|
-
setOpen={setIsInfoModalOpen}
|
|
196
|
-
/>
|
|
197
|
-
) : (
|
|
198
|
-
<InfoModal
|
|
199
|
-
open={isInfoModalOpen}
|
|
200
|
-
setOpen={setIsInfoModalOpen}
|
|
201
|
-
content={infoModalContent}
|
|
202
|
-
/>
|
|
203
|
-
)}
|
|
204
|
-
|
|
205
|
-
<renderer.Content
|
|
206
|
-
isChecked={isAgreementChecked}
|
|
207
|
-
toggle={() => setIsAgreementChecked(!isAgreementChecked)}
|
|
208
|
-
setIsInfoModalOpen={setIsInfoModalOpen}
|
|
209
|
-
onChange={(value) => setAccountAliasName(value)}
|
|
210
|
-
onSubmit={registerCard}
|
|
211
|
-
loading={isBusy}
|
|
212
|
-
error={formError}
|
|
213
|
-
showGoBackLink={
|
|
214
|
-
accountStatus !== MasterpassStatus.NoAccount && cards?.length > 0
|
|
215
|
-
}
|
|
216
|
-
onClickGoBackLink={() => {
|
|
217
|
-
dispatch(setIsDirectPurchase(false));
|
|
218
|
-
dispatch(setInstallmentOptions([]));
|
|
219
|
-
}}
|
|
220
|
-
/>
|
|
221
|
-
</>
|
|
222
|
-
);
|
|
223
|
-
}
|
|
224
|
-
|
|
225
171
|
return (
|
|
226
172
|
<div className={twMerge('w-full', className)}>
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
) : (
|
|
233
|
-
<InfoModal
|
|
234
|
-
open={isInfoModalOpen}
|
|
235
|
-
setOpen={setIsInfoModalOpen}
|
|
236
|
-
content={infoModalContent}
|
|
237
|
-
/>
|
|
238
|
-
)}
|
|
173
|
+
<InfoModal
|
|
174
|
+
open={isInfoModalOpen}
|
|
175
|
+
setOpen={setIsInfoModalOpen}
|
|
176
|
+
content={infoModalContent}
|
|
177
|
+
/>
|
|
239
178
|
|
|
240
179
|
<div className="border border-[#ddd]">
|
|
241
180
|
<div className="p-4">
|
|
@@ -15,39 +15,15 @@ const defaultTranslations = {
|
|
|
15
15
|
|
|
16
16
|
export interface MasterpassDeleteConfirmationModalProps {
|
|
17
17
|
translations?: typeof defaultTranslations;
|
|
18
|
-
renderer?: {
|
|
19
|
-
Content?: (props: {
|
|
20
|
-
open: boolean;
|
|
21
|
-
setOpen: (open: boolean) => void;
|
|
22
|
-
onConfirm: () => void;
|
|
23
|
-
onCancel: () => void;
|
|
24
|
-
loading: boolean;
|
|
25
|
-
error: string | null;
|
|
26
|
-
}) => JSX.Element;
|
|
27
|
-
};
|
|
28
18
|
}
|
|
29
19
|
|
|
30
20
|
export const MasterpassDeleteConfirmationModal = ({
|
|
31
|
-
translations
|
|
32
|
-
renderer = {}
|
|
21
|
+
translations
|
|
33
22
|
}: MasterpassDeleteConfirmationModalProps) => {
|
|
34
23
|
const { deletion } = useAppSelector((state) => state.masterpass);
|
|
35
24
|
const { deleteCard, isLoading, error } = useDeleteCard();
|
|
36
25
|
const dispatch = useAppDispatch();
|
|
37
26
|
|
|
38
|
-
if (renderer.Content) {
|
|
39
|
-
return (
|
|
40
|
-
<renderer.Content
|
|
41
|
-
open={deletion.isModalVisible}
|
|
42
|
-
setOpen={() => dispatch(setDeletionModalVisible(false))}
|
|
43
|
-
onConfirm={deleteCard}
|
|
44
|
-
onCancel={() => dispatch(setDeletionModalVisible(false))}
|
|
45
|
-
loading={isLoading}
|
|
46
|
-
error={error}
|
|
47
|
-
/>
|
|
48
|
-
);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
27
|
return (
|
|
52
28
|
<Modal
|
|
53
29
|
portalId="masterpass-remove-card-modal"
|
|
@@ -21,20 +21,10 @@ const defaultTranslations = {
|
|
|
21
21
|
|
|
22
22
|
export interface MasterpassLinkModalProps {
|
|
23
23
|
translations?: typeof defaultTranslations;
|
|
24
|
-
renderer?: {
|
|
25
|
-
Content?: (props: {
|
|
26
|
-
open: boolean;
|
|
27
|
-
setOpen: (open: boolean) => void;
|
|
28
|
-
onClick: () => void;
|
|
29
|
-
loading: boolean;
|
|
30
|
-
error: string | null;
|
|
31
|
-
}) => JSX.Element;
|
|
32
|
-
};
|
|
33
24
|
}
|
|
34
25
|
|
|
35
26
|
export const MasterpassLinkModal = ({
|
|
36
|
-
translations
|
|
37
|
-
renderer = {}
|
|
27
|
+
translations
|
|
38
28
|
}: MasterpassLinkModalProps) => {
|
|
39
29
|
const { msisdn, token, accountStatus, otp, language } = useAppSelector(
|
|
40
30
|
(state) => state.masterpass
|
|
@@ -103,18 +93,6 @@ export const MasterpassLinkModal = ({
|
|
|
103
93
|
}
|
|
104
94
|
}, [otp.response]);
|
|
105
95
|
|
|
106
|
-
if (renderer.Content) {
|
|
107
|
-
return (
|
|
108
|
-
<renderer.Content
|
|
109
|
-
open={isOpen}
|
|
110
|
-
setOpen={setIsOpen}
|
|
111
|
-
onClick={onLinkButtonClick}
|
|
112
|
-
loading={isLoading}
|
|
113
|
-
error={error}
|
|
114
|
-
/>
|
|
115
|
-
);
|
|
116
|
-
}
|
|
117
|
-
|
|
118
96
|
return (
|
|
119
97
|
<Modal
|
|
120
98
|
portalId="masterpass-check-user"
|
|
@@ -12,32 +12,15 @@ import { OtpForm, OtpFormProps, defaultTranslations } from './otp-form';
|
|
|
12
12
|
import { useAppDispatch, useAppSelector } from '@akinon/next/redux/hooks';
|
|
13
13
|
import { setOtpModalVisible, setOtpResponse } from '../../redux/reducer';
|
|
14
14
|
import { Image } from '@akinon/next/components/image';
|
|
15
|
-
import { useCountdown } from '../../hooks/use-countdown';
|
|
16
15
|
|
|
17
16
|
export interface MasterpassOtpModalProps {
|
|
18
17
|
translations?: {
|
|
19
18
|
5001?: string;
|
|
20
19
|
} & OtpFormProps['translations'];
|
|
21
|
-
renderer?: {
|
|
22
|
-
Content?: (props: {
|
|
23
|
-
open: boolean;
|
|
24
|
-
setOpen: (open: boolean) => void;
|
|
25
|
-
onSubmit: (data: { otp_code: string }) => void;
|
|
26
|
-
loading: boolean;
|
|
27
|
-
error: string | null;
|
|
28
|
-
resendSms: () => void;
|
|
29
|
-
resendSmsFetching: boolean;
|
|
30
|
-
targetDate: number;
|
|
31
|
-
otpRef: string | null;
|
|
32
|
-
minutes?: number;
|
|
33
|
-
seconds?: number;
|
|
34
|
-
}) => JSX.Element;
|
|
35
|
-
};
|
|
36
20
|
}
|
|
37
21
|
|
|
38
22
|
export const MasterpassOtpModal = ({
|
|
39
|
-
translations
|
|
40
|
-
renderer = {}
|
|
23
|
+
translations
|
|
41
24
|
}: MasterpassOtpModalProps) => {
|
|
42
25
|
const { token, otp, language } = useAppSelector((state) => state.masterpass);
|
|
43
26
|
const [isModalOpen, setIsModalOpen] = useState(false);
|
|
@@ -128,26 +111,6 @@ export const MasterpassOtpModal = ({
|
|
|
128
111
|
}
|
|
129
112
|
}, [isModalOpen]);
|
|
130
113
|
|
|
131
|
-
if (renderer.Content) {
|
|
132
|
-
const [minutes, seconds] = useCountdown(new Date(otpTime));
|
|
133
|
-
|
|
134
|
-
return (
|
|
135
|
-
<renderer.Content
|
|
136
|
-
open={isModalOpen}
|
|
137
|
-
setOpen={handleModalVisibility}
|
|
138
|
-
onSubmit={onFormSubmit}
|
|
139
|
-
loading={isBusy}
|
|
140
|
-
error={otpError}
|
|
141
|
-
resendSms={resendSms}
|
|
142
|
-
resendSmsFetching={isBusy}
|
|
143
|
-
targetDate={otpTime}
|
|
144
|
-
otpRef={otpRef}
|
|
145
|
-
minutes={minutes}
|
|
146
|
-
seconds={seconds}
|
|
147
|
-
/>
|
|
148
|
-
);
|
|
149
|
-
}
|
|
150
|
-
|
|
151
114
|
return (
|
|
152
115
|
<Modal
|
|
153
116
|
portalId="otp-masterpass"
|