Search code examples
javascriptreactjshoverjsxcart

CartWidget to show products on hover


I have a cartwidget that i would like to show the items that are already in the cart when I put the mouse on the CartWidget. I do not kow how to implement this code. I just create a CartHover component with function and the Cart.js component inside of it. Then, I added CartHover in the CartWidget. But, nothing happened. Maybe there is someone that can help me and do the hover on the cartWidget in another way. This is the CartHover:

import { useState } from "react";
import CartComponent from "../Cart/Cart";

const CartHover = () => {
    const [show, setShow] = useState(false);
    const showCart = (e)=>{
        setShow(!show);
    };
    const hideCart = e => {
        setShow(false);
    };
    return (
        <>
        <div>
            <CartComponent
            show={show}
            onMouseEnter={showCart} 
            onMouseLeave={hideCart}/>
        </div>
        </>
    )
};
export default CartHover;

This is the Cart.jsx where are all the items in the shopping-cart and I want to be seen in the hover, perhaps it is necessary to do a smaller version of it:

import { Table } from "react-bootstrap";
import { Link } from "react-router-dom";
import { useCartContext } from "../../Context/CartContext";

const CartComponent = () => {
  const { list, totalPrice, deleteProd } = useCartContext();
    return (
      <>
      <h1 className="py-4 text-center text-muted">
        Cart
      </h1>
      {list.length > 0 ? (<Table striped hover className="text-muted">
          <thead>
            <tr>
              <th>Product</th>
              <th>Title</th>
              <th>Quantity</th>
              <th>Price</th>
            </tr>
          </thead>
          <tbody>
            {list.map((varietal) => (
              <tr key={varietal.id}>
                <td>
                  <img
                    src={varietal.pictureUrl}
                    alt='img'
                    style={{ width: "82px" }}
                  />
                </td>
                <td className="align-middle">{varietal.title}</td>                
                <td className="align-middle">{varietal.count}</td>
                <td className="align-middle">${varietal.price}</td>
                <td className="align-middle"><button onClick={() => deleteProd(varietal)} className="badge badge-info">Remove</button></td>
              </tr>
            ))}
          </tbody>
          <thead>
            <tr className="font-weight-bold">
              <td colSpan="3">Total</td>
              <td>${totalPrice()}</td>
            </tr>
          </thead>
        </Table>) : (<div className="py-5">
            <h3 className="d-flex justify-content-center pt-5 text-muted">The Cart is empty</h3>
            <p className="d-flex justify-content-center text-muted">
              Return to home to see our products
            </p>
            <Link to='/' className="d-flex justify-content-center text-decoration-none"><button className="btn btn-info"> Home </button></Link>
        </div>)}
        </>
    );
  };

export default CartComponent;

This is the NavBar:

import React from "react";
import { Navbar as NavbarBootstrap, Nav } from "react-bootstrap";
import { Link, NavLink } from "react-router-dom";
import CartHover from "../CartHover/CartHover";
import CartWidgetComponet from "../CartWidget/CartWidget";
import LogoComponent from "../Logo/LogoComponent";

const NavBar = () => (
  <>
    <NavbarBootstrap bg="light" variant="light">        
        <Link to="/" className="text-decoration-none">
            <NavbarBootstrap.Brand className="mx-5 px-5"><LogoComponent /> AIMARA</NavbarBootstrap.Brand>
        </Link>
        <Nav className="ml-auto">
            <Link to="/" className="text-decoration-none text-dark">
                <Nav className="mx-3">Aimara</Nav>
            </Link>
            <Link to="/category/red" className="text-decoration-none text-dark">
                <Nav className="mx-3">Red Wines</Nav>
            </Link>
            <Link to="/category/white" className="text-decoration-none text-dark">
                <Nav className="mx-3">White Wines</Nav>
            </Link>
            <Link to="/Contact" className="text-decoration-none text-dark">
                <Nav className="mx-3">Contact</Nav>
            </Link>
        </Nav>
        <NavLink to="/Cart" className="pl-3 pr-1 text-muted"><CartWidgetComponet><CartHover /></CartWidgetComponet></NavLink>
    </NavbarBootstrap>
  </>
);

export default NavBar;

and this is the CartWidgetComponent:

import { useCartContext } from "../../Context/CartContext";

const CartWidgetComponet = () => {
  const { list, totalQuantity } = useCartContext();
  return (
    <>
      <svg xmlns="http://www.w3.org/2000/svg" width="25" height="25" fill="currentColor" className="bi bi-cart2" viewBox="0 0 16 16">
        <path d="M0 2.5A.5.5 0 0 1 .5 2H2a.5.5 0 0 1 .485.379L2.89 4H14.5a.5.5 0 0 1 .485.621l-1.5 6A.5.5 0 0 1 13 11H4a.5.5 0 0 1-.485-.379L1.61 3H.5a.5.5 0 0 1-.5-.5zM3.14 5l1.25 5h8.22l1.25-5H3.14zM5 13a1 1 0 1 0 0 2 1 1 0 0 0 0-2zm-2 1a2 2 0 1 1 4 0 2 2 0 0 1-4 0zm9-1a1 1 0 1 0 0 2 1 1 0 0 0 0-2zm-2 1a2 2 0 1 1 4 0 2 2 0 0 1-4 0z"/>
      </svg>
      {list.length > 0 ? (<span className="badge badge-info">{totalQuantity()}</span>) : null}
    </>
  );
};

export default CartWidgetComponet;

I hope there is someone that could help me. Cheers


Solution

  • I see you're using React Boostrap. It has OverlayTrigger that you can put to use in this case. The idea is to make your CartHover element a popover for the OverlayTrigger so that whatever triggers it (hover in our case) shows your CardHover elements. So here is some code:

    const CartHover = () => {
      return (
        <>
          <div>
            You have x number of items in your cart and here they are
            <br />
            Item 1
            <br />
            Item 2
          </div>
        </>
      );
    };
    
    const CartIcon = () => {
      const popover = (
        <Popover>
          <Popover.Content>
            <CartHover />
          </Popover.Content>
        </Popover>
      );
    
      return (
        <OverlayTrigger
          trigger={["click", "hover"]}
          rootClose={true}
          placement={"bottom"}
          overlay={popover}
        >
          <div className={"d-inline-block"}>
            <svg
              xmlns="http://www.w3.org/2000/svg"
              width="25"
              height="25"
              fill="currentColor"
              className="bi bi-cart2"
              viewBox="0 0 16 16"
            >
              <path d="M0 2.5A.5.5 0 0 1 .5 2H2a.5.5 0 0 1 .485.379L2.89 4H14.5a.5.5 0 0 1 .485.621l-1.5 6A.5.5 0 0 1 13 11H4a.5.5 0 0 1-.485-.379L1.61 3H.5a.5.5 0 0 1-.5-.5zM3.14 5l1.25 5h8.22l1.25-5H3.14zM5 13a1 1 0 1 0 0 2 1 1 0 0 0 0-2zm-2 1a2 2 0 1 1 4 0 2 2 0 0 1-4 0zm9-1a1 1 0 1 0 0 2 1 1 0 0 0 0-2zm-2 1a2 2 0 1 1 4 0 2 2 0 0 1-4 0z" />
            </svg>
            <span className="badge badge-info">8</span>
          </div>
        </OverlayTrigger>
      );
    };
    
    export default function App() {
      return (
        <div className="App">
          <CartIcon />
        </div>
      );
    }
    

    Sandbox: https://codesandbox.io/s/wizardly-shape-ow5wz?file=/src/App.js