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 25

Preguntas 4

Ordenar por:

驴Quieres ver m谩s aportes, preguntas y respuestas de la comunidad?

o inicia sesi贸n.

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:

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'>

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

Asi va mi Cart

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([鈥ontext.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>
};

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

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?

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>
        )}
la lista de videos esta muy mal ubicado, me es incomodo bajar hasta abajo, pierdo tiempo y concentracion
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
驴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 鈥榗antidad鈥 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 .