Skip to content
This repository has been archived by the owner on Feb 23, 2024. It is now read-only.

Commit

Permalink
Sync customer data during checkout with draft orders. (#4197)
Browse files Browse the repository at this point in the history
* Update store when email changes

* Add pluckEmail helper and convert to TS

* improve guard

* sync draft order with customer data
  • Loading branch information
mikejolley committed May 13, 2021
1 parent 3120dae commit 6a8e839
Show file tree
Hide file tree
Showing 4 changed files with 114 additions and 17 deletions.
29 changes: 23 additions & 6 deletions assets/js/base/context/hooks/use-customer-data.ts
Expand Up @@ -9,6 +9,7 @@ import isShallowEqual from '@wordpress/is-shallow-equal';
import {
formatStoreApiErrorMessage,
pluckAddress,
pluckEmail,
} from '@woocommerce/base-utils';
import type {
CartResponseBillingAddress,
Expand All @@ -26,8 +27,16 @@ declare type CustomerData = {
import { useStoreCart } from './cart/use-store-cart';
import { useStoreNotices } from './use-store-notices';

function instanceOfCartResponseBillingAddress(
address: CartResponseBillingAddress | CartResponseShippingAddress
): address is CartResponseBillingAddress {
return 'email' in address;
}

/**
* Does a shallow compare of important address data to determine if the cart needs updating.
* Does a shallow compare of important address data to determine if the cart needs updating on the server.
*
* This takes the current and previous address into account, as well as the billing email field.
*
* @param {Object} previousAddress An object containing all previous address information
* @param {Object} address An object containing all address information
Expand All @@ -40,12 +49,20 @@ const shouldUpdateAddressStore = <
previousAddress: T,
address: T
): boolean => {
if ( ! address.country ) {
return false;
if (
instanceOfCartResponseBillingAddress( address ) &&
pluckEmail( address ) !==
pluckEmail( previousAddress as CartResponseBillingAddress )
) {
return true;
}
return ! isShallowEqual(
pluckAddress( previousAddress ),
pluckAddress( address )

return (
!! address.country &&
! isShallowEqual(
pluckAddress( previousAddress ),
pluckAddress( address )
)
);
};

Expand Down
7 changes: 4 additions & 3 deletions assets/js/base/context/tsconfig.json
Expand Up @@ -8,9 +8,10 @@
"../../settings/blocks/index.ts",
"../../base/hooks/index.js",
"../utils/type-guards.ts",
"../../base/utils/",
"../../data/",
"../../type-defs"
"../../base/utils/",
"../../data/",
"../../type-defs",
"../components"
],
"exclude": [ "**/test/**" ]
}
Expand Up @@ -3,6 +3,11 @@
*/
import { defaultAddressFields } from '@woocommerce/settings';
import prepareAddressFields from '@woocommerce/base-components/cart-checkout/address-form/prepare-address-fields';
import { isEmail } from '@wordpress/url';
import type {
CartResponseBillingAddress,
CartResponseShippingAddress,
} from '@woocommerce/types';

/**
* pluckAddress takes a full address object and returns relevant fields for calculating
Expand All @@ -21,27 +26,60 @@ export const pluckAddress = ( {
state = '',
city = '',
postcode = '',
} ) => ( {
}: CartResponseBillingAddress | CartResponseShippingAddress ): {
country: string;
state: string;
city: string;
postcode: string;
} => ( {
country: country.trim(),
state: state.trim(),
city: city.trim(),
postcode: postcode ? postcode.replace( ' ', '' ).toUpperCase() : '',
} );

/**
* pluckEmail takes a full address object and returns only the email address, if set and valid. Otherwise returns an empty string.
*
* @param {Object} address An object containing all address information
* @param {string} address.email The email address.
* @return {string} The email address.
*/
export const pluckEmail = ( {
email = '',
}: CartResponseBillingAddress ): string =>
isEmail( email ) ? email.trim() : '';

/**
* Type-guard.
*/
const isValidAddressKey = (
key: string,
address: CartResponseBillingAddress | CartResponseShippingAddress
): key is keyof typeof address => {
return key in address;
};

/**
* Sets fields to an empty string in an address if they are hidden by the settings in countryLocale.
*
* @param {Object} address The address to empty fields from.
* @return {Object} The address with hidden fields values removed.
*/
export const emptyHiddenAddressFields = ( address ) => {
export const emptyHiddenAddressFields = <
T extends CartResponseBillingAddress | CartResponseShippingAddress
>(
address: T
): T => {
const fields = Object.keys( defaultAddressFields );
const addressFields = prepareAddressFields( fields, {}, address.country );
const newAddress = Object.assign( {}, address );
addressFields.forEach( ( field ) => {
if ( field.hidden ) {
newAddress[ field.key ] = '';
const newAddress = Object.assign( {}, address ) as T;

addressFields.forEach( ( { key = '', hidden = false } ) => {
if ( hidden && isValidAddressKey( key, address ) ) {
newAddress[ key ] = '';
}
} );

return newAddress;
};
45 changes: 43 additions & 2 deletions src/StoreApi/Routes/CartUpdateCustomer.php
Expand Up @@ -119,9 +119,50 @@ protected function get_route_post_response( \WP_REST_Request $request ) {
);
wc()->customer->save();

$cart->calculate_shipping();
$cart->calculate_totals();
$this->calculate_totals();
$this->maybe_update_order();

return rest_ensure_response( $this->schema->get_item_response( $cart ) );
}

/**
* If there is a draft order, update customer data there also.
*
* @return void
*/
protected function maybe_update_order() {
$draft_order_id = wc()->session->get( 'store_api_draft_order', 0 );
$draft_order = $draft_order_id ? wc_get_order( $draft_order_id ) : false;

if ( ! $draft_order ) {
return;
}

$draft_order->set_props(
[
'billing_first_name' => wc()->customer->get_billing_first_name(),
'billing_last_name' => wc()->customer->get_billing_last_name(),
'billing_company' => wc()->customer->get_billing_company(),
'billing_address_1' => wc()->customer->get_billing_address_1(),
'billing_address_2' => wc()->customer->get_billing_address_2(),
'billing_city' => wc()->customer->get_billing_city(),
'billing_state' => wc()->customer->get_billing_state(),
'billing_postcode' => wc()->customer->get_billing_postcode(),
'billing_country' => wc()->customer->get_billing_country(),
'billing_email' => wc()->customer->get_billing_email(),
'billing_phone' => wc()->customer->get_billing_phone(),
'shipping_first_name' => wc()->customer->get_shipping_first_name(),
'shipping_last_name' => wc()->customer->get_shipping_last_name(),
'shipping_company' => wc()->customer->get_shipping_company(),
'shipping_address_1' => wc()->customer->get_shipping_address_1(),
'shipping_address_2' => wc()->customer->get_shipping_address_2(),
'shipping_city' => wc()->customer->get_shipping_city(),
'shipping_state' => wc()->customer->get_shipping_state(),
'shipping_postcode' => wc()->customer->get_shipping_postcode(),
'shipping_country' => wc()->customer->get_shipping_country(),
]
);

$draft_order->save();
}
}

0 comments on commit 6a8e839

Please sign in to comment.