mirror of
https://github.com/woocommerce/woocommerce-paypal-payments.git
synced 2025-09-06 09:08:09 +08:00
Initial Axo Blocks commit
This commit is contained in:
parent
796ded031e
commit
ebd87b70e9
27 changed files with 43827 additions and 1 deletions
197
modules/ppcp-axo-block/resources/js/components/AxoBlock.js
Normal file
197
modules/ppcp-axo-block/resources/js/components/AxoBlock.js
Normal file
|
@ -0,0 +1,197 @@
|
|||
import { useEffect, useState } from '@wordpress/element';
|
||||
import { useCustomerData } from './useCustomerData';
|
||||
import { ShippingChangeButton } from './ShippingChangeButton';
|
||||
import { loadPaypalScript } from '../utils/ScriptLoading';
|
||||
import Payment from './Payment';
|
||||
import useAxoBlockManager from './useAxoBlockManager';
|
||||
|
||||
const ppcpConfig = wc.wcSettings.getSetting( 'ppcp-credit-card-gateway_data' );
|
||||
|
||||
if ( typeof window.PayPalCommerceGateway === 'undefined' ) {
|
||||
window.PayPalCommerceGateway = ppcpConfig;
|
||||
}
|
||||
|
||||
const axoConfig = window.wc_ppcp_axo;
|
||||
|
||||
// AxoBlock Component
|
||||
const AxoBlock = () => {
|
||||
const [ paypalLoaded, setPaypalLoaded ] = useState( false );
|
||||
const [ isGuest, setIsGuest ] = useState( true );
|
||||
const [ shippingAddress, setShippingAddress ] = useState( null );
|
||||
const [ card, setCard ] = useState( null );
|
||||
|
||||
const fastlaneSdk = useAxoBlockManager( axoConfig, ppcpConfig );
|
||||
|
||||
// WooCommerce customer data hooks
|
||||
const {
|
||||
shippingAddress: wooShippingAddress,
|
||||
billingAddress: wooBillingAddress,
|
||||
setShippingAddress: updateWooShippingAddress,
|
||||
setBillingAddress: updateWooBillingAddress,
|
||||
} = useCustomerData();
|
||||
|
||||
// Snapshot and restore original checkout fields from localStorage
|
||||
const snapshotFields = () => {
|
||||
const originalData = {
|
||||
shippingAddress: wooShippingAddress,
|
||||
billingAddress: wooBillingAddress,
|
||||
};
|
||||
localStorage.setItem(
|
||||
'originalCheckoutFields',
|
||||
JSON.stringify( originalData )
|
||||
);
|
||||
console.log( 'originalFields saved to localStorage', originalData );
|
||||
};
|
||||
|
||||
const restoreOriginalFields = () => {
|
||||
const savedData = JSON.parse(
|
||||
localStorage.getItem( 'originalCheckoutFields' )
|
||||
);
|
||||
if ( savedData ) {
|
||||
if ( savedData.shippingAddress ) {
|
||||
updateWooShippingAddress( savedData.shippingAddress );
|
||||
}
|
||||
if ( savedData.billingAddress ) {
|
||||
updateWooBillingAddress( savedData.billingAddress );
|
||||
}
|
||||
console.log(
|
||||
'originalFields restored from localStorage',
|
||||
savedData
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
// Cleanup function to handle component unmounting
|
||||
useEffect( () => {
|
||||
// Perform cleanup when the component unmounts
|
||||
return () => {
|
||||
console.log( 'Axo component unmounted, restoring original fields' );
|
||||
restoreOriginalFields(); // Restore original fields when Axo is unmounted
|
||||
};
|
||||
}, [] );
|
||||
|
||||
useEffect( () => {
|
||||
console.log( 'ppcpConfig', ppcpConfig );
|
||||
loadPaypalScript( ppcpConfig, () => {
|
||||
console.log( 'PayPal script loaded' );
|
||||
setPaypalLoaded( true );
|
||||
} );
|
||||
}, [] );
|
||||
|
||||
const onEmailSubmit = async ( email ) => {
|
||||
try {
|
||||
console.log( 'Email value being looked up:', email );
|
||||
const lookup =
|
||||
await fastlaneSdk.identity.lookupCustomerByEmail( email );
|
||||
|
||||
if ( ! lookup.customerContextId ) {
|
||||
console.warn( 'No customerContextId found in the response' );
|
||||
return;
|
||||
}
|
||||
|
||||
const { authenticationState, profileData } =
|
||||
await fastlaneSdk.identity.triggerAuthenticationFlow(
|
||||
lookup.customerContextId
|
||||
);
|
||||
|
||||
if ( authenticationState === 'succeeded' ) {
|
||||
// Snapshot original fields before updating with Fastlane data
|
||||
snapshotFields();
|
||||
|
||||
// Update WooCommerce fields with Fastlane data
|
||||
setIsGuest( false );
|
||||
setShippingAddress( profileData.shippingAddress );
|
||||
setCard( profileData.card );
|
||||
|
||||
const { address, name, phoneNumber } =
|
||||
profileData.shippingAddress;
|
||||
updateWooShippingAddress( {
|
||||
first_name: name.firstName,
|
||||
last_name: name.lastName,
|
||||
address_1: address.addressLine1,
|
||||
address_2: address.addressLine2 || '',
|
||||
city: address.adminArea2,
|
||||
state: address.adminArea1,
|
||||
postcode: address.postalCode,
|
||||
country: address.countryCode,
|
||||
phone: phoneNumber.nationalNumber,
|
||||
} );
|
||||
|
||||
const billingData =
|
||||
profileData.card.paymentSource.card.billingAddress;
|
||||
updateWooBillingAddress( {
|
||||
first_name: profileData.name.firstName,
|
||||
last_name: profileData.name.lastName,
|
||||
address_1: billingData.addressLine1,
|
||||
address_2: billingData.addressLine2 || '',
|
||||
city: billingData.adminArea2,
|
||||
state: billingData.adminArea1,
|
||||
postcode: billingData.postalCode,
|
||||
country: billingData.countryCode,
|
||||
} );
|
||||
} else {
|
||||
console.warn( 'Authentication failed or did not succeed' );
|
||||
}
|
||||
} catch ( error ) {
|
||||
console.error(
|
||||
'Error during email lookup or authentication:',
|
||||
error
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
const onChangeShippingAddressClick = async () => {
|
||||
if ( fastlaneSdk ) {
|
||||
const { selectionChanged, selectedAddress } =
|
||||
await fastlaneSdk.profile.showShippingAddressSelector();
|
||||
if ( selectionChanged ) {
|
||||
setShippingAddress( selectedAddress );
|
||||
const { address, name, phoneNumber } = selectedAddress;
|
||||
|
||||
updateWooShippingAddress( {
|
||||
first_name: name.firstName,
|
||||
last_name: name.lastName,
|
||||
address_1: address.addressLine1,
|
||||
address_2: address.addressLine2 || '',
|
||||
city: address.adminArea2,
|
||||
state: address.adminArea1,
|
||||
postcode: address.postalCode,
|
||||
country: address.countryCode,
|
||||
phone: phoneNumber.nationalNumber,
|
||||
} );
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const onChangeButtonClick = async () => {
|
||||
const { selectionChanged, selectedCard } =
|
||||
await fastlaneSdk.profile.showCardSelector();
|
||||
if ( selectionChanged ) {
|
||||
setCard( selectedCard );
|
||||
}
|
||||
};
|
||||
|
||||
const handlePaymentLoad = ( paymentComponent ) => {
|
||||
console.log( 'Payment component loaded', paymentComponent );
|
||||
};
|
||||
|
||||
return fastlaneSdk ? (
|
||||
<div>
|
||||
<Payment
|
||||
fastlaneSdk={ fastlaneSdk }
|
||||
card={ card }
|
||||
shippingAddress={ shippingAddress }
|
||||
isGuestFlow={ isGuest }
|
||||
onPaymentLoad={ handlePaymentLoad }
|
||||
onChangeButtonClick={ onChangeButtonClick }
|
||||
/>
|
||||
<ShippingChangeButton
|
||||
onChangeShippingAddressClick={ onChangeShippingAddressClick }
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
<div>Loading Fastlane...</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default AxoBlock;
|
|
@ -0,0 +1,21 @@
|
|||
import { useEffect } from '@wordpress/element';
|
||||
|
||||
export const FastlaneWatermark = ( {
|
||||
fastlaneSdk,
|
||||
name = 'fastlane-watermark-container',
|
||||
includeAdditionalInfo = true,
|
||||
} ) => {
|
||||
// This web component can be instantiated inside of a useEffect.
|
||||
useEffect( () => {
|
||||
( async () => {
|
||||
const watermark = await fastlaneSdk.FastlaneWatermarkComponent( {
|
||||
includeAdditionalInfo,
|
||||
} );
|
||||
// The ID can be a react element
|
||||
watermark.render( `#${ name }` );
|
||||
} )();
|
||||
}, [] );
|
||||
|
||||
// Give the react element the ID that you will render the watermark component into.
|
||||
return <div id={ name } />;
|
||||
};
|
66
modules/ppcp-axo-block/resources/js/components/Payment.js
Normal file
66
modules/ppcp-axo-block/resources/js/components/Payment.js
Normal file
|
@ -0,0 +1,66 @@
|
|||
import { useEffect } from '@wordpress/element';
|
||||
|
||||
const cardIcons = {
|
||||
VISA: 'visa-light.svg',
|
||||
MASTER_CARD: 'mastercard-light.svg',
|
||||
AMEX: 'amex-light.svg',
|
||||
DISCOVER: 'discover-light.svg',
|
||||
DINERS: 'dinersclub-light.svg',
|
||||
JCB: 'jcb-light.svg',
|
||||
UNIONPAY: 'unionpay-light.svg',
|
||||
};
|
||||
|
||||
export const Payment = ( {
|
||||
fastlaneSdk,
|
||||
card,
|
||||
shippingAddress,
|
||||
isGuestFlow,
|
||||
onPaymentLoad,
|
||||
} ) => {
|
||||
const { brand, lastDigits, expiry } = card?.paymentSource?.card ?? {};
|
||||
|
||||
const { fullName } = shippingAddress?.name ?? {};
|
||||
|
||||
useEffect( () => {
|
||||
if ( isGuestFlow ) {
|
||||
( async () => {
|
||||
const paymentComponent =
|
||||
await fastlaneSdk.FastlaneCardComponent( {} );
|
||||
paymentComponent.render( `#fastlane-card` );
|
||||
onPaymentLoad( paymentComponent );
|
||||
} )();
|
||||
}
|
||||
}, [ fastlaneSdk, onPaymentLoad, isGuestFlow ] );
|
||||
|
||||
const cardLogo = cardIcons[ brand ] ? (
|
||||
<img
|
||||
className="wc-block-axo-block-card__meta-icon"
|
||||
title={ brand }
|
||||
src={ `${ window.wc_ppcp_axo.icons_directory }${ cardIcons[ brand ] }` }
|
||||
alt={ brand }
|
||||
/>
|
||||
) : (
|
||||
<span>{ brand }</span>
|
||||
);
|
||||
|
||||
const formattedExpiry = expiry
|
||||
? `${ expiry.split( '-' )[ 1 ] }/${ expiry.split( '-' )[ 0 ] }`
|
||||
: '';
|
||||
|
||||
return isGuestFlow ? (
|
||||
<div id="fastlane-card" key="fastlane-card" />
|
||||
) : (
|
||||
<div key="custom-card" className="wc-block-checkout-axo-block-card">
|
||||
<div className="wc-block-checkout-axo-block-card__meta-container">
|
||||
<div className="wc-block-axo-block-card__meta">
|
||||
<span className="wc-block-axo-block-card__meta__digits">{ `**** **** **** ${ lastDigits }` }</span>
|
||||
{ cardLogo }
|
||||
</div>
|
||||
<div className="wc-block-axo-block-card__meta">
|
||||
<span>{ fullName }</span>
|
||||
<span>{ formattedExpiry }</span>{ ' ' }
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
|
@ -0,0 +1,57 @@
|
|||
import { useEffect } from '@wordpress/element';
|
||||
|
||||
// Inject the change button next to the Shipping title
|
||||
const injectShippingChangeButton = ( onChangeShippingAddressClick ) => {
|
||||
const shippingTitle = document.querySelector(
|
||||
'#shipping-fields h2.wc-block-components-title'
|
||||
);
|
||||
|
||||
if (
|
||||
shippingTitle &&
|
||||
! shippingTitle.nextElementSibling?.classList?.contains(
|
||||
'wc-block-checkout-axo-block-card__edit'
|
||||
)
|
||||
) {
|
||||
const buttonElement = document.createElement( 'button' );
|
||||
buttonElement.classList.add( 'wc-block-checkout-axo-block-card__edit' );
|
||||
buttonElement.setAttribute( 'aria-label', 'Change shipping details' );
|
||||
buttonElement.textContent = 'Change';
|
||||
buttonElement.onclick = ( event ) => {
|
||||
event.preventDefault();
|
||||
onChangeShippingAddressClick();
|
||||
};
|
||||
|
||||
// Ensure the button is inserted correctly after the shipping title
|
||||
shippingTitle.parentNode.insertBefore(
|
||||
buttonElement,
|
||||
shippingTitle.nextSibling
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
// Cleanup function to remove the "Change" button when the payment gateway switches
|
||||
const removeShippingChangeButton = () => {
|
||||
const existingButton = document.querySelector(
|
||||
'#shipping-fields .wc-block-checkout-axo-block-card__edit'
|
||||
);
|
||||
if ( existingButton ) {
|
||||
existingButton.remove();
|
||||
}
|
||||
};
|
||||
|
||||
// ShippingChangeButton component that will handle injection and cleanup
|
||||
const ShippingChangeButton = ( { onChangeShippingAddressClick } ) => {
|
||||
useEffect( () => {
|
||||
// Inject the button when the component mounts
|
||||
injectShippingChangeButton( onChangeShippingAddressClick );
|
||||
|
||||
// Cleanup the button when the component unmounts or the payment gateway switches
|
||||
return () => {
|
||||
removeShippingChangeButton();
|
||||
};
|
||||
}, [ onChangeShippingAddressClick ] );
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
export default ShippingChangeButton;
|
|
@ -0,0 +1,112 @@
|
|||
import ReactDOM from 'react-dom/client';
|
||||
import { FastlaneWatermark } from '../components/FastlaneWatermark';
|
||||
|
||||
export const onEmailSubmit = async (
|
||||
email,
|
||||
fastlaneSdk,
|
||||
setIsGuest,
|
||||
setShippingAddress,
|
||||
setCard,
|
||||
snapshotFields,
|
||||
wooShippingAddress,
|
||||
wooBillingAddress,
|
||||
setWooShippingAddress,
|
||||
setWooBillingAddress,
|
||||
handlePaymentGatewaySwitch,
|
||||
onChangeShippingAddressClick,
|
||||
onChangeButtonClick,
|
||||
shouldIncludeAdditionalInfo,
|
||||
setShouldIncludeAdditionalInfo
|
||||
) => {
|
||||
try {
|
||||
console.log( 'Email value being looked up:', email );
|
||||
const lookup =
|
||||
await fastlaneSdk.identity.lookupCustomerByEmail( email );
|
||||
|
||||
console.log( 'Lookup response:', lookup );
|
||||
|
||||
if ( ! lookup.customerContextId ) {
|
||||
console.warn( 'No customerContextId found in the response' );
|
||||
return;
|
||||
}
|
||||
|
||||
const { authenticationState, profileData } =
|
||||
await fastlaneSdk.identity.triggerAuthenticationFlow(
|
||||
lookup.customerContextId
|
||||
);
|
||||
|
||||
console.log( 'authenticationState', authenticationState );
|
||||
|
||||
if ( authenticationState === 'succeeded' ) {
|
||||
// Capture the existing WooCommerce data before updating it
|
||||
snapshotFields( wooShippingAddress, wooBillingAddress );
|
||||
|
||||
// Update WooCommerce fields with Fastlane data
|
||||
setIsGuest( false );
|
||||
setShippingAddress( profileData.shippingAddress );
|
||||
setCard( profileData.card );
|
||||
setShouldIncludeAdditionalInfo( false );
|
||||
|
||||
console.log( 'Profile Data:', profileData );
|
||||
|
||||
const { address, name, phoneNumber } = profileData.shippingAddress;
|
||||
|
||||
setWooShippingAddress( {
|
||||
first_name: name.firstName,
|
||||
last_name: name.lastName,
|
||||
address_1: address.addressLine1,
|
||||
address_2: address.addressLine2 || '',
|
||||
city: address.adminArea2,
|
||||
state: address.adminArea1,
|
||||
postcode: address.postalCode,
|
||||
country: address.countryCode,
|
||||
phone: phoneNumber.nationalNumber,
|
||||
} );
|
||||
|
||||
const billingData =
|
||||
profileData.card.paymentSource.card.billingAddress;
|
||||
setWooBillingAddress( {
|
||||
first_name: profileData.name.firstName,
|
||||
last_name: profileData.name.lastName,
|
||||
address_1: billingData.addressLine1,
|
||||
address_2: billingData.addressLine2 || '',
|
||||
city: billingData.adminArea2,
|
||||
state: billingData.adminArea1,
|
||||
postcode: billingData.postalCode,
|
||||
country: billingData.countryCode,
|
||||
} );
|
||||
|
||||
const radioLabelElement = document.getElementById(
|
||||
'ppcp-axo-block-radio-label'
|
||||
);
|
||||
if ( radioLabelElement ) {
|
||||
const watermarkRoot = ReactDOM.createRoot( radioLabelElement );
|
||||
watermarkRoot.render(
|
||||
<>
|
||||
<FastlaneWatermark
|
||||
fastlaneSdk={ fastlaneSdk }
|
||||
name="fastlane-watermark-radio"
|
||||
includeAdditionalInfo={
|
||||
false
|
||||
}
|
||||
/>
|
||||
<button
|
||||
className="wc-block-checkout-axo-block-card__edit"
|
||||
aria-label="Change billing details"
|
||||
type="button"
|
||||
onClick={ onChangeButtonClick }
|
||||
>
|
||||
Change
|
||||
</button>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
handlePaymentGatewaySwitch( onChangeShippingAddressClick );
|
||||
} else {
|
||||
console.warn( 'Authentication failed or did not succeed' );
|
||||
}
|
||||
} catch ( error ) {
|
||||
console.error( 'Error during email lookup or authentication:', error );
|
||||
}
|
||||
};
|
33
modules/ppcp-axo-block/resources/js/helpers/buttonHelpers.js
Normal file
33
modules/ppcp-axo-block/resources/js/helpers/buttonHelpers.js
Normal file
|
@ -0,0 +1,33 @@
|
|||
export const injectShippingChangeButton = ( onChangeShippingAddressClick ) => {
|
||||
const shippingTitle = document.querySelector(
|
||||
'#shipping-fields h2.wc-block-components-title'
|
||||
);
|
||||
if (
|
||||
shippingTitle &&
|
||||
! shippingTitle.nextElementSibling?.classList?.contains(
|
||||
'wc-block-checkout-axo-block-card__edit'
|
||||
)
|
||||
) {
|
||||
const buttonElement = document.createElement( 'button' );
|
||||
buttonElement.classList.add( 'wc-block-checkout-axo-block-card__edit' );
|
||||
buttonElement.setAttribute( 'aria-label', 'Change shipping details' );
|
||||
buttonElement.textContent = 'Change';
|
||||
buttonElement.onclick = ( event ) => {
|
||||
event.preventDefault();
|
||||
onChangeShippingAddressClick();
|
||||
};
|
||||
shippingTitle.parentNode.insertBefore(
|
||||
buttonElement,
|
||||
shippingTitle.nextSibling
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export const removeShippingChangeButton = () => {
|
||||
const existingButton = document.querySelector(
|
||||
'#shipping-fields .wc-block-checkout-axo-block-card__edit'
|
||||
);
|
||||
if ( existingButton ) {
|
||||
existingButton.remove();
|
||||
}
|
||||
};
|
39
modules/ppcp-axo-block/resources/js/helpers/fieldHelpers.js
Normal file
39
modules/ppcp-axo-block/resources/js/helpers/fieldHelpers.js
Normal file
|
@ -0,0 +1,39 @@
|
|||
export const snapshotFields = ( shippingAddress, billingAddress ) => {
|
||||
if ( ! shippingAddress || ! billingAddress ) {
|
||||
console.warn( 'Shipping or billing address is missing:', {
|
||||
shippingAddress,
|
||||
billingAddress,
|
||||
} );
|
||||
}
|
||||
|
||||
const originalData = { shippingAddress, billingAddress };
|
||||
console.log( 'Snapshot data:', originalData ); // Debug data
|
||||
localStorage.setItem(
|
||||
'originalCheckoutFields',
|
||||
JSON.stringify( originalData )
|
||||
);
|
||||
console.log( 'Original fields saved to localStorage', originalData );
|
||||
};
|
||||
|
||||
export const restoreOriginalFields = (
|
||||
updateShippingAddress,
|
||||
updateBillingAddress
|
||||
) => {
|
||||
const savedData = localStorage.getItem( 'originalCheckoutFields' );
|
||||
console.log( 'Data retrieved from localStorage:', savedData );
|
||||
|
||||
if ( savedData ) {
|
||||
const parsedData = JSON.parse( savedData );
|
||||
if ( parsedData.shippingAddress ) {
|
||||
updateShippingAddress( parsedData.shippingAddress );
|
||||
}
|
||||
if ( parsedData.billingAddress ) {
|
||||
updateBillingAddress( parsedData.billingAddress );
|
||||
}
|
||||
console.log( 'Original fields restored from localStorage', parsedData );
|
||||
} else {
|
||||
console.warn(
|
||||
'No data found in localStorage under originalCheckoutFields'
|
||||
);
|
||||
}
|
||||
};
|
|
@ -0,0 +1,62 @@
|
|||
import ReactDOM from 'react-dom/client';
|
||||
import { FastlaneWatermark } from '../components/FastlaneWatermark';
|
||||
|
||||
export const setupWatermark = ( fastlaneSdk, shouldIncludeAdditionalInfo ) => {
|
||||
const emailInput = document.getElementById( 'email' );
|
||||
let watermarkRoot = null;
|
||||
let watermarkContainer = null;
|
||||
|
||||
if ( emailInput ) {
|
||||
const emailLabel =
|
||||
emailInput.parentNode.querySelector( 'label[for="email"]' );
|
||||
watermarkContainer = document.createElement( 'div' );
|
||||
watermarkContainer.setAttribute(
|
||||
'class',
|
||||
'ppcp-axo-block-watermark-container'
|
||||
);
|
||||
|
||||
if ( emailLabel ) {
|
||||
emailLabel.parentNode.insertBefore(
|
||||
watermarkContainer,
|
||||
emailLabel.nextSibling
|
||||
);
|
||||
} else {
|
||||
emailInput.parentNode.appendChild( watermarkContainer );
|
||||
}
|
||||
|
||||
const watermarkElement = document.createElement( 'div' );
|
||||
watermarkContainer.appendChild( watermarkElement );
|
||||
|
||||
watermarkRoot = ReactDOM.createRoot( watermarkElement );
|
||||
watermarkRoot.render(
|
||||
<FastlaneWatermark
|
||||
fastlaneSdk={ fastlaneSdk }
|
||||
name="fastlane-watermark-email"
|
||||
includeAdditionalInfo={ shouldIncludeAdditionalInfo }
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return { watermarkRoot, watermarkContainer, emailInput };
|
||||
};
|
||||
|
||||
export const cleanupWatermark = ( {
|
||||
watermarkRoot,
|
||||
watermarkContainer,
|
||||
emailInput,
|
||||
onEmailSubmit,
|
||||
} ) => {
|
||||
if ( watermarkRoot && watermarkContainer ) {
|
||||
watermarkRoot.unmount();
|
||||
watermarkContainer.parentNode.removeChild( watermarkContainer );
|
||||
console.log( 'Fastlane watermark removed' );
|
||||
}
|
||||
if ( emailInput ) {
|
||||
emailInput.removeEventListener( 'keyup', async ( event ) => {
|
||||
const email = event.target.value;
|
||||
if ( email ) {
|
||||
await onEmailSubmit( email );
|
||||
}
|
||||
} );
|
||||
}
|
||||
};
|
|
@ -0,0 +1,41 @@
|
|||
import { useEffect, useState } from '@wordpress/element';
|
||||
import Fastlane from '../../../../ppcp-axo/resources/js/Connection/Fastlane';
|
||||
import { log } from '../../../../ppcp-axo/resources/js/Helper/Debug';
|
||||
|
||||
const useAxoBlockManager = ( axoConfig, ppcpConfig ) => {
|
||||
const [ fastlaneSdk, setFastlaneSdk ] = useState( null );
|
||||
const [ initialized, setInitialized ] = useState( false );
|
||||
|
||||
useEffect( () => {
|
||||
const initFastlane = async () => {
|
||||
log( 'Init Fastlane' );
|
||||
|
||||
if ( initialized ) {
|
||||
return;
|
||||
}
|
||||
|
||||
setInitialized( true );
|
||||
|
||||
const fastlane = new Fastlane();
|
||||
|
||||
if ( axoConfig.environment.is_sandbox ) {
|
||||
window.localStorage.setItem( 'axoEnv', 'sandbox' );
|
||||
}
|
||||
|
||||
await fastlane.connect( {
|
||||
locale: ppcpConfig.locale,
|
||||
styles: ppcpConfig.styles,
|
||||
} );
|
||||
|
||||
fastlane.setLocale( 'en_us' );
|
||||
|
||||
setFastlaneSdk( fastlane );
|
||||
};
|
||||
|
||||
initFastlane();
|
||||
}, [ axoConfig, ppcpConfig, initialized ] );
|
||||
|
||||
return fastlaneSdk;
|
||||
};
|
||||
|
||||
export default useAxoBlockManager;
|
16
modules/ppcp-axo-block/resources/js/hooks/useCustomerData.js
Normal file
16
modules/ppcp-axo-block/resources/js/hooks/useCustomerData.js
Normal file
|
@ -0,0 +1,16 @@
|
|||
import { useDispatch, useSelect } from '@wordpress/data';
|
||||
|
||||
export const useCustomerData = () => {
|
||||
const customerData = useSelect( ( select ) =>
|
||||
select( 'wc/store/cart' ).getCustomerData()
|
||||
);
|
||||
const { setShippingAddress, setBillingAddress } =
|
||||
useDispatch( 'wc/store/cart' );
|
||||
|
||||
return {
|
||||
shippingAddress: customerData.shippingAddress,
|
||||
billingAddress: customerData.billingAddress,
|
||||
setShippingAddress,
|
||||
setBillingAddress,
|
||||
};
|
||||
};
|
207
modules/ppcp-axo-block/resources/js/index.js
Normal file
207
modules/ppcp-axo-block/resources/js/index.js
Normal file
|
@ -0,0 +1,207 @@
|
|||
import { useEffect, useState } from '@wordpress/element';
|
||||
import { registerPaymentMethod } from '@woocommerce/blocks-registry';
|
||||
|
||||
import { loadPaypalScript } from '../../../ppcp-button/resources/js/modules/Helper/ScriptLoading';
|
||||
|
||||
// Hooks
|
||||
import useAxoBlockManager from './hooks/useAxoBlockManager';
|
||||
import { useCustomerData } from './hooks/useCustomerData';
|
||||
|
||||
// Components
|
||||
import { Payment } from './components/Payment';
|
||||
|
||||
// Helpers
|
||||
import {
|
||||
injectShippingChangeButton,
|
||||
removeShippingChangeButton,
|
||||
} from './helpers/buttonHelpers';
|
||||
import { snapshotFields, restoreOriginalFields } from './helpers/fieldHelpers';
|
||||
import { setupWatermark, cleanupWatermark } from './helpers/watermarkHelpers';
|
||||
|
||||
// Event handlers
|
||||
import { onEmailSubmit } from './events/fastlaneEmailManager';
|
||||
|
||||
const ppcpConfig = wc.wcSettings.getSetting( 'ppcp-credit-card-gateway_data' );
|
||||
|
||||
if ( typeof window.PayPalCommerceGateway === 'undefined' ) {
|
||||
window.PayPalCommerceGateway = ppcpConfig;
|
||||
}
|
||||
|
||||
const axoConfig = window.wc_ppcp_axo;
|
||||
|
||||
// Call this function when the payment gateway is loaded or switched
|
||||
const handlePaymentGatewaySwitch = ( onChangeShippingAddressClick ) => {
|
||||
removeShippingChangeButton();
|
||||
injectShippingChangeButton( onChangeShippingAddressClick );
|
||||
};
|
||||
|
||||
// Axo Component
|
||||
const Axo = () => {
|
||||
const [ paypalLoaded, setPaypalLoaded ] = useState( false );
|
||||
const [ isGuest, setIsGuest ] = useState( true );
|
||||
const [ shippingAddress, setShippingAddress ] = useState( null );
|
||||
const [ card, setCard ] = useState( null );
|
||||
const [ shouldIncludeAdditionalInfo, setShouldIncludeAdditionalInfo ] =
|
||||
useState( true );
|
||||
const fastlaneSdk = useAxoBlockManager( axoConfig, ppcpConfig );
|
||||
|
||||
// Access WooCommerce customer data
|
||||
const {
|
||||
shippingAddress: wooShippingAddress,
|
||||
billingAddress: wooBillingAddress,
|
||||
setShippingAddress: updateWooShippingAddress,
|
||||
setBillingAddress: updateWooBillingAddress,
|
||||
} = useCustomerData();
|
||||
|
||||
// Cleanup function to handle component unmounting
|
||||
useEffect( () => {
|
||||
return () => {
|
||||
console.log( 'Axo component unmounted, restoring original fields' );
|
||||
restoreOriginalFields(
|
||||
updateWooShippingAddress,
|
||||
updateWooBillingAddress
|
||||
); // Pass the correct arguments
|
||||
};
|
||||
}, [ updateWooShippingAddress, updateWooBillingAddress ] ); // Add the dependencies
|
||||
|
||||
const {
|
||||
setShippingAddress: setWooShippingAddress,
|
||||
setBillingAddress: setWooBillingAddress,
|
||||
} = useCustomerData();
|
||||
|
||||
useEffect( () => {
|
||||
console.log( 'ppcpConfig', ppcpConfig );
|
||||
loadPaypalScript( ppcpConfig, () => {
|
||||
console.log( 'PayPal script loaded' );
|
||||
setPaypalLoaded( true );
|
||||
} );
|
||||
}, [] );
|
||||
|
||||
useEffect( () => {
|
||||
let watermarkHandlers = {};
|
||||
|
||||
if ( paypalLoaded && fastlaneSdk ) {
|
||||
console.log( 'Fastlane SDK and PayPal loaded' );
|
||||
|
||||
watermarkHandlers = setupWatermark(
|
||||
fastlaneSdk,
|
||||
shouldIncludeAdditionalInfo
|
||||
);
|
||||
const { emailInput } = watermarkHandlers;
|
||||
|
||||
console.log(
|
||||
'shouldIncludeAdditionalInfo',
|
||||
shouldIncludeAdditionalInfo
|
||||
);
|
||||
|
||||
if ( emailInput ) {
|
||||
emailInput.addEventListener( 'keyup', async ( event ) => {
|
||||
const email = event.target.value;
|
||||
if ( email ) {
|
||||
await onEmailSubmit(
|
||||
email,
|
||||
fastlaneSdk,
|
||||
setIsGuest,
|
||||
setShippingAddress,
|
||||
setCard,
|
||||
snapshotFields,
|
||||
wooShippingAddress,
|
||||
wooBillingAddress,
|
||||
setWooShippingAddress,
|
||||
setWooBillingAddress,
|
||||
handlePaymentGatewaySwitch,
|
||||
onChangeShippingAddressClick,
|
||||
onChangeButtonClick,
|
||||
shouldIncludeAdditionalInfo,
|
||||
setShouldIncludeAdditionalInfo
|
||||
);
|
||||
}
|
||||
} );
|
||||
}
|
||||
}
|
||||
|
||||
return () => {
|
||||
cleanupWatermark( watermarkHandlers );
|
||||
};
|
||||
}, [ paypalLoaded, fastlaneSdk, shouldIncludeAdditionalInfo ] );
|
||||
|
||||
const onChangeShippingAddressClick = async () => {
|
||||
if ( fastlaneSdk ) {
|
||||
const { selectionChanged, selectedAddress } =
|
||||
await fastlaneSdk.profile.showShippingAddressSelector();
|
||||
if ( selectionChanged ) {
|
||||
setShippingAddress( selectedAddress );
|
||||
console.log(
|
||||
'Selected shipping address changed:',
|
||||
selectedAddress
|
||||
);
|
||||
|
||||
const { address, name, phoneNumber } = selectedAddress;
|
||||
|
||||
setWooShippingAddress( {
|
||||
first_name: name.firstName,
|
||||
last_name: name.lastName,
|
||||
address_1: address.addressLine1,
|
||||
address_2: address.addressLine2 || '',
|
||||
city: address.adminArea2,
|
||||
state: address.adminArea1,
|
||||
postcode: address.postalCode,
|
||||
country: address.countryCode,
|
||||
phone: phoneNumber.nationalNumber,
|
||||
} );
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const onChangeButtonClick = async () => {
|
||||
const { selectionChanged, selectedCard } =
|
||||
await fastlaneSdk.profile.showCardSelector();
|
||||
if ( selectionChanged ) {
|
||||
setCard( selectedCard );
|
||||
}
|
||||
};
|
||||
|
||||
const handlePaymentLoad = ( paymentComponent ) => {
|
||||
console.log( 'Payment component loaded', paymentComponent );
|
||||
};
|
||||
|
||||
const handleChange = ( selectedCard ) => {
|
||||
console.log( 'Selected card changed', selectedCard );
|
||||
setCard( selectedCard );
|
||||
};
|
||||
|
||||
return fastlaneSdk ? (
|
||||
<Payment
|
||||
fastlaneSdk={ fastlaneSdk }
|
||||
card={ card }
|
||||
shippingAddress={ shippingAddress }
|
||||
onChange={ handleChange }
|
||||
isGuestFlow={ isGuest }
|
||||
onPaymentLoad={ handlePaymentLoad }
|
||||
onChangeButtonClick={ onChangeButtonClick }
|
||||
/>
|
||||
) : (
|
||||
<div>Loading Fastlane...</div>
|
||||
);
|
||||
};
|
||||
|
||||
// Register the payment method
|
||||
registerPaymentMethod( {
|
||||
name: ppcpConfig.id,
|
||||
label: (
|
||||
<div
|
||||
id="ppcp-axo-block-radio-label"
|
||||
dangerouslySetInnerHTML={ { __html: ppcpConfig.title } }
|
||||
/>
|
||||
),
|
||||
content: <Axo />,
|
||||
edit: <h1>This is Axo Blocks in the editor</h1>,
|
||||
ariaLabel: ppcpConfig.title,
|
||||
canMakePayment: () => true,
|
||||
supports: {
|
||||
showSavedCards: true,
|
||||
features: ppcpConfig.supports,
|
||||
},
|
||||
} );
|
||||
|
||||
export default Axo;
|
Loading…
Add table
Add a link
Reference in a new issue