diff --git a/changelog/cart-pmme-total-updates b/changelog/cart-pmme-total-updates new file mode 100644 index 00000000000..d1a3379da0f --- /dev/null +++ b/changelog/cart-pmme-total-updates @@ -0,0 +1,5 @@ +Significance: patch +Type: add +Comment: Adding skeleton component to BNPL messaging on cart page which has not yet been deployed. + + diff --git a/client/product-details/bnpl-site-messaging/index.js b/client/product-details/bnpl-site-messaging/index.js index b0ebf24f054..a93981f5ef1 100644 --- a/client/product-details/bnpl-site-messaging/index.js +++ b/client/product-details/bnpl-site-messaging/index.js @@ -149,6 +149,58 @@ export const initializeBnplSiteMessaging = async () => { document .getElementById( 'payment-method-message' ) .classList.add( 'ready' ); + + // On the cart page, get the height of the PMME after it's rendered and store it in a CSS variable. This helps + // prevent layout shifts when the PMME is loaded asynchronously upon cart total update. + if ( isCart ) { + // An element that won't be removed with the cart total update. + const cartCollaterals = document.querySelector( + '.cart-collaterals' + ); + const wcBnplHeight = getComputedStyle( cartCollaterals ) + .getPropertyValue( '--wc-bnpl-height' ) + .trim(); + + if ( wcBnplHeight ) { + return; + } + + const pmme = document.getElementById( + 'payment-method-message' + ); + const pmmeContainer = document.querySelector( + '.cart_totals .__PrivateStripeElement' + ); + setTimeout( () => { + const pmmeComputedStyle = window.getComputedStyle( pmme ); + const pmmeHeight = parseFloat( pmmeComputedStyle.height ); + const pmmeMarginBottom = parseFloat( bottomMargin ); + const pmmeTotalHeight = pmmeHeight + pmmeMarginBottom; + + const pmmeContainerComputedStyle = window.getComputedStyle( + pmmeContainer + ); + const pmmeContainerHeight = parseFloat( + pmmeContainerComputedStyle.height + ); + + cartCollaterals.style.setProperty( + '--wc-bnpl-height', + pmmeTotalHeight + 'px' + ); + cartCollaterals.style.setProperty( + '--wc-bnpl-container-height', + pmmeContainerHeight - 12 + 'px' + ); + + cartCollaterals.style.setProperty( + '--wc-bnpl-loader-margin', + pmmeMarginBottom + 2 + 'px' + ); + + pmme.style.setProperty( '--wc-bnpl-margin-bottom', '-4px' ); + }, 2000 ); + } } ); } diff --git a/client/product-details/bnpl-site-messaging/style.scss b/client/product-details/bnpl-site-messaging/style.scss index 6ae65d7555c..243ea0d777d 100644 --- a/client/product-details/bnpl-site-messaging/style.scss +++ b/client/product-details/bnpl-site-messaging/style.scss @@ -17,13 +17,37 @@ } .cart_totals { - &:has( + #payment-method-message.ready ) { - margin-bottom: 0; + #payment-method-message { + margin: -8px 0 4px; + height: var( --wc-bnpl-height ); + padding: 2px 1em 0; + margin-bottom: var( --wc-bnpl-margin-bottom ); + + &.pmme-updated { + margin: -12px 0 0; + padding: 0 1em; + } + + &.skeleton { + margin-bottom: 4px; + background: #afafaf; + } } - #payment-method-message.ready { - margin-bottom: var( --wc-bnpl-margin-bottom ); - padding: 0 1em; + .pmme-loading { + animation: pmme-loading 1s linear infinite alternate; + background: #afafaf; + height: var( --wc-bnpl-container-height ); + margin: -4px 1em var( --wc-bnpl-loader-margin ) 1em; + } +} + +@keyframes pmme-loading { + 0% { + background-color: hsl( 204, 10%, 90% ); + } + 100% { + background-color: hsl( 200, 20%, 95% ); } } diff --git a/client/product-details/index.js b/client/product-details/index.js index 4ed333ad46d..0591b84e794 100644 --- a/client/product-details/index.js +++ b/client/product-details/index.js @@ -126,9 +126,19 @@ jQuery( async function ( $ ) { } ); $( document.body ).on( 'updated_cart_totals', () => { + $( '#payment-method-message' ).before( + '
' + ); + $( '#payment-method-message' ).hide(); bnplGetCartTotal().then( ( response ) => { window.wcpayStripeSiteMessaging.cartTotal = response.total; - initializeBnplSiteMessaging(); + initializeBnplSiteMessaging().then( () => { + setTimeout( () => { + $( '.pmme-loading' ).remove(); + $( '#payment-method-message' ).show(); + $( '#payment-method-message' ).addClass( 'pmme-updated' ); + }, 1000 ); + } ); } ); } );