Skip to content

Commit

Permalink
Refresh page when ECE is dismissed (#9888)
Browse files Browse the repository at this point in the history
  • Loading branch information
rafaelzaleski authored Dec 17, 2024
1 parent 0c7422e commit 129fe05
Show file tree
Hide file tree
Showing 7 changed files with 291 additions and 1 deletion.
4 changes: 4 additions & 0 deletions changelog/fix-9794-refresh-page-when-ece-dismissed
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Significance: patch
Type: add

Refresh the cart and checkout pages when ECE is dismissed and the shipping options were modified in the payment sheet.
10 changes: 10 additions & 0 deletions client/express-checkout/event-handlers.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,15 @@ import {
normalizeShippingAddress,
normalizeLineItems,
getExpressCheckoutData,
updateShippingAddressUI,
} from './utils';
import {
trackExpressCheckoutButtonClick,
trackExpressCheckoutButtonLoad,
} from './tracking';

let lastSelectedAddress = null;

export const shippingAddressChangeHandler = async ( api, event, elements ) => {
try {
const response = await api.expressCheckoutECECalculateShippingOptions(
Expand All @@ -29,6 +32,9 @@ export const shippingAddressChangeHandler = async ( api, event, elements ) => {
elements.update( {
amount: response.total.amount,
} );

lastSelectedAddress = event.address;

event.resolve( {
shippingRates: response.shipping_options,
lineItems: normalizeLineItems( response.displayItems ),
Expand Down Expand Up @@ -171,5 +177,9 @@ export const onCompletePaymentHandler = () => {
};

export const onCancelHandler = () => {
if ( lastSelectedAddress ) {
updateShippingAddressUI( lastSelectedAddress );
}
lastSelectedAddress = null;
unblockUI();
};
1 change: 1 addition & 0 deletions client/express-checkout/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
* Internal dependencies
*/
export * from './normalize';
export * from './shipping-fields';
import { getDefaultBorderRadius } from 'wcpay/utils/express-checkout';

interface MyWindow extends Window {
Expand Down
131 changes: 131 additions & 0 deletions client/express-checkout/utils/shipping-fields.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
/* global jQuery */
/**
* Internal dependencies
*/
import { normalizeShippingAddress, getExpressCheckoutData } from '.';

/**
* Checks if the intermediate address is redacted for the given country.
* CA and GB addresses are redacted and are causing errors until WooCommerce is able to
* handle redacted addresses.
* https://developers.google.com/pay/api/web/reference/response-objects#IntermediateAddress
*
* @param {string} country - The country code.
*
* @return {boolean} True if the postcode is redacted for the country, false otherwise.
*/
const isPostcodeRedactedForCountry = ( country ) => {
return [ 'CA', 'GB' ].includes( country );
};

/*
* Updates a field in a form with a new value.
*
* @param {String} formSelector - The selector for the form containing the field.
* @param {Object} fieldName - The name of the field to update.
* @param {Object} value - The new value for the field.
*/
const updateShortcodeField = ( formSelector, fieldName, value ) => {
const field = document.querySelector(
`${ formSelector } [name="${ fieldName }"]`
);

if ( ! field ) return;

// Check if the field is a dropdown (country/state).
if ( field.tagName === 'SELECT' && /country|state/.test( fieldName ) ) {
const options = Array.from( field.options );
const match = options.find(
( opt ) =>
opt.value === value ||
opt.textContent.trim().toLowerCase() === value.toLowerCase()
);

if ( match ) {
field.value = match.value;
jQuery( field ).trigger( 'change' ).trigger( 'close' );
}
} else {
// Default behavior for text inputs.
field.value = value;
jQuery( field ).trigger( 'change' );
}
};

/**
* Updates the WooCommerce Blocks shipping UI to reflect a new shipping address.
*
* @param {Object} eventAddress - The shipping address returned by the payment event.
*/
const updateBlocksShippingUI = ( eventAddress ) => {
wp?.data
?.dispatch( 'wc/store/cart' )
?.setShippingAddress( normalizeShippingAddress( eventAddress ) );
};

/**
* Updates the WooCommerce shortcode cart/checkout shipping UI to reflect a new shipping address.
*
* @param {Object} eventAddress - The shipping address returned by the payment event.
*/
const updateShortcodeShippingUI = ( eventAddress ) => {
const context = getExpressCheckoutData( 'button_context' );
const address = normalizeShippingAddress( eventAddress );

const keys = [ 'country', 'state', 'city', 'postcode' ];

if ( context === 'cart' ) {
keys.forEach( ( key ) => {
if ( address[ key ] ) {
updateShortcodeField(
'form.woocommerce-shipping-calculator',
`calc_shipping_${ key }`,
address[ key ]
);
}
} );
document
.querySelector(
'form.woocommerce-shipping-calculator [name="calc_shipping"]'
)
?.click();
} else if ( context === 'checkout' ) {
keys.forEach( ( key ) => {
if ( address[ key ] ) {
updateShortcodeField(
'form.woocommerce-checkout',
`billing_${ key }`,
address[ key ]
);
}
} );
}
};

/**
* Updates the WooCommerce shipping UI to reflect a new shipping address.
*
* Determines the current context (cart or checkout) and updates either
* WooCommerce Blocks or shortcode-based shipping forms, if applicable.
*
* @param {Object} newAddress - The new shipping address object returned by the payment event.
* @param {string} newAddress.country - The country code of the shipping address.
* @param {string} [newAddress.state] - The state/province of the shipping address.
* @param {string} [newAddress.city] - The city of the shipping address.
* @param {string} [newAddress.postcode] - The postal/ZIP code of the shipping address.
*/
export const updateShippingAddressUI = ( newAddress ) => {
const context = getExpressCheckoutData( 'button_context' );
const isBlocks = getExpressCheckoutData( 'has_block' );

if (
[ 'cart', 'checkout' ].includes( context ) &&
! isPostcodeRedactedForCountry( newAddress.country )
) {
if ( isBlocks ) {
updateBlocksShippingUI( newAddress );
} else {
updateShortcodeShippingUI( newAddress );
}
}
};
14 changes: 13 additions & 1 deletion client/tokenized-express-checkout/event-handlers.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,11 @@ import { applyFilters } from '@wordpress/hooks';
/**
* Internal dependencies
*/
import { getErrorMessageFromNotice, getExpressCheckoutData } from './utils';
import {
getErrorMessageFromNotice,
getExpressCheckoutData,
updateShippingAddressUI,
} from './utils';
import {
trackExpressCheckoutButtonClick,
trackExpressCheckoutButtonLoad,
Expand All @@ -24,6 +28,7 @@ import {
transformPrice,
} from './transformers/wc-to-stripe';

let lastSelectedAddress = null;
let cartApi = new ExpressCheckoutCartApi();
export const setCartApiHandler = ( handler ) => ( cartApi = handler );
export const getCartApiHandler = () => cartApi;
Expand Down Expand Up @@ -56,6 +61,9 @@ export const shippingAddressChangeHandler = async ( event, elements ) => {
cartData.totals
),
} );

lastSelectedAddress = event.address;

event.resolve( {
shippingRates: transformCartDataForShippingRates( cartData ),
lineItems: transformCartDataForDisplayItems( cartData ),
Expand Down Expand Up @@ -216,5 +224,9 @@ export const onCompletePaymentHandler = () => {
};

export const onCancelHandler = () => {
if ( lastSelectedAddress ) {
updateShippingAddressUI( lastSelectedAddress );
}
lastSelectedAddress = null;
unblockUI();
};
1 change: 1 addition & 0 deletions client/tokenized-express-checkout/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
*/
import { WCPayExpressCheckoutParams } from 'wcpay/express-checkout/utils';
export * from './normalize';
export * from './shipping-fields';
import { getDefaultBorderRadius } from 'wcpay/utils/express-checkout';

export const getExpressCheckoutData = <
Expand Down
131 changes: 131 additions & 0 deletions client/tokenized-express-checkout/utils/shipping-fields.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
/* global jQuery */
/**
* Internal dependencies
*/
import { normalizeShippingAddress, getExpressCheckoutData } from '.';

/**
* Checks if the intermediate address is redacted for the given country.
* CA and GB addresses are redacted and are causing errors until WooCommerce is able to
* handle redacted addresses.
* https://developers.google.com/pay/api/web/reference/response-objects#IntermediateAddress
*
* @param {string} country - The country code.
*
* @return {boolean} True if the postcode is redacted for the country, false otherwise.
*/
const isPostcodeRedactedForCountry = ( country ) => {
return [ 'CA', 'GB' ].includes( country );
};

/*
* Updates a field in a form with a new value.
*
* @param {String} formSelector - The selector for the form containing the field.
* @param {Object} fieldName - The name of the field to update.
* @param {Object} value - The new value for the field.
*/
const updateShortcodeField = ( formSelector, fieldName, value ) => {
const field = document.querySelector(
`${ formSelector } [name="${ fieldName }"]`
);

if ( ! field ) return;

// Check if the field is a dropdown (country/state).
if ( field.tagName === 'SELECT' && /country|state/.test( fieldName ) ) {
const options = Array.from( field.options );
const match = options.find(
( opt ) =>
opt.value === value ||
opt.textContent.trim().toLowerCase() === value.toLowerCase()
);

if ( match ) {
field.value = match.value;
jQuery( field ).trigger( 'change' ).trigger( 'close' );
}
} else {
// Default behavior for text inputs.
field.value = value;
jQuery( field ).trigger( 'change' );
}
};

/**
* Updates the WooCommerce Blocks shipping UI to reflect a new shipping address.
*
* @param {Object} eventAddress - The shipping address returned by the payment event.
*/
const updateBlocksShippingUI = ( eventAddress ) => {
wp?.data
?.dispatch( 'wc/store/cart' )
?.setShippingAddress( normalizeShippingAddress( eventAddress ) );
};

/**
* Updates the WooCommerce shortcode cart/checkout shipping UI to reflect a new shipping address.
*
* @param {Object} eventAddress - The shipping address returned by the payment event.
*/
const updateShortcodeShippingUI = ( eventAddress ) => {
const context = getExpressCheckoutData( 'button_context' );
const address = normalizeShippingAddress( eventAddress );

const keys = [ 'country', 'state', 'city', 'postcode' ];

if ( context === 'cart' ) {
keys.forEach( ( key ) => {
if ( address[ key ] ) {
updateShortcodeField(
'form.woocommerce-shipping-calculator',
`calc_shipping_${ key }`,
address[ key ]
);
}
} );
document
.querySelector(
'form.woocommerce-shipping-calculator [name="calc_shipping"]'
)
?.click();
} else if ( context === 'checkout' ) {
keys.forEach( ( key ) => {
if ( address[ key ] ) {
updateShortcodeField(
'form.woocommerce-checkout',
`billing_${ key }`,
address[ key ]
);
}
} );
}
};

/**
* Updates the WooCommerce shipping UI to reflect a new shipping address.
*
* Determines the current context (cart or checkout) and updates either
* WooCommerce Blocks or shortcode-based shipping forms, if applicable.
*
* @param {Object} newAddress - The new shipping address object returned by the payment event.
* @param {string} newAddress.country - The country code of the shipping address.
* @param {string} [newAddress.state] - The state/province of the shipping address.
* @param {string} [newAddress.city] - The city of the shipping address.
* @param {string} [newAddress.postcode] - The postal/ZIP code of the shipping address.
*/
export const updateShippingAddressUI = ( newAddress ) => {
const context = getExpressCheckoutData( 'button_context' );
const isBlocks = getExpressCheckoutData( 'has_block' );

if (
[ 'cart', 'checkout' ].includes( context ) &&
! isPostcodeRedactedForCountry( newAddress.country )
) {
if ( isBlocks ) {
updateBlocksShippingUI( newAddress );
} else {
updateShortcodeShippingUI( newAddress );
}
}
};

0 comments on commit 129fe05

Please sign in to comment.