import { useState, useEffect } from "react"; import { Box, Typography, Button, TextField, CircularProgress } from "@mui/material"; import AddIcon from '@mui/icons-material/Add'; import RemoveIcon from '@mui/icons-material/Remove'; import { useSelector, useDispatch } from "react-redux"; import { createCart, addItemToCart } from "../../redux/slices/cartSlice"; import Alert from '@mui/material/Alert'; import AlertTitle from '@mui/material/AlertTitle'; // Utility function to check if an object is empty const isEmptyObject = (obj) => Object.keys(obj).length === 0 && obj.constructor === Object; // Check if every key in the target object matches the source object const hasMatchingProperties = (source, target) => { return Object.entries(target).every(([key, value]) => source[key] === value); }; const ProductDetails = () => { const dispatch = useDispatch() const product = useSelector((state) => state.products.product.data) const cart = useSelector((state) => state.cart.cart) const [quantity, setQuantity] = useState(1) const [variantSelection, setVariantSelection] = useState({ amount: "0", currencyCode: "" }) const [variants, setVariants] = useState([]) const [showLoader, setShowLoader] = useState(false) const [alert, setAlert] = useState({ open: false, severity: '', message: '' }); useEffect(() => { if (!isEmptyObject(product)) { console.log("Product: ", product) let productVariants = product?.variants // get all variant type if (!productVariants || productVariants?.length == 0) return // we want to get the title for each variant const uniqueOptions = {}; productVariants.forEach(variant => { variant.selectedOptions.forEach(option => { if (!uniqueOptions[option.name]) { uniqueOptions[option.name] = new Set(); } uniqueOptions[option.name].add(option.value); }); }); const VariantsArr = Object.entries(uniqueOptions).map(([key, valueSet]) => ({ name: key, options: Array.from(valueSet), })); // get variants value setVariants(VariantsArr) // setting Initial value for variants selection setVariantSelection((prev) => { let newVariantSelection = { ...prev } // setting inital selection VariantsArr.forEach(({ name, options }) => { newVariantSelection = { ...newVariantSelection, [name]: options[0] } }) // find variant price if it all match initial variant selection for (const { selectedOptions, price, compareAtPrice, id, quantityAvailable } of productVariants) { let { amount, currencyCode } = price; if (compareAtPrice?.amount > 0) { amount = compareAtPrice?.amount currencyCode = compareAtPrice?.currencyCode } // Convert array to object const optionsObject = selectedOptions.reduce( (a, { name, value }) => ({ ...a, [name]: value }), {} ); if (hasMatchingProperties(newVariantSelection, optionsObject)) { newVariantSelection = { ...newVariantSelection, amount, currencyCode, id, quantityAvailable }; break; // Exit the loop when condition is met } } return newVariantSelection }) } }, [product]) useEffect(() => { console.log("variantSelection: ", variantSelection) }, [variantSelection]) const handleVariantClick = (name, value) => { setVariantSelection({ ...variantSelection, [name]: value }) setVariantSelection((prev) => { let newVariantSelection = { ...prev } newVariantSelection = { ...newVariantSelection, [name]: value } let productVariants = product?.variants // find variant price if it all match initial variant selection for (const { selectedOptions, price, compareAtPrice, id, quantityAvailable } of productVariants) { let { amount, currencyCode } = price; if (compareAtPrice?.amount > 0) { amount = compareAtPrice?.amount currencyCode = compareAtPrice?.currencyCode } // Convert array to object const optionsObject = selectedOptions.reduce( (a, { name, value }) => ({ ...a, [name]: value }), {} ); if (hasMatchingProperties(newVariantSelection, optionsObject)) { newVariantSelection = { ...newVariantSelection, amount, currencyCode, id, quantityAvailable }; if (quantityAvailable == 0) setQuantity(0) else setQuantity(1) break; // Exit the loop when condition is met } } return newVariantSelection }) } const handleCart = () => { let cartHistory = localStorage.getItem('amber-cart'); cartHistory = cartHistory ? JSON.parse(cartHistory) : {}; setShowLoader(true) //cause I want to prevent user from mutiple clicking // if we got no cart, then create a new one if (isEmptyObject(cart) || isEmptyObject(cartHistory)) { dispatch(createCart()) .then(() => { showAlert('success', 'Cart created successfully!'); }) .catch(() => { showAlert('error', 'Failed to create cart. Please try again.'); }) .finally(() => setShowLoader(false)); } else { console.log("ADD ITEM:", variantSelection) dispatch(addItemToCart({ cartId: cartHistory.id, lines: [ { merchandiseId: variantSelection.id, quantity } ] })) .then(() => { showAlert('success', 'Item added to cart successfully!'); }) .catch(() => { showAlert('error', 'Failed to add item to cart. Please try again.'); }) .finally(() => setShowLoader(false)); } } const showAlert = (severity, message) => { setAlert({ open: true, severity, message }); // Auto-close the alert after 3 seconds setTimeout(() => { setAlert({ ...alert, open: false }); }, 2000); }; const handleIncrement = () => { setQuantity((prevQuantity) => (prevQuantity >= variantSelection.quantityAvailable ? variantSelection.quantityAvailable : prevQuantity + 1)); }; const handleDecrement = () => { setQuantity((prevQuantity) => (prevQuantity > 1 ? prevQuantity - 1 : 1)); }; return ( {/* Flex Container */} {/* Section 1: Product Info */} {product?.title} {/* {product?.collections?.nodes[0]?.title} */} {(variantSelection?.quantityAvailable == 0) ? {`OUT OF STOCK`} : `${variantSelection.currencyCode} ${parseFloat(variantSelection.amount).toFixed(2)}`} {/* Section 2: Variants */} {variants.map(({ name, options }, index) => { return ( {name} {options?.map((value) => ( ))} ) })} {/* Section 3: Quantity */} Quantity {/* Section 4: Description */} Description
{cart?.lines?.nodes?.length > 0 && }
{alert.open && ( setAlert({ ...alert, open: false })} sx={{ marginTop: 2 }} > {alert.severity === 'success' ? 'Success' : 'Error'} {alert.message} )}
); }; export default ProductDetails;