No tienes acceso a esta clase

¡Continúa aprendiendo! Únete y comienza a potenciar tu carrera

Evitando productos duplicados en el carrito

18/31
Recursos

Aportes 56

Preguntas 5

Ordenar por:

¿Quieres ver más aportes, preguntas y respuestas de la comunidad?

por si alguien le sirve, yo desde antes habia creado es una funcion que agrega los productos al carrito y si se vuelve a dar al mismo producto lo que hace es sumar la cantidad y el precio

  //Agrega un producto al carrito, y si ya existe aumenta la cantidad y suma los productos
  const addProduct = payload => {
    const productIndex = cart.findIndex(product => product.id === payload.id)
    let newCart = []
    if (productIndex >= 0) {
      newCart = [...cart]
      newCart[productIndex].quantity++
      newCart[productIndex].price = payload.price + newCart[productIndex].price
    } else {
      newCart = [...cart, { ...payload, quantity: 1 }]
    }
    setCart(newCart)
    getTotalInfo(newCart)
    openCheckoutSideMenu()
  }

Les comparto como lo realicé haciendo uso del método some, el cual directamente nos devuelve el booleano de si hay al menos un elemento que cumpla con la condición que le damos:

Me parece que esa función auxiliar renderIcon que estamos definiendo dentro del mismo componente debería hacerse por fuera del mismo, incluso como un componente aparte. Así evitamos que react redefina la función en cada re-render del componente padre, y dejamos que react decida cuándo re-renderizar el componente hijo, así:

import { useContext } from "react"
import { PlusIcon, CheckIcon } from '@heroicons/react/24/solid'
import { ShoppingCartContext } from "../../context"

const AddItemButton = ({ isInCart, onItemAdded }) => {
  if ( isInCart ) {
    return (
      <div className="absolute top-0 right-0 flex justify-center items-center bg-black w-6 h-6 rounded-full m-2 p-1">
        <CheckIcon className="w-6 h-6 text-white" />
      </div>
    )
  }

  return (
    <div
      className="absolute top-0 right-0 flex justify-center items-center bg-white w-6 h-6 rounded-full m-2 p-1"
      onClick={onItemAdded}
    >
      <PlusIcon className="w-6 h-6 text-black" />
    </div>
  )
}

export default function Card({ item }) {
  const context = useContext(ShoppingCartContext)

  const showProduct = () => {
    context.setSelectedProduct(item)
    context.openProductDetails()
    context.closeCheckoutMenu()
  }

  const addToCart = (event) => {
    event.stopPropagation();

    const newCartProducts = [...context.cartProducts, item]
    context.setCartProducts(newCartProducts)
    context.setCount(context.count + 1)
    context.openCheckoutMenu()
    context.closeProductDetails()
  }

  const isInCart = !!context.cartProducts.find(product => product.id === item.id)

  return (
    <div
      className="bg-white cursor-pointer w-56 h-60"
      onClick={showProduct}
    >
      <figure className="relative mb-2 w-full h-4/5">
        <span className="absolute bottom-0 left-0 bg-white/60 rounded-full text-black text-xs px-3 py-1 m-2">
          { item.category.name }
        </span>
        <img className="w-full h-full object-cover rounded-lg" src={item.images[0]} alt={item.title} />

        <AddItemButton
          isInCart={isInCart}
          onItemAdded={addToCart}
        />
      </figure>

      <p className="flex justify-between items-center">
        <span className="text-sm font-light">
          { item.title }
        </span>
        <span className="text-lg font-medium">
          ${ item.price }
        </span>
      </p>
    </div>
  )
}

En este caso tal vez no haga gran diferencia, pero en otros escenarios ese patrón de definir componentes dentro de componentes puede causar bugs raros, por ejemplo esto:

https://levelup.gitconnected.com/code-review-avoid-declaring-react-component-inside-parent-component-1768a645f523

En mi caso trate de no sobre cargar el componente card y cree un componente aparte para del boton de AddToCart sin repetir mucho codigo

Yo agregué al bg una transparencia:

className='absolute top-0 right-0 flex justify-center items-center bg-black/50 w-6 h-6 rounded-full m-2 p-1'>

Asi va mi Cart

Buen día Estoy siguiendo el curso y voy bien. Estoy revisando los comentarios de los compañeros , es mas interesante escoger del mismo producto varias veces con un contador. hasta el momento lo llevo igual a los videos , mientras aprendo mas de react. saludos a todos ![](https://static.platzi.com/media/user_upload/imagen-c35ce926-2439-46cd-9115-59ac63d1e017.jpg)

Por si a alguien le suena, no hice función:

<figure className='relative mb-5 w-full h-4/5'>
        <span className='absolute bottom-0 left-0 bg-white/80 rounded-lg text-black text-xs m-2 p-1'>
          Categorie {data?.volumeInfo?.categories}
        </span>
        <img
          className='w-full h-full object-fit rounded-lg'
          src={data?.data?.volumeInfo?.imageLinks?.thumbnail}
          alt='book'
        />
        {context.cartProducts.filter((product) => product.id === data?.data?.id)
          .length > 0 ? (
          <div className='absolute top-0 right-0 flex justify-center items-center text-xs bg-white w-6 h-6 rounded-full m-2'>
            <AiOutlineCheck className='h-5 w-5 text-green-600' />
          </div>
        ) : (
          <div
            className='absolute top-0 right-0 flex justify-center items-center text-xs bg-white/80 w-6 h-6 rounded-full m-2'
            onClick={(event) => addBookToCart(event, data?.data)}
          >
            <HiOutlinePlus />
          </div>
        )}
Por que quitaron la fecha de los comentarios del curso? me era util para poder visualizar el ultimo comentario, al menos asi me entero lo desactualizado que es esta el curso en algunos comentarios se podia ver como que le falta al curso y si esta desactualizado con que lo actualizaron

lo resumí un poco más sencillo: cree un estado isClicked el cual se cambia cuando se hace click en el más y dependiendo de ello se muestra o un icono u otro
![](```
const [isClicked, setIsClicked] = useState(false);

const handleAddToCart = (event) => {
event.stopPropagation();
context.setCart([…context.cart, data.data]);
context.setCount(context.count + 1);
context.handleOpenCheckout();
setIsClicked(true);

<button className={${isClicked ? 'hover:bg-red-600' :'hover:bg-blue-500'} absolute top-0 right-0 flex justify-centetr items-center bg-white w-6 h-6 rounded-full m-2 p-1}>
{isClicked ? (
<CheckIcon className="h-6 w-6 text-green-600 " />
) : (
<PlusCircleIcon
className="h-6 w-6 text-black hover:text-white "
onClick={(event) => handleAddToCart(event)}
/>
)}
</button>
};

Yo lo hice agregando una propiedad quantity que inicia en 1 y cuando se vuelve a agregar un producto que ya está en el carrito se incrementa quantity

Esto facilita mucho todo porque no es necesario crear otra función para incrementar los productos.
(cambiando el += 1 por -= 1 se puede decrementar la cantidad de productos)

const addToCart = (product) => {
  // Busca el índice del producto en el carrito
  const productInCart = cart.findIndex(item => item.id === product.id)

  // Si el producto ya está en el carrito (índice mayor o igual a 0)
  if (productInCart >= 0) {
    // Clona el carrito existente para no mutar el estado directamente
    const newCart = structuredClone(cart)

    // Incrementa la cantidad del producto existente en el carrito
    newCart[productInCart].quantity += 1

    // Actualiza el estado del carrito con el nuevo carrito clonado
    setCart(newCart)
  } else {
    // Si el producto no está en el carrito, crea un nuevo carrito
    // usando el estado anterior y agrega el nuevo producto con cantidad 1
    setCart(prevState => ([
      ...prevState,
      {
        ...product,
        quantity: 1
      }
    ]))
  }
}

yo lo hice con un operador ternario y utilice también la propiedad 'stroke' de Tailwind que permite establecer color a los trazos del svg , en éste caso 'stroke-current' ya que no lo vi muy lindo el check con un bg-black.   const renderIcon = (id) => {    const isInCart = cartProducts.filter(product => product.id === id).length > 0    return(      \
        {isInCart          ? \<CheckIcon className='w-6 h-6  text-green-700 stroke-current' />          : \<PlusIcon className='w-6 h-6 text-black stroke-current' onClick={(event) => addProductsToCart(event, data.data)}/>        }      \
    )  }
Definitivamente voy por cartProducts.some(...) que ya devuleve un booleano, pero como siempre, lo importante primero es encontrar una solución eficaz y después mejorar la eficiencia si es requerido.
Una mejor manera es usar el método some de los arrays para encontrar si existe algún producto en el carro "isInCart", es mas eficiente por que se detiene hasta encontrar uno, retorna un booleano y es menos código que escribir ejemplo `const isInCart = context.cartProducts.some(``p`` => p.id === product.id)`

Si estan en Windows pueden agregar la siguientes clases de TailwindCSS para que el Scroll se vea mas estilizado.

[&::-webkit-scrollbar]:w-2
[&::-webkit-scrollbar-track]:rounded-full
[&::-webkit-scrollbar-track]:bg-gray-100
[&::-webkit-scrollbar-thumb]:rounded-full
[&::-webkit-scrollbar-thumb]:bg-gray-300

Con SVG sin necesidad de instalar dependencias:

const renderIcon = (id) => {
    const isInCard = context.CartProducts.filter((product) => product.id === id).length > 0

    if (isInCard) {
      return (
        <button className="absolute top-0 right-0 flex justify-center items-center bg-black w-6 h-6 rounded-full m-2 p-1 cursor-pointer">
          {/* check icon */}
          <svg xmlns="https://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" className="w-6 h-6 text-white">
            <path fillRule="evenodd" d="M19.916 4.626a.75.75 0 01.208 1.04l-9 13.5a.75.75 0 01-1.154.114l-6-6a.75.75 0 011.06-1.06l5.353 5.353 8.493-12.739a.75.75 0 011.04-.208z" clipRule="evenodd" />
          </svg>
        </button>
      )
    } else {
      return (
        <button
          onClick={(event)=> addProductsToCart(event, data.data)}
          className="absolute top-0 right-0 flex justify-center items-center bg-white w-6 h-6 rounded-full m-2 p-1 cursor-pointer"
        >
          {/* + plus icon */}
          <svg xmlns="https://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" className="w-6 h-6">
            <path fillRule="evenodd" d="M12 3.75a.75.75 0 01.75.75v6.75h6.75a.75.75 0 010 1.5h-6.75v6.75a.75.75 0 01-1.5 0v-6.75H4.5a.75.75 0 010-1.5h6.75V4.5a.75.75 0 01.75-.75z" clipRule="evenodd" />
          </svg>
        </button>
      )
    }
  }

Una consulta

const addProductToCard=(e,productData)=>{
    
        const test={
            id:productData.id,
            price:productData.price,
            images:productData.images,
            title:productData.title,
            counter:productData.counter,
            priceref:productData.price
        }
        
        const checker=context.cartProducts.findIndex((prd)=>prd.id===test.id)
        if(checker!=-1){
            test.price=context.cartProducts[checker].price+productData.price
            context.cartProducts.splice(checker,1)
             
        }
        context.setCartProducts([...context.cartProducts,test])
        ;
        e.stopPropagation()
        context.setCount(context.count+1)        
        context.openCheckoutSideMenu()
    }
<code> 

Quería conseguir que los precios se sumaran cuando un cliente comprase varios productos del mismo tipo,pero tuve que crear un objeto adicional (const test)y copiar manualmente los valores del productData,ya que al modificar el productData, el Data.Data(objeto que se renderiza en la pantalla principal como Card) tambien se modificaba y terminaba con los precios sumados en la misma pantalla principal.

Alguien podria decirme por que pasa esto y como evitarlo o sortearlo sin tener que hacer otro objeto?

Agregaría un total para tener en el checkoutsidemenu, ```js const total = productsInCart.reduce((acc, product) => acc + product.price, 0); ```
Nuevamente mi funcion, veo que no quedo bien: ```js const renderIcon = (id) => { const IconComponent = cartProducts.some(product => product.id === id) ? FaCheck : FaPlus; return ( <IconComponent className='absolute top-0 right-0 flex justify-center items-center bg-white text-black w-6 h-6 rounded-full m-2 p-1' onClick={(e) => addProductsToCart(e, data?.data)} /> ) } ```
Está es mi función: ```jsx const renderIcon = (id) => { const IconComponent = cartProducts.some(product => product.id === id) ? FaCheck : FaPlus; return ( <IconComponent className='absolute top-0 right-0 flex justify-center items-center bg-white text-black w-6 h-6 rounded-full m-2 p-1' onClick={(e) => addProductsToCart(e, data?.data)} /> ) } ```const renderIcon = (id) => { const IconComponent = cartProducts.some(product => product.id === id) ? FaCheck : FaPlus; return ( \<IconComponent className='absolute top-0 right-0 flex justify-center items-center bg-white text-black w-6 h-6 rounded-full m-2 p-1' onClick={(e) => addProductsToCart(e, data?.data)} /> ) }
## ✨🦄 En lo personal, declaré un estado local que determina si el producto se encuentra en el carrito o no. Este estado se actualiza cada que carrito cambia, gracias al uso de useEffect. Con eso podemos ahorrarnos líneas de código y solamente modificar lo que nos interese del botón de añadir. ![](https://static.platzi.com/media/user_upload/image-1bda12d4-5aba-4583-9c33-1fd628141bf8.jpg) Así también podemos seguir evitando la propagación y restringir las funciones de incrementar, setear el carrito y abrir el Checkout menu. ![](https://static.platzi.com/media/user_upload/image-52b49d68-a7d0-41b0-8d44-d2b487e207ea.jpg) Finalmente, así quedó el botón de añadir. ![](https://static.platzi.com/media/user_upload/image-ef585ace-5a9e-4817-bdea-6be3e937ecf1.jpg)
Asi va: Hice que sumara catidad de unidades al producto en el carrito en lugar de permitir uno solo por compra. ![](https://static.platzi.com/media/user_upload/image-4d9ddc82-d44d-4195-ba67-8f947d025d38.jpg)
Mi version de la funcion renderIcon tiene un operador ternario y una variable con las clases dependiendo de si encuentra eo no el elemento en el contexto de cartProducts. ```js import { PlusIcon, CheckBadgeIcon } from '@heroicons/react/24/outline'; import PropTypes from 'prop-types'; import { useContext } from 'react'; import { ShoppingCartContext } from '../../Context'; const Card = ({ data }) => { const context = useContext(ShoppingCartContext); const showProduct = (productDetail) => { context.closeCheckoutSideMenu(); context.openProductDetail(); context.setProductToShow(productDetail); }; const addProductToCart = (event, productData) => { event.stopPropagation(); context.closeProductDetail(); const products = context.cartProducts; const exists = products.some(item => item.id === productData.id); if (!exists) { context.setCartProducts([...products, productData]); context.setCount(context.count + 1); } context.openCheckoutSideMenu(); }; const renderIcon = (id) => { const productObj = context.cartProducts.find(product => product.id === id); const icon = (productObj === undefined) ? <PlusIcon className='size-5'/> : <CheckBadgeIcon className='size-5'/>; const style = (productObj === undefined) ? 'bg-red-400' : 'bg-green-400 cursor-not-allowed'; return (
addProductToCart(event, data) } > { icon }
); }; return (
showProduct(data)} >
{ data.category } { renderIcon(data.id) }

{ context.getFirstThreeWords(data.title) } ${ data.price }

); }; Card.propTypes = { data: PropTypes.shape({ id: PropTypes.string.isRequired, category: PropTypes.string.isRequired, image: PropTypes.string.isRequired, title: PropTypes.string.isRequired, price: PropTypes.number.isRequired, }).isRequired, }; export default Card; ```
Mi version usa un operador ternario y una variable extra para escoger el icono y las clases que lleva. ```jsx import { PlusIcon, CheckBadgeIcon } from '@heroicons/react/24/outline'; import PropTypes from 'prop-types'; import { useContext } from 'react'; import { ShoppingCartContext } from '../../Context'; const Card = ({ data }) => { const context = useContext(ShoppingCartContext); const showProduct = (productDetail) => { context.closeCheckoutSideMenu(); context.openProductDetail(); context.setProductToShow(productDetail); }; const addProductToCart = (event, productData) => { event.stopPropagation(); context.closeProductDetail(); const products = context.cartProducts; const exists = products.some(item => item.id === productData.id); if (!exists) { context.setCartProducts([...products, productData]); context.setCount(context.count + 1); } context.openCheckoutSideMenu(); }; const renderIcon = (id) => { const productObj = context.cartProducts.find(product => product.id === id); const icon = (productObj === undefined) ? <PlusIcon className='size-5'/> : <CheckBadgeIcon className='size-5'/>; const style = (productObj === undefined) ? 'bg-red-400' : 'bg-green-400 cursor-not-allowed'; return (
addProductToCart(event, data) } > { icon }
); }; return (
showProduct(data)} >
{ data.category } { renderIcon(data.id) }

{ context.getFirstThreeWords(data.title) } ${ data.price }

); }; Card.propTypes = { data: PropTypes.shape({ id: PropTypes.string.isRequired, category: PropTypes.string.isRequired, image: PropTypes.string.isRequired, title: PropTypes.string.isRequired, price: PropTypes.number.isRequired, }).isRequired, }; export default Card; ```
Asi Va: ![](https://static.platzi.com/media/user_upload/image-0e56442c-12ce-4ffe-8bfc-7647985af926.jpg)
Podemos establecer en la Card de una vez el remover el item entonces solo al hacer click al boton de check disminuye el contador en uno, cambia de boton a close , en ese paso lo que use fue un useState local, con true y false, y por ultimo filtra el elemento con todos los que no sean iguales al id mandado y eso es lo que le pasamos a la setCartProducts ![](https://static.platzi.com/media/user_upload/image-4ede69c0-4ba0-4d61-949c-5d05004229ad.jpg)
Me pareció más interesante poder agregar más productos del mismo por cantidad. A nivel de estilos no es lo mejor, pero muestro el producto en el carrito, la cantidad de productos agregado y su precio. Además el contador de productos total, va ligado a el total de productos que he agregado:![](https://static.platzi.com/media/user_upload/image-274178f7-3ef0-4972-b91b-28e4aa6f79b7.jpg)
Así vamos 🤩
Si quieres mostrar la cantidad de objectos y ademas poder comprar el mismo objecto.```js const saveCardProductDetail = (product) => { // Buscamos si ya existe el producto en el carrito const existingProductIndex = context.cardToShow.findIndex((p) => p.id === product.id); if (existingProductIndex >= 0) { // Si ya existe, clonamos el array y actualizamos la cantidad y el precio del producto existente const updatedCardToShow = [...context.cardToShow]; updatedCardToShow[existingProductIndex].quantity++; updatedCardToShow[existingProductIndex].price += product.price; // Actualizamos el contexto con el nuevo array de productos context.setCardToShow(updatedCardToShow); } else { // Si no existe, clonamos el array y agregamos el nuevo producto con cantidad inicial 1 const updatedCardToShow = [...context.cardToShow, { ...product, quantity: 1 }]; // Actualizamos el contexto con el nuevo array de productos context.setCardToShow(updatedCardToShow); } // Incrementamos el contador de productos en el carrito context.setCount((prevCount) => prevCount + 1); const newTotal = Math.round((context.totalPayment + product.price) * 100) / 100; // Actualizamos el total del pago sumando el precio del producto añadido context.setTotalPayment((prevTotal) => Math.round((prevTotal + product.price)*100)/100); // Cerramos el detalle del producto context.toggleProductDetail(); }; ```
Si quieres guardar varias veces el mismo producto. const saveCardProductDetail = (product) => { // Buscamos si ya existe el producto en el carrito const existingProductIndex = context.cardToShow.findIndex((p) => p.id === product.id); if (existingProductIndex >= 0) { // Si ya existe, clonamos el array y actualizamos la cantidad y el precio del producto existente const updatedCardToShow = \[...context.cardToShow]; updatedCardToShow\[existingProductIndex].quantity++; updatedCardToShow\[existingProductIndex].price += product.price; // Actualizamos el contexto con el nuevo array de productos context.setCardToShow(updatedCardToShow); } else { // Si no existe, clonamos el array y agregamos el nuevo producto con cantidad inicial 1 const updatedCardToShow = \[...context.cardToShow, { ...product, quantity: 1 }]; // Actualizamos el contexto con el nuevo array de productos context.setCardToShow(updatedCardToShow); } // Incrementamos el contador de productos en el carrito context.setCount((prevCount) => prevCount + 1); const newTotal = Math.round((context.totalPayment + product.price) \* 100) / 100; // Actualizamos el total del pago sumando el precio del producto añadido context.setTotalPayment((prevTotal) => Math.round((prevTotal + product.price)\*100)/100); // Cerramos el detalle del producto context.toggleProductDetail(); };```js const saveCardProductDetail = (product) => { // Buscamos si ya existe el producto en el carrito const existingProductIndex = context.cardToShow.findIndex((p) => p.id === product.id); if (existingProductIndex >= 0) { // Si ya existe, clonamos el array y actualizamos la cantidad y el precio del producto existente const updatedCardToShow = [...context.cardToShow]; updatedCardToShow[existingProductIndex].quantity++; updatedCardToShow[existingProductIndex].price += product.price; // Actualizamos el contexto con el nuevo array de productos context.setCardToShow(updatedCardToShow); } else { // Si no existe, clonamos el array y agregamos el nuevo producto con cantidad inicial 1 const updatedCardToShow = [...context.cardToShow, { ...product, quantity: 1 }]; // Actualizamos el contexto con el nuevo array de productos context.setCardToShow(updatedCardToShow); } // Incrementamos el contador de productos en el carrito context.setCount((prevCount) => prevCount + 1); const newTotal = Math.round((context.totalPayment + product.price) * 100) / 100; // Actualizamos el total del pago sumando el precio del producto añadido context.setTotalPayment((prevTotal) => Math.round((prevTotal + product.price)*100)/100); // Cerramos el detalle del producto context.toggleProductDetail(); }; ```

Dejo mi resultado y mi código, yo he copiado directamente el svg

el componente card en TS:![](https://static.platzi.com/media/user_upload/carbon%20%284%29-76b97e14-1511-40c9-8ba6-196a8eb67232.jpg)
Buenas, por sí a alguien le sirve dejo por acá mi solución al problema. Le agregué una propiedad al objeto de la API llamada isInCart, a la hora de agregar el producto al carrito, la propiedad pasará a true y cambiará el ícono al check. `const addProductsToCart = () => {` ` context.setCount(context.count + 1);` ` context.setShoppingCart([...context.shoppingCart, card]);` ` // Agrega la propiedad isInCart` ` card.isInCart = true;` ` context.setProductInCart();` ` console.log(context.shoppingCart);` `};` `// Aquí decide mostrar el ícono de agregar o mostrar el check` `{card.isInCart ? <CheckCircleIcon className="h-6 w-6 text-white text-lg"></CheckCircleIcon> : <PlusCircleIcon onClick={() => addProductsToCart()} className="h-6 w-6 text-white text-lg"></PlusCircleIcon>}`
Asi va el mio: ![](https://static.platzi.com/media/user_upload/image-ff14b1a8-8405-4714-9317-271e36ad96fb.jpg)
![](https://static.platzi.com/media/user_upload/image-5abf9af4-de2f-4f54-a14e-53640ef83083.jpg)

para quien le interese, yo le hice un contador para que se agregue mas de 1 unidad:

Context:

    const addCartProductsToCart = (productData)=>{
        openCheckoutSideMenu()
        closeProductDetails()
        setCount(count + 1)
        
  // Verifica si el producto ya está en el carrito
        const existingProductIndex = cartProduct.findIndex((product) => product.id === productData.id);

        if (existingProductIndex !== -1) {
            // Si el producto ya está en el carrito, aumenta la cantidad
            const updatedCartProduct = [...cartProduct];
            updatedCartProduct[existingProductIndex].quantity += 1;
            setCartProduct(updatedCartProduct);
        } else {
            // Si el producto no está en el carrito, agrégalo con cantidad 1
            setCartProduct([...cartProduct, { ...productData, quantity: 1 }]);
        }
    }

checkoutSIdeMenu:

                {
                    cartProduct.map(product=>(
                        <OrderCard
                        key={product.id} 
                        title={product.title}
                        imageUrl={product.image}
                        price={product.price}
                        quantity={product.quantity} // Mostrar la cantidad en lugar de contar entradas
                        />
                        ))

en el OrderCard:

    return(
        <div className="flex justify-between items-center mb-3">
            <div className='flex items-center gap-2 h-[20%]'>
                <figure className='w-20 h-20'>
                    <img className='w-full h-full rounded-lg object-contain' src={imageUrl} alt={title} />
                </figure>
            <div className='w-[60%]'>
                <p className='text-sm font-semibold'>{quantity} Und. </p>
                <p className='text-sm font-light'>{title}</p>
            </div>
            </div>
            <div className='flex items-center gap-2'>
                <p className='text-lg font-medium'>${quantity*price}</p>
                <XMarkIcon className="h-6 w-6 text-black cursor-pointer" />          
            </div>
        </div>
    )

![] (C:\Users\User\Dropbox\Mi PC (LAPTOP-R3ADV6PS)\Downloads\ecommerce.png)

![](https://static.platzi.com/media/user_upload/image-c40c53c3-a75a-41b9-bef5-3c43e9a253d4.jpg)
![](https://static.platzi.com/media/user_upload/image-ef91eccb-7be9-4938-b74b-18dbe8fe2913.jpg)
Así va mi e-commerce. ![](https://static.platzi.com/media/user_upload/image-6ab5432c-400b-4700-9fe1-65087730eb80.jpg)

Así va mi app 💪🏻

Asi vamos!!

la lista de videos esta muy mal ubicado, me es incomodo bajar hasta abajo, pierdo tiempo y concentracion
¿De qué otra manera se puede hacer esto? Hacerlo con un filter es súper pesado para react hace como 4610 de verificaciones; por lo que el performance cae mucho

Asi vamos…

Yo hice una acumulación de los productos.

En el contexto agregue un metodo para hacer la acumulación

const addProductsToCart = (productData) =>{
        console.log("get",getProductsToCart([...cartProducts,productData]));
        setCartProducts(getProductsToCart([...cartProducts,productData]));
    }


    const getProductsToCart = (products) =>{
        const uniqueProducts = products.reduce((accumulator, product) => {
            const existingProduct = accumulator.find(item => item.id === product.id);
          
            if (existingProduct) {
              existingProduct.count ++;
            } else {
              accumulator.push({ id: product.id, count: product.count?product.count:1,image:product.image,price: product.price,title:product.title});
            }
          
            return accumulator;
          }, []);
          return uniqueProducts;
    }

En el ordercard

<div className="flex justify-between items-center">
            <div className="flex items-center gap-2">
                <figure className="w-8 h-8">
                    <img className="w-full h-full rounded-lg object-cover" src={imageUrl} alt={title} />
                </figure>
                <p className="text-medium font-light">{title} x{count}</p>
            </div>
            <div className="flex items-center gap-2">
                <p className="text-lg font-medium">{price}</p>
                <p className="text-lg font-medium">{price*count}</p>
                <XMarkIcon className="h-6 w-6 cursor-pointer"/>
            </div>
        </div>

Así va mi e-commerce

Lo que yo hice fue que; al darle click en el icono se agregue al carrito y al volver a darle click se salga del carrito, en ese caso que seria mejor?

  • que solo se agregue desde la tarjeta y que se quite el producto directamente desde el carrito

o

-como yo hice que se quite y se agrege desde la targeta del producto?

Creo que en el curso no se añaden los botones para aumentar o disminuir la cantidad de cada item añadido al carrito. Aquí las 2 funciones para hacer eso:
Van en el Contexto y se importan en la OrderCard.
En la OrderCard hay que pasar id como props porque se necesita el id para añadir o disminuir la cantidad:

    const quantityAdd = (productId) => {
        const updatedCartProducts = cartProducts.map((item) => {
            if (item.id === productId && item.quantity < 10) {
                return { ...item, quantity: item.quantity + 1 };
            }
            return item;
            });
            setCartProducts(updatedCartProducts);
    }
        
    const quantitySubtract = (productId) => {
        const updatedCartProducts = cartProducts.map((item) => {
        if (item.id === productId && item.quantity > 1) {
            return { ...item, quantity: item.quantity - 1 };
        }
        return item;
        });
        setCartProducts(updatedCartProducts);
    }

Por ahí habían compartido en comentarios en clases anteriores el código para añadir ‘cantidad’ al objeto de cada item a la hora de añadirlo a My Order.

const addProductsToCart = (product) =>{
    //Buscar product en el cart: true/false
    const productExists = cartProducts.some(p => p.id === product.id);
    console.log('product exists: '+productExists);

    //Si el producto existe:
    if (productExists) {
			const productCart = cartProducts.find(p => p.id === product.id); // Busca el producto
			productCart.quantity += 1; // Cantidad = +1
		} else {
			product.quantity = 1; // Si no, crea la propiedad quantity = 1.
      setCartProducts([...cartProducts, product]);
		}

    setCounter(counter+1);
    closeProductDetail();
    openCheckoutSM();
  }

el mi esta quedando asi, ya que es mi pirmera ves usando tailwind cree un archivo css general para yo ir poniendo mis propios estilos .

La API más inestable del mundo. Deberían arreglar esa API.