From aef50100e38e375ee5f0b9d9bb87a41ef284aef0 Mon Sep 17 00:00:00 2001 From: Amir Amiri Date: Wed, 15 Feb 2023 20:44:58 +0330 Subject: [PATCH] checkout component added --- src/App.js | 3 ++ .../cart-dropdown/cart-dropdown.component.jsx | 7 +++- .../checkout-item/checkout-item.component.jsx | 30 +++++++++++++ .../checkout-item/checkout-item.styles.scss | 42 +++++++++++++++++++ src/contexts/cart.context.jsx | 42 ++++++++++++++++++- src/routes/checkout/checkout.component.jsx | 39 +++++++++++++++++ src/routes/checkout/checkout.styles.scss | 32 ++++++++++++++ 7 files changed, 192 insertions(+), 3 deletions(-) create mode 100644 src/components/checkout-item/checkout-item.component.jsx create mode 100644 src/components/checkout-item/checkout-item.styles.scss create mode 100644 src/routes/checkout/checkout.component.jsx create mode 100644 src/routes/checkout/checkout.styles.scss diff --git a/src/App.js b/src/App.js index 05822de..5204acf 100644 --- a/src/App.js +++ b/src/App.js @@ -3,6 +3,8 @@ import Home from "./routes/home/home.component"; import Navigation from "./routes/navigation/navigation.component"; import Authentication from './routes/authentication/authentication.component'; import Shop from './routes/shop/shop.component'; +import Checkout from './routes/checkout/checkout.component'; + const App = () => { return ( < Routes > @@ -10,6 +12,7 @@ const App = () => { } /> } /> } /> + } /> ) diff --git a/src/components/cart-dropdown/cart-dropdown.component.jsx b/src/components/cart-dropdown/cart-dropdown.component.jsx index b07a3b8..2813f56 100644 --- a/src/components/cart-dropdown/cart-dropdown.component.jsx +++ b/src/components/cart-dropdown/cart-dropdown.component.jsx @@ -1,4 +1,5 @@ import { useContext } from 'react'; +import { useNavigate } from 'react-router-dom'; import { CartContext } from '../../contexts/cart.context'; import Button from '../button/button.component'; import CartItem from '../cart-item/cart-item.component'; @@ -6,12 +7,16 @@ import './cart-dropdown.styles.scss'; const CartDropdown = () => { const {cartItems} = useContext(CartContext) + const navigate = useNavigate() + const goToCheckoutHandler = () => { + navigate('/checkout') + } return (
{cartItems.map((item) => )}
- +
) } diff --git a/src/components/checkout-item/checkout-item.component.jsx b/src/components/checkout-item/checkout-item.component.jsx new file mode 100644 index 0000000..e0a70a1 --- /dev/null +++ b/src/components/checkout-item/checkout-item.component.jsx @@ -0,0 +1,30 @@ +import { useContext } from 'react'; +import { CartContext } from '../../contexts/cart.context'; +import './checkout-item.styles.scss'; + +const CheckoutItem = ({ cartItem }) => { + const { name, imageUrl, price, quantity } = cartItem; + const { clearItemFromCart, addItemToCart, removeItemFromCart } = useContext(CartContext); + + return ( +
+
+ {`${name}`} +
+ {name} + +
removeItemFromCart(cartItem)}> + ❮ +
+ {quantity} +
addItemToCart(cartItem)}> + ❯ +
+
+ ${price} +
clearItemFromCart(cartItem)} className='remove-button'>✕
+
+ ) +} + +export default CheckoutItem; \ No newline at end of file diff --git a/src/components/checkout-item/checkout-item.styles.scss b/src/components/checkout-item/checkout-item.styles.scss new file mode 100644 index 0000000..047f19d --- /dev/null +++ b/src/components/checkout-item/checkout-item.styles.scss @@ -0,0 +1,42 @@ +.checkout-item-container { + width: 100%; + display: flex; + min-height: 100px; + border-bottom: 1px solid darkgrey; + padding: 15px 0; + font-size: 20px; + align-items: center; + + .image-container { + width: 23%; + padding-right: 15px; + + img { + width: 100%; + height: 100%; + } + } + .name, + .quantity, + .price { + width: 23%; + } + + .quantity { + display: flex; + + .arrow { + cursor: pointer; + } + + .value { + margin: 0 10px; + } + } + + .remove-button { + padding-left: 12px; + cursor: pointer; + } + } + \ No newline at end of file diff --git a/src/contexts/cart.context.jsx b/src/contexts/cart.context.jsx index 2f46544..0e92b15 100644 --- a/src/contexts/cart.context.jsx +++ b/src/contexts/cart.context.jsx @@ -9,28 +9,66 @@ const addCartItem = (cartItems, productToAdd) => { } +const removeCartItem = (cartItems, cartItemToRemove) => { + const exsistingCartItem = cartItems.find((cartItem) => cartItem.id === cartItemToRemove.id) + if (exsistingCartItem.quantity === 1) { + return cartItems.filter(cartItem => cartItem.id !== cartItemToRemove.id); + } + + return cartItems.map((cartItem) => + cartItem.id === cartItemToRemove.id + ? { ...cartItem, quantity: cartItem.quantity - 1 } + : cartItem + ) + +} + +const clearCartItem = (cartItems, cartItemToClear) => { + return cartItems.filter(cartItem => cartItem.id !== cartItemToClear.id); + +} export const CartContext = createContext({ isCartOpen: false, setIsCartOpen: () => { }, cartItems: [], addItemToCart: () => { }, - cartCount: 0 + removeItemFromCart: () => { }, + clearItemFromCart: () => { }, + cartCount: 0, + cartTotal: 0 }); export const CartProvider = ({ children }) => { const [isCartOpen, setIsCartOpen] = useState(false) const [cartItems, setCartItems] = useState([]); const [cartCount, setCartCount] = useState(0); + const [cartTotal, setCartTotal] = useState(0); + useEffect(() => { const newCartCount = cartItems.reduce((total, cartItem) => total + cartItem.quantity, 0) setCartCount(newCartCount); }, [cartItems]) + + useEffect(() => { + const newCartTotal = cartItems.reduce((total, cartItem) => total + cartItem.quantity * cartItem.price, 0) + setCartTotal(newCartTotal); + }, [cartItems]) + + const addItemToCart = (product) => { setCartItems(addCartItem(cartItems, product)) } - const value = { isCartOpen, setIsCartOpen, addItemToCart, cartItems, cartCount }; + + const removeItemFromCart = (product) => { + setCartItems(removeCartItem(cartItems, product)) + } + + const clearItemFromCart = (product) => { + setCartItems(clearCartItem(cartItems, product)) + } + const value = { isCartOpen, setIsCartOpen, addItemToCart, cartItems, cartCount, removeItemFromCart, clearItemFromCart, cartTotal }; return ( {children} ) diff --git a/src/routes/checkout/checkout.component.jsx b/src/routes/checkout/checkout.component.jsx new file mode 100644 index 0000000..79ff02c --- /dev/null +++ b/src/routes/checkout/checkout.component.jsx @@ -0,0 +1,39 @@ +import { useContext } from 'react'; +import { CartContext } from '../../contexts/cart.context'; +import CheckoutItem from '../../components/checkout-item/checkout-item.component'; +import './checkout.styles.scss'; + +const Checkout = () => { + const { cartItems, cartTotal } = useContext(CartContext); + return ( +
+
+
+ Product +
+
+ Description +
+
+ Quantity +
+
+ Price +
+
+ Remove +
+
+ { + cartItems.map((cartItem) => { + return ( + + ) + }) + } + Total: ${cartTotal} +
+ ) +} + +export default Checkout; \ No newline at end of file diff --git a/src/routes/checkout/checkout.styles.scss b/src/routes/checkout/checkout.styles.scss new file mode 100644 index 0000000..d624bb7 --- /dev/null +++ b/src/routes/checkout/checkout.styles.scss @@ -0,0 +1,32 @@ +.checkout-container { + width: 55%; + min-height: 90vh; + display: flex; + flex-direction: column; + align-items: center; + margin: 50px auto 0; + + .checkout-header { + width: 100%; + padding: 10px 0; + display: flex; + justify-content: space-between; + border-bottom: 1px solid darkgrey; + + .header-block { + text-transform: capitalize; + width: 23%; + + &:last-child { + width: 8%; + } + } + } + + .total { + margin-top: 30px; + margin-left: auto; + font-size: 36px; + } + } + \ No newline at end of file