woocommerce/plugins/woocommerce-blocks/assets/js/base/context/hooks/use-store-add-to-cart.ts

96 lines
2.7 KiB
TypeScript
Raw Normal View History

/**
* External dependencies
*/
import { useState, useEffect, useRef } from '@wordpress/element';
import { useDispatch } from '@wordpress/data';
import { CART_STORE_KEY as storeKey } from '@woocommerce/block-data';
import { decodeEntities } from '@wordpress/html-entities';
import type { CartItem } from '@woocommerce/types';
/**
* Internal dependencies
*/
import { useStoreCart } from './cart/use-store-cart';
/**
* @typedef {import('@woocommerce/type-defs/hooks').StoreCartItemAddToCart} StoreCartItemAddToCart
*/
interface StoreAddToCart {
cartQuantity: number;
addingToCart: boolean;
cartIsLoading: boolean;
addToCart: ( quantity?: number ) => Promise< boolean >;
}
/**
* Get the quantity of a product in the cart.
*
* @param {Object} cartItems Array of items.
* @param {number} productId The product id to look for.
* @return {number} Quantity in the cart.
*/
const getQuantityFromCartItems = (
cartItems: Array< CartItem >,
productId: number
): number => {
const productItem = cartItems.find( ( { id } ) => id === productId );
return productItem ? productItem.quantity : 0;
};
/**
* A custom hook for exposing cart related data for a given product id and an
* action for adding a single quantity of the product _to_ the cart.
*
*
* @param {number} productId The product id to be added to the cart.
*
* @return {StoreCartItemAddToCart} An object exposing data and actions relating
* to add to cart functionality.
*/
export const useStoreAddToCart = ( productId: number ): StoreAddToCart => {
const { addItemToCart } = useDispatch( storeKey );
const { cartItems, cartIsLoading } = useStoreCart();
Remove `useStoreNotices` and interact directly with data store instead (https://github.com/woocommerce/woocommerce-blocks/pull/6159) * Make useStoreNotices interact directly with the store * Get/set error notices directly in store in paymentMethodDataContext * Add hasNoticesOfType util * Remove useStoreNotices and interact directly with data store * Create/remove notices directly in store * Remove tests for useStoreNotices * Add tests for notices util * Use setIsSuppressed from useStoreNoticesContext * remove useStoreNotices hook * Update context typedef to define only isSuppressed and setIsSuppressed * Remove all values from StoreNoticesContext besides setIsSuppressed * Wrap Cart and Checkout blocks in StoreNoticesProvider (for isSuppressed) * Make StoreNoticesContainer a named export This is required so we can import it from @wooommerce/base-context * Change addErrorNotice to createErrorNotice to match store action * Remove unnecessary StoreNoticeProviders and pass only context to container * Accept a context in StoreNoticesContainer * Pass relevant context to StoreNoticesContainer * Add function to remove notices by status * Prevent checkout from breaking when removing notices during processing * Prevent TS error about not included path * Add StoreNoticesContainer to single product block * Add StoreNoticesContainer to All Products Block * Ensure errors are shown when using All Products & Single Product Blocks * Add a context arg to removeNoticesByStatus * Use correct contexts for all products and single product block * Update tests to reflect new context argument * Re-add missing block file for order-summary * Remove block file for order-summary * Send context to useStoreCartCoupons to show errors correctly
2022-04-08 12:11:50 +00:00
const { createErrorNotice, removeNotice } = useDispatch( 'core/notices' );
const [ addingToCart, setAddingToCart ] = useState( false );
const currentCartItemQuantity = useRef(
getQuantityFromCartItems( cartItems, productId )
);
const addToCart = ( quantity = 1 ) => {
setAddingToCart( true );
return addItemToCart( productId, quantity )
.then( () => {
removeNotice( 'add-to-cart' );
} )
.catch( ( error ) => {
Remove `useStoreNotices` and interact directly with data store instead (https://github.com/woocommerce/woocommerce-blocks/pull/6159) * Make useStoreNotices interact directly with the store * Get/set error notices directly in store in paymentMethodDataContext * Add hasNoticesOfType util * Remove useStoreNotices and interact directly with data store * Create/remove notices directly in store * Remove tests for useStoreNotices * Add tests for notices util * Use setIsSuppressed from useStoreNoticesContext * remove useStoreNotices hook * Update context typedef to define only isSuppressed and setIsSuppressed * Remove all values from StoreNoticesContext besides setIsSuppressed * Wrap Cart and Checkout blocks in StoreNoticesProvider (for isSuppressed) * Make StoreNoticesContainer a named export This is required so we can import it from @wooommerce/base-context * Change addErrorNotice to createErrorNotice to match store action * Remove unnecessary StoreNoticeProviders and pass only context to container * Accept a context in StoreNoticesContainer * Pass relevant context to StoreNoticesContainer * Add function to remove notices by status * Prevent checkout from breaking when removing notices during processing * Prevent TS error about not included path * Add StoreNoticesContainer to single product block * Add StoreNoticesContainer to All Products Block * Ensure errors are shown when using All Products & Single Product Blocks * Add a context arg to removeNoticesByStatus * Use correct contexts for all products and single product block * Update tests to reflect new context argument * Re-add missing block file for order-summary * Remove block file for order-summary * Send context to useStoreCartCoupons to show errors correctly
2022-04-08 12:11:50 +00:00
createErrorNotice( decodeEntities( error.message ), {
id: 'add-to-cart',
Remove `useStoreNotices` and interact directly with data store instead (https://github.com/woocommerce/woocommerce-blocks/pull/6159) * Make useStoreNotices interact directly with the store * Get/set error notices directly in store in paymentMethodDataContext * Add hasNoticesOfType util * Remove useStoreNotices and interact directly with data store * Create/remove notices directly in store * Remove tests for useStoreNotices * Add tests for notices util * Use setIsSuppressed from useStoreNoticesContext * remove useStoreNotices hook * Update context typedef to define only isSuppressed and setIsSuppressed * Remove all values from StoreNoticesContext besides setIsSuppressed * Wrap Cart and Checkout blocks in StoreNoticesProvider (for isSuppressed) * Make StoreNoticesContainer a named export This is required so we can import it from @wooommerce/base-context * Change addErrorNotice to createErrorNotice to match store action * Remove unnecessary StoreNoticeProviders and pass only context to container * Accept a context in StoreNoticesContainer * Pass relevant context to StoreNoticesContainer * Add function to remove notices by status * Prevent checkout from breaking when removing notices during processing * Prevent TS error about not included path * Add StoreNoticesContainer to single product block * Add StoreNoticesContainer to All Products Block * Ensure errors are shown when using All Products & Single Product Blocks * Add a context arg to removeNoticesByStatus * Use correct contexts for all products and single product block * Update tests to reflect new context argument * Re-add missing block file for order-summary * Remove block file for order-summary * Send context to useStoreCartCoupons to show errors correctly
2022-04-08 12:11:50 +00:00
context: 'wc/all-products',
isDismissible: true,
} );
} )
.finally( () => {
setAddingToCart( false );
} );
};
useEffect( () => {
const quantity = getQuantityFromCartItems( cartItems, productId );
if ( quantity !== currentCartItemQuantity.current ) {
currentCartItemQuantity.current = quantity;
}
}, [ cartItems, productId ] );
return {
cartQuantity: Number.isFinite( currentCartItemQuantity.current )
? currentCartItemQuantity.current
: 0,
addingToCart,
cartIsLoading,
addToCart,
};
};