Skip to content

Commit 13e7fa4

Browse files
committed
fix: update payment request amounts on cart changes in blocks checkout
Apple/Google Pay and PayPal blocks components now subscribe to WooCommerce cart totals and recreate components when amounts change (e.g., shipping method changes, coupons applied). Classic checkout already had this logic. - Add useSelect hook to subscribe to cart totals - Add refs for tracking (lastAmountRef, isInitializedRef) - Create updateAmount functions to recreate components - Split useEffect for init/update/cleanup lifecycle
1 parent eaf9107 commit 13e7fa4

File tree

3 files changed

+303
-38
lines changed

3 files changed

+303
-38
lines changed

assets/js/components/monei-apple-google-component.js

Lines changed: 115 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ export const createAppleGoogleLabel = ( moneiData ) => {
4141
*/
4242
export const MoneiAppleGoogleContent = ( props ) => {
4343
const { useEffect, useRef, useState, createPortal } = wp.element;
44+
const { useSelect } = wp.data;
4445
const { onPaymentSetup, onCheckoutSuccess } = props.eventRegistration;
4546
const { activePaymentMethod } = props;
4647
const moneiData =
@@ -49,8 +50,15 @@ export const MoneiAppleGoogleContent = ( props ) => {
4950
wc.wcSettings.getSetting( 'monei_apple_google_data' );
5051

5152
const paymentRequestRef = useRef( null );
53+
const lastAmountRef = useRef( null );
54+
const isInitializedRef = useRef( false );
5255
const [ isConfirming, setIsConfirming ] = useState( false );
5356
const [ error, setError ] = useState( '' );
57+
58+
// Subscribe to cart totals
59+
const cartTotals = useSelect( ( select ) => {
60+
return select( 'wc/store/cart' ).getCartTotals();
61+
}, [] );
5462
const isActive =
5563
activePaymentMethod ===
5664
( props.paymentMethodId || 'monei_apple_google' );
@@ -72,6 +80,12 @@ export const MoneiAppleGoogleContent = ( props ) => {
7280
return;
7381
}
7482

83+
const currentTotal = cartTotals?.total_price
84+
? parseInt( cartTotals.total_price )
85+
: Math.round( moneiData.total * 100 );
86+
87+
lastAmountRef.current = currentTotal;
88+
7589
// Clean up existing instance
7690
if ( paymentRequestRef.current?.close ) {
7791
try {
@@ -81,12 +95,23 @@ export const MoneiAppleGoogleContent = ( props ) => {
8195
}
8296
}
8397

98+
const container = document.getElementById(
99+
'payment-request-container'
100+
);
101+
if ( ! container ) {
102+
console.error( 'Payment request container not found' );
103+
return;
104+
}
105+
106+
// Clear container
107+
container.innerHTML = '';
108+
84109
// eslint-disable-next-line no-undef
85110
const paymentRequest = monei.PaymentRequest( {
86111
accountId: moneiData.accountId,
87112
sessionId: moneiData.sessionId,
88113
language: moneiData.language,
89-
amount: Math.round( moneiData.total * 100 ),
114+
amount: currentTotal,
90115
currency: moneiData.currency,
91116
style: moneiData.paymentRequestStyle || {},
92117
onSubmit( result ) {
@@ -106,19 +131,103 @@ export const MoneiAppleGoogleContent = ( props ) => {
106131
},
107132
} );
108133

109-
const container = document.getElementById(
110-
'payment-request-container'
111-
);
112-
if ( container ) {
134+
paymentRequest.render( container );
135+
paymentRequestRef.current = paymentRequest;
136+
};
137+
138+
/**
139+
* Update the amount in the existing Payment Request instance
140+
*/
141+
const updatePaymentRequestAmount = () => {
142+
const currentTotal = cartTotals?.total_price
143+
? parseInt( cartTotals.total_price )
144+
: Math.round( moneiData.total * 100 );
145+
146+
// Only update if amount actually changed
147+
if ( currentTotal === lastAmountRef.current ) {
148+
return;
149+
}
150+
151+
lastAmountRef.current = currentTotal;
152+
153+
if ( paymentRequestRef.current ) {
154+
// Clean up existing instance
155+
if ( paymentRequestRef.current?.close ) {
156+
try {
157+
paymentRequestRef.current.close();
158+
} catch ( e ) {
159+
// Silent fail
160+
}
161+
}
162+
163+
const container = document.getElementById(
164+
'payment-request-container'
165+
);
166+
if ( ! container ) {
167+
return;
168+
}
169+
170+
// Clear container
171+
container.innerHTML = '';
172+
173+
// eslint-disable-next-line no-undef
174+
const paymentRequest = monei.PaymentRequest( {
175+
accountId: moneiData.accountId,
176+
sessionId: moneiData.sessionId,
177+
language: moneiData.language,
178+
amount: currentTotal,
179+
currency: moneiData.currency,
180+
style: moneiData.paymentRequestStyle || {},
181+
onSubmit( result ) {
182+
if ( result.token ) {
183+
setError( '' );
184+
buttonManager.enableCheckout( result.token );
185+
}
186+
},
187+
onError( error ) {
188+
const errorMessage =
189+
error.message ||
190+
`${ error.status || 'Error' } ${
191+
error.statusCode ? `(${ error.statusCode })` : ''
192+
}`;
193+
setError( errorMessage );
194+
console.error( 'Payment Request error:', error );
195+
},
196+
} );
197+
113198
paymentRequest.render( container );
114199
paymentRequestRef.current = paymentRequest;
115200
}
116201
};
117202

118203
// Initialize on mount
119204
useEffect( () => {
120-
initPaymentRequest();
205+
// eslint-disable-next-line no-undef
206+
if (
207+
typeof monei !== 'undefined' &&
208+
monei.PaymentRequest &&
209+
! isInitializedRef.current
210+
) {
211+
initPaymentRequest();
212+
isInitializedRef.current = true;
213+
} else if ( ! monei || ! monei.PaymentRequest ) {
214+
console.error( 'MONEI SDK is not available' );
215+
}
216+
}, [] );
217+
218+
// Update amount when cart totals change
219+
useEffect( () => {
220+
if (
221+
isInitializedRef.current &&
222+
paymentRequestRef.current &&
223+
cartTotals
224+
) {
225+
updatePaymentRequestAmount();
226+
}
227+
}, [ cartTotals ] );
121228

229+
// Cleanup on unmount
230+
useEffect( () => {
122231
return () => {
123232
if ( paymentRequestRef.current?.close ) {
124233
try {

assets/js/monei-apple-google-classic.js

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
data.fragments.monei_new_total
1111
) {
1212
wc_monei_form.total = data.fragments.monei_new_total;
13+
// Reset to allow re-initialization
14+
wc_monei_form.init_apple_counter = 0;
1315
}
1416

1517
if ( wc_monei_form.is_apple_selected() ) {
@@ -183,14 +185,21 @@
183185
);
184186
}
185187

186-
wc_monei_form.instantiate_payment_request();
188+
wc_monei_form.init_apple_google_component();
187189
wc_monei_form.$payment_request_container = document.getElementById(
188190
'payment-request-container'
189191
);
190192

191193
// We already init the button.
192194
this.init_apple_counter++;
193195
},
196+
init_apple_google_component() {
197+
if ( window.paymentRequest ) {
198+
window.paymentRequest.close();
199+
}
200+
// Total amount updated
201+
wc_monei_form.instantiate_payment_request();
202+
},
194203
instantiate_payment_request() {
195204
const paymentRequest = monei.PaymentRequest( {
196205
accountId: wc_monei_apple_google_params.accountId,

0 commit comments

Comments
 (0)