I creating clone of frontend of this website, everything is going smoothly but when I reached at cart section I find there is a lot of work. In short, I just create a Add to Cart button for my website and as user clicks the item placed in cart. In cart I want to create an edit functionality in which user can select his/her size of dress for this I create a modal (using Frammer-Motion) which will shown when user clicks add to cart button but every time when I click on Edit button, modal opens with the same data(which is the last item in cart) and when I click on sizeOption(i.e M, L, XL) it updates the same item (which is the last item)
Cart Component
import { BiEdit, BiMinusCircle, BiPlusCircle } from "react-icons/bi"
import { BsCartX } from "react-icons/bs"
import { MdDeleteOutline } from "react-icons/md"
import { Link } from "react-router-dom"
import { cartState } from "../recoilState"
import { useRecoilState } from "recoil"
import toast, { Toaster } from 'react-hot-toast';
import NewModal from '../../components/NewModal'
import { useState } from "react"
import { AnimatePresence} from "framer-motion"
const notify = () =\> toast.error('Item Removed From Cart')
const Cart = () =\> {
const [cart, setCart] = useRecoilState(cartState)
const [modalOpen, setModalOpen] = useState(false)
const close = () => setModalOpen(false)
const open = () => setModalOpen(true)
const handleEdit = (selectedSize: any, id: string) => {
setCart((prevCart) => {
return prevCart.map((item) => {
console.log('Checking Item', item.productId)
if (item.productId === id) {
console.log('updating Item', item.productId)
return {
...item,
selectedSize: selectedSize,
}
} else {
return item
}
});
});
};
const handleQuantityChange = (id: string, action: string) => {
setCart((prevCart) => {
return prevCart.map((item) => {
if (item.productId === id) {
if (action === 'increment') {
return { ...item, quantityInCart: item.quantityInCart + 1 };
} else if (action === 'decrement' && item.quantityInCart > 1) {
return { ...item, quantityInCart: item.quantityInCart - 1 };
}
}
return item;
});
});
};
const removeItem = (id: string) => {
setCart((prevCart) => prevCart.filter((item) => item.productId !== id));
};
return (
<div className="p-40">
{cart.length === 0
?
(
<div className='flex flex-col items-center gap-y-44 '>
<h1 className='font-bold text-xl'>SHOPPING CART</h1>
<div className="flex flex-col items-center w-[800px] text-left gap-y-10">
<BsCartX size={150} />
<p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Pariatur similique voluptatem nisi fugit aperiam quasi veniam temporibus, magni fuga repudiandae.</p>
<Link to={'/'}>
<button className="bg-black p-4 text-lg text-white rounded-lg">Return to Shopping</button>
</Link>
</div>
</div>
)
:
(
<>
<h1 className="text-xl text-center font-semibold mb-10 uppercase">Your Cart</h1>
{cart.map((item, index) => {
return (
<div className="flex gap-x-5 mt-16" key={index}>
<div className="flex flex-col gap-y-10 items-start w-[50%]">
<h2 className="font-semibold uppercase ">
Product
</h2>
<div className="flex gap-x-5 items-center">
<img
src={item.image}
className="rounded-lg w-[100px]"
/>
<div className="flex flex-col justify-between">
<div className="text-sm flex flex-col gap-y-2">
<h4 className="font-semibold">{item.name}</h4>
<p className="">Category: {item.category}</p>
<p>Size: {item.selectedSize}</p>
</div>
<div className="flex gap-x-2 mt-5">
<BiEdit
size={20}
onClick={open}
className="cursor-pointer"
/>
<MdDeleteOutline
className="cursor-pointer"
size={20}
onClick={() => {
removeItem(item.productId)
notify()
}}
/>
<Toaster />
</div>
</div>
</div>
</div>
<div className="flex flex-col w-[20%] gap-y-24">
<h2 className="font-semibold uppercase ">Price</h2>
<p>Rs. {item.price}</p>
</div>
<div className="flex flex-col items-center w-[20%] gap-y-24">
<h2 className="font-semibold uppercase ">Quantity</h2>
<div className="flex gap-x-3 items-center">
<BiPlusCircle size={20} onClick={() => handleQuantityChange(item.productId, 'increment')} />
{item.quantityInCart}
{item.quantityInCart > 1 && <BiMinusCircle size={20} onClick={() => handleQuantityChange(item.productId, 'decrement')} />}
</div>
</div>
<div className="flex flex-col items-end w-[20%] gap-y-24">
<h2 className="font-semibold uppercase ">Total</h2>
<p>Total Price: {item.quantityInCart * item.price}</p>
</div>
<AnimatePresence
initial={false}
mode='wait'
onExitComplete={() => null}
>
{modalOpen && <NewModal modalOpen={modalOpen} handleClose={close} text={item.name} size={item.sizeOptions} id={item.productId} handleEdit={handleEdit} infoModal={false} />}
</AnimatePresence>
</div>
)
})}
<div className="mt-20 text-xl font-semibold">
Total Bill: {cart.reduce((total: any, item: any) => total + item.quantityInCart * item.price, 0)}
</div>
</>
)
}
</div>
)
}
export default Cart
Modal Component
import React from "react";
import { motion } from "framer-motion";
import Backdrop from "./Backdrop";
const dropIn = {
hidden: {
y: "-100vh",
opacity: 0,
},
visible: {
y: "0",
opacity: 1,
transition: {
duration: 0.1,
type: "spring",
damping: 25,
stiffness: 500,
},
},
exit: {
y: "100vh",
opacity: 0,
},
};
const styles: React.CSSProperties = {
width: 'clamp(50%, 700px, 90%)',
borderRadius: '12px',
backgroundColor: '#fff',
}
const Modal = ({ handleClose, text, infoModal, size, id, handleEdit }: any) => {
return (
<Backdrop onClick={handleClose}>
<motion.div
onClick={(e) => e.stopPropagation()}
style={styles}
variants={dropIn}
initial="hidden"
animate="visible"
exit="exit"
>
{infoModal === true ?
(
<div className="flex justify-between items-center p-10">
<p className="text-2xl">{text}</p>
<button onClick={handleClose} className=" bg-orange-600 px-4 py-2 rounded-full" >Close</button>
</div>
)
:
(
<div className="p-10 flex flex-col gap-y-5">
{text}
<div className="flex gap-x-5 items-center">
<p>Size:</p>
{size.map((selectedSize: any, index: any) => {
return (
<motion.div
key={index}
className="border cursor-pointer px-4 py-2 text-lg"
onClick={() => handleEdit(selectedSize, id)}
whileHover={{backgroundColor: "black", color: 'white'}}
whileTap={{backgroundColor: "#707B7C"}}
>
{selectedSize}
</motion.div>
)
})}
</div>
<button onClick={handleClose} className=" bg-orange-600 px-4 py-2 rounded-full" >Close</button>
</div>
)
}
</motion.div>
</Backdrop>
);
};
export default Modal;
I want to display data on the modal according to the input and update on cart accordingly