From d43bb39339e2c52b5c78fe9aa9f28ad9a0b08317 Mon Sep 17 00:00:00 2001 From: Payton Swick Date: Mon, 9 Dec 2024 13:27:44 -0500 Subject: [PATCH] Checkout: Break cache of PayPal PPCP payment method button when cart changes or cancelling (#97253) * Break cache of PayPalButtons when cancelling payment * Break cache of PayPalButtons when cart changes --- .../checkout/src/payment-methods/paypal-js.tsx | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/client/my-sites/checkout/src/payment-methods/paypal-js.tsx b/client/my-sites/checkout/src/payment-methods/paypal-js.tsx index 84bfce2f0f4214..54eb2cced35f93 100644 --- a/client/my-sites/checkout/src/payment-methods/paypal-js.tsx +++ b/client/my-sites/checkout/src/payment-methods/paypal-js.tsx @@ -13,7 +13,7 @@ import { } from '@paypal/react-paypal-js'; import debugFactory from 'debug'; import { useTranslate } from 'i18n-calypso'; -import { useEffect } from 'react'; +import { useEffect, useState } from 'react'; import useCartKey from 'calypso/my-sites/checkout/use-cart-key'; import { PaymentMethodLogos } from '../components/payment-method-logos'; @@ -81,6 +81,9 @@ function PayPalSubmitButton( { } ) { const translate = useTranslate(); const togglePaymentMethod = useTogglePaymentMethod(); + const [ forceReRender, setForceReRender ] = useState< number >( 0 ); + const cartKey = useCartKey(); + const { responseCart } = useShoppingCart( cartKey ); // Wait for PayPal.js to load before marking this payment method as active. const [ { isResolved, isPending } ] = usePayPalScriptReducer(); @@ -90,6 +93,14 @@ function PayPalSubmitButton( { } }, [ isResolved, togglePaymentMethod ] ); + useEffect( () => { + debug( 'cart changed; rerendering PayPalSubmitButton' ); + // The PayPalButtons component appears to cache certain data about the + // order process and in order to make sure it has the latest data, we + // have to use the `forceReRender` prop. + setForceReRender( ( val ) => val + 1 ); + }, [ responseCart ] ); + // We have to wait for the active payment method to switch because the // contents of the `onClick` function will change when the active state // changes and if we render `PayPalButtons` too soon it will keep the old @@ -139,6 +150,10 @@ function PayPalSubmitButton( { const onCancel: PayPalButtonsComponentProps[ 'onCancel' ] = async () => { debug( 'order cancelled' ); + // The PayPalButtons component appears to cache certain data about the + // order process and in order to make sure it has the latest data, we + // have to use the `forceReRender` prop. + setForceReRender( ( val ) => val + 1 ); rejectPayPalApprovalPromise( new Error( translate( 'The PayPal transaction was not approved.' ) ) ); @@ -176,6 +191,7 @@ function PayPalSubmitButton( { // transaction system that the purchase is complete. return (