Try move shipping related dat to a `@wordpress/data` store (https://github.com/woocommerce/woocommerce-blocks/pull/5896)
* Add address-related items to wc/store/cart data store * Add useUpdateCustomerData hook This allows us to have a single hook responsible for updating the customer information on the server. * Add useUpdateCustomerData hook in Checkout block * Remove shippingAsBilling from previousCustomerData ref type * Add useShippingAsBillingCheckbox hook * Remove checkbox handling from useCheckoutAddress * Merge with woocommerce/woocommerce-blocks#5810 changes * Move shipping as billing to checkout state context provider * Subscribe to changes * Cache customerDataToUpdate * Combine customerDataType and customerDataContextType * Fix notice context * Clean up inline docs for push changes * Add useShippingData hook * Add shipping related selectors to cart store * Update useShippingDataContext to useCustomerData hook * Update uses of useShippingDataContext to get data from hook instead * Remove rogue linebreak * Re-add linebreak * Re-add linebreak, remove shippingAsBilling * Re-add linebreak * Use useShippingData and useCustomerData instead of context * Fix fromEntriesPolyfill to use number or undefined as an index option * Convert derive-selected-shipping-rates to TS * Add SelectShippingRateType * Get needsShipping from new hook and not context * Get address data from useCustomerData instead of useShippingDataContext * Move selectedRates, selectShippingRate and isSelectingRate * Remove items from ShippingDatacontext that are available in data stores * Get shipping data from stores, not context in payment method interface * Consider shipping rates to be loading if customer data is updating * Get rates from useShippingData hook instead of context * Fix incorrect TypeScript types and incorrectly named destructure * Move useShippingData into shipping folder * Update tests to mock useShippingData instead of context * Remove empty string fallback from shipping phone * Get types from Cart declaration instead of Picking them Co-authored-by: Mike Jolley <mike.jolley@me.com>
This commit is contained in:
parent
719c7f7c23
commit
6b8ef2773a
|
@ -1,8 +1,8 @@
|
||||||
/**
|
/**
|
||||||
* External dependencies
|
* External dependencies
|
||||||
*/
|
*/
|
||||||
import { useShippingDataContext } from '@woocommerce/base-context';
|
|
||||||
import type { EnteredAddress } from '@woocommerce/settings';
|
import type { EnteredAddress } from '@woocommerce/settings';
|
||||||
|
import { useCustomerData } from '@woocommerce/base-context/hooks';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal dependencies
|
* Internal dependencies
|
||||||
|
@ -21,7 +21,7 @@ const ShippingCalculator = ( {
|
||||||
},
|
},
|
||||||
addressFields = [ 'country', 'state', 'city', 'postcode' ],
|
addressFields = [ 'country', 'state', 'city', 'postcode' ],
|
||||||
}: ShippingCalculatorProps ): JSX.Element => {
|
}: ShippingCalculatorProps ): JSX.Element => {
|
||||||
const { shippingAddress, setShippingAddress } = useShippingDataContext();
|
const { shippingAddress, setShippingAddress } = useCustomerData();
|
||||||
return (
|
return (
|
||||||
<div className="wc-block-components-shipping-calculator">
|
<div className="wc-block-components-shipping-calculator">
|
||||||
<ShippingCalculatorAddress
|
<ShippingCalculatorAddress
|
||||||
|
|
|
@ -23,6 +23,7 @@ import { usePaymentMethodDataContext } from '../../providers/cart-checkout/payme
|
||||||
import { useShippingDataContext } from '../../providers/cart-checkout/shipping';
|
import { useShippingDataContext } from '../../providers/cart-checkout/shipping';
|
||||||
import { useCustomerDataContext } from '../../providers/cart-checkout/customer';
|
import { useCustomerDataContext } from '../../providers/cart-checkout/customer';
|
||||||
import { prepareTotalItems } from './utils';
|
import { prepareTotalItems } from './utils';
|
||||||
|
import { useShippingData } from '../shipping/use-shipping-data';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns am interface to use as payment method props.
|
* Returns am interface to use as payment method props.
|
||||||
|
@ -50,17 +51,19 @@ export const usePaymentMethodInterface = (): PaymentMethodInterface => {
|
||||||
const {
|
const {
|
||||||
shippingErrorStatus,
|
shippingErrorStatus,
|
||||||
shippingErrorTypes,
|
shippingErrorTypes,
|
||||||
shippingRates,
|
|
||||||
shippingRatesLoading,
|
|
||||||
selectedRates,
|
|
||||||
setSelectedRates,
|
|
||||||
isSelectingRate,
|
|
||||||
onShippingRateSuccess,
|
onShippingRateSuccess,
|
||||||
onShippingRateFail,
|
onShippingRateFail,
|
||||||
onShippingRateSelectSuccess,
|
onShippingRateSelectSuccess,
|
||||||
onShippingRateSelectFail,
|
onShippingRateSelectFail,
|
||||||
needsShipping,
|
|
||||||
} = useShippingDataContext();
|
} = useShippingDataContext();
|
||||||
|
const {
|
||||||
|
shippingRates,
|
||||||
|
shippingRatesLoading,
|
||||||
|
selectedRates,
|
||||||
|
isSelectingRate,
|
||||||
|
selectShippingRate,
|
||||||
|
needsShipping,
|
||||||
|
} = useShippingData();
|
||||||
const {
|
const {
|
||||||
billingData,
|
billingData,
|
||||||
shippingAddress,
|
shippingAddress,
|
||||||
|
@ -157,7 +160,7 @@ export const usePaymentMethodInterface = (): PaymentMethodInterface => {
|
||||||
isSelectingRate,
|
isSelectingRate,
|
||||||
needsShipping,
|
needsShipping,
|
||||||
selectedRates,
|
selectedRates,
|
||||||
setSelectedRates,
|
selectShippingRate,
|
||||||
setShippingAddress,
|
setShippingAddress,
|
||||||
shippingAddress,
|
shippingAddress,
|
||||||
shippingRates,
|
shippingRates,
|
||||||
|
|
|
@ -1 +1,2 @@
|
||||||
export * from './use-select-shipping-rate';
|
export * from './use-select-shipping-rate';
|
||||||
|
export * from './use-shipping-data';
|
||||||
|
|
|
@ -5,6 +5,7 @@ import { useDispatch, useSelect } from '@wordpress/data';
|
||||||
import { useCallback } from '@wordpress/element';
|
import { useCallback } from '@wordpress/element';
|
||||||
import { CART_STORE_KEY as storeKey } from '@woocommerce/block-data';
|
import { CART_STORE_KEY as storeKey } from '@woocommerce/block-data';
|
||||||
import { useThrowError } from '@woocommerce/base-hooks';
|
import { useThrowError } from '@woocommerce/base-hooks';
|
||||||
|
import { SelectShippingRateType } from '@woocommerce/type-defs/shipping';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal dependencies
|
* Internal dependencies
|
||||||
|
@ -18,15 +19,7 @@ import { useStoreEvents } from '../use-store-events';
|
||||||
* - selectShippingRate: A function that immediately returns the selected rate and dispatches an action generator.
|
* - selectShippingRate: A function that immediately returns the selected rate and dispatches an action generator.
|
||||||
* - isSelectingRate: True when rates are being resolved to the API.
|
* - isSelectingRate: True when rates are being resolved to the API.
|
||||||
*/
|
*/
|
||||||
export const useSelectShippingRate = (): {
|
export const useSelectShippingRate = (): SelectShippingRateType => {
|
||||||
// Returns a function that accepts a shipping rate ID and a package ID.
|
|
||||||
selectShippingRate: (
|
|
||||||
newShippingRateId: string,
|
|
||||||
packageId: string | number
|
|
||||||
) => unknown;
|
|
||||||
// True when a rate is currently being selected and persisted to the server.
|
|
||||||
isSelectingRate: boolean;
|
|
||||||
} => {
|
|
||||||
const throwError = useThrowError();
|
const throwError = useThrowError();
|
||||||
const { dispatchCheckoutEvent } = useStoreEvents();
|
const { dispatchCheckoutEvent } = useStoreEvents();
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,66 @@
|
||||||
|
/**
|
||||||
|
* External dependencies
|
||||||
|
*/
|
||||||
|
import { CART_STORE_KEY as storeKey } from '@woocommerce/block-data';
|
||||||
|
import { useSelect } from '@wordpress/data';
|
||||||
|
import { Cart } from '@woocommerce/type-defs/cart';
|
||||||
|
import { SelectShippingRateType } from '@woocommerce/type-defs/shipping';
|
||||||
|
import { useEffect, useRef } from '@wordpress/element';
|
||||||
|
import { deriveSelectedShippingRates } from '@woocommerce/base-utils';
|
||||||
|
import isShallowEqual from '@wordpress/is-shallow-equal';
|
||||||
|
import { isObject } from '@woocommerce/types';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal dependencies
|
||||||
|
*/
|
||||||
|
import { useSelectShippingRate } from './use-select-shipping-rate';
|
||||||
|
|
||||||
|
interface ShippingData extends SelectShippingRateType {
|
||||||
|
needsShipping: Cart[ 'needsShipping' ];
|
||||||
|
hasCalculatedShipping: Cart[ 'hasCalculatedShipping' ];
|
||||||
|
shippingRates: Cart[ 'shippingRates' ];
|
||||||
|
shippingRatesLoading: boolean;
|
||||||
|
selectedRates: Record< string, string | unknown >;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useShippingData = (): ShippingData => {
|
||||||
|
const {
|
||||||
|
shippingRates,
|
||||||
|
needsShipping,
|
||||||
|
hasCalculatedShipping,
|
||||||
|
shippingRatesLoading,
|
||||||
|
} = useSelect( ( select ) => {
|
||||||
|
const store = select( storeKey );
|
||||||
|
return {
|
||||||
|
shippingRates: store.getShippingRates(),
|
||||||
|
needsShipping: store.getNeedsShipping(),
|
||||||
|
hasCalculatedShipping: store.getHasCalculatedShipping(),
|
||||||
|
shippingRatesLoading: store.isCustomerDataUpdating(),
|
||||||
|
};
|
||||||
|
} );
|
||||||
|
const { isSelectingRate, selectShippingRate } = useSelectShippingRate();
|
||||||
|
|
||||||
|
// set selected rates on ref so it's always current.
|
||||||
|
const selectedRates = useRef< Record< string, unknown > >( {} );
|
||||||
|
useEffect( () => {
|
||||||
|
const derivedSelectedRates = deriveSelectedShippingRates(
|
||||||
|
shippingRates
|
||||||
|
);
|
||||||
|
if (
|
||||||
|
isObject( derivedSelectedRates ) &&
|
||||||
|
! isShallowEqual( selectedRates.current, derivedSelectedRates )
|
||||||
|
) {
|
||||||
|
selectedRates.current = derivedSelectedRates;
|
||||||
|
}
|
||||||
|
}, [ shippingRates ] );
|
||||||
|
|
||||||
|
return {
|
||||||
|
isSelectingRate,
|
||||||
|
selectedRates: selectedRates.current,
|
||||||
|
selectShippingRate,
|
||||||
|
shippingRates,
|
||||||
|
needsShipping,
|
||||||
|
hasCalculatedShipping,
|
||||||
|
shippingRatesLoading,
|
||||||
|
};
|
||||||
|
};
|
|
@ -13,11 +13,9 @@ import { useCallback } from '@wordpress/element';
|
||||||
/**
|
/**
|
||||||
* Internal dependencies
|
* Internal dependencies
|
||||||
*/
|
*/
|
||||||
import {
|
import { useCheckoutContext } from '../providers/cart-checkout';
|
||||||
useShippingDataContext,
|
|
||||||
useCheckoutContext,
|
|
||||||
} from '../providers/cart-checkout';
|
|
||||||
import { useCustomerData } from './use-customer-data';
|
import { useCustomerData } from './use-customer-data';
|
||||||
|
import { useShippingData } from './shipping/use-shipping-data';
|
||||||
|
|
||||||
interface CheckoutAddress {
|
interface CheckoutAddress {
|
||||||
shippingAddress: ShippingAddress;
|
shippingAddress: ShippingAddress;
|
||||||
|
@ -38,7 +36,7 @@ interface CheckoutAddress {
|
||||||
* Custom hook for exposing address related functionality for the checkout address form.
|
* Custom hook for exposing address related functionality for the checkout address form.
|
||||||
*/
|
*/
|
||||||
export const useCheckoutAddress = (): CheckoutAddress => {
|
export const useCheckoutAddress = (): CheckoutAddress => {
|
||||||
const { needsShipping } = useShippingDataContext();
|
const { needsShipping } = useShippingData();
|
||||||
const {
|
const {
|
||||||
useShippingAsBilling,
|
useShippingAsBilling,
|
||||||
setUseShippingAsBilling,
|
setUseShippingAsBilling,
|
||||||
|
|
|
@ -8,12 +8,11 @@ import { useCallback, useMemo } from '@wordpress/element';
|
||||||
*/
|
*/
|
||||||
import { actions, ActionType } from './actions';
|
import { actions, ActionType } from './actions';
|
||||||
import { STATUS } from './constants';
|
import { STATUS } from './constants';
|
||||||
import { useCustomerDataContext } from '../customer';
|
|
||||||
import { useShippingDataContext } from '../shipping';
|
|
||||||
import type {
|
import type {
|
||||||
PaymentStatusDispatchers,
|
PaymentStatusDispatchers,
|
||||||
PaymentMethodDispatchers,
|
PaymentMethodDispatchers,
|
||||||
} from './types';
|
} from './types';
|
||||||
|
import { useCustomerData } from '../../../hooks/use-customer-data';
|
||||||
|
|
||||||
export const usePaymentMethodDataDispatchers = (
|
export const usePaymentMethodDataDispatchers = (
|
||||||
dispatch: React.Dispatch< ActionType >
|
dispatch: React.Dispatch< ActionType >
|
||||||
|
@ -21,8 +20,7 @@ export const usePaymentMethodDataDispatchers = (
|
||||||
dispatchActions: PaymentMethodDispatchers;
|
dispatchActions: PaymentMethodDispatchers;
|
||||||
setPaymentStatus: () => PaymentStatusDispatchers;
|
setPaymentStatus: () => PaymentStatusDispatchers;
|
||||||
} => {
|
} => {
|
||||||
const { setBillingData } = useCustomerDataContext();
|
const { setBillingData, setShippingAddress } = useCustomerData();
|
||||||
const { setShippingAddress } = useShippingDataContext();
|
|
||||||
|
|
||||||
const dispatchActions = useMemo(
|
const dispatchActions = useMemo(
|
||||||
(): PaymentMethodDispatchers => ( {
|
(): PaymentMethodDispatchers => ( {
|
||||||
|
|
|
@ -21,12 +21,12 @@ import { useDebouncedCallback } from 'use-debounce';
|
||||||
* Internal dependencies
|
* Internal dependencies
|
||||||
*/
|
*/
|
||||||
import { useEditorContext } from '../../editor-context';
|
import { useEditorContext } from '../../editor-context';
|
||||||
import { useShippingDataContext } from '../shipping';
|
|
||||||
import { useCustomerDataContext } from '../customer';
|
import { useCustomerDataContext } from '../customer';
|
||||||
import { useStoreCart } from '../../../hooks/cart/use-store-cart';
|
import { useStoreCart } from '../../../hooks/cart/use-store-cart';
|
||||||
import { useStoreNotices } from '../../../hooks/use-store-notices';
|
import { useStoreNotices } from '../../../hooks/use-store-notices';
|
||||||
import { useEmitResponse } from '../../../hooks/use-emit-response';
|
import { useEmitResponse } from '../../../hooks/use-emit-response';
|
||||||
import type { PaymentMethodsDispatcherType } from './types';
|
import type { PaymentMethodsDispatcherType } from './types';
|
||||||
|
import { useShippingData } from '../../../hooks/shipping/use-shipping-data';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This hook handles initializing registered payment methods and exposing all
|
* This hook handles initializing registered payment methods and exposing all
|
||||||
|
@ -48,7 +48,7 @@ const usePaymentMethodRegistration = (
|
||||||
) => {
|
) => {
|
||||||
const [ isInitialized, setIsInitialized ] = useState( false );
|
const [ isInitialized, setIsInitialized ] = useState( false );
|
||||||
const { isEditor } = useEditorContext();
|
const { isEditor } = useEditorContext();
|
||||||
const { selectedRates } = useShippingDataContext();
|
const { selectedRates } = useShippingData();
|
||||||
const { billingData, shippingAddress } = useCustomerDataContext();
|
const { billingData, shippingAddress } = useCustomerDataContext();
|
||||||
const selectedShippingMethods = useShallowEqual( selectedRates );
|
const selectedShippingMethods = useShallowEqual( selectedRates );
|
||||||
const paymentMethodsOrder = useShallowEqual( paymentMethodsSortOrder );
|
const paymentMethodsOrder = useShallowEqual( paymentMethodsSortOrder );
|
||||||
|
|
|
@ -9,8 +9,6 @@ import {
|
||||||
useMemo,
|
useMemo,
|
||||||
useRef,
|
useRef,
|
||||||
} from '@wordpress/element';
|
} from '@wordpress/element';
|
||||||
import isShallowEqual from '@wordpress/is-shallow-equal';
|
|
||||||
import { deriveSelectedShippingRates } from '@woocommerce/base-utils';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal dependencies
|
* Internal dependencies
|
||||||
|
@ -25,9 +23,9 @@ import {
|
||||||
emitEvent,
|
emitEvent,
|
||||||
} from './event-emit';
|
} from './event-emit';
|
||||||
import { useCheckoutContext } from '../checkout-state';
|
import { useCheckoutContext } from '../checkout-state';
|
||||||
import { useCustomerDataContext } from '../customer';
|
|
||||||
import { useStoreCart } from '../../../hooks/cart/use-store-cart';
|
import { useStoreCart } from '../../../hooks/cart/use-store-cart';
|
||||||
import { useSelectShippingRate } from '../../../hooks/shipping/use-select-shipping-rate';
|
import { useSelectShippingRate } from '../../../hooks/shipping/use-select-shipping-rate';
|
||||||
|
import { useShippingData } from '../../../hooks/shipping/use-shipping-data';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {import('@woocommerce/type-defs/contexts').ShippingDataContext} ShippingDataContext
|
* @typedef {import('@woocommerce/type-defs/contexts').ShippingDataContext} ShippingDataContext
|
||||||
|
@ -52,15 +50,9 @@ export const useShippingDataContext = () => {
|
||||||
*/
|
*/
|
||||||
export const ShippingDataProvider = ( { children } ) => {
|
export const ShippingDataProvider = ( { children } ) => {
|
||||||
const { dispatchActions } = useCheckoutContext();
|
const { dispatchActions } = useCheckoutContext();
|
||||||
const { shippingAddress, setShippingAddress } = useCustomerDataContext();
|
const { shippingRates, shippingRatesLoading, cartErrors } = useStoreCart();
|
||||||
const {
|
const { isSelectingRate } = useSelectShippingRate();
|
||||||
cartNeedsShipping: needsShipping,
|
const { selectedRates } = useShippingData();
|
||||||
cartHasCalculatedShipping: hasCalculatedShipping,
|
|
||||||
shippingRates,
|
|
||||||
shippingRatesLoading,
|
|
||||||
cartErrors,
|
|
||||||
} = useStoreCart();
|
|
||||||
const { selectShippingRate, isSelectingRate } = useSelectShippingRate();
|
|
||||||
const [ shippingErrorStatus, dispatchErrorStatus ] = useReducer(
|
const [ shippingErrorStatus, dispatchErrorStatus ] = useReducer(
|
||||||
errorStatusReducer,
|
errorStatusReducer,
|
||||||
NONE
|
NONE
|
||||||
|
@ -85,19 +77,6 @@ export const ShippingDataProvider = ( { children } ) => {
|
||||||
currentObservers.current = observers;
|
currentObservers.current = observers;
|
||||||
}, [ observers ] );
|
}, [ observers ] );
|
||||||
|
|
||||||
// set selected rates on ref so it's always current.
|
|
||||||
const selectedRates = useRef( () =>
|
|
||||||
deriveSelectedShippingRates( shippingRates )
|
|
||||||
);
|
|
||||||
useEffect( () => {
|
|
||||||
const derivedSelectedRates = deriveSelectedShippingRates(
|
|
||||||
shippingRates
|
|
||||||
);
|
|
||||||
if ( ! isShallowEqual( selectedRates.current, derivedSelectedRates ) ) {
|
|
||||||
selectedRates.current = derivedSelectedRates;
|
|
||||||
}
|
|
||||||
}, [ shippingRates ] );
|
|
||||||
|
|
||||||
// increment/decrement checkout calculating counts when shipping is loading.
|
// increment/decrement checkout calculating counts when shipping is loading.
|
||||||
useEffect( () => {
|
useEffect( () => {
|
||||||
if ( shippingRatesLoading ) {
|
if ( shippingRatesLoading ) {
|
||||||
|
@ -198,6 +177,7 @@ export const ShippingDataProvider = ( { children } ) => {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}, [
|
}, [
|
||||||
|
selectedRates,
|
||||||
isSelectingRate,
|
isSelectingRate,
|
||||||
currentErrorStatus.hasError,
|
currentErrorStatus.hasError,
|
||||||
currentErrorStatus.hasInvalidAddress,
|
currentErrorStatus.hasInvalidAddress,
|
||||||
|
@ -210,15 +190,6 @@ export const ShippingDataProvider = ( { children } ) => {
|
||||||
shippingErrorStatus: currentErrorStatus,
|
shippingErrorStatus: currentErrorStatus,
|
||||||
dispatchErrorStatus,
|
dispatchErrorStatus,
|
||||||
shippingErrorTypes: ERROR_TYPES,
|
shippingErrorTypes: ERROR_TYPES,
|
||||||
shippingRates,
|
|
||||||
shippingRatesLoading,
|
|
||||||
selectedRates: selectedRates.current,
|
|
||||||
setSelectedRates: selectShippingRate,
|
|
||||||
isSelectingRate,
|
|
||||||
shippingAddress,
|
|
||||||
setShippingAddress,
|
|
||||||
needsShipping,
|
|
||||||
hasCalculatedShipping,
|
|
||||||
...eventObservers,
|
...eventObservers,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,17 @@
|
||||||
|
/**
|
||||||
|
* External dependencies
|
||||||
|
*/
|
||||||
|
import { CartShippingRate } from '@woocommerce/type-defs/cart';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get an array of selected shipping rates keyed by Package ID.
|
* Get an array of selected shipping rates keyed by Package ID.
|
||||||
*
|
*
|
||||||
* @param {Array} shippingRates Array of shipping rates.
|
* @param {Array} shippingRates Array of shipping rates.
|
||||||
* @return {Object} Object containing the package IDs and selected rates in the format: { [packageId:string]: rateId:string }
|
* @return {Object} Object containing the package IDs and selected rates in the format: { [packageId:string]: rateId:string }
|
||||||
*/
|
*/
|
||||||
export const deriveSelectedShippingRates = ( shippingRates ) =>
|
export const deriveSelectedShippingRates = (
|
||||||
|
shippingRates: CartShippingRate[]
|
||||||
|
): Record< string, string | unknown > =>
|
||||||
Object.fromEntries(
|
Object.fromEntries(
|
||||||
shippingRates.map(
|
shippingRates.map(
|
||||||
( { package_id: packageId, shipping_rates: packageRates } ) => [
|
( { package_id: packageId, shipping_rates: packageRates } ) => [
|
|
@ -4,10 +4,8 @@
|
||||||
import classnames from 'classnames';
|
import classnames from 'classnames';
|
||||||
import { __ } from '@wordpress/i18n';
|
import { __ } from '@wordpress/i18n';
|
||||||
import { FormStep } from '@woocommerce/base-components/cart-checkout';
|
import { FormStep } from '@woocommerce/base-components/cart-checkout';
|
||||||
import {
|
import { useCheckoutContext } from '@woocommerce/base-context';
|
||||||
useCheckoutContext,
|
import { useShippingData } from '@woocommerce/base-context/hooks';
|
||||||
useShippingDataContext,
|
|
||||||
} from '@woocommerce/base-context';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal dependencies
|
* Internal dependencies
|
||||||
|
@ -15,7 +13,7 @@ import {
|
||||||
import CheckoutOrderNotes from '../../order-notes';
|
import CheckoutOrderNotes from '../../order-notes';
|
||||||
|
|
||||||
const Block = ( { className }: { className?: string } ): JSX.Element => {
|
const Block = ( { className }: { className?: string } ): JSX.Element => {
|
||||||
const { needsShipping } = useShippingDataContext();
|
const { needsShipping } = useShippingData();
|
||||||
const {
|
const {
|
||||||
isProcessing: checkoutIsProcessing,
|
isProcessing: checkoutIsProcessing,
|
||||||
orderNotes,
|
orderNotes,
|
||||||
|
|
|
@ -18,17 +18,13 @@ import {
|
||||||
} from '@woocommerce/blocks-checkout';
|
} from '@woocommerce/blocks-checkout';
|
||||||
|
|
||||||
import { getCurrencyFromPriceResponse } from '@woocommerce/price-format';
|
import { getCurrencyFromPriceResponse } from '@woocommerce/price-format';
|
||||||
import { useShippingDataContext } from '@woocommerce/base-context';
|
|
||||||
import {
|
import {
|
||||||
useStoreCartCoupons,
|
useStoreCartCoupons,
|
||||||
useStoreCart,
|
useStoreCart,
|
||||||
|
useShippingData,
|
||||||
} from '@woocommerce/base-context/hooks';
|
} from '@woocommerce/base-context/hooks';
|
||||||
import { getSetting } from '@woocommerce/settings';
|
import { getSetting } from '@woocommerce/settings';
|
||||||
|
|
||||||
/**
|
|
||||||
* Internal dependencies
|
|
||||||
*/
|
|
||||||
|
|
||||||
const Block = ( {
|
const Block = ( {
|
||||||
showRateAfterTaxName = false,
|
showRateAfterTaxName = false,
|
||||||
className,
|
className,
|
||||||
|
@ -44,7 +40,7 @@ const Block = ( {
|
||||||
isRemovingCoupon,
|
isRemovingCoupon,
|
||||||
} = useStoreCartCoupons();
|
} = useStoreCartCoupons();
|
||||||
|
|
||||||
const { needsShipping } = useShippingDataContext();
|
const { needsShipping } = useShippingData();
|
||||||
const totalsCurrency = getCurrencyFromPriceResponse( cartTotals );
|
const totalsCurrency = getCurrencyFromPriceResponse( cartTotals );
|
||||||
|
|
||||||
// Prepare props to pass to the ExperimentalOrderMeta slot fill.
|
// Prepare props to pass to the ExperimentalOrderMeta slot fill.
|
||||||
|
|
|
@ -18,7 +18,6 @@ import {
|
||||||
textContentMatcherAcrossSiblings,
|
textContentMatcherAcrossSiblings,
|
||||||
} from '../../../../../../../tests/utils/find-by-text';
|
} from '../../../../../../../tests/utils/find-by-text';
|
||||||
const baseContextHooks = jest.requireMock( '@woocommerce/base-context/hooks' );
|
const baseContextHooks = jest.requireMock( '@woocommerce/base-context/hooks' );
|
||||||
const baseContext = jest.requireMock( '@woocommerce/base-context' );
|
|
||||||
const woocommerceSettings = jest.requireMock( '@woocommerce/settings' );
|
const woocommerceSettings = jest.requireMock( '@woocommerce/settings' );
|
||||||
|
|
||||||
const defaultUseStoreCartValue = {
|
const defaultUseStoreCartValue = {
|
||||||
|
@ -51,15 +50,7 @@ jest.mock( '@woocommerce/base-context/hooks', () => ( {
|
||||||
billingAddress: mockPreviewCart.billing_address,
|
billingAddress: mockPreviewCart.billing_address,
|
||||||
cartHasCalculatedShipping: mockPreviewCart.has_calculated_shipping,
|
cartHasCalculatedShipping: mockPreviewCart.has_calculated_shipping,
|
||||||
} ),
|
} ),
|
||||||
} ) );
|
useShippingData: jest.fn().mockReturnValue( {
|
||||||
|
|
||||||
jest.mock( '@woocommerce/base-context', () => ( {
|
|
||||||
...jest.requireActual( '@woocommerce/base-context' ),
|
|
||||||
useContainerWidthContext: jest.fn().mockReturnValue( {
|
|
||||||
hasContainerWidth: true,
|
|
||||||
isLarge: true,
|
|
||||||
} ),
|
|
||||||
useShippingDataContext: jest.fn().mockReturnValue( {
|
|
||||||
needsShipping: true,
|
needsShipping: true,
|
||||||
shippingRates: [
|
shippingRates: [
|
||||||
{
|
{
|
||||||
|
@ -167,6 +158,14 @@ jest.mock( '@woocommerce/base-context', () => ( {
|
||||||
} ),
|
} ),
|
||||||
} ) );
|
} ) );
|
||||||
|
|
||||||
|
jest.mock( '@woocommerce/base-context', () => ( {
|
||||||
|
...jest.requireActual( '@woocommerce/base-context' ),
|
||||||
|
useContainerWidthContext: jest.fn().mockReturnValue( {
|
||||||
|
hasContainerWidth: true,
|
||||||
|
isLarge: true,
|
||||||
|
} ),
|
||||||
|
} ) );
|
||||||
|
|
||||||
jest.mock( '@woocommerce/settings', () => {
|
jest.mock( '@woocommerce/settings', () => {
|
||||||
const originalModule = jest.requireActual( '@woocommerce/settings' );
|
const originalModule = jest.requireActual( '@woocommerce/settings' );
|
||||||
|
|
||||||
|
@ -189,12 +188,14 @@ const setGetSettingImplementation = ( implementation ) => {
|
||||||
woocommerceSettings.getSetting.mockImplementation( implementation );
|
woocommerceSettings.getSetting.mockImplementation( implementation );
|
||||||
};
|
};
|
||||||
|
|
||||||
const setUseShippingDataContextReturnValue = ( value ) => {
|
const setUseShippingDataReturnValue = ( value ) => {
|
||||||
baseContext.useShippingDataContext.mockReturnValue( value );
|
baseContextHooks.useShippingData.mockReturnValue( value );
|
||||||
};
|
};
|
||||||
|
|
||||||
describe( 'Checkout Order Summary', () => {
|
describe( 'Checkout Order Summary', () => {
|
||||||
beforeEach( () => setUseStoreCartReturnValue() );
|
beforeEach( () => {
|
||||||
|
setUseStoreCartReturnValue();
|
||||||
|
} );
|
||||||
|
|
||||||
it( 'Renders the standard preview items in the sidebar', async () => {
|
it( 'Renders the standard preview items in the sidebar', async () => {
|
||||||
const { container } = render( <Block showRateAfterTaxName={ true } /> );
|
const { container } = render( <Block showRateAfterTaxName={ true } /> );
|
||||||
|
@ -335,7 +336,7 @@ describe( 'Checkout Order Summary', () => {
|
||||||
...defaultUseStoreCartValue,
|
...defaultUseStoreCartValue,
|
||||||
needsShipping: false,
|
needsShipping: false,
|
||||||
} );
|
} );
|
||||||
setUseShippingDataContextReturnValue( { needsShipping: false } );
|
setUseShippingDataReturnValue( { needsShipping: false } );
|
||||||
const { container } = render( <Block showRateAfterTaxName={ true } /> );
|
const { container } = render( <Block showRateAfterTaxName={ true } /> );
|
||||||
expect( queryByText( container, 'Shipping' ) ).not.toBeInTheDocument();
|
expect( queryByText( container, 'Shipping' ) ).not.toBeInTheDocument();
|
||||||
} );
|
} );
|
||||||
|
@ -349,7 +350,6 @@ describe( 'Checkout Order Summary', () => {
|
||||||
tax_lines: [ { name: 'Tax', price: '1000', rate: '5%' } ],
|
tax_lines: [ { name: 'Tax', price: '1000', rate: '5%' } ],
|
||||||
},
|
},
|
||||||
} );
|
} );
|
||||||
setUseShippingDataContextReturnValue( { needsShipping: false } );
|
|
||||||
setGetSettingImplementation( ( setting, ...rest ) => {
|
setGetSettingImplementation( ( setting, ...rest ) => {
|
||||||
if ( setting === 'displayCartPricesIncludingTax' ) {
|
if ( setting === 'displayCartPricesIncludingTax' ) {
|
||||||
return true;
|
return true;
|
||||||
|
@ -378,7 +378,7 @@ describe( 'Checkout Order Summary', () => {
|
||||||
tax_lines: [ { name: 'Tax', price: '1000', rate: '5%' } ],
|
tax_lines: [ { name: 'Tax', price: '1000', rate: '5%' } ],
|
||||||
},
|
},
|
||||||
} );
|
} );
|
||||||
setUseShippingDataContextReturnValue( { needsShipping: false } );
|
setUseShippingDataReturnValue( { needsShipping: false } );
|
||||||
setGetSettingImplementation( ( setting, ...rest ) => {
|
setGetSettingImplementation( ( setting, ...rest ) => {
|
||||||
if ( setting === 'displayCartPricesIncludingTax' ) {
|
if ( setting === 'displayCartPricesIncludingTax' ) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -407,7 +407,7 @@ describe( 'Checkout Order Summary', () => {
|
||||||
...mockPreviewCart.totals,
|
...mockPreviewCart.totals,
|
||||||
},
|
},
|
||||||
} );
|
} );
|
||||||
setUseShippingDataContextReturnValue( { needsShipping: false } );
|
setUseShippingDataReturnValue( { needsShipping: false } );
|
||||||
const { container } = render( <Block showRateAfterTaxName={ true } /> );
|
const { container } = render( <Block showRateAfterTaxName={ true } /> );
|
||||||
expect(
|
expect(
|
||||||
await findByText(
|
await findByText(
|
||||||
|
@ -425,7 +425,7 @@ describe( 'Checkout Order Summary', () => {
|
||||||
total_shipping: '4000',
|
total_shipping: '4000',
|
||||||
},
|
},
|
||||||
} );
|
} );
|
||||||
setUseShippingDataContextReturnValue( {
|
setUseShippingDataReturnValue( {
|
||||||
needsShipping: true,
|
needsShipping: true,
|
||||||
shippingRates: [
|
shippingRates: [
|
||||||
{
|
{
|
||||||
|
|
|
@ -2,14 +2,12 @@
|
||||||
* External dependencies
|
* External dependencies
|
||||||
*/
|
*/
|
||||||
import { __ } from '@wordpress/i18n';
|
import { __ } from '@wordpress/i18n';
|
||||||
|
import { useShippingData } from '@woocommerce/base-context/hooks';
|
||||||
import { ShippingRatesControl } from '@woocommerce/base-components/cart-checkout';
|
import { ShippingRatesControl } from '@woocommerce/base-components/cart-checkout';
|
||||||
import { getShippingRatesPackageCount } from '@woocommerce/base-utils';
|
import { getShippingRatesPackageCount } from '@woocommerce/base-utils';
|
||||||
import { getCurrencyFromPriceResponse } from '@woocommerce/price-format';
|
import { getCurrencyFromPriceResponse } from '@woocommerce/price-format';
|
||||||
import FormattedMonetaryAmount from '@woocommerce/base-components/formatted-monetary-amount';
|
import FormattedMonetaryAmount from '@woocommerce/base-components/formatted-monetary-amount';
|
||||||
import {
|
import { useEditorContext } from '@woocommerce/base-context';
|
||||||
useEditorContext,
|
|
||||||
useShippingDataContext,
|
|
||||||
} from '@woocommerce/base-context';
|
|
||||||
import { decodeEntities } from '@wordpress/html-entities';
|
import { decodeEntities } from '@wordpress/html-entities';
|
||||||
import { Notice } from 'wordpress-components';
|
import { Notice } from 'wordpress-components';
|
||||||
import classnames from 'classnames';
|
import classnames from 'classnames';
|
||||||
|
@ -50,12 +48,13 @@ const renderShippingRatesControlOption = (
|
||||||
|
|
||||||
const Block = (): JSX.Element | null => {
|
const Block = (): JSX.Element | null => {
|
||||||
const { isEditor } = useEditorContext();
|
const { isEditor } = useEditorContext();
|
||||||
|
|
||||||
const {
|
const {
|
||||||
shippingRates,
|
shippingRates,
|
||||||
shippingRatesLoading,
|
|
||||||
needsShipping,
|
needsShipping,
|
||||||
|
shippingRatesLoading,
|
||||||
hasCalculatedShipping,
|
hasCalculatedShipping,
|
||||||
} = useShippingDataContext();
|
} = useShippingData();
|
||||||
|
|
||||||
if ( ! needsShipping ) {
|
if ( ! needsShipping ) {
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -1,7 +1,13 @@
|
||||||
/**
|
/**
|
||||||
* External dependencies
|
* External dependencies
|
||||||
*/
|
*/
|
||||||
import type { Cart, CartTotals, CartMeta, CartItem } from '@woocommerce/types';
|
import type {
|
||||||
|
Cart,
|
||||||
|
CartTotals,
|
||||||
|
CartMeta,
|
||||||
|
CartItem,
|
||||||
|
CartShippingRate,
|
||||||
|
} from '@woocommerce/types';
|
||||||
import { BillingAddress, ShippingAddress } from '@woocommerce/settings';
|
import { BillingAddress, ShippingAddress } from '@woocommerce/settings';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -32,6 +38,36 @@ export const getCustomerData = (
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves shipping rates from state.
|
||||||
|
*
|
||||||
|
* @param { CartState } state The current state.
|
||||||
|
* @return { CartShippingRate[] } The shipping rates on the cart.
|
||||||
|
*/
|
||||||
|
export const getShippingRates = ( state: CartState ): CartShippingRate[] => {
|
||||||
|
return state.cartData.shippingRates;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves whether the cart needs shipping.
|
||||||
|
*
|
||||||
|
* @param { CartState } state The current state.
|
||||||
|
* @return { boolean } True if the cart needs shipping.
|
||||||
|
*/
|
||||||
|
export const getNeedsShipping = ( state: CartState ): boolean => {
|
||||||
|
return state.cartData.needsShipping;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves whether the cart shipping has been calculated.
|
||||||
|
*
|
||||||
|
* @param { CartState } state The current state.
|
||||||
|
* @return { boolean } True if the shipping has been calculated.
|
||||||
|
*/
|
||||||
|
export const getHasCalculatedShipping = ( state: CartState ): boolean => {
|
||||||
|
return state.cartData.hasCalculatedShipping;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves cart totals from state.
|
* Retrieves cart totals from state.
|
||||||
*
|
*
|
||||||
|
|
|
@ -10,10 +10,7 @@ import type LoadingMask from '@woocommerce/base-components/loading-mask';
|
||||||
* Internal dependencies
|
* Internal dependencies
|
||||||
*/
|
*/
|
||||||
import type { Currency } from './currency';
|
import type { Currency } from './currency';
|
||||||
import type {
|
import type { CartBillingAddress, CartShippingRate } from './cart';
|
||||||
CartBillingAddress,
|
|
||||||
CartShippingPackageShippingRate,
|
|
||||||
} from './cart';
|
|
||||||
import type {
|
import type {
|
||||||
responseTypes,
|
responseTypes,
|
||||||
noticeContexts,
|
noticeContexts,
|
||||||
|
@ -114,8 +111,8 @@ export interface ShippingDataProps {
|
||||||
isSelectingRate: boolean;
|
isSelectingRate: boolean;
|
||||||
// True if cart requires shipping.
|
// True if cart requires shipping.
|
||||||
needsShipping: boolean;
|
needsShipping: boolean;
|
||||||
// An array of selected rates (rate ids).
|
// An object containing package IDs as the key and selected rate as the value (rate ids).
|
||||||
selectedRates: string[];
|
selectedRates: Record< string, unknown >;
|
||||||
// A function for setting selected rates (receives id).
|
// A function for setting selected rates (receives id).
|
||||||
setSelectedRates: (
|
setSelectedRates: (
|
||||||
newShippingRateId: string,
|
newShippingRateId: string,
|
||||||
|
@ -126,7 +123,7 @@ export interface ShippingDataProps {
|
||||||
// The current set shipping address.
|
// The current set shipping address.
|
||||||
shippingAddress: CartResponseShippingAddress;
|
shippingAddress: CartResponseShippingAddress;
|
||||||
// All the available shipping rates.
|
// All the available shipping rates.
|
||||||
shippingRates: CartShippingPackageShippingRate[];
|
shippingRates: CartShippingRate[];
|
||||||
// Whether the rates are loading or not.
|
// Whether the rates are loading or not.
|
||||||
shippingRatesLoading: boolean;
|
shippingRatesLoading: boolean;
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,3 +11,13 @@ export interface PackageRateOption {
|
||||||
secondaryDescription?: string;
|
secondaryDescription?: string;
|
||||||
id?: string;
|
id?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface SelectShippingRateType {
|
||||||
|
// Returns a function that accepts a shipping rate ID and a package ID.
|
||||||
|
selectShippingRate: (
|
||||||
|
newShippingRateId: string,
|
||||||
|
packageId: string | number
|
||||||
|
) => unknown;
|
||||||
|
// True when a rate is currently being selected and persisted to the server.
|
||||||
|
isSelectingRate: boolean;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue