2020-02-28 11:51:30 +00:00
|
|
|
/** @typedef { import('@woocommerce/type-defs/hooks').StoreCartItem } StoreCartItem */
|
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-09 02:09:47 +00:00
|
|
|
import { useDebounce } from 'use-debounce';
|
2020-02-28 02:05:10 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Internal dependencies
|
|
|
|
*/
|
|
|
|
import { useStoreCart } from './use-store-cart';
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 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
|
|
|
*
|
|
|
|
* @param {string} cartItemKey Key for a cart item.
|
2020-02-28 11:51:30 +00:00
|
|
|
* @return {StoreCartItem} An object exposing data and actions relating to cart items.
|
2020-02-28 02:05:10 +00:00
|
|
|
*/
|
|
|
|
export const useStoreCartItem = ( cartItemKey ) => {
|
|
|
|
const { cartItems, cartIsLoading } = useStoreCart();
|
2020-03-09 02:09:47 +00:00
|
|
|
const [ cartItem, setCartItem ] = useState( {
|
|
|
|
key: '',
|
|
|
|
isLoading: true,
|
|
|
|
cartData: {},
|
|
|
|
quantity: 0,
|
|
|
|
isPending: false,
|
|
|
|
changeQuantity: () => void null,
|
|
|
|
removeItem: () => void null,
|
|
|
|
} );
|
|
|
|
// Store quantity in hook state. This is used to keep the UI
|
|
|
|
// updated while server request is updated.
|
|
|
|
const [ quantity, changeQuantity ] = useState( cartItem.quantity );
|
|
|
|
const [ debouncedQuantity ] = useDebounce( quantity, 400 );
|
|
|
|
const isPending = useSelect(
|
|
|
|
( select ) => {
|
2020-02-28 02:05:10 +00:00
|
|
|
const store = select( storeKey );
|
2020-03-09 02:09:47 +00:00
|
|
|
return store.isItemQuantityPending( cartItemKey );
|
2020-02-28 02:05:10 +00:00
|
|
|
},
|
|
|
|
[ cartItemKey ]
|
|
|
|
);
|
2020-03-09 02:09:47 +00:00
|
|
|
useEffect( () => {
|
|
|
|
if ( ! cartIsLoading ) {
|
|
|
|
const foundCartItem = cartItems.find(
|
|
|
|
( item ) => item.key === cartItemKey
|
|
|
|
);
|
|
|
|
if ( foundCartItem ) {
|
|
|
|
setCartItem( foundCartItem );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}, [ cartItems, cartIsLoading, cartItemKey ] );
|
|
|
|
|
|
|
|
const { removeItemFromCart, changeCartItemQuantity } = useDispatch(
|
|
|
|
storeKey
|
|
|
|
);
|
|
|
|
const removeItem = () => {
|
|
|
|
removeItemFromCart( cartItemKey );
|
|
|
|
};
|
|
|
|
|
|
|
|
// Observe debounced quantity value, fire action to update server when it
|
|
|
|
// changes.
|
|
|
|
useEffect( () => {
|
|
|
|
if ( debouncedQuantity === 0 ) {
|
|
|
|
changeQuantity( cartItem.quantity );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
changeCartItemQuantity( cartItemKey, debouncedQuantity );
|
|
|
|
}, [ debouncedQuantity, cartItemKey, cartItem.quantity ] );
|
2020-02-28 02:05:10 +00:00
|
|
|
|
|
|
|
return {
|
2020-03-09 02:09:47 +00:00
|
|
|
isPending,
|
|
|
|
quantity,
|
|
|
|
changeQuantity,
|
|
|
|
removeItem,
|
2020-02-28 02:05:10 +00:00
|
|
|
isLoading: cartIsLoading,
|
|
|
|
cartItem,
|
|
|
|
};
|
|
|
|
};
|