Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refresh page when ECE is dismissed #9888

Merged
merged 35 commits into from
Dec 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
4a45962
Add condition to identify button context when dismissed
rafaelzaleski Dec 5, 2024
e1be2e2
Add flag to control if a refresh is needed.
rafaelzaleski Dec 5, 2024
21e38d7
Simplify logic to refresh page.
rafaelzaleski Dec 5, 2024
c03c229
Add changelog
rafaelzaleski Dec 5, 2024
ffa1286
Add prototype for shortcode cart handling
rafaelzaleski Dec 11, 2024
41d527c
remove unused comment
rafaelzaleski Dec 12, 2024
46defc4
create helper to interact with shortcode fields
rafaelzaleski Dec 12, 2024
0db8da6
Only update UI in the cancel event
rafaelzaleski Dec 12, 2024
84ced5a
Add shortcodeCheckout to utils index
rafaelzaleski Dec 12, 2024
ee2b1d2
use select2 triggers for cart interactions
rafaelzaleski Dec 12, 2024
eaf650d
Update shipping addr on blocks cart and checkout
rafaelzaleski Dec 12, 2024
8cfe829
Merge branch 'develop' into fix/9794-refresh-page-when-ece-dismissed
rafaelzaleski Dec 12, 2024
c04f201
Remove console statements
rafaelzaleski Dec 16, 2024
752a88e
Remove todo comment and add check for cart data store
rafaelzaleski Dec 16, 2024
7d8c479
Remove code redundancy
rafaelzaleski Dec 16, 2024
b399fb6
Simplify assignment of last addr
rafaelzaleski Dec 16, 2024
e57f86a
Rename utils file
rafaelzaleski Dec 16, 2024
5ca6d08
Simplify null check in updateShortcodeField
rafaelzaleski Dec 16, 2024
959eb6e
Merge branch 'develop' into fix/9794-refresh-page-when-ece-dismissed
rafaelzaleski Dec 16, 2024
0e665d7
Add doc to new functions
rafaelzaleski Dec 16, 2024
f68ea83
Rename util
rafaelzaleski Dec 16, 2024
b5a0e47
Add reset to lastSelectedAddress in the onCancelHandler
rafaelzaleski Dec 16, 2024
1831e70
Add doc for updateShortcodeField
rafaelzaleski Dec 16, 2024
64f118e
Add implementation for tokenized express checkout
rafaelzaleski Dec 16, 2024
86f69cf
Remove update for CA and GB addresses
rafaelzaleski Dec 16, 2024
c0728be
Add comment to clarify why CA and UK addresses are not included
rafaelzaleski Dec 16, 2024
ce9aa79
Mirror code for tokenized ece
rafaelzaleski Dec 16, 2024
b47ab71
Refactor logic to determine countries with redacted addresses
rafaelzaleski Dec 17, 2024
08d18fc
Add logic to fallback to option text when value is not found
rafaelzaleski Dec 17, 2024
42dad17
Remove comment for external dependencies
rafaelzaleski Dec 17, 2024
240576d
Merge branch 'develop' into fix/9794-refresh-page-when-ece-dismissed
rafaelzaleski Dec 17, 2024
ec81858
Fix comparison to be case-insensitive.
rafaelzaleski Dec 17, 2024
80f40dc
Copy changes to tokenized carts.
rafaelzaleski Dec 17, 2024
20c4e42
Remove redundant check in isPostcodeRedactedForCountry
rafaelzaleski Dec 17, 2024
9dd5e1d
Merge branch 'develop' into fix/9794-refresh-page-when-ece-dismissed
rafaelzaleski Dec 17, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 );
}
}
};
Loading