2020-02-28 02:05:10 +00:00
|
|
|
/**
|
|
|
|
* External dependencies
|
|
|
|
*/
|
2020-03-09 02:09:47 +00:00
|
|
|
import { useSelect, useDispatch } from '@wordpress/data';
|
|
|
|
import { useState, useEffect } from '@wordpress/element';
|
2020-02-28 02:05:10 +00:00
|
|
|
import { CART_STORE_KEY as storeKey } from '@woocommerce/block-data';
|
2020-03-10 16:50:18 +00:00
|
|
|
import { usePrevious } from '@woocommerce/base-hooks';
|
2020-03-09 02:09:47 +00:00
|
|
|
import { useDebounce } from 'use-debounce';
|
2020-04-07 11:03:22 +00:00
|
|
|
import { useCheckoutContext } from '@woocommerce/base-context';
|
2020-02-28 02:05:10 +00:00
|
|
|
|
2020-03-10 15:49:26 +00:00
|
|
|
/**
|
|
|
|
* Internal dependencies
|
|
|
|
*/
|
|
|
|
import { useStoreCart } from './use-store-cart';
|
|
|
|
|
2020-03-09 12:24:56 +00:00
|
|
|
/**
|
|
|
|
* @typedef {import('@woocommerce/type-defs/hooks').StoreCartItemQuantity} StoreCartItemQuantity
|
|
|
|
* @typedef {import('@woocommerce/type-defs/cart').CartItem} CartItem
|
|
|
|
*/
|
|
|
|
|
2020-02-28 02:05:10 +00:00
|
|
|
/**
|
|
|
|
* This is a custom hook for loading the Store API /cart/ endpoint and
|
|
|
|
* actions for removing or changing item quantity.
|
2020-02-28 11:51:30 +00:00
|
|
|
*
|
|
|
|
* @see https://github.com/woocommerce/woocommerce-gutenberg-products-block/tree/master/src/RestApi/StoreApi
|
2020-02-28 02:05:10 +00:00
|
|
|
*
|
2020-03-10 11:43:57 +00:00
|
|
|
* @param {CartItem} cartItem The cartItem to get quantity info from and
|
|
|
|
* will have quantity updated on.
|
|
|
|
* @return {StoreCartItemQuantity} An object exposing data and actions relating
|
|
|
|
* to cart items.
|
2020-02-28 02:05:10 +00:00
|
|
|
*/
|
2020-03-10 11:43:57 +00:00
|
|
|
export const useStoreCartItemQuantity = ( cartItem ) => {
|
2020-03-17 15:34:33 +00:00
|
|
|
const { key: cartItemKey = '', quantity: cartItemQuantity = 1 } = cartItem;
|
2020-03-10 15:49:26 +00:00
|
|
|
const { cartErrors } = useStoreCart();
|
2020-04-07 11:03:22 +00:00
|
|
|
const { dispatchActions } = useCheckoutContext();
|
|
|
|
|
2020-03-09 02:09:47 +00:00
|
|
|
// Store quantity in hook state. This is used to keep the UI
|
|
|
|
// updated while server request is updated.
|
2020-03-17 15:34:33 +00:00
|
|
|
const [ quantity, changeQuantity ] = useState( cartItemQuantity );
|
2020-03-09 02:09:47 +00:00
|
|
|
const [ debouncedQuantity ] = useDebounce( quantity, 400 );
|
2020-03-10 16:50:18 +00:00
|
|
|
const previousDebouncedQuantity = usePrevious( debouncedQuantity );
|
2020-03-17 15:34:33 +00:00
|
|
|
const { removeItemFromCart, changeCartItemQuantity } = useDispatch(
|
|
|
|
storeKey
|
|
|
|
);
|
|
|
|
|
2020-04-07 11:03:22 +00:00
|
|
|
const isPendingQuantity = useSelect(
|
2020-03-09 02:09:47 +00:00
|
|
|
( select ) => {
|
2020-03-17 15:34:33 +00:00
|
|
|
if ( ! cartItemKey ) {
|
|
|
|
return false;
|
|
|
|
}
|
2020-04-07 11:03:22 +00:00
|
|
|
|
2020-02-28 02:05:10 +00:00
|
|
|
const store = select( storeKey );
|
2020-04-07 11:03:22 +00:00
|
|
|
return store.isItemPendingQuantity( cartItemKey );
|
2020-02-28 02:05:10 +00:00
|
|
|
},
|
2020-03-17 15:34:33 +00:00
|
|
|
[ cartItemKey ]
|
2020-02-28 02:05:10 +00:00
|
|
|
);
|
2020-03-09 02:09:47 +00:00
|
|
|
|
2020-04-07 11:03:22 +00:00
|
|
|
const isPendingDelete = useSelect(
|
|
|
|
( select ) => {
|
|
|
|
if ( ! cartItemKey ) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
const store = select( storeKey );
|
|
|
|
return store.isItemPendingDelete( cartItemKey );
|
|
|
|
},
|
|
|
|
[ cartItemKey ]
|
|
|
|
);
|
2020-03-09 02:09:47 +00:00
|
|
|
const removeItem = () => {
|
2020-03-17 15:34:33 +00:00
|
|
|
return cartItemKey ? removeItemFromCart( cartItemKey ) : false;
|
2020-03-09 02:09:47 +00:00
|
|
|
};
|
|
|
|
|
2020-03-17 15:34:33 +00:00
|
|
|
// Observe debounced quantity value, fire action to update server on change.
|
2020-03-09 02:09:47 +00:00
|
|
|
useEffect( () => {
|
2020-03-10 16:50:18 +00:00
|
|
|
// Don't run it if quantity didn't change but it was set for the first time.
|
2020-03-17 15:34:33 +00:00
|
|
|
if ( cartItemKey && Number.isFinite( previousDebouncedQuantity ) ) {
|
|
|
|
changeCartItemQuantity( cartItemKey, debouncedQuantity );
|
2020-03-10 16:50:18 +00:00
|
|
|
}
|
2020-03-17 15:34:33 +00:00
|
|
|
}, [ debouncedQuantity, cartItemKey ] );
|
2020-04-07 11:03:22 +00:00
|
|
|
useEffect( () => {
|
|
|
|
if ( isPendingQuantity ) {
|
|
|
|
dispatchActions.incrementCalculating();
|
|
|
|
} else {
|
|
|
|
dispatchActions.decrementCalculating();
|
|
|
|
}
|
|
|
|
}, [ isPendingQuantity ] );
|
|
|
|
|
|
|
|
useEffect( () => {
|
|
|
|
if ( isPendingDelete ) {
|
|
|
|
dispatchActions.incrementCalculating();
|
|
|
|
} else if ( ! isPendingDelete && cartErrors.length ) {
|
|
|
|
dispatchActions.decrementCalculating();
|
|
|
|
}
|
|
|
|
return () => {
|
|
|
|
if ( isPendingDelete ) {
|
|
|
|
dispatchActions.decrementCalculating();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}, [ isPendingDelete ] );
|
2020-02-28 02:05:10 +00:00
|
|
|
|
|
|
|
return {
|
2020-04-07 11:03:22 +00:00
|
|
|
isPendingDelete,
|
2020-03-09 02:09:47 +00:00
|
|
|
quantity,
|
|
|
|
changeQuantity,
|
|
|
|
removeItem,
|
2020-03-10 15:49:26 +00:00
|
|
|
cartItemQuantityErrors: cartErrors,
|
2020-02-28 02:05:10 +00:00
|
|
|
};
|
|
|
|
};
|