diff --git a/plugins/woocommerce-blocks/assets/js/base/components/payment-methods/express-payment-methods.js b/plugins/woocommerce-blocks/assets/js/base/components/payment-methods/express-payment-methods.js index 676e9f47edf..5cb719f652e 100644 --- a/plugins/woocommerce-blocks/assets/js/base/components/payment-methods/express-payment-methods.js +++ b/plugins/woocommerce-blocks/assets/js/base/components/payment-methods/express-payment-methods.js @@ -2,34 +2,30 @@ * External dependencies */ import { - useCheckoutData, - usePaymentEvents, useExpressPaymentMethods, + usePaymentMethodInterface, } from '@woocommerce/base-hooks'; import { cloneElement, isValidElement } from '@wordpress/element'; import { useCheckoutContext } from '@woocommerce/base-context'; const ExpressPaymentMethods = () => { - const [ checkoutData ] = useCheckoutData(); const { isEditor } = useCheckoutContext(); - const { dispatch, select } = usePaymentEvents(); + const paymentMethodInterface = usePaymentMethodInterface(); // not implementing isInitialized here because it's utilized further // up in the tree for express payment methods. We won't even get here if // there's no payment methods after initialization. const { paymentMethods } = useExpressPaymentMethods(); - const paymentMethodSlugs = Object.keys( paymentMethods ); + const paymentMethodIds = Object.keys( paymentMethods ); const content = - paymentMethodSlugs.length > 0 ? ( - paymentMethodSlugs.map( ( slug ) => { + paymentMethodIds.length > 0 ? ( + paymentMethodIds.map( ( id ) => { const expressPaymentMethod = isEditor - ? paymentMethods[ slug ].edit - : paymentMethods[ slug ].activeContent; - const paymentEvents = { dispatch, select }; + ? paymentMethods[ id ].edit + : paymentMethods[ id ].activeContent; return isValidElement( expressPaymentMethod ) ? ( -
  • +
  • { cloneElement( expressPaymentMethod, { - checkoutData, - paymentEvents, + ...paymentMethodInterface, } ) }
  • ) : null; diff --git a/plugins/woocommerce-blocks/assets/js/base/components/payment-methods/payment-methods.js b/plugins/woocommerce-blocks/assets/js/base/components/payment-methods/payment-methods.js index 345ffa1dd97..1ccc01d4c64 100644 --- a/plugins/woocommerce-blocks/assets/js/base/components/payment-methods/payment-methods.js +++ b/plugins/woocommerce-blocks/assets/js/base/components/payment-methods/payment-methods.js @@ -2,10 +2,8 @@ * External dependencies */ import { - useCheckoutData, - usePaymentEvents, - useActivePaymentMethod, usePaymentMethods, + usePaymentMethodInterface, } from '@woocommerce/base-hooks'; import { useCallback, @@ -31,12 +29,12 @@ const noPaymentMethodTab = () => { }; const createTabs = ( paymentMethods ) => { - const paymentMethodsKeys = Object.keys( paymentMethods ); - return paymentMethodsKeys.length > 0 - ? paymentMethodsKeys.map( ( key ) => { - const { label, ariaLabel } = paymentMethods[ key ]; + const paymentMethodIds = Object.keys( paymentMethods ); + return paymentMethodIds.length > 0 + ? paymentMethodIds.map( ( id ) => { + const { label, ariaLabel } = paymentMethods[ id ]; return { - name: key, + name: id, title: () => label, ariaLabel, }; @@ -64,21 +62,21 @@ const getPaymentMethod = ( id, paymentMethods, isEditor ) => { }; const PaymentMethods = () => { - const [ checkoutData ] = useCheckoutData(); const { isEditor } = useCheckoutContext(); - const { dispatch, select } = usePaymentEvents(); const { isInitialized, paymentMethods } = usePaymentMethods(); const currentPaymentMethods = useRef( paymentMethods ); + const { + activePaymentMethod, + setActivePaymentMethod, + ...paymentMethodInterface + } = usePaymentMethodInterface(); + const currentPaymentMethodInterface = useRef( paymentMethodInterface ); // update ref on changes useEffect( () => { currentPaymentMethods.current = paymentMethods; - }, [ paymentMethods ] ); - - const { - activePaymentMethod, - setActivePaymentMethod, - } = useActivePaymentMethod(); + currentPaymentMethodInterface.current = paymentMethodInterface; + }, [ paymentMethods, paymentMethodInterface, activePaymentMethod ] ); const getRenderedTab = useCallback( () => ( selectedTab ) => { const paymentMethod = getPaymentMethod( @@ -86,16 +84,14 @@ const PaymentMethods = () => { currentPaymentMethods.current, isEditor ); - const paymentEvents = { dispatch, select }; return paymentMethod ? cloneElement( paymentMethod, { - isActive: true, - checkoutData, - paymentEvents, + activePaymentMethod: paymentMethod.id, + ...currentPaymentMethodInterface.current, } ) : null; }, - [ checkoutData, dispatch, select, isEditor ] + [ isEditor, activePaymentMethod ] ); if ( ! isInitialized || diff --git a/plugins/woocommerce-blocks/assets/js/base/hooks/cart/index.js b/plugins/woocommerce-blocks/assets/js/base/hooks/cart/index.js new file mode 100644 index 00000000000..8f510164b6b --- /dev/null +++ b/plugins/woocommerce-blocks/assets/js/base/hooks/cart/index.js @@ -0,0 +1,3 @@ +export * from './use-store-cart'; +export * from './use-store-cart-coupons'; +export * from './use-store-cart-item-quantity'; diff --git a/plugins/woocommerce-blocks/assets/js/base/hooks/use-store-cart-coupons.js b/plugins/woocommerce-blocks/assets/js/base/hooks/cart/use-store-cart-coupons.js similarity index 100% rename from plugins/woocommerce-blocks/assets/js/base/hooks/use-store-cart-coupons.js rename to plugins/woocommerce-blocks/assets/js/base/hooks/cart/use-store-cart-coupons.js diff --git a/plugins/woocommerce-blocks/assets/js/base/hooks/use-store-cart-item-quantity.js b/plugins/woocommerce-blocks/assets/js/base/hooks/cart/use-store-cart-item-quantity.js similarity index 100% rename from plugins/woocommerce-blocks/assets/js/base/hooks/use-store-cart-item-quantity.js rename to plugins/woocommerce-blocks/assets/js/base/hooks/cart/use-store-cart-item-quantity.js diff --git a/plugins/woocommerce-blocks/assets/js/base/hooks/use-store-cart.js b/plugins/woocommerce-blocks/assets/js/base/hooks/cart/use-store-cart.js similarity index 98% rename from plugins/woocommerce-blocks/assets/js/base/hooks/use-store-cart.js rename to plugins/woocommerce-blocks/assets/js/base/hooks/cart/use-store-cart.js index 5a22bb556ec..1c59671c576 100644 --- a/plugins/woocommerce-blocks/assets/js/base/hooks/use-store-cart.js +++ b/plugins/woocommerce-blocks/assets/js/base/hooks/cart/use-store-cart.js @@ -19,6 +19,7 @@ const defaultCartData = { cartTotals: {}, cartIsLoading: true, cartErrors: [], + shippingRates: [], }; /** diff --git a/plugins/woocommerce-blocks/assets/js/base/hooks/checkout/index.js b/plugins/woocommerce-blocks/assets/js/base/hooks/checkout/index.js index 1fb03f107db..ae53992083e 100644 --- a/plugins/woocommerce-blocks/assets/js/base/hooks/checkout/index.js +++ b/plugins/woocommerce-blocks/assets/js/base/hooks/checkout/index.js @@ -1,4 +1,2 @@ -export { default as useCheckoutEvents } from './use-checkout-events'; -export { default as useCheckoutNotices } from './use-checkout-notices'; -export { default as useCheckoutRedirectUrls } from './use-checkout-redirect-urls'; -export { default as useCheckoutData } from './use-checkout-data'; +export * from './use-checkout-redirect-url'; +export * from './use-checkout-submit'; diff --git a/plugins/woocommerce-blocks/assets/js/base/hooks/checkout/use-checkout-data.js b/plugins/woocommerce-blocks/assets/js/base/hooks/checkout/use-checkout-data.js deleted file mode 100644 index 860565ed8f2..00000000000 --- a/plugins/woocommerce-blocks/assets/js/base/hooks/checkout/use-checkout-data.js +++ /dev/null @@ -1,29 +0,0 @@ -// @todo this should be a value object. Provided via wc-settings? -const currencyObject = { - code: 'USD', - precision: 2, - symbol: '$', - symbolPosition: 'left', - decimalSeparator: '.', - priceFormat: '%1$s%2$s', - thousandSeparator: ',', -}; - -const useCheckoutData = () => { - // @todo this will likely be a global wp.data store state so that things - // like shipping selection, quantity changes, etc that affect totals etc - // will automatically update the payment data. For POC this is hardcoded - const checkoutData = { - // this likely should be a float. - total: 10.123, - currency: currencyObject, - // @todo, should this be a standard format of items in the checkout/cart - // provided to ALL payment methods? Line items includes taxes/shipping - // costs? Coupons? - lineItems: [], - }; - const updateCheckoutData = () => {}; - return [ checkoutData, updateCheckoutData ]; -}; - -export default useCheckoutData; diff --git a/plugins/woocommerce-blocks/assets/js/base/hooks/checkout/use-checkout-events.js b/plugins/woocommerce-blocks/assets/js/base/hooks/checkout/use-checkout-events.js deleted file mode 100644 index 03777c8d917..00000000000 --- a/plugins/woocommerce-blocks/assets/js/base/hooks/checkout/use-checkout-events.js +++ /dev/null @@ -1,41 +0,0 @@ -/** - * External dependencies - */ -import useCheckoutContext from '@woocommerce/base-context'; - -export const useCheckoutEvents = () => { - const { - isCheckoutComplete, - setIsCheckoutComplete, - checkoutHasError, - setCheckoutHasError, - isCalculating, - setIsCalculating, - } = useCheckoutContext(); - const setHasError = () => { - setCheckoutHasError( true ); - }; - const cancelCheckoutError = () => { - setCheckoutHasError( false ); - }; - const setComplete = () => { - cancelCheckoutError(); - setIsCheckoutComplete( true ); - }; - const setCalculating = () => { - setIsCalculating( true ); - }; - const cancelCalculating = () => { - setIsCalculating( false ); - }; - return { - setIsCheckoutComplete: setComplete, - setCheckoutHasError: setHasError, - cancelCheckoutError, - setIsCalculating: setCalculating, - cancelCalculating, - isCalculating, - isCheckoutComplete, - checkoutHasError, - }; -}; diff --git a/plugins/woocommerce-blocks/assets/js/base/hooks/checkout/use-checkout-notices.js b/plugins/woocommerce-blocks/assets/js/base/hooks/checkout/use-checkout-notices.js deleted file mode 100644 index ccd7f2b5906..00000000000 --- a/plugins/woocommerce-blocks/assets/js/base/hooks/checkout/use-checkout-notices.js +++ /dev/null @@ -1,24 +0,0 @@ -/** - * External dependencies - */ -import useCheckoutContext from '@woocommerce/base-context'; - -const useCheckoutNotices = () => { - const { notices, updateNotices } = useCheckoutContext(); - const addNotice = ( notice ) => { - updateNotices( ( originalNotices ) => [ ...originalNotices, notice ] ); - }; - const clearAllNotices = () => { - // @todo...figure out how notices are saved - might need unique ids? - // Do we have a special notice creator that takes care of that? - // Use wp notice api? - updateNotices( [] ); - }; - return { - notices, - addNotice, - clearAllNotices, - }; -}; - -export default useCheckoutNotices; diff --git a/plugins/woocommerce-blocks/assets/js/base/hooks/checkout/use-checkout-place-order-label.js b/plugins/woocommerce-blocks/assets/js/base/hooks/checkout/use-checkout-place-order-label.js deleted file mode 100644 index 8a88cc102d7..00000000000 --- a/plugins/woocommerce-blocks/assets/js/base/hooks/checkout/use-checkout-place-order-label.js +++ /dev/null @@ -1,9 +0,0 @@ -/** - * External dependencies - */ -import useCheckoutContext from '@woocommerce/base-context'; - -export const useCheckoutPlaceOrderLabel = () => { - const { placeOrderLabel } = useCheckoutContext(); - return placeOrderLabel; -}; diff --git a/plugins/woocommerce-blocks/assets/js/base/hooks/checkout/use-checkout-redirect-url.js b/plugins/woocommerce-blocks/assets/js/base/hooks/checkout/use-checkout-redirect-url.js new file mode 100644 index 00000000000..ba6d8ad97d8 --- /dev/null +++ b/plugins/woocommerce-blocks/assets/js/base/hooks/checkout/use-checkout-redirect-url.js @@ -0,0 +1,16 @@ +/** + * External dependencies + */ +import { useCheckoutContext } from '@woocommerce/base-context'; + +/** + * Returns redirect url interface from checkout context. + */ +export const useCheckoutRedirectUrl = () => { + const { redirectUrl, dispatchActions } = useCheckoutContext(); + + return { + redirectUrl, + setRedirectUrl: dispatchActions.setRedirectUrl, + }; +}; diff --git a/plugins/woocommerce-blocks/assets/js/base/hooks/checkout/use-checkout-redirect-urls.js b/plugins/woocommerce-blocks/assets/js/base/hooks/checkout/use-checkout-redirect-urls.js deleted file mode 100644 index a68ff79e510..00000000000 --- a/plugins/woocommerce-blocks/assets/js/base/hooks/checkout/use-checkout-redirect-urls.js +++ /dev/null @@ -1,22 +0,0 @@ -/** - * External dependencies - */ -import useCheckoutContext from '@woocommerce/base-context'; - -const useCheckoutRedirectUrls = () => { - const { - successRedirectUrl, - setSuccessRedirectUrl, - failureRedirectUrl, - setFailureRedirectUrl, - } = useCheckoutContext(); - - return { - successRedirectUrl, - setSuccessRedirectUrl, - failureRedirectUrl, - setFailureRedirectUrl, - }; -}; - -export default useCheckoutRedirectUrls; diff --git a/plugins/woocommerce-blocks/assets/js/base/hooks/checkout/use-checkout-submit.js b/plugins/woocommerce-blocks/assets/js/base/hooks/checkout/use-checkout-submit.js new file mode 100644 index 00000000000..abaec4731c3 --- /dev/null +++ b/plugins/woocommerce-blocks/assets/js/base/hooks/checkout/use-checkout-submit.js @@ -0,0 +1,12 @@ +/** + * External dependencies + */ +import { useCheckoutContext } from '@woocommerce/base-context'; + +/** + * Returns the submitLabel and onSubmit interface from the checkout context + */ +export const useCheckoutSubmit = () => { + const { submitLabel, onSubmit } = useCheckoutContext(); + return { submitLabel, onSubmit }; +}; diff --git a/plugins/woocommerce-blocks/assets/js/base/hooks/index.js b/plugins/woocommerce-blocks/assets/js/base/hooks/index.js index 2f36d841964..05f82fa0f80 100644 --- a/plugins/woocommerce-blocks/assets/js/base/hooks/index.js +++ b/plugins/woocommerce-blocks/assets/js/base/hooks/index.js @@ -1,15 +1,13 @@ -export * from './use-query-state'; -export * from './use-shallow-equal'; -export * from './use-store-cart'; -export * from './use-store-cart-coupons'; -export * from './use-store-cart-item-quantity'; -export * from './use-store-products'; -export * from './use-store-notices'; +export * from './cart'; +export * from './checkout'; +export * from './order'; +export * from './payment-methods'; +export * from './shipping'; export * from './use-collection'; export * from './use-collection-header'; export * from './use-collection-data'; export * from './use-previous'; -export * from './checkout'; -export * from './payment-methods'; -export * from './use-shipping-rates'; -export * from './use-select-shipping-rate'; +export * from './use-shallow-equal'; +export * from './use-store-products'; +export * from './use-store-notices'; +export * from './use-query-state'; diff --git a/plugins/woocommerce-blocks/assets/js/base/hooks/order/index.js b/plugins/woocommerce-blocks/assets/js/base/hooks/order/index.js new file mode 100644 index 00000000000..2546ed1007f --- /dev/null +++ b/plugins/woocommerce-blocks/assets/js/base/hooks/order/index.js @@ -0,0 +1,2 @@ +export * from './use-store-order'; +export * from './use-billing-data'; diff --git a/plugins/woocommerce-blocks/assets/js/base/hooks/order/use-billing-data.js b/plugins/woocommerce-blocks/assets/js/base/hooks/order/use-billing-data.js new file mode 100644 index 00000000000..5ca8dd37ceb --- /dev/null +++ b/plugins/woocommerce-blocks/assets/js/base/hooks/order/use-billing-data.js @@ -0,0 +1,15 @@ +/** + * External dependencies + */ +import { usePaymentMethodDataContext } from '@woocommerce/base-context'; + +/** + * Exposes billing data api interface from the payment method data context. + */ +export const useBillingData = () => { + const { billingData, setBillingData } = usePaymentMethodDataContext(); + return { + billingData, + setBillingData, + }; +}; diff --git a/plugins/woocommerce-blocks/assets/js/base/hooks/order/use-store-order.js b/plugins/woocommerce-blocks/assets/js/base/hooks/order/use-store-order.js new file mode 100644 index 00000000000..d8b70c9271e --- /dev/null +++ b/plugins/woocommerce-blocks/assets/js/base/hooks/order/use-store-order.js @@ -0,0 +1,10 @@ +// @todo finish out this hook which will return a store draft order id and +// order loading (likely from payment data context). + +export const useStoreOrder = () => { + const orderId = 0; + return { + orderId, + isLoading: false, + }; +}; diff --git a/plugins/woocommerce-blocks/assets/js/base/hooks/payment-methods/constants.js b/plugins/woocommerce-blocks/assets/js/base/hooks/payment-methods/constants.js deleted file mode 100644 index 8207038ec98..00000000000 --- a/plugins/woocommerce-blocks/assets/js/base/hooks/payment-methods/constants.js +++ /dev/null @@ -1,7 +0,0 @@ -export const STATUS = { - PRISTINE: 'pristine', - STARTED: 'started', - ERROR: 'has_error', - FAILED: 'failed', - SUCCESS: 'success', -}; diff --git a/plugins/woocommerce-blocks/assets/js/base/hooks/payment-methods/index.js b/plugins/woocommerce-blocks/assets/js/base/hooks/payment-methods/index.js index f42576bc699..829faa6f0fc 100644 --- a/plugins/woocommerce-blocks/assets/js/base/hooks/payment-methods/index.js +++ b/plugins/woocommerce-blocks/assets/js/base/hooks/payment-methods/index.js @@ -1,3 +1,2 @@ -export { default as useActivePaymentMethod } from './use-active-payment-method'; -export { default as usePaymentEvents } from './use-payment-events'; +export * from './use-payment-method-interface'; export * from './use-payment-methods'; diff --git a/plugins/woocommerce-blocks/assets/js/base/hooks/payment-methods/use-active-payment-method.js b/plugins/woocommerce-blocks/assets/js/base/hooks/payment-methods/use-active-payment-method.js deleted file mode 100644 index 9dff8fd23a2..00000000000 --- a/plugins/woocommerce-blocks/assets/js/base/hooks/payment-methods/use-active-payment-method.js +++ /dev/null @@ -1,37 +0,0 @@ -/** - * External dependencies - */ -import { usePaymentMethodDataContext } from '@woocommerce/base-context'; -import { usePaymentMethods } from '@woocommerce/base-hooks'; -import { useEffect } from '@wordpress/element'; - -const useActivePaymentMethod = () => { - const { - activePaymentMethod, - setActivePaymentMethod, - } = usePaymentMethodDataContext(); - const { paymentMethods, isInitialized } = usePaymentMethods(); - // if payment method has not been set yet, let's set it. - useEffect( () => { - // if not initialized yet bail - if ( ! isInitialized ) { - return; - } - if ( ! activePaymentMethod && activePaymentMethod !== null ) { - const paymentMethodIds = Object.keys( paymentMethods ); - setActivePaymentMethod( - paymentMethodIds.length > 0 - ? paymentMethods[ paymentMethodIds[ 0 ] ].id - : null - ); - } - }, [ - activePaymentMethod, - setActivePaymentMethod, - isInitialized, - paymentMethods, - ] ); - return { activePaymentMethod, setActivePaymentMethod }; -}; - -export default useActivePaymentMethod; diff --git a/plugins/woocommerce-blocks/assets/js/base/hooks/payment-methods/use-payment-events.js b/plugins/woocommerce-blocks/assets/js/base/hooks/payment-methods/use-payment-events.js deleted file mode 100644 index de59b1ab19a..00000000000 --- a/plugins/woocommerce-blocks/assets/js/base/hooks/payment-methods/use-payment-events.js +++ /dev/null @@ -1,38 +0,0 @@ -/** - * External dependencies - */ -import { useState, useMemo } from '@wordpress/element'; - -/** - * Internal dependencies - */ -import { STATUS } from './constants'; -const { STARTED, ERROR, FAILED, SUCCESS, PRISTINE } = STATUS; - -const usePaymentEvents = () => { - const { paymentStatus, setPaymentStatus } = useState( PRISTINE ); - const dispatch = useMemo( - () => ( { - started: () => setPaymentStatus( STARTED ), - error: () => setPaymentStatus( ERROR ), - failed: () => setPaymentStatus( FAILED ), - success: () => setPaymentStatus( SUCCESS ), - } ), - [ setPaymentStatus ] - ); - const select = useMemo( - () => ( { - isPristine: () => paymentStatus === PRISTINE, - isStarted: () => paymentStatus === STARTED, - isFinished: () => - [ ERROR, FAILED, SUCCESS ].includes( paymentStatus ), - hasError: () => paymentStatus === ERROR, - hasFailed: () => paymentStatus === FAILED, - isSuccessful: () => paymentStatus === SUCCESS, - } ), - [ paymentStatus ] - ); - return { dispatch, select }; -}; - -export default usePaymentEvents; diff --git a/plugins/woocommerce-blocks/assets/js/base/hooks/payment-methods/use-payment-method-interface.js b/plugins/woocommerce-blocks/assets/js/base/hooks/payment-methods/use-payment-method-interface.js new file mode 100644 index 00000000000..a9bdb233917 --- /dev/null +++ b/plugins/woocommerce-blocks/assets/js/base/hooks/payment-methods/use-payment-method-interface.js @@ -0,0 +1,175 @@ +/** + * External dependencies + */ +import { + useCheckoutContext, + usePaymentMethodDataContext, + useShippingMethodDataContext, +} from '@woocommerce/base-context'; +import { __ } from '@wordpress/i18n'; +import { getCurrencyFromPriceResponse } from '@woocommerce/base-utils'; +import { useEffect, useRef } from '@wordpress/element'; + +/** + * Internal dependencies + */ +import { + useStoreOrder, + useStoreCartCoupons, + useStoreCart, + useBillingData, +} from '..'; + +/** + * @typedef {import('@woocommerce/type-defs/registered-payment-method-props').RegisteredPaymentMethodProps} RegisteredPaymentMethodProps + * @typedef {import('@woocommerce/type-defs/registered-payment-method-props').CartTotalItem} CartTotalItem + */ + +// @todo similar logic is done in `blocks/cart-checkout/cart/full-cart/index.js` +// we should extract this to use in both places so it's consistent. +// @todo this will need to account for `DISPLAY_PRICES_INCLUDING_TAXES`. +/** + * @param {Object} totals Current cart total items + * @param {boolean} needsShipping Whether or not shipping is needed. + * + * @return {CartTotalItem[]} Array for cart total items prepared for use. + */ +const prepareTotalItems = ( totals, needsShipping ) => { + const newTotals = []; + newTotals.push( { + label: __( 'Subtotal:', 'woo-gutenberg-products-block' ), + value: parseInt( totals.total_items, 10 ), + } ); + newTotals.push( { + label: __( 'Fees:', 'woo-gutenberg-products-block' ), + value: parseInt( totals.total_fees, 10 ), + } ); + newTotals.push( { + label: __( 'Discount:', 'woo-gutenberg-products-block' ), + value: parseInt( totals.total_discount, 10 ), + } ); + newTotals.push( { + label: __( 'Taxes:', 'woo-gutenberg-products-block' ), + value: parseInt( totals.total_tax, 10 ), + } ); + if ( needsShipping ) { + newTotals.push( { + label: __( 'Shipping:', 'woo-gutenberg-products-block' ), + value: parseInt( totals.total_shipping, 10 ), + } ); + } + return newTotals; +}; + +// @todo This will expose the consistent properties used as the payment method +// interface pulled from the various contexts exposing data for the interface. +// @todo need to also include notices interfaces here (maybe?). +/** + * @return {RegisteredPaymentMethodProps} Interface to use as payment method props. + */ +export const usePaymentMethodInterface = () => { + const { + isCalculating, + isComplete, + isIdle, + isProcessing, + onCheckoutCompleteSuccess, + onCheckoutCompleteError, + onCheckoutProcessing, + onSubmit, + } = useCheckoutContext(); + const { + setPaymentStatus, + currentStatus, + activePaymentMethod, + setActivePaymentMethod, + } = usePaymentMethodDataContext(); + const { + shippingErrorStatus, + shippingErrorTypes, + shippingRates, + shippingRatesLoading, + selectedRates, + setSelectedRates, + shippingAddress, + setShippingAddress, + onShippingRateSuccess, + onShippingRateFail, + onShippingRateSelectSuccess, + onShippingRateSelectFail, + needsShipping, + } = useShippingMethodDataContext(); + const { billingData, setBillingData } = useBillingData(); + const { order, isLoading: orderLoading } = useStoreOrder(); + const { cartTotals } = useStoreCart(); + const { appliedCoupons } = useStoreCartCoupons(); + const currentCartTotals = useRef( + prepareTotalItems( cartTotals, needsShipping ) + ); + const currentCartTotal = useRef( { + label: __( 'Total', 'woo-gutenberg-products-block' ), + value: parseInt( cartTotals.total_price, 10 ), + } ); + + useEffect( () => { + currentCartTotals.current = prepareTotalItems( + cartTotals, + needsShipping + ); + currentCartTotal.current = { + label: __( 'Total', 'woo-gutenberg-products-block' ), + value: parseInt( cartTotals.total_price, 10 ), + }; + }, [ cartTotals, needsShipping ] ); + + return { + checkoutStatus: { + isCalculating, + isComplete, + isIdle, + isProcessing, + }, + paymentStatus: { + currentStatus, + setPaymentStatus, + }, + shippingStatus: { + shippingErrorStatus, + shippingErrorTypes, + }, + shippingData: { + shippingRates, + shippingRatesLoading, + selectedRates, + setSelectedRates, + shippingAddress, + setShippingAddress, + needsShipping, + }, + billing: { + billingData, + setBillingData, + order, + orderLoading, + cartTotal: currentCartTotal.current, + currency: getCurrencyFromPriceResponse( cartTotals ), + // @todo need to pass along the default country set for the site + // if it's available. + country: '', + cartItems: currentCartTotals.current, + appliedCoupons, + }, + eventRegistration: { + onCheckoutCompleteSuccess, + onCheckoutCompleteError, + onCheckoutProcessing, + onShippingRateSuccess, + onShippingRateFail, + onShippingRateSelectSuccess, + onShippingRateSelectFail, + }, + onSubmit, + activePaymentMethod, + setActivePaymentMethod, + }; +}; diff --git a/plugins/woocommerce-blocks/assets/js/base/hooks/shipping/index.js b/plugins/woocommerce-blocks/assets/js/base/hooks/shipping/index.js new file mode 100644 index 00000000000..c3f8b53b5dd --- /dev/null +++ b/plugins/woocommerce-blocks/assets/js/base/hooks/shipping/index.js @@ -0,0 +1,2 @@ +export * from './use-select-shipping-rate'; +export * from './use-shipping-rates'; diff --git a/plugins/woocommerce-blocks/assets/js/base/hooks/use-select-shipping-rate.js b/plugins/woocommerce-blocks/assets/js/base/hooks/shipping/use-select-shipping-rate.js similarity index 100% rename from plugins/woocommerce-blocks/assets/js/base/hooks/use-select-shipping-rate.js rename to plugins/woocommerce-blocks/assets/js/base/hooks/shipping/use-select-shipping-rate.js diff --git a/plugins/woocommerce-blocks/assets/js/base/hooks/use-shipping-rates.js b/plugins/woocommerce-blocks/assets/js/base/hooks/shipping/use-shipping-rates.js similarity index 95% rename from plugins/woocommerce-blocks/assets/js/base/hooks/use-shipping-rates.js rename to plugins/woocommerce-blocks/assets/js/base/hooks/shipping/use-shipping-rates.js index 2dd81771934..9ce21cd7a3e 100644 --- a/plugins/woocommerce-blocks/assets/js/base/hooks/use-shipping-rates.js +++ b/plugins/woocommerce-blocks/assets/js/base/hooks/shipping/use-shipping-rates.js @@ -10,8 +10,8 @@ import { CART_STORE_KEY as storeKey } from '@woocommerce/block-data'; /** * Internal dependencies */ -import { useStoreCart } from './use-store-cart'; -import { pluckAddress } from '../utils'; +import { useStoreCart } from '../cart/use-store-cart'; +import { pluckAddress } from '../../utils'; /** * This is a custom hook that is wired up to the `wc/store/cart/shipping-rates` route. * Given a a set of default fields keys, this will handle shipping form state and load diff --git a/plugins/woocommerce-blocks/assets/js/base/hooks/test/use-shipping-rates.js b/plugins/woocommerce-blocks/assets/js/base/hooks/test/use-shipping-rates.js index 07d78e3ee83..a8dfb74be68 100644 --- a/plugins/woocommerce-blocks/assets/js/base/hooks/test/use-shipping-rates.js +++ b/plugins/woocommerce-blocks/assets/js/base/hooks/test/use-shipping-rates.js @@ -8,7 +8,7 @@ import { CART_STORE_KEY as storeKey } from '@woocommerce/block-data'; /** * Internal dependencies */ -import { useShippingRates } from '../use-shipping-rates'; +import { useShippingRates } from '../shipping'; jest.mock( '@woocommerce/block-data', () => ( { __esModule: true, diff --git a/plugins/woocommerce-blocks/assets/js/type-defs/registered-payment-method-props.js b/plugins/woocommerce-blocks/assets/js/type-defs/registered-payment-method-props.js new file mode 100644 index 00000000000..3f7f6c33095 --- /dev/null +++ b/plugins/woocommerce-blocks/assets/js/type-defs/registered-payment-method-props.js @@ -0,0 +1,206 @@ +/** + * @typedef {import('@woocommerce/type-defs/cart').CartTotalItem} CartTotalItem + * @typedef {import('@woocommerce/type-defs/cart').CartShippingOption} CartShippingOption + * @typedef {import('@woocommerce/type-defs/cart').CartBillingAddress} CartBillingAddress + * @typedef {import('@woocommerce/type-defs/cart').CartShippingAddress} CartShippingAddress + * @typedef {import('@woocommerce/type-defs/contexts').PaymentMethodCurrentStatus} PaymentMethodCurrentStatus + * @typedef {import('@woocommerce/type-defs/contexts').PaymentStatusDispatch} PaymentStatusDispatch + * @typedef {import('@woocommerce/type-defs/contexts').ShippingErrorTypes} ShippingErrorTypes + * @typedef {import('@woocommerce/type-defs/settings').WooCommerceSiteCurrency} SiteCurrency + */ + +/** + * Payment Event Status Action Creators + * + * @typedef {Object} PaymentStatusActions + * + * @property {Function} started + * @property {Function} processing + * @property {Function} completed + * @property {Function} error + * @property {Function} failed + * @property {Function} success + */ + +/** + * @typedef {Object} PaymentMethodShipping + * + * @property {boolean} required If shipping is required this + * will be true. + * @property {CartShippingOption[]} options Available shipping options. + * @property {Function} selectOptions Used to set the selected + * shipping options. + * @property {Function} updateAddress Used to update the shipping + * address. + * @property {Function} setStatus Used to set the current + * shipping options status. + * @property {Function} selectStatus Returns helpers for + * determining the current + * shipping options status. + * @property {string} status What the current shipping + * options status is. + */ + +/** + * @typedef {Object} PaymentMethodEvents + * + * @property {boolean} isCalculating If true, means the cart/checkout is + * currently calculating totals. + * @property {boolean} isCheckoutComplete If true, means the checkout process + * is complete (useful if the payment + * method has something to do after + * checkout is complete before setting + * payment status to complete. Redirect + * doesn't happen until both checkout + * and payment status is complete) + * @property {PaymentStatusActions} dispatchStatus Used to dispatch a payment event. + * @property {Function} selectStatus Returns helpers for determining + * current payment event status. + * @property {string} status What the current payment event status + * is. + */ + +/** + * @typedef CheckoutStatusProps + * + * @property {boolean} isCalculating If true then totals are being calculated in + * the checkout. + * @property {boolean} isComplete If true then the checkout has completed + * it's processing. + * @property {boolean} isIdle If true then the checkout is idle (no + * activity happening). + * @property {boolean} isProcessing If true then checkout is processing + * (finalizing) the order with the server. + */ + +/** + * @typedef PaymentStatusProps + * + * @property {PaymentMethodCurrentStatus} currentStatus Various status state + * indicators for the + * payment method based + * on it's current + * status. + * @property {PaymentStatusDispatch} setPaymentStatus Used to dispatch + * various payment + * status updates. + */ + +/** + * @typedef ShippingStatusProps + * + * @property {string} shippingErrorStatus Current error status for + * shipping. + * @property {ShippingErrorTypes} shippingErrorTypes An object containing all + * the possible types for + * shipping error status. + */ + +/** + * @typedef ShippingDataProps + * + * @property {CartShippingOption[]} shippingRates All the available + * shipping rates. + * @property {boolean} shippingRatesLoading Whether the rates are + * loading or not. + * @property {string[]} selectedRates An array of selected + * rates (rate ids). + * @property {Function} setSelectedRates A function for setting + * selected rates + * (recieves id) + * @property {CartShippingAddress} shippingAddress The current set + * shipping address. + * @property {Function} setShippingAddress A function for setting + * the shipping address. + * @property {boolean} needsShipping True if cart requires + * shipping. + */ + +/** + * @typedef BillingDataProps + * + * @property {CartBillingAddress} billingData The address used for billing. + * @property {Function} setBillingData Used to set the cart billing + * address. + * @property {Object} order The order object for the + * purchase. + * @property {boolean} orderLoading True if the order is being + * loaded. + * @property {CartTotalItem} cartTotal The total item for the cart. + * @property {SiteCurrency} currency Currency object. + * @property {string} country ISO country code for the + * default country for the site. + * @property {CartTotalItem[]} cartItems The various subtotal amounts. + * @property {string[]} appliedCoupons All the coupons that were + * applied. + */ + +/** + * @typedef EventRegistrationProps + * + * @property {function()} onCheckoutCompleteSuccess Used to subscribe callbacks + * firing when checkout has + * completed processing + * successfully. + * @property {function()} onCheckoutCompleteError Used to subscribe callbacks + * firing when checkout has + * completed processing with an + * error. + * @property {function()} onCheckoutProcessing Used to subscribe callbacks + * that will fire when checkout + * begins processing (as a part + * of the processing process). + * @property {function()} onShippingRateSuccess Used to subscribe callbacks + * that will fire when shipping + * rates for a given address have + * been received successfully. + * @property {function()} onShippingRateFail Used to subscribe callbacks + * that will fire when retrieving + * shipping rates failed. + * @property {function()} onShippingRateSelectSuccess Used to subscribe + * callbacks that will fire after + * selecting a shipping rate + * successfully. + * @property {function()} onShippingRateSelectFail Used to subscribe callbacks + * that will fire after selecting + * a shipping rate unsuccessfully. + */ + +/** + * Registered payment method props + * + * @typedef {Object} RegisteredPaymentMethodProps + * + * @property {CheckoutStatusProps} checkoutStatus The current + * checkout status + * exposed as + * various boolean + * state. + * @property {PaymentStatusProps} paymentStatus Various payment + * status helpers. + * @property {ShippingStatusProps} shippingStatus Various shipping + * status helpers. + * @property {ShippingDataProps} shippingData Various data + * related to + * shipping. + * @property {BillingDataProps} billing Various billing + * data items. + * @property {EventRegistrationProps} eventRegistration Various event + * registration + * helpers for + * subscribing + * callbacks for + * events. + * @property {Function} [onSubmit] Used to trigger + * checkout + * processing. + * @property {string} [activePaymentMethod] Indicates what + * the active + * payment method + * is. + * @property {function( string )} [setActivePaymentMethod] Used to set the + * active payment + * method. + */ + +export {}; diff --git a/plugins/woocommerce-blocks/tests/js/jest.config.json b/plugins/woocommerce-blocks/tests/js/jest.config.json index 4efdbff7dcc..b1cb8520aaf 100644 --- a/plugins/woocommerce-blocks/tests/js/jest.config.json +++ b/plugins/woocommerce-blocks/tests/js/jest.config.json @@ -17,6 +17,7 @@ "@woocommerce/base-context(.*)$": "assets/js/base/context/$1", "@woocommerce/base-hocs(.*)$": "assets/js/base/hocs/$1", "@woocommerce/base-hooks(.*)$": "assets/js/base/hooks/$1", + "@woocommerce/base-utils(.*)$": "assets/js/base/utils", "@woocommerce/block-data": "assets/js/data" }, "setupFiles": [