Merge branch 'react-version' of https://github.com/MarcEricMartel/420-5DW-HY-TP into react-version
This commit is contained in:
commit
fba4921a56
94
GrossesMitaines/grosses-mitaines-ui/src/components/Cart.js
Normal file
94
GrossesMitaines/grosses-mitaines-ui/src/components/Cart.js
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
import { createContext, useState } from "react";
|
||||||
|
|
||||||
|
export const CartContext = createContext({
|
||||||
|
items: [],
|
||||||
|
getProductQuantity: () => { },
|
||||||
|
addOneToCart: () => { },
|
||||||
|
removeOneFromCart: () => { },
|
||||||
|
deleteFromCart: () => { },
|
||||||
|
getTotalCost: () => { },
|
||||||
|
addToCart: () => { }
|
||||||
|
});
|
||||||
|
|
||||||
|
export function CartProvider({ children }) {
|
||||||
|
|
||||||
|
const [cartProducts, setCartProducts] = useState([]);
|
||||||
|
|
||||||
|
function addToCart(product, qty) {
|
||||||
|
|
||||||
|
setCartProducts([...cartProducts, {...product, quantity: parseFloat(qty)}]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getProductQuantity(id) {
|
||||||
|
const quantity = cartProducts.find(product => product.id === id)?.quantity;
|
||||||
|
if (quantity === undefined) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return quantity;
|
||||||
|
};
|
||||||
|
|
||||||
|
function addOneToCart(id, qty) {
|
||||||
|
const currentQty = getProductQuantity(id);
|
||||||
|
|
||||||
|
if (qty > currentQty) {
|
||||||
|
setCartProducts(
|
||||||
|
cartProducts.map(
|
||||||
|
product => product.id === id
|
||||||
|
? { ...product, quantity: parseFloat(product.quantity) + 1 }
|
||||||
|
: product
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function removeOneFromCart(id) {
|
||||||
|
const currentQty = getProductQuantity(id);
|
||||||
|
|
||||||
|
if (currentQty === 1)
|
||||||
|
deleteFromCart();
|
||||||
|
else
|
||||||
|
setCartProducts(
|
||||||
|
cartProducts.map(
|
||||||
|
product => product.id === id
|
||||||
|
? { ...product, quantity: parseFloat(product.quantity) - 1 }
|
||||||
|
: product
|
||||||
|
)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
function deleteFromCart(id) {
|
||||||
|
setCartProducts(
|
||||||
|
cartProducts => cartProducts.filter(currentProduct => {
|
||||||
|
return currentProduct.id != id;
|
||||||
|
})
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
function getTotalCost() {
|
||||||
|
let totalCost = 0;
|
||||||
|
cartProducts.map((cartItem) => {
|
||||||
|
totalCost += (cartItem.Price * cartItem.quantity);
|
||||||
|
});
|
||||||
|
|
||||||
|
return totalCost;
|
||||||
|
};
|
||||||
|
|
||||||
|
const contextValue = {
|
||||||
|
items: cartProducts,
|
||||||
|
getProductQuantity,
|
||||||
|
addOneToCart,
|
||||||
|
removeOneFromCart,
|
||||||
|
deleteFromCart,
|
||||||
|
getTotalCost,
|
||||||
|
addToCart
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<CartContext.Provider value={contextValue}>
|
||||||
|
{children}
|
||||||
|
</CartContext.Provider>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default CartProvider;
|
@ -1,14 +1,42 @@
|
|||||||
import { Button } from "react-bootstrap";
|
import { Button } from "react-bootstrap";
|
||||||
import { faCartShopping } from "@fortawesome/free-solid-svg-icons";
|
import { faCartShopping } from "@fortawesome/free-solid-svg-icons";
|
||||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||||
|
import { Modal, ModalBody, ModalHeader } from "react-bootstrap";
|
||||||
|
import { useState, useContext } from "react";
|
||||||
|
import { CartCard } from './CartCard';
|
||||||
|
import { CartContext } from './Cart';
|
||||||
|
|
||||||
const CartButton = () =>{
|
const CartButton = () => {
|
||||||
|
|
||||||
return(
|
const [show, setShow] = useState(false);
|
||||||
<Button id="cart-button">
|
const handleClose = () => setShow(false);
|
||||||
<FontAwesomeIcon icon={faCartShopping}/>
|
const handleShow = () => setShow(true);
|
||||||
<div id="cart-count">3</div>
|
const cart = useContext(CartContext);
|
||||||
</Button>
|
|
||||||
|
const productsCount = cart.items.reduce((sum, product) => sum + product.quantity, 0)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Button id="cart-button" onClick={handleShow}>
|
||||||
|
<FontAwesomeIcon icon={faCartShopping} />
|
||||||
|
<div id="cart-count">{productsCount}</div>
|
||||||
|
</Button>
|
||||||
|
<Modal show={show} onHide={handleClose} className="carosse">
|
||||||
|
<ModalHeader closeButton>
|
||||||
|
<Modal.Title>Carosse</Modal.Title>
|
||||||
|
</ModalHeader>
|
||||||
|
<ModalBody>
|
||||||
|
{productsCount > 0 ?
|
||||||
|
<>
|
||||||
|
<p></p>
|
||||||
|
{cart.items.map((item) => <CartCard product={item}></CartCard>)}
|
||||||
|
</>
|
||||||
|
:
|
||||||
|
<h1>C'est vide! Rempli le hi hi!</h1>
|
||||||
|
}
|
||||||
|
</ModalBody>
|
||||||
|
</Modal>
|
||||||
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,43 @@
|
|||||||
|
import { Card, Button, Form, Row, Col } from 'react-bootstrap';
|
||||||
|
import { useContext, useState, useEffect } from 'react';
|
||||||
|
import { CartContext } from './Cart';
|
||||||
|
|
||||||
|
const CartCard = ({ product }) => {
|
||||||
|
|
||||||
|
const cart = useContext(CartContext);
|
||||||
|
const productQuantity = cart.getProductQuantity(product.id);
|
||||||
|
|
||||||
|
const [imageSrc, setImageSrc] = useState(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
fetch(`https://localhost:7292/api/Image?id=${product.id}&thumbnail=true`)
|
||||||
|
.then(response => response.blob())
|
||||||
|
.then(blob => {
|
||||||
|
const imageUrl = URL.createObjectURL(blob);
|
||||||
|
setImageSrc(imageUrl);
|
||||||
|
})
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Card>
|
||||||
|
<Card.Body>
|
||||||
|
<div className={!imageSrc ? "cat-load" : "d-none cat-load"} />
|
||||||
|
<Card.Img className="item-img" variant="top" src={imageSrc} />
|
||||||
|
<Card.Title>{product.Title}</Card.Title>
|
||||||
|
<Card.Text>{product.Price}$ CA</Card.Text>
|
||||||
|
<Form as={Row}>
|
||||||
|
<Form.Label column="true" sm="6">Dans l'carosse: {productQuantity}</Form.Label>
|
||||||
|
<Col sm="6">
|
||||||
|
<Button sm="6" className='mx-2' onClick={() => cart.addOneToCart(product.id, product.quantity)}>+</Button>
|
||||||
|
<Button sm="6" className='mx-2' onClick={() => cart.removeOneFromCart(product.id)}>-</Button>
|
||||||
|
</Col>
|
||||||
|
</Form>
|
||||||
|
<Button variant="danger" className='my-2' onClick={() => cart.deleteFromCart(product.id)}>Supprimer</Button>
|
||||||
|
</Card.Body>
|
||||||
|
</Card>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default CartCard;
|
@ -12,6 +12,8 @@ const Topbar = () => {
|
|||||||
const [cookies, setCookie, removeCookie] = useCookies(['name']);
|
const [cookies, setCookie, removeCookie] = useCookies(['name']);
|
||||||
const [user, setLogin] = useState(null);
|
const [user, setLogin] = useState(null);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
async function reset() {
|
async function reset() {
|
||||||
await setLogin(await cookies.GMGM ?? null);
|
await setLogin(await cookies.GMGM ?? null);
|
||||||
@ -29,103 +31,103 @@ const Topbar = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Navbar expand="sm" className="topbar-container">
|
<>
|
||||||
<Container>
|
<Navbar expand="sm" className="topbar-container">
|
||||||
<Link className="navbar-brand" to="/">
|
<Container>
|
||||||
<img src="/images/LesGrossesMitaines.png" alt="" height="45" />
|
<Link className="navbar-brand" to="/">
|
||||||
</Link>
|
<img src="/images/LesGrossesMitaines.png" alt="" height="45" />
|
||||||
<Navbar.Toggle aria-controls="basic-navbar-nav" />
|
|
||||||
<Navbar.Collapse id="basic-navbar-nav">
|
|
||||||
<Nav className="me-auto">
|
|
||||||
<Link className="nav-link" to="/" >
|
|
||||||
Maison
|
|
||||||
</Link>
|
|
||||||
<Link className="nav-link" to="/morceaux" >
|
|
||||||
Morceaux
|
|
||||||
</Link>
|
|
||||||
<Link className="nav-link" to="/aboutUs" >
|
|
||||||
À propos de nous
|
|
||||||
</Link>
|
|
||||||
<Link className="nav-link" to="/contactUs" >
|
|
||||||
Contactez-nous
|
|
||||||
</Link>
|
|
||||||
<Link className="nav-link" to="/privacy" >
|
|
||||||
Vie privée
|
|
||||||
</Link>
|
|
||||||
{(user === null || user.LoggedIn === false) &&
|
|
||||||
<Link className="nav-link" to="/login" >
|
|
||||||
Connexion
|
|
||||||
</Link>
|
|
||||||
}
|
|
||||||
{(user === null || user.LoggedIn === false) &&
|
|
||||||
<Link className="nav-link" to="/register">
|
|
||||||
S'inscrire
|
|
||||||
</Link>
|
|
||||||
}
|
|
||||||
{user !== null && user.LoggedIn &&
|
|
||||||
<Dropdown className="dropdown-gestion-container">
|
|
||||||
<Dropdown.Toggle className="dropdown-gestion" >
|
|
||||||
Bonjour, {user.firstName} {user.lastName}!
|
|
||||||
</Dropdown.Toggle>
|
|
||||||
<Dropdown.Menu className="dropdown-gestion-menu">
|
|
||||||
<Dropdown.Item>
|
|
||||||
<Link className="nav-link" to="/myaccount" >
|
|
||||||
Mon Compte
|
|
||||||
</Link>
|
|
||||||
</Dropdown.Item>
|
|
||||||
<Dropdown.Item>
|
|
||||||
<Link className="nav-link" to="/myaddresses" >
|
|
||||||
Mes Addresses
|
|
||||||
</Link>
|
|
||||||
</Dropdown.Item>
|
|
||||||
<Dropdown.Item>
|
|
||||||
<Link className="nav-link" to="/myinvoices" >
|
|
||||||
Mes Commandes
|
|
||||||
</Link>
|
|
||||||
</Dropdown.Item>
|
|
||||||
<Dropdown.Item>
|
|
||||||
<Button className="nav-link" onClick={() => logOut()}>
|
|
||||||
Déconnexion
|
|
||||||
</Button>
|
|
||||||
</Dropdown.Item>
|
|
||||||
{user.role === "Administrateur" &&
|
|
||||||
<Container>
|
|
||||||
<Dropdown.Divider />
|
|
||||||
<Dropdown.ItemText>
|
|
||||||
Gestion
|
|
||||||
</Dropdown.ItemText>
|
|
||||||
<Dropdown.Item>
|
|
||||||
<Link className="nav-link" to="/inventaire" >
|
|
||||||
Inventaire
|
|
||||||
</Link>
|
|
||||||
</Dropdown.Item>
|
|
||||||
<Dropdown.Item>
|
|
||||||
<Link className="nav-link" to="/invoices" >
|
|
||||||
Commandes
|
|
||||||
</Link>
|
|
||||||
</Dropdown.Item>
|
|
||||||
<Dropdown.Item>
|
|
||||||
<Link className="nav-link" to="/clients" >
|
|
||||||
Clients
|
|
||||||
</Link>
|
|
||||||
</Dropdown.Item>
|
|
||||||
<Dropdown.Item>
|
|
||||||
<Link className="nav-link" to="/addresses" >
|
|
||||||
Adresses
|
|
||||||
</Link>
|
|
||||||
</Dropdown.Item>
|
|
||||||
</Container>
|
|
||||||
}
|
|
||||||
</Dropdown.Menu>
|
|
||||||
</Dropdown>
|
|
||||||
}
|
|
||||||
</Nav>
|
|
||||||
<Link className="nav-link" to="/formulaire" >
|
|
||||||
<CartButton />
|
|
||||||
</Link>
|
</Link>
|
||||||
</Navbar.Collapse>
|
<Navbar.Toggle aria-controls="basic-navbar-nav" />
|
||||||
</Container>
|
<Navbar.Collapse id="basic-navbar-nav">
|
||||||
</Navbar>
|
<Nav className="me-auto">
|
||||||
|
<Link className="nav-link" to="/" >
|
||||||
|
Maison
|
||||||
|
</Link>
|
||||||
|
<Link className="nav-link" to="/morceaux" >
|
||||||
|
Morceaux
|
||||||
|
</Link>
|
||||||
|
<Link className="nav-link" to="/aboutUs" >
|
||||||
|
À propos de nous
|
||||||
|
</Link>
|
||||||
|
<Link className="nav-link" to="/contactUs" >
|
||||||
|
Contactez-nous
|
||||||
|
</Link>
|
||||||
|
<Link className="nav-link" to="/privacy" >
|
||||||
|
Vie privée
|
||||||
|
</Link>
|
||||||
|
{(user === null || user.LoggedIn === false) &&
|
||||||
|
<Link className="nav-link" to="/login" >
|
||||||
|
Connexion
|
||||||
|
</Link>
|
||||||
|
}
|
||||||
|
{(user === null || user.LoggedIn === false) &&
|
||||||
|
<Link className="nav-link" to="/register">
|
||||||
|
S'inscrire
|
||||||
|
</Link>
|
||||||
|
}
|
||||||
|
{user !== null && user.LoggedIn &&
|
||||||
|
<Dropdown className="dropdown-gestion-container">
|
||||||
|
<Dropdown.Toggle className="dropdown-gestion" >
|
||||||
|
Bonjour, {user.firstName} {user.lastName}!
|
||||||
|
</Dropdown.Toggle>
|
||||||
|
<Dropdown.Menu className="dropdown-gestion-menu">
|
||||||
|
<Dropdown.Item>
|
||||||
|
<Link className="nav-link" to="/myaccount" >
|
||||||
|
Mon Compte
|
||||||
|
</Link>
|
||||||
|
</Dropdown.Item>
|
||||||
|
<Dropdown.Item>
|
||||||
|
<Link className="nav-link" to="/myaddresses" >
|
||||||
|
Mes Addresses
|
||||||
|
</Link>
|
||||||
|
</Dropdown.Item>
|
||||||
|
<Dropdown.Item>
|
||||||
|
<Link className="nav-link" to="/myinvoices" >
|
||||||
|
Mes Commandes
|
||||||
|
</Link>
|
||||||
|
</Dropdown.Item>
|
||||||
|
<Dropdown.Item>
|
||||||
|
<Button className="nav-link" onClick={() => logOut()}>
|
||||||
|
Déconnexion
|
||||||
|
</Button>
|
||||||
|
</Dropdown.Item>
|
||||||
|
{user.role === "Administrateur" &&
|
||||||
|
<Container>
|
||||||
|
<Dropdown.Divider />
|
||||||
|
<Dropdown.ItemText>
|
||||||
|
Gestion
|
||||||
|
</Dropdown.ItemText>
|
||||||
|
<Dropdown.Item>
|
||||||
|
<Link className="nav-link" to="/inventaire" >
|
||||||
|
Inventaire
|
||||||
|
</Link>
|
||||||
|
</Dropdown.Item>
|
||||||
|
<Dropdown.Item>
|
||||||
|
<Link className="nav-link" to="/invoices" >
|
||||||
|
Commandes
|
||||||
|
</Link>
|
||||||
|
</Dropdown.Item>
|
||||||
|
<Dropdown.Item>
|
||||||
|
<Link className="nav-link" to="/clients" >
|
||||||
|
Clients
|
||||||
|
</Link>
|
||||||
|
</Dropdown.Item>
|
||||||
|
<Dropdown.Item>
|
||||||
|
<Link className="nav-link" to="/addresses" >
|
||||||
|
Adresses
|
||||||
|
</Link>
|
||||||
|
</Dropdown.Item>
|
||||||
|
</Container>
|
||||||
|
}
|
||||||
|
</Dropdown.Menu>
|
||||||
|
</Dropdown>
|
||||||
|
}
|
||||||
|
</Nav>
|
||||||
|
<CartButton/>
|
||||||
|
</Navbar.Collapse>
|
||||||
|
</Container>
|
||||||
|
</Navbar>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,13 +2,16 @@ import React from "react";
|
|||||||
import { Outlet } from "react-router-dom";
|
import { Outlet } from "react-router-dom";
|
||||||
import Topbar from "../components/Topbar";
|
import Topbar from "../components/Topbar";
|
||||||
import Footer from "../components/Footer";
|
import Footer from "../components/Footer";
|
||||||
|
import CartProvider from "../components/Cart";
|
||||||
|
|
||||||
const Layout = () => {
|
const Layout = () => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Topbar />
|
<CartProvider>
|
||||||
<Outlet />
|
<Topbar />
|
||||||
<Footer />
|
<Outlet />
|
||||||
|
<Footer />
|
||||||
|
</CartProvider>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
import { useEffect } from "react";
|
import { useEffect } from "react";
|
||||||
import { useParams } from "react-router-dom";
|
import { useParams } from "react-router-dom";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { Button } from "react-bootstrap";
|
import { Button, Form, Row} from 'react-bootstrap';
|
||||||
import QtySelect from "../components/QtySelect";
|
import QtySelect from "../components/QtySelect";
|
||||||
|
import { CartContext } from "../components/Cart";
|
||||||
|
import { useContext } from "react";
|
||||||
|
|
||||||
const MorceauDetail = () => {
|
const MorceauDetail = () => {
|
||||||
|
|
||||||
@ -12,11 +14,14 @@ const MorceauDetail = () => {
|
|||||||
const [itemQty, setItemQty] = useState(0);
|
const [itemQty, setItemQty] = useState(0);
|
||||||
const [currentQty, setCurrentQty] = useState(1);
|
const [currentQty, setCurrentQty] = useState(1);
|
||||||
|
|
||||||
|
const cart = useContext(CartContext);
|
||||||
|
const inCartQuantity = cart.getProductQuantity(item.id)
|
||||||
|
|
||||||
const isNoStock = () => {
|
const isNoStock = () => {
|
||||||
return item.status == 1 || item.status == 2 || item.status == 5;
|
return item.status == 1 || item.status == 2 || item.status == 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
const currentQtyChange = (newQty) =>{
|
const currentQtyChange = (newQty) => {
|
||||||
setCurrentQty(newQty);
|
setCurrentQty(newQty);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -139,14 +144,38 @@ const MorceauDetail = () => {
|
|||||||
<p className="detail-description">{item.description}</p>
|
<p className="detail-description">{item.description}</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="detail-container-controls">
|
<div className="detail-container-controls">
|
||||||
<QtySelect
|
{inCartQuantity > 0 ?
|
||||||
qty={isNoStock() ? 0 : itemQty}
|
<>
|
||||||
onChange={currentQtyChange}
|
<Form as={Row}>
|
||||||
/>
|
<Form.Label sm="6">Dans l'carosse: {inCartQuantity}</Form.Label>
|
||||||
<Button disabled={isNoStock()} className="add-to-cart">
|
<Button disabled={isNoStock()} className="add-to-cart"
|
||||||
Ajouter au panier
|
onClick={() => cart.addOneToCart(item.id, item.quantity)}
|
||||||
</Button>
|
sm="6">
|
||||||
|
+
|
||||||
|
</Button >
|
||||||
|
<Button disabled={isNoStock()} className="add-to-cart"
|
||||||
|
onClick={() => cart.removeOneFromCart(item.id)}
|
||||||
|
sm="6">
|
||||||
|
-
|
||||||
|
</Button >
|
||||||
|
</Form>
|
||||||
|
<Button disabled={isNoStock()} className="add-to-cart"
|
||||||
|
onClick={() => cart.deleteFromCart(item.id)} variant="danger"
|
||||||
|
column="true" sm="6" >
|
||||||
|
Sortir du carosse
|
||||||
|
</Button>
|
||||||
|
</>
|
||||||
|
:
|
||||||
|
<>
|
||||||
|
<QtySelect
|
||||||
|
qty={isNoStock() ? 0 : itemQty}
|
||||||
|
onChange={currentQtyChange}
|
||||||
|
/>
|
||||||
|
<Button disabled={isNoStock()} className="add-to-cart" onClick={() => cart.addToCart(item, currentQty)}>
|
||||||
|
Ajouter au carosse
|
||||||
|
</Button>
|
||||||
|
</>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
|
Loading…
Reference in New Issue
Block a user