From e3996b1f6e93f9b3ed82148ff562cfe34d252a99 Mon Sep 17 00:00:00 2001 From: Daniel Dudzic Date: Tue, 10 Sep 2024 18:46:27 +0200 Subject: [PATCH] Add Submit button --- .../ppcp-axo-block/resources/css/gateway.scss | 99 ++++++++++++++++- .../js/components/EmailSubmitButton.js | 102 ++++++++++++++++++ .../resources/js/helpers/classnamesManager.js | 102 ++++++++++++++++++ .../resources/js/helpers/watermarkHelpers.js | 65 +++++------ modules/ppcp-axo-block/resources/js/index.js | 9 ++ 5 files changed, 341 insertions(+), 36 deletions(-) create mode 100644 modules/ppcp-axo-block/resources/js/components/EmailSubmitButton.js create mode 100644 modules/ppcp-axo-block/resources/js/helpers/classnamesManager.js diff --git a/modules/ppcp-axo-block/resources/css/gateway.scss b/modules/ppcp-axo-block/resources/css/gateway.scss index ac62f1b4c..dfb405606 100644 --- a/modules/ppcp-axo-block/resources/css/gateway.scss +++ b/modules/ppcp-axo-block/resources/css/gateway.scss @@ -6,11 +6,6 @@ padding-right: 1em; } -.ppcp-axo-block-watermark-container { - float: right; - margin-top: 10px; -} - .wc-block-checkout-axo-block-card { display: flex; justify-content: center; @@ -81,3 +76,97 @@ .wc-block-axo-block-card__meta-icon { max-height: 25px; } + +.wp-block-woocommerce-checkout-express-payment-block { + transition: opacity .2s ease-in, + scale .2s ease-in, + display .4s ease-in; + /* key to transitioning out */ + transition-behavior: allow-discrete; + + /* stage enter */ + /* key to transitioning in */ + @starting-style { + opacity: 0; + scale: 1.1; + } + + &.wc-block-axo-is-authenticated { + opacity: 0; + scale: .9; + + /* hidden sets display: none, but loses easily */ + display: none !important; + + /* faster leaving the stage then entering */ + transition-duration: .2s; + transition-timing-function: var(--ease-out-5); + } +} + +.wc-block-axo-is-loaded .wc-block-components-text-input { + display: flex; +} + +.wc-block-axo-is-loaded .wc-block-components-text-input { + margin-bottom: 0.5em; +} + +.wc-block-checkout-axo-block-watermark-container { + margin-left: 5px; +} + +.wc-block-axo-is-loaded { + .wc-block-components-text-input { + display: grid; + grid-template-areas: + "input button" + "watermark watermark" + "error error"; + grid-template-columns: 1fr auto; + gap: 6px 8px; + align-items: start; + } + + &.wc-block-axo-is-authenticated .wc-block-components-text-input { + gap: 14px 0; + } + + .wc-block-components-text-input input[type="email"] { + grid-area: input; + width: 100%; + } + + .wc-block-axo-email-submit-button-container { + grid-area: button; + align-self: start; + } + + .wc-block-checkout-axo-block-watermark-container { + grid-area: watermark; + width: 100%; + } + + .wc-block-components-validation-error { + grid-area: error; + width: 100%; + margin-top: 4px; + } + + /* Ensure the button doesn't stretch */ + .wc-block-axo-email-submit-button-container .wc-block-components-button { + white-space: nowrap; + } + + /* Responsive adjustments */ + @media (max-width: 768px) { + .wc-block-components-text-input { + grid-template-areas: + "input" + "button" + "watermark" + "error"; + grid-template-columns: 1fr; + } + } +} diff --git a/modules/ppcp-axo-block/resources/js/components/EmailSubmitButton.js b/modules/ppcp-axo-block/resources/js/components/EmailSubmitButton.js new file mode 100644 index 000000000..7f156ffef --- /dev/null +++ b/modules/ppcp-axo-block/resources/js/components/EmailSubmitButton.js @@ -0,0 +1,102 @@ +import { createElement, createRoot } from '@wordpress/element'; +import { useSelect } from '@wordpress/data'; +import { STORE_NAME } from '../stores/axoStore'; + +const EmailSubmitButton = ( { onEmailSubmit } ) => { + const { isGuest, isAxoActive } = useSelect( ( select ) => ( { + isGuest: select( STORE_NAME ).getIsGuest(), + isAxoActive: select( STORE_NAME ).getIsAxoActive(), + } ) ); + + const handleSubmit = () => { + const emailInput = document.getElementById( 'email' ); + if ( emailInput && emailInput.value ) { + onEmailSubmit( emailInput.value ); + } + }; + + if ( ! isGuest || ! isAxoActive ) { + return null; + } + + return ( + + ); +}; + +// Setup and removal functions +let submitButtonReference = { + container: null, + root: null, +}; + +export const setupEmailSubmitButton = ( onEmailSubmit ) => { + const emailInput = document.getElementById( 'email' ); + + if ( emailInput ) { + if ( ! submitButtonReference.container ) { + submitButtonReference.container = document.createElement( 'div' ); + submitButtonReference.container.setAttribute( + 'class', + 'wc-block-axo-email-submit-button-container' + ); + + emailInput.parentNode.insertBefore( + submitButtonReference.container, + emailInput.nextSibling + ); + + submitButtonReference.root = createRoot( + submitButtonReference.container + ); + } + + if ( submitButtonReference.root ) { + const renderButton = () => { + submitButtonReference.root.render( + createElement( EmailSubmitButton, { onEmailSubmit } ) + ); + }; + + renderButton(); // Initial render + + // Subscribe to state changes + const unsubscribe = wp.data.subscribe( () => { + renderButton(); + } ); + + // Store the unsubscribe function for cleanup + submitButtonReference.unsubscribe = unsubscribe; + } else { + console.warn( 'Submit button root not found' ); + } + } else { + console.warn( 'Email input not found' ); + } +}; + +export const removeEmailSubmitButton = () => { + if ( submitButtonReference.root ) { + submitButtonReference.root.unmount(); + } + if ( submitButtonReference.unsubscribe ) { + submitButtonReference.unsubscribe(); + } + if ( + submitButtonReference.container && + submitButtonReference.container.parentNode + ) { + submitButtonReference.container.parentNode.removeChild( + submitButtonReference.container + ); + } + submitButtonReference = { container: null, root: null, unsubscribe: null }; +}; + +export default EmailSubmitButton; diff --git a/modules/ppcp-axo-block/resources/js/helpers/classnamesManager.js b/modules/ppcp-axo-block/resources/js/helpers/classnamesManager.js new file mode 100644 index 000000000..df2181164 --- /dev/null +++ b/modules/ppcp-axo-block/resources/js/helpers/classnamesManager.js @@ -0,0 +1,102 @@ +import { select, subscribe } from '@wordpress/data'; +import { STORE_NAME } from '../stores/axoStore'; + +/** + * Sets up a class toggle based on the isGuest state for the express payment block. + * @return {Function} Unsubscribe function for cleanup. + */ +export const setupAuthenticationClassToggle = () => { + const targetSelector = + '.wp-block-woocommerce-checkout-express-payment-block'; + const authClass = 'wc-block-axo-is-authenticated'; + + const updateAuthenticationClass = () => { + const targetElement = document.querySelector( targetSelector ); + if ( ! targetElement ) { + console.warn( `Target element not found: ${ targetSelector }` ); + return; + } + + const isGuest = select( STORE_NAME ).getIsGuest(); + + if ( ! isGuest ) { + targetElement.classList.add( authClass ); + } else { + targetElement.classList.remove( authClass ); + } + }; + + // Initial update + updateAuthenticationClass(); + + // Subscribe to state changes + const unsubscribe = subscribe( () => { + updateAuthenticationClass(); + } ); + + // Return the unsubscribe function for cleanup + return unsubscribe; +}; + +/** + * Sets up class toggles for the contact information block based on isAxoActive and isGuest states. + * @return {Function} Unsubscribe function for cleanup. + */ +export const setupContactInfoClassToggles = () => { + const targetSelector = + '.wp-block-woocommerce-checkout-contact-information-block'; + const axoLoadedClass = 'wc-block-axo-is-loaded'; + const authClass = 'wc-block-axo-is-authenticated'; + + const updateContactInfoClasses = () => { + const targetElement = document.querySelector( targetSelector ); + if ( ! targetElement ) { + console.warn( `Target element not found: ${ targetSelector }` ); + return; + } + + const isAxoActive = select( STORE_NAME ).getIsAxoActive(); + const isGuest = select( STORE_NAME ).getIsGuest(); + + if ( isAxoActive ) { + targetElement.classList.add( axoLoadedClass ); + } else { + targetElement.classList.remove( axoLoadedClass ); + } + + if ( ! isGuest ) { + targetElement.classList.add( authClass ); + } else { + targetElement.classList.remove( authClass ); + } + }; + + // Initial update + updateContactInfoClasses(); + + // Subscribe to state changes + const unsubscribe = subscribe( () => { + updateContactInfoClasses(); + } ); + + // Return the unsubscribe function for cleanup + return unsubscribe; +}; + +/** + * Initializes all class toggles. + * @return {Function} Cleanup function. + */ +export const initializeClassToggles = () => { + const unsubscribeAuth = setupAuthenticationClassToggle(); + const unsubscribeContactInfo = setupContactInfoClassToggles(); + + return () => { + if ( unsubscribeAuth ) { + unsubscribeAuth(); + } + if ( unsubscribeContactInfo ) { + unsubscribeContactInfo(); + } + }; +}; diff --git a/modules/ppcp-axo-block/resources/js/helpers/watermarkHelpers.js b/modules/ppcp-axo-block/resources/js/helpers/watermarkHelpers.js index 4059b094e..dfc69eb6e 100644 --- a/modules/ppcp-axo-block/resources/js/helpers/watermarkHelpers.js +++ b/modules/ppcp-axo-block/resources/js/helpers/watermarkHelpers.js @@ -17,50 +17,53 @@ const WatermarkManager = ( { fastlaneSdk } ) => { ); useEffect( () => { - const emailInput = document.getElementById( 'email' ); + const textInputContainer = document.querySelector( + '.wp-block-woocommerce-checkout-contact-information-block .wc-block-components-text-input' + ); - if ( emailInput ) { - if ( ! watermarkReference.container ) { - watermarkReference.container = document.createElement( 'div' ); - watermarkReference.container.setAttribute( - 'class', - 'ppcp-axo-block-watermark-container' - ); + if ( textInputContainer ) { + const emailInput = textInputContainer.querySelector( + 'input[type="email"]' + ); - const emailLabel = - emailInput.parentNode.querySelector( 'label[for="email"]' ); - if ( emailLabel ) { - emailLabel.parentNode.insertBefore( - watermarkReference.container, - emailLabel.nextSibling + if ( emailInput ) { + if ( ! watermarkReference.container ) { + watermarkReference.container = + document.createElement( 'div' ); + watermarkReference.container.setAttribute( + 'class', + 'wc-block-checkout-axo-block-watermark-container' ); - } else { + + // Insert the watermark container after the email input emailInput.parentNode.insertBefore( watermarkReference.container, emailInput.nextSibling ); + + watermarkReference.root = createRoot( + watermarkReference.container + ); } - watermarkReference.root = createRoot( - watermarkReference.container - ); - } - - if ( watermarkReference.root && isAxoActive ) { - watermarkReference.root.render( - createElement( FastlaneWatermark, { - fastlaneSdk, - name: 'fastlane-watermark-email', - includeAdditionalInfo: isGuest, - } ) - ); + if ( watermarkReference.root && isAxoActive ) { + watermarkReference.root.render( + createElement( FastlaneWatermark, { + fastlaneSdk, + name: 'fastlane-watermark-email', + includeAdditionalInfo: isGuest, + } ) + ); + } else if ( ! isAxoActive && watermarkReference.root ) { + watermarkReference.root.render( null ); + } } else { - console.warn( 'Watermark root not found' ); + console.warn( 'Email input not found' ); } } else { - console.warn( 'Email input not found' ); + console.warn( 'Text input container not found' ); } - }, [ fastlaneSdk, isGuest ] ); + }, [ fastlaneSdk, isGuest, isAxoActive ] ); return null; }; diff --git a/modules/ppcp-axo-block/resources/js/index.js b/modules/ppcp-axo-block/resources/js/index.js index 8c8359391..e629fe9bc 100644 --- a/modules/ppcp-axo-block/resources/js/index.js +++ b/modules/ppcp-axo-block/resources/js/index.js @@ -21,6 +21,7 @@ import { snapshotFields, restoreOriginalFields } from './helpers/fieldHelpers'; import { removeWatermark, setupWatermark } from './helpers/watermarkHelpers'; import { removeCardChangeButton } from './helpers/cardChangeButtonManager'; import { removeShippingChangeButton } from './helpers/shippingChangeButtonManager'; +import { initializeClassToggles } from './helpers/classnamesManager'; // Stores import { STORE_NAME } from './stores/axoStore'; @@ -32,6 +33,7 @@ import { removeEmailEvent, isEmailEventSetup, } from './helpers/emailHelpers'; +import { setupEmailSubmitButton } from './components/EmailSubmitButton'; const ppcpConfig = wc.wcSettings.getSetting( 'ppcp-credit-card-gateway_data' ); @@ -66,6 +68,10 @@ const Axo = () => { console.log( 'isAxoActive updated:', isAxoActive ); }, [ isAxoActive ] ); + useEffect( () => { + initializeClassToggles(); + }, [] ); + useEffect( () => { return () => { // Restore WooCommerce fields @@ -141,6 +147,9 @@ const Axo = () => { console.log( 'Enabling Axo' ); setIsAxoActive( true ); setupWatermark( fastlaneSdk ); + setupEmailSubmitButton( async ( email ) => { + await onEmailSubmit( email ); + } ); setupEmailEvent( handleEmailInputRef.current ); } }, [ paypalLoaded, fastlaneSdk, setIsAxoActive ] );