From 6babd2bee09eaf88ff8ffc38033c479eca988c9a Mon Sep 17 00:00:00 2001 From: Mike Smith <89040888+smiggiddy@users.noreply.github.com> Date: Thu, 17 Oct 2024 12:34:45 -0400 Subject: [PATCH] basic features --- shopping-cart/src/Cart.jsx | 103 ++++++++++++++---- shopping-cart/src/Store.jsx | 8 +- .../components/productCollection.module.css | 2 +- .../src/components/productDetails.jsx | 55 ++++++---- .../src/components/productDetails.module.css | 16 +++ shopping-cart/src/components/products.jsx | 8 +- .../src/components/products.module.css | 2 + shopping-cart/src/utils/currency.js | 3 + 8 files changed, 146 insertions(+), 51 deletions(-) create mode 100644 shopping-cart/src/components/productDetails.module.css create mode 100644 shopping-cart/src/utils/currency.js diff --git a/shopping-cart/src/Cart.jsx b/shopping-cart/src/Cart.jsx index 06e918c..e1ba498 100644 --- a/shopping-cart/src/Cart.jsx +++ b/shopping-cart/src/Cart.jsx @@ -1,51 +1,106 @@ import PropTypes from "prop-types"; import styles from "./css/cart.module.css"; import { useOutletContext } from "react-router-dom"; +import { currencyFormat } from "./utils/currency"; const Cart = () => { - const [cart, setCart, items, SetItems] = useOutletContext(); + const [cart, setCart] = useOutletContext(); - const cartItems = Object.keys(cart); + const cartKeys = Object.keys(cart); return ( - <> -
- {cart ? ( -
-

Cart

- {cartItems.map((item, index) => ( - - ))} -
- ) : ( -

Your cart is empty

- )} -
- +
+

Cart

+ +
); }; -function CartItem({ item }) { +function Bag({ cartKeys, cart, setCart }) { + return ( + <> + {cartKeys.length > 0 ? ( +
+ {cartKeys.map((key, index) => ( + + ))} +
+ ) : ( +

Your cart is empty

+ )} + + ); +} + +function CartItem({ item, cart, setCart }) { const { title, price, image, qty } = item; return (
{title} -

{title}

-

Qty: {qty}

-

Price: {price}

-

Total: {price * qty}

-

{item.id}

+
+

{title}

+

Price: ${currencyFormat(price)}

+

Qty: {qty}

+
+
+ +

{qty}

+ +
+
+

Total: {currencyFormat(qty * price)}

+ +
); } +function increaseQty(item, cart, setCart) { + if (cart[item.id]) { + let obj = { ...cart }; + obj[item.id].qty += 1; + setCart(obj); + } +} + +function decreaseQty(item, cart, setCart) { + if (cart[item.id]) { + let obj = { ...cart }; + if (obj[item.id].qty > 1) obj[item.id].qty -= 1; + setCart(obj); + } +} + +function removeFromCart(item, cart, setCart) { + if (cart[item.id]) { + let obj = { ...cart }; + delete obj[item.id]; + setCart(obj); + } +} + CartItem.propTypes = { item: PropTypes.object, + cart: PropTypes.object, + setCart: PropTypes.func, }; -Cart.propTypes = { - cart: PropTypes.array, +Bag.propTypes = { + cartKeys: PropTypes.array, + cart: PropTypes.object, + setCart: PropTypes.func, }; export default Cart; diff --git a/shopping-cart/src/Store.jsx b/shopping-cart/src/Store.jsx index c0dc81e..017663c 100644 --- a/shopping-cart/src/Store.jsx +++ b/shopping-cart/src/Store.jsx @@ -10,7 +10,7 @@ export default function Store() { return (
-

Smig.Tech Coaching Store

+

Smig.Tech Store

{ if (response.status >= 400) { throw new Error("unable to fetch items"); @@ -40,7 +42,7 @@ function useFakeStoreAPIData(items, setItems, loading, setLoading) { response.forEach((item) => { arr.push({ title: item.title, - price: item.price, + price: item.price * 100, image: item.image, id: crypto.randomUUID(), }); diff --git a/shopping-cart/src/components/productCollection.module.css b/shopping-cart/src/components/productCollection.module.css index dbbfe00..0d26554 100644 --- a/shopping-cart/src/components/productCollection.module.css +++ b/shopping-cart/src/components/productCollection.module.css @@ -8,7 +8,7 @@ .card { display: flex; flex-direction: column; - max-width: calc(100% / 4); + max-width: calc(100% / 5); justify-content: end; /*flex: 1;*/ padding: 1.5rem; diff --git a/shopping-cart/src/components/productDetails.jsx b/shopping-cart/src/components/productDetails.jsx index 3b02bd1..13f85c7 100644 --- a/shopping-cart/src/components/productDetails.jsx +++ b/shopping-cart/src/components/productDetails.jsx @@ -1,47 +1,62 @@ -import { useParams, useOutletContext } from "react-router-dom"; +import { useParams, useOutletContext, Link } from "react-router-dom"; import Products from "./products"; -import PropTypes from "prop-types"; -import styles from "./productCollection.module.css"; +import styles from "./productDetails.module.css"; export default function ProductDetails() { - const [cart, setCart, items, setItems] = useOutletContext(); + const [cart, setCart, items] = useOutletContext(); const { id } = useParams(); - const item = items.filter((item) => item.id === id)[0]; + + if (!items) return ; + const item = items.find((item) => item.id === id); return (
{item ? (
+ Back + View Cart
- ) : null} + ) : ( + + )} +
+ ); +} + +function HandleInvalidItem() { + return ( +
+
+

Product Does Not Exist!

+ Return to Store +
); } function addToCart(item, cart, setCart) { let obj = { ...cart }; - if (obj[item.id]) { - obj[item.id].qty += 1; - } else { - obj[item.id] = item; - obj[item.id].qty = 1; - } - + obj[item.id] = item; + obj[item.id].qty = 1; setCart(obj); } -ProductDetails.propTypes = { - item: PropTypes.object, - cart: PropTypes.object, - setCart: PropTypes.func, -}; +function removeFromCart(item, cart, setCart) { + if (cart[item.id]) { + let obj = { ...cart }; + delete obj[item.id]; + setCart(obj); + } +} diff --git a/shopping-cart/src/components/productDetails.module.css b/shopping-cart/src/components/productDetails.module.css new file mode 100644 index 0000000..0d26554 --- /dev/null +++ b/shopping-cart/src/components/productDetails.module.css @@ -0,0 +1,16 @@ +.container { + display: flex; + gap: 2rem; + justify-content: center; + flex-wrap: wrap; + align-items: stretch; +} +.card { + display: flex; + flex-direction: column; + max-width: calc(100% / 5); + justify-content: end; + /*flex: 1;*/ + padding: 1.5rem; + margin: 1.5rem; +} diff --git a/shopping-cart/src/components/products.jsx b/shopping-cart/src/components/products.jsx index 2adf8a2..6c58aa4 100644 --- a/shopping-cart/src/components/products.jsx +++ b/shopping-cart/src/components/products.jsx @@ -2,13 +2,15 @@ import PropTypes from "prop-types"; import styles from "./products.module.css"; +import { currencyFormat } from "../utils/currency"; + export default function Products({ item, cart, setCart }) { return ( -
+ <> {item.title}

{item.title}

-

${item.price}

-
+

${currencyFormat(item.price)}

+ ); } diff --git a/shopping-cart/src/components/products.module.css b/shopping-cart/src/components/products.module.css index fc99ff0..302ced5 100644 --- a/shopping-cart/src/components/products.module.css +++ b/shopping-cart/src/components/products.module.css @@ -2,4 +2,6 @@ width: 100%; height: auto; vertical-align: middle; + object-fit: cover; + float: left; } diff --git a/shopping-cart/src/utils/currency.js b/shopping-cart/src/utils/currency.js new file mode 100644 index 0000000..03bd066 --- /dev/null +++ b/shopping-cart/src/utils/currency.js @@ -0,0 +1,3 @@ +export function currencyFormat(str) { + return (str / 100).toFixed(2); +}