@@ -10,19 +10,18 @@ import {
10
10
type PaymentMethod ,
11
11
type PaymentRequestOptions ,
12
12
} from '@bigcommerce/checkout-sdk' ;
13
- import classNames from 'classnames' ;
14
13
import { find , noop } from 'lodash' ;
15
14
import React , {
16
15
type ReactElement ,
17
16
type ReactNode ,
18
17
useCallback ,
19
18
useEffect ,
19
+ useMemo ,
20
20
useRef ,
21
21
useState ,
22
22
} from 'react' ;
23
23
import { type ObjectSchema } from 'yup' ;
24
24
25
- import { preventDefault } from '@bigcommerce/checkout/dom-utils' ;
26
25
import {
27
26
AccountInstrumentFieldset ,
28
27
assertIsCardInstrument ,
@@ -31,10 +30,13 @@ import {
31
30
isCardInstrument ,
32
31
StoreInstrumentFieldset ,
33
32
} from '@bigcommerce/checkout/instrument-utils' ;
34
- import { TranslatedString } from '@bigcommerce/checkout/locale' ;
35
33
import { type PaymentFormValues } from '@bigcommerce/checkout/payment-integration-api' ;
36
34
import { LoadingOverlay } from '@bigcommerce/checkout/ui' ;
37
35
36
+ import { EditButton } from './EditButton' ;
37
+ import { PaymentDescriptor } from './PaymentDescriptor' ;
38
+ import { PaymentWidget } from './PaymentWidget' ;
39
+
38
40
export interface PaymentContextProps {
39
41
disableSubmit ( method : PaymentMethod , disabled ?: boolean ) : void ;
40
42
setSubmit ( method : PaymentMethod , fn : ( ( values : PaymentFormValues ) => void ) | null ) : void ;
@@ -175,33 +177,39 @@ const HostedWidgetPaymentComponent = ({
175
177
storedCardValidationSchema ,
176
178
] ) ;
177
179
178
- const getSelectedBankAccountInstrument = (
179
- addingNew : boolean ,
180
- currentSelectedInstrument : PaymentInstrument ,
181
- ) : AccountInstrument | undefined => {
182
- return ! addingNew && isBankAccountInstrument ( currentSelectedInstrument )
183
- ? currentSelectedInstrument
184
- : undefined ;
185
- } ;
180
+ const getSelectedBankAccountInstrument = useCallback (
181
+ (
182
+ addingNew : boolean ,
183
+ currentSelectedInstrument : PaymentInstrument ,
184
+ ) : AccountInstrument | undefined => {
185
+ return ! addingNew && isBankAccountInstrument ( currentSelectedInstrument )
186
+ ? currentSelectedInstrument
187
+ : undefined ;
188
+ } ,
189
+ [ ] ,
190
+ ) ;
186
191
187
- const handleDeleteInstrument = ( id : string ) : void => {
188
- if ( instruments . length === 0 ) {
189
- setIsAddingNewCard ( true ) ;
190
- setSelectedInstrumentId ( undefined ) ;
191
- setFieldValue ( 'instrumentId' , '' ) ;
192
+ const handleDeleteInstrument = useCallback (
193
+ ( id : string ) : void => {
194
+ if ( instruments . length === 0 ) {
195
+ setIsAddingNewCard ( true ) ;
196
+ setSelectedInstrumentId ( undefined ) ;
197
+ setFieldValue ( 'instrumentId' , '' ) ;
192
198
193
- return ;
194
- }
199
+ return ;
200
+ }
195
201
196
- if ( selectedInstrumentId === id ) {
197
- const nextId = getDefaultInstrumentId ( ) ;
202
+ if ( selectedInstrumentId === id ) {
203
+ const nextId = getDefaultInstrumentId ( ) ;
198
204
199
- setSelectedInstrumentId ( nextId ) ;
200
- setFieldValue ( 'instrumentId' , nextId ) ;
201
- }
202
- } ;
205
+ setSelectedInstrumentId ( nextId ) ;
206
+ setFieldValue ( 'instrumentId' , nextId ) ;
207
+ }
208
+ } ,
209
+ [ instruments , selectedInstrumentId , getDefaultInstrumentId ] ,
210
+ ) ;
203
211
204
- const handleUseNewCard = async ( ) => {
212
+ const handleUseNewCard = useCallback ( async ( ) => {
205
213
setIsAddingNewCard ( true ) ;
206
214
setSelectedInstrumentId ( undefined ) ;
207
215
@@ -218,14 +226,14 @@ const HostedWidgetPaymentComponent = ({
218
226
methodId : method . id ,
219
227
} ) ;
220
228
}
221
- } ;
229
+ } , [ method , deinitializePayment , initializePayment ] ) ;
222
230
223
- const handleSelectInstrument = ( id : string ) => {
231
+ const handleSelectInstrument = useCallback ( ( id : string ) => {
224
232
setIsAddingNewCard ( false ) ;
225
233
setSelectedInstrumentId ( id ) ;
226
- } ;
234
+ } , [ ] ) ;
227
235
228
- const getValidateInstrument = ( ) : ReactNode | undefined => {
236
+ const getValidateInstrument = useCallback ( ( ) : ReactNode | undefined => {
229
237
const currentSelectedId = selectedInstrumentId || getDefaultInstrumentId ( ) ;
230
238
const currentSelectedInstrument = find ( instruments , { bigpayToken : currentSelectedId } ) ;
231
239
@@ -247,7 +255,14 @@ const HostedWidgetPaymentComponent = ({
247
255
}
248
256
249
257
return undefined ;
250
- } ;
258
+ } , [
259
+ selectedInstrumentId ,
260
+ getDefaultInstrumentId ,
261
+ instruments ,
262
+ method ,
263
+ hideVerificationFields ,
264
+ validateInstrument ,
265
+ ] ) ;
251
266
252
267
const initializeMethod = async ( ) : Promise < CheckoutSelectors | void > => {
253
268
if ( ! isPaymentDataRequired ) {
@@ -291,23 +306,49 @@ const HostedWidgetPaymentComponent = ({
291
306
} ;
292
307
293
308
// Below values are for lower level components
294
- const effectiveSelectedInstrumentId = selectedInstrumentId || getDefaultInstrumentId ( ) ;
295
- const selectedInstrument = effectiveSelectedInstrumentId
296
- ? instruments . find ( ( i ) => i . bigpayToken === effectiveSelectedInstrumentId ) || instruments [ 0 ]
297
- : instruments [ 0 ] ;
298
- const cardInstruments : CardInstrument [ ] = instruments . filter (
299
- ( i ) : i is CardInstrument => ! isBankAccountInstrument ( i ) ,
309
+ const effectiveSelectedInstrumentId = useMemo (
310
+ ( ) => selectedInstrumentId || getDefaultInstrumentId ( ) ,
311
+ [ selectedInstrumentId , getDefaultInstrumentId ] ,
312
+ ) ;
313
+ const selectedInstrument = useMemo (
314
+ ( ) =>
315
+ effectiveSelectedInstrumentId
316
+ ? instruments . find ( ( i ) => i . bigpayToken === effectiveSelectedInstrumentId ) ||
317
+ instruments [ 0 ]
318
+ : instruments [ 0 ] ,
319
+ [ instruments , effectiveSelectedInstrumentId ] ,
320
+ ) ;
321
+ const cardInstruments : CardInstrument [ ] = useMemo (
322
+ ( ) => instruments . filter ( ( i ) : i is CardInstrument => ! isBankAccountInstrument ( i ) ) ,
323
+ [ instruments ] ,
324
+ ) ;
325
+ const accountInstruments : AccountInstrument [ ] = useMemo (
326
+ ( ) => instruments . filter ( ( i ) : i is AccountInstrument => isBankAccountInstrument ( i ) ) ,
327
+ [ instruments ] ,
300
328
) ;
301
- const accountInstruments : AccountInstrument [ ] = instruments . filter (
302
- ( i ) : i is AccountInstrument => isBankAccountInstrument ( i ) ,
329
+ const shouldShowInstrumentFieldset = useMemo (
330
+ ( ) => isInstrumentFeatureAvailableProp && instruments . length > 0 ,
331
+ [ isInstrumentFeatureAvailableProp , instruments ] ,
332
+ ) ;
333
+ const shouldShowCreditCardFieldset = useMemo (
334
+ ( ) => ! shouldShowInstrumentFieldset || isAddingNewCard ,
335
+ [ shouldShowInstrumentFieldset , isAddingNewCard ] ,
336
+ ) ;
337
+ const isLoading = useMemo (
338
+ ( ) => ( isInitializing || isLoadingInstruments ) && ! hideWidget ,
339
+ [ isInitializing , isLoadingInstruments , hideWidget ] ,
340
+ ) ;
341
+ const selectedAccountInstrument = useMemo (
342
+ ( ) =>
343
+ selectedInstrument
344
+ ? getSelectedBankAccountInstrument ( isAddingNewCard , selectedInstrument )
345
+ : undefined ,
346
+ [ selectedInstrument , isAddingNewCard ] ,
347
+ ) ;
348
+ const shouldShowAccountInstrument = useMemo (
349
+ ( ) => instruments [ 0 ] && isBankAccountInstrument ( instruments [ 0 ] ) ,
350
+ [ instruments ] ,
303
351
) ;
304
- const shouldShowInstrumentFieldset = isInstrumentFeatureAvailableProp && instruments . length > 0 ;
305
- const shouldShowCreditCardFieldset = ! shouldShowInstrumentFieldset || isAddingNewCard ;
306
- const isLoading = ( isInitializing || isLoadingInstruments ) && ! hideWidget ;
307
- const selectedAccountInstrument = selectedInstrument
308
- ? getSelectedBankAccountInstrument ( isAddingNewCard , selectedInstrument )
309
- : undefined ;
310
- const shouldShowAccountInstrument = instruments [ 0 ] && isBankAccountInstrument ( instruments [ 0 ] ) ;
311
352
312
353
useEffect ( ( ) => {
313
354
const init = async ( ) => {
@@ -399,58 +440,6 @@ const HostedWidgetPaymentComponent = ({
399
440
}
400
441
} , [ selectedInstrumentId , instruments , isPaymentDataRequired ] ) ;
401
442
402
- const PaymentDescriptor = ( ) : ReactNode => {
403
- if ( shouldShowDescriptor && paymentDescriptor ) {
404
- return < div className = "payment-descriptor" > { paymentDescriptor } </ div > ;
405
- }
406
-
407
- return null ;
408
- } ;
409
-
410
- const PaymentWidget = ( ) : ReactElement => (
411
- < div
412
- className = { classNames (
413
- 'widget' ,
414
- `widget--${ method . id } ` ,
415
- 'payment-widget' ,
416
- shouldRenderCustomInstrument ? '' : additionalContainerClassName ,
417
- ) }
418
- id = { containerId }
419
- style = { {
420
- display :
421
- ( hideContentWhenSignedOut && isSignInRequired && ! isSignedIn ) ||
422
- ! shouldShowCreditCardFieldset ||
423
- hideWidget
424
- ? 'none'
425
- : undefined ,
426
- } }
427
- tabIndex = { - 1 }
428
- >
429
- { shouldRenderCustomInstrument && renderCustomPaymentForm && renderCustomPaymentForm ( ) }
430
- </ div >
431
- ) ;
432
-
433
- const EditButton = ( ) : ReactNode => {
434
- if ( shouldShowEditButton ) {
435
- const translatedString = < TranslatedString id = "remote.select_different_card_action" /> ;
436
-
437
- return (
438
- < p >
439
- < button
440
- className = { classNames ( 'stepHeader' , 'widget-link-amazonpay' ) }
441
- id = { buttonId }
442
- onClick = { preventDefault ( ) }
443
- type = "button"
444
- >
445
- { translatedString }
446
- </ button >
447
- </ p >
448
- ) ;
449
- }
450
-
451
- return null ;
452
- } ;
453
-
454
443
if ( ! shouldShow ) {
455
444
return < div style = { { display : 'none' } } /> ;
456
445
}
@@ -478,9 +467,23 @@ const HostedWidgetPaymentComponent = ({
478
467
/>
479
468
) }
480
469
481
- < PaymentDescriptor />
482
-
483
- < PaymentWidget />
470
+ < PaymentDescriptor
471
+ paymentDescriptor = { paymentDescriptor }
472
+ shouldShowDescriptor = { shouldShowDescriptor }
473
+ />
474
+
475
+ < PaymentWidget
476
+ additionalContainerClassName = { additionalContainerClassName }
477
+ containerId = { containerId }
478
+ hideContentWhenSignedOut = { hideContentWhenSignedOut }
479
+ hideWidget = { hideWidget }
480
+ isSignInRequired = { isSignInRequired }
481
+ isSignedIn = { isSignedIn }
482
+ method = { method }
483
+ renderCustomPaymentForm = { renderCustomPaymentForm }
484
+ shouldRenderCustomInstrument = { shouldRenderCustomInstrument }
485
+ shouldShowCreditCardFieldset = { shouldShowCreditCardFieldset }
486
+ />
484
487
485
488
{ isInstrumentFeatureAvailableProp && (
486
489
< StoreInstrumentFieldset
@@ -492,7 +495,7 @@ const HostedWidgetPaymentComponent = ({
492
495
/>
493
496
) }
494
497
495
- < EditButton />
498
+ < EditButton buttonId = { buttonId } shouldShowEditButton = { shouldShowEditButton } />
496
499
</ div >
497
500
</ LoadingOverlay >
498
501
) ;
0 commit comments