mirror of
https://github.com/woocommerce/woocommerce-paypal-payments.git
synced 2025-09-05 08:59:14 +08:00
Further reduce prop drilling and move the phone number to the Redux store
This commit is contained in:
parent
5a31fdd183
commit
9b7cb5f401
6 changed files with 75 additions and 79 deletions
|
@ -1,5 +1,7 @@
|
|||
import { useMemo } from '@wordpress/element';
|
||||
import { useSelect } from '@wordpress/data';
|
||||
import { Watermark } from '../Watermark';
|
||||
import { STORE_NAME } from '../../stores/axoStore';
|
||||
|
||||
const cardIcons = {
|
||||
VISA: 'visa-light.svg',
|
||||
|
@ -11,7 +13,14 @@ const cardIcons = {
|
|||
UNIONPAY: 'unionpay-light.svg',
|
||||
};
|
||||
|
||||
const Card = ( { card, fastlaneSdk, showWatermark = true } ) => {
|
||||
const Card = ( { fastlaneSdk, showWatermark = true } ) => {
|
||||
const { card } = useSelect(
|
||||
( select ) => ( {
|
||||
card: select( STORE_NAME ).getCardDetails(),
|
||||
} ),
|
||||
[]
|
||||
);
|
||||
|
||||
const { brand, lastDigits, expiry, name } = card?.paymentSource?.card ?? {};
|
||||
|
||||
const cardLogo = useMemo( () => {
|
||||
|
|
|
@ -3,13 +3,14 @@ import { useSelect } from '@wordpress/data';
|
|||
import { Card } from '../Card';
|
||||
import { STORE_NAME } from '../../stores/axoStore';
|
||||
|
||||
export const Payment = ( { fastlaneSdk, card, onPaymentLoad } ) => {
|
||||
const isGuest = useSelect( ( select ) =>
|
||||
select( STORE_NAME ).getIsGuest()
|
||||
);
|
||||
|
||||
const isEmailLookupCompleted = useSelect( ( select ) =>
|
||||
select( STORE_NAME ).getIsEmailLookupCompleted()
|
||||
export const Payment = ( { fastlaneSdk, onPaymentLoad } ) => {
|
||||
const { isGuest, isEmailLookupCompleted } = useSelect(
|
||||
( select ) => ( {
|
||||
isGuest: select( STORE_NAME ).getIsGuest(),
|
||||
isEmailLookupCompleted:
|
||||
select( STORE_NAME ).getIsEmailLookupCompleted(),
|
||||
} ),
|
||||
[]
|
||||
);
|
||||
|
||||
const loadPaymentComponent = useCallback( async () => {
|
||||
|
@ -36,11 +37,5 @@ export const Payment = ( { fastlaneSdk, card, onPaymentLoad } ) => {
|
|||
</div>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<Card
|
||||
card={ card }
|
||||
fastlaneSdk={ fastlaneSdk }
|
||||
showWatermark={ ! isGuest }
|
||||
/>
|
||||
);
|
||||
return <Card fastlaneSdk={ fastlaneSdk } showWatermark={ ! isGuest } />;
|
||||
};
|
||||
|
|
|
@ -5,18 +5,14 @@ import usePayPalScript from './usePayPalScript';
|
|||
import { setupWatermark } from '../components/Watermark';
|
||||
import { setupEmailFunctionality } from '../components/EmailButton';
|
||||
import { createEmailLookupHandler } from '../events/emailLookupManager';
|
||||
import { usePhoneSyncHandler } from './usePhoneSyncHandler';
|
||||
import usePhoneSyncHandler from './usePhoneSyncHandler';
|
||||
import { initializeClassToggles } from '../helpers/classnamesManager';
|
||||
import { snapshotFields } from '../helpers/fieldHelpers';
|
||||
import useCustomerData from './useCustomerData';
|
||||
import useShippingAddressChange from './useShippingAddressChange';
|
||||
import useCardChange from './useCardChange';
|
||||
|
||||
const useAxoSetup = (
|
||||
ppcpConfig,
|
||||
fastlaneSdk,
|
||||
paymentComponent,
|
||||
onChangeCardButtonClick
|
||||
) => {
|
||||
const useAxoSetup = ( ppcpConfig, fastlaneSdk, paymentComponent ) => {
|
||||
const {
|
||||
setIsAxoActive,
|
||||
setIsAxoScriptLoaded,
|
||||
|
@ -24,7 +20,7 @@ const useAxoSetup = (
|
|||
setCardDetails,
|
||||
} = useDispatch( STORE_NAME );
|
||||
const paypalLoaded = usePayPalScript( ppcpConfig );
|
||||
|
||||
const onChangeCardButtonClick = useCardChange( fastlaneSdk );
|
||||
const onChangeShippingAddressClick = useShippingAddressChange(
|
||||
fastlaneSdk,
|
||||
setShippingAddress
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
import { useEffect, useRef } from 'react';
|
||||
import { useSelect } from '@wordpress/data';
|
||||
import { useEffect, useRef, useCallback } from '@wordpress/element';
|
||||
import { useSelect, useDispatch } from '@wordpress/data';
|
||||
import { debounce } from '../../../../ppcp-blocks/resources/js/Helper/debounce';
|
||||
import { STORE_NAME } from '../stores/axoStore';
|
||||
import useCustomerData from './useCustomerData';
|
||||
|
||||
const WOO_STORE_NAME = 'wc/store/cart';
|
||||
const PHONE_DEBOUNCE_DELAY = 250;
|
||||
|
||||
/**
|
||||
|
@ -15,23 +16,9 @@ const PHONE_DEBOUNCE_DELAY = 250;
|
|||
const sanitizePhoneNumber = ( phoneNumber = '' ) => {
|
||||
const localNumber = phoneNumber.replace( /^\+?[01]+/, '' );
|
||||
const cleanNumber = localNumber.replace( /[^0-9]/g, '' );
|
||||
|
||||
return cleanNumber.length === 10 ? cleanNumber : '';
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieves and sanitizes the phone number from WooCommerce customer data.
|
||||
*
|
||||
* @param {Function} select - The select function from @wordpress/data.
|
||||
* @return {string} The sanitized phone number.
|
||||
*/
|
||||
const getSanitizedPhoneNumber = ( select ) => {
|
||||
const data = select( WOO_STORE_NAME ).getCustomerData() || {};
|
||||
const billingPhone = sanitizePhoneNumber( data.billingAddress?.phone );
|
||||
const shippingPhone = sanitizePhoneNumber( data.shippingAddress?.phone );
|
||||
return billingPhone || shippingPhone || '';
|
||||
};
|
||||
|
||||
/**
|
||||
* Updates the prefilled phone number in the Fastlane CardField component.
|
||||
*
|
||||
|
@ -48,17 +35,37 @@ const updatePrefills = ( paymentComponent, phoneNumber ) => {
|
|||
*
|
||||
* @param {Object} paymentComponent - The CardField component from Fastlane.
|
||||
*/
|
||||
export const usePhoneSyncHandler = ( paymentComponent ) => {
|
||||
// Fetch and sanitize phone number from WooCommerce.
|
||||
const phoneNumber = useSelect( ( select ) =>
|
||||
getSanitizedPhoneNumber( select )
|
||||
);
|
||||
const usePhoneSyncHandler = ( paymentComponent ) => {
|
||||
const { setPhoneNumber } = useDispatch( STORE_NAME );
|
||||
|
||||
const { phoneNumber } = useSelect( ( select ) => ( {
|
||||
phoneNumber: select( STORE_NAME ).getPhoneNumber(),
|
||||
} ) );
|
||||
|
||||
const { shippingAddress, billingAddress } = useCustomerData();
|
||||
|
||||
// Create a debounced function that updates the prefilled phone-number.
|
||||
const debouncedUpdatePhone = useRef(
|
||||
debounce( updatePrefills, PHONE_DEBOUNCE_DELAY )
|
||||
).current;
|
||||
|
||||
// Fetch and update the phone number from the billing or shipping address.
|
||||
const fetchAndUpdatePhoneNumber = useCallback( () => {
|
||||
const billingPhone = billingAddress?.phone || '';
|
||||
const shippingPhone = shippingAddress?.phone || '';
|
||||
const sanitizedPhoneNumber = sanitizePhoneNumber(
|
||||
billingPhone || shippingPhone
|
||||
);
|
||||
|
||||
if ( sanitizedPhoneNumber && sanitizedPhoneNumber !== phoneNumber ) {
|
||||
setPhoneNumber( sanitizedPhoneNumber );
|
||||
}
|
||||
}, [ billingAddress, shippingAddress, phoneNumber, setPhoneNumber ] );
|
||||
|
||||
// Fetch and update the phone number from the billing or shipping address.
|
||||
useEffect( () => {
|
||||
fetchAndUpdatePhoneNumber();
|
||||
}, [ fetchAndUpdatePhoneNumber ] );
|
||||
|
||||
// Invoke debounced function when paymentComponent or phoneNumber changes.
|
||||
useEffect( () => {
|
||||
if ( paymentComponent && phoneNumber ) {
|
||||
|
@ -75,3 +82,5 @@ export const usePhoneSyncHandler = ( paymentComponent ) => {
|
|||
};
|
||||
}, [ debouncedUpdatePhone ] );
|
||||
};
|
||||
|
||||
export default usePhoneSyncHandler;
|
||||
|
|
|
@ -1,21 +1,16 @@
|
|||
import { useState } from '@wordpress/element';
|
||||
import { useSelect } from '@wordpress/data';
|
||||
import { registerPaymentMethod } from '@woocommerce/blocks-registry';
|
||||
|
||||
// Hooks
|
||||
import useFastlaneSdk from './hooks/useFastlaneSdk';
|
||||
import useTokenizeCustomerData from './hooks/useTokenizeCustomerData';
|
||||
import useCardChange from './hooks/useCardChange';
|
||||
import useAxoSetup from './hooks/useAxoSetup';
|
||||
import useAxoCleanup from './hooks/useAxoCleanup';
|
||||
import useHandlePaymentSetup from './hooks/useHandlePaymentSetup';
|
||||
import usePaymentSetupEffect from './hooks/usePaymentSetupEffect';
|
||||
|
||||
// Components
|
||||
import { Payment } from './components/Payment/Payment';
|
||||
import usePaymentSetupEffect from './hooks/usePaymentSetupEffect';
|
||||
|
||||
// Store
|
||||
import { STORE_NAME } from './stores/axoStore';
|
||||
|
||||
const gatewayHandle = 'ppcp-axo-gateway';
|
||||
const ppcpConfig = wc.wcSettings.getSetting( `${ gatewayHandle }_data` );
|
||||
|
@ -31,28 +26,15 @@ const Axo = ( props ) => {
|
|||
const { onPaymentSetup } = eventRegistration;
|
||||
const [ paymentComponent, setPaymentComponent ] = useState( null );
|
||||
|
||||
const { cardDetails } = useSelect(
|
||||
( select ) => ( {
|
||||
cardDetails: select( STORE_NAME ).getCardDetails(),
|
||||
} ),
|
||||
[]
|
||||
);
|
||||
|
||||
const fastlaneSdk = useFastlaneSdk( axoConfig, ppcpConfig );
|
||||
const tokenizedCustomerData = useTokenizeCustomerData();
|
||||
const onChangeCardButtonClick = useCardChange( fastlaneSdk );
|
||||
const handlePaymentSetup = useHandlePaymentSetup(
|
||||
emitResponse,
|
||||
paymentComponent,
|
||||
tokenizedCustomerData
|
||||
);
|
||||
|
||||
useAxoSetup(
|
||||
ppcpConfig,
|
||||
fastlaneSdk,
|
||||
paymentComponent,
|
||||
onChangeCardButtonClick
|
||||
);
|
||||
useAxoSetup( ppcpConfig, fastlaneSdk, paymentComponent );
|
||||
|
||||
const { handlePaymentLoad } = usePaymentSetupEffect(
|
||||
onPaymentSetup,
|
||||
|
@ -62,17 +44,10 @@ const Axo = ( props ) => {
|
|||
|
||||
useAxoCleanup();
|
||||
|
||||
console.log( 'Rendering Axo component', {
|
||||
fastlaneSdk,
|
||||
} );
|
||||
|
||||
return fastlaneSdk ? (
|
||||
<Payment
|
||||
fastlaneSdk={ fastlaneSdk }
|
||||
card={ cardDetails }
|
||||
onChange={ onChangeCardButtonClick }
|
||||
onPaymentLoad={ handlePaymentLoad }
|
||||
onChangeButtonClick={ onChangeCardButtonClick }
|
||||
/>
|
||||
) : (
|
||||
<div>Loading Fastlane...</div>
|
||||
|
|
|
@ -2,7 +2,7 @@ import { createReduxStore, register, dispatch } from '@wordpress/data';
|
|||
|
||||
export const STORE_NAME = 'woocommerce-paypal-payments/axo-block';
|
||||
|
||||
// Initial state.
|
||||
// Initial state
|
||||
const DEFAULT_STATE = {
|
||||
isGuest: true,
|
||||
isAxoActive: false,
|
||||
|
@ -11,9 +11,10 @@ const DEFAULT_STATE = {
|
|||
isEmailLookupCompleted: false,
|
||||
shippingAddress: null,
|
||||
cardDetails: null,
|
||||
phoneNumber: '',
|
||||
};
|
||||
|
||||
// Actions.
|
||||
// Actions
|
||||
const actions = {
|
||||
setIsGuest: ( isGuest ) => ( {
|
||||
type: 'SET_IS_GUEST',
|
||||
|
@ -43,9 +44,13 @@ const actions = {
|
|||
type: 'SET_CARD_DETAILS',
|
||||
payload: cardDetails,
|
||||
} ),
|
||||
setPhoneNumber: ( phoneNumber ) => ( {
|
||||
type: 'SET_PHONE_NUMBER',
|
||||
payload: phoneNumber,
|
||||
} ),
|
||||
};
|
||||
|
||||
// Reducer.
|
||||
// Reducer
|
||||
const reducer = ( state = DEFAULT_STATE, action ) => {
|
||||
switch ( action.type ) {
|
||||
case 'SET_IS_GUEST':
|
||||
|
@ -62,12 +67,14 @@ const reducer = ( state = DEFAULT_STATE, action ) => {
|
|||
return { ...state, shippingAddress: action.payload };
|
||||
case 'SET_CARD_DETAILS':
|
||||
return { ...state, cardDetails: action.payload };
|
||||
case 'SET_PHONE_NUMBER':
|
||||
return { ...state, phoneNumber: action.payload };
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
};
|
||||
|
||||
// Selectors.
|
||||
// Selectors
|
||||
const selectors = {
|
||||
getIsGuest: ( state ) => state.isGuest,
|
||||
getIsAxoActive: ( state ) => state.isAxoActive,
|
||||
|
@ -76,9 +83,10 @@ const selectors = {
|
|||
getIsEmailLookupCompleted: ( state ) => state.isEmailLookupCompleted,
|
||||
getShippingAddress: ( state ) => state.shippingAddress,
|
||||
getCardDetails: ( state ) => state.cardDetails,
|
||||
getPhoneNumber: ( state ) => state.phoneNumber,
|
||||
};
|
||||
|
||||
// Create and register the store.
|
||||
// Create and register the store
|
||||
const store = createReduxStore( STORE_NAME, {
|
||||
reducer,
|
||||
actions,
|
||||
|
@ -87,7 +95,7 @@ const store = createReduxStore( STORE_NAME, {
|
|||
|
||||
register( store );
|
||||
|
||||
// Action dispatchers.
|
||||
// Action dispatchers
|
||||
export const setIsGuest = ( isGuest ) => {
|
||||
dispatch( STORE_NAME ).setIsGuest( isGuest );
|
||||
};
|
||||
|
@ -103,3 +111,7 @@ export const setShippingAddress = ( shippingAddress ) => {
|
|||
export const setCardDetails = ( cardDetails ) => {
|
||||
dispatch( STORE_NAME ).setCardDetails( cardDetails );
|
||||
};
|
||||
|
||||
export const setPhoneNumber = ( phoneNumber ) => {
|
||||
dispatch( STORE_NAME ).setPhoneNumber( phoneNumber );
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue