0

I want to explain the use case i have so you can understand it well

I have Cart & Products when the user adds the product (product_id = 1) twice to the cart and the product has the same options (red, xl) I increment the quantity,

if the user adds the same (product_id = 1) but with other options (green, xl), I add this product to the cart as a separate product.

Now this works well!

but when the user after added the above 2 products and add the same product with the same option (red, xl) again, It's added as a separated product!

What I expected if the product options existing before should increment the quantity otherwise added it as a separate.

What i tried

add the option ids into the Product property and check if it exists before or not then handle what I want but it does not work well and added the third product as a separate one!

Screen Record

code snippet

zustand Store

interface CartProductsProp extends State {
  cartProducts: ProductProps[];
  addToCart: (Products: ProductProps) => void;
  updateProductQuantity: (
    Product: ProductProps,
    updatedQuantity: number,
  ) => void;
  checkProductOptionsExist: (
    Product: ProductProps,
    updatedQuantity: number,
  ) => void;
  ...
}


export const useCartProduct = create<CartProductsProp>(
  persist(
    (set, get) => ({
      cartProducts: [],
      addToCart: (product) => {
        set((prev) => ({
          cartProducts: [...prev.cartProducts, {...product}],
        }));
      },
      checkProductOptionsExist: (
         product: ProductProps,
         updatedQuantity: number,
       ) => {
         set((prev) => {
           console.log('->prev', JSON.stringify(prev.cartProducts));
           console.log(
          'check==>IDs',
              cartProduct.id === product.id &&
              product.productOptionIds === cartProduct.productOptionIds,
           ); // for some reason this run towic when add the third product"with same options as first product "red,xl" true then false

           return prev.cartProducts.map((cartProduct) => {
             cartProduct.id === product.id &&
             product.productOptionIds === cartProduct.productOptionIds
               ? get().updateProductQuantity(product, updatedQuantity)
               : get().addToCart(product);
           });
         });
       },
       // To Update the quantity when product exist in cart before
       updateProductQuantity: (
         product: ProductProps,
         updatedQuantity: number,
       ) => {
         set((prev) => {
           let currentCart = prev.cartProducts.map((cartProduct) =>
             cartProduct.id === product.id &&
             areEqual(cartProduct.selectedOptions, product.selectedOptions)
               ? 
                 {
                  ...product,
                  quantity: cartProduct?.quantity! + updatedQuantity,
                  updated: 'yes@',
                  productTotalPrice:
                    (cartProduct?.quantity! + updatedQuantity) *
                    cartProduct.price,
                }
              : cartProduct,
            );
          console.log('##currentCart', JSON.stringify(currentCart));
          return {
            cartProducts: currentCart,
          };
        });
        ...
      },
    }),
    {
      name: 'cartListProduct-local',
      getStorage: () => AsyncStorage,
    },
  ),
);

Product Details

 const addProductToCart = () => {
      let productOptionIds = allOptions
        .map(({id}: {id: number | string}) => id)
        .sort()
        .join(',');
      let currentProduct = {
        ...item,
        id: item.id,
        product_id: item.id,
        quantity: currentQuantity,
        price: updatedPrice,
        productTotalPrice: updatedPrice * currentQuantity,
        selectedOptions: allOptions,
        productOptionIds: productOptionIds,
      };
      setAddToCartLoading(true);
      if (
        !cartProductList.some((alreadyExist) => alreadyExist.id === item.id)
      ) {
        addToCart(currentProduct);
        Alert.alert(t('addedSuccessfully'));
        setAddToCartLoading(false);
      } else {
        checkProductOptionsExist(currentProduct, currentQuantity);
        Alert.alert(t('addedSuccessfully'));
      }
  };

Utility

export const areEqual = (a: arrayProps = [], b: arrayProps = []): boolean => {
  // compare length of arrays
  if (a.length !== b.length) {
    return false;
  }
  // get ids set in b
  const idsSetInB = new Set(b.map(({id}: {id: number | string}) => id));
  console.log('idsSetInB', idsSetInB);
  // iterate over a, and check if the id of an item is not in b
  for (let {id} of a) {
    if (!idsSetInB.has(id)) {
      return false;
    }
  }
  // if it passes all the items, return true
  return true;
};
Oliver D
  • 2,579
  • 6
  • 37
  • 80
  • It seems that the code here is not complete. Can you provide a simple sandbox showing your demo? It doesn't necessarily have to use the technologies you're using. – Majed Badawi Jun 05 '21 at 16:19
  • 1
    Hey, @MajedBadawi I solve it, check the Below answer :) thanks for your interest – Oliver D Jun 05 '21 at 16:25

1 Answers1

1

I just add the checks in the Product Details, not in the store,

first, get the targeted product from the Cart so I can here check if it exists before or not based on the optionsIDs if the return undefined that's mean the product + options, not in the cart so I add it as a separated product otherwise I update the quantity and it works well.

Maybe I can't do this in the store itself checkProductOptionsExist, (if u have any explanation tell me please)

If u have an any better idea do it please ;)

...
if (
    !cartProductList.some((alreadyExist) => alreadyExist.id === item.id)
  ) {
    addToCart(currentProduct);
    Alert.alert(t('addedSuccessfully'));
    setAddToCartLoading(false);
}
else {
        let res = cartProductList.find(
          (currentProd) =>
            currentProd.product_id === currentProduct.product_id &&
            currentProd.productOptionIds === currentProduct.productOptionIds, // or areEqual FC ;)
        );
        res != null
          ? updateProductQuantity(currentProduct, currentQuantity)
          : addToCart(currentProduct);
        setAddToCartLoading(false);
        Alert.alert(t('addedSuccessfully'));
  }

store

....
updateProductQuantity: (
        product: ProductProps,
        updatedQuantity: number,
      ) => {
        set((prev) => {
          let currentCart = prev.cartProducts.map((cartProduct) =>
            cartProduct.id === product.id &&
            areEqual(cartProduct.selectedOptions, product.selectedOptions)
              ? {
                  ...product,
                  quantity: cartProduct?.quantity! + updatedQuantity,
                  productTotalPrice:
                    (cartProduct?.quantity! + updatedQuantity) *
                    cartProduct.price,
                }
              : cartProduct,
          );
          return {
            cartProducts: currentCart,
          };
        });
      },
....
Oliver D
  • 2,579
  • 6
  • 37
  • 80