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!
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;
};
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,
};
});
},
....