This commit is contained in:
Mike 2024-11-22 07:08:58 -05:00
parent 0664755110
commit aca34ffb10
18 changed files with 818 additions and 94 deletions

View file

@ -10,7 +10,7 @@
rel="stylesheet" rel="stylesheet"
/> />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Smig.Tech Coaching</title> <title>Hobby Tech</title>
</head> </head>
<body> <body>
<div id="root"></div> <div id="root"></div>

File diff suppressed because it is too large Load diff

View file

@ -10,6 +10,10 @@
"preview": "vite preview" "preview": "vite preview"
}, },
"dependencies": { "dependencies": {
"@emotion/react": "^11.13.5",
"@emotion/styled": "^11.13.5",
"@mui/icons-material": "^6.1.8",
"@mui/material": "^6.1.8",
"prop-types": "^15.8.1", "prop-types": "^15.8.1",
"react": "^18.3.1", "react": "^18.3.1",
"react-dom": "^18.3.1", "react-dom": "^18.3.1",

Binary file not shown.

After

Width:  |  Height:  |  Size: 481 KiB

View file

@ -1,3 +1,4 @@
import Button from "./components/button";
import PropTypes from "prop-types"; import PropTypes from "prop-types";
import styles from "./css/cart.module.css"; import styles from "./css/cart.module.css";
import { useOutletContext } from "react-router-dom"; import { useOutletContext } from "react-router-dom";
@ -23,7 +24,6 @@ function Bag({ cartKeys, cart, setCart }) {
<> <>
{cartKeys.length > 0 ? ( {cartKeys.length > 0 ? (
<div className={styles.fullwidth}> <div className={styles.fullwidth}>
<h2 className={styles.header}>Cart</h2>
<div className={styles.cartItems}> <div className={styles.cartItems}>
{cartKeys.map((key, index) => ( {cartKeys.map((key, index) => (
<CartItem <CartItem
@ -36,7 +36,9 @@ function Bag({ cartKeys, cart, setCart }) {
</div> </div>
</div> </div>
) : ( ) : (
<h2>Your cart is empty</h2> <div className={styles["empty-cart"]}>
<h2>Your cart is empty</h2>
</div>
)} )}
</> </>
); );
@ -44,15 +46,17 @@ function Bag({ cartKeys, cart, setCart }) {
function OrderSummary({ cart }) { function OrderSummary({ cart }) {
const cartItems = Object.keys(cart); const cartItems = Object.keys(cart);
const shippingFee = 0.1;
let numItems = 0; let numItems = 0;
let subTotal = 0; let subTotal = 0;
cartItems.forEach((item) => { cartItems.forEach((item) => {
subTotal += cart[item].price * cart[item].qty; subTotal += Number(cart[item].price) * Number(cart[item].qty);
numItems += cart[item].qty; numItems += Number(cart[item].qty);
}); });
const shippingFee = subTotal * 0.1;
const total = subTotal + shippingFee; const shippingCosts = shippingFee * subTotal;
const total = shippingCosts + subTotal;
return ( return (
<div className={styles.summary}> <div className={styles.summary}>
@ -60,9 +64,9 @@ function OrderSummary({ cart }) {
<p> <p>
Subtotal ({numItems} items): ${currencyFormat(subTotal)} Subtotal ({numItems} items): ${currencyFormat(subTotal)}
</p> </p>
<p>Shipping (10%): ${currencyFormat(shippingFee)}</p> <p>Shipping (10%): ${currencyFormat(shippingCosts)}</p>
<p>Total: ${currencyFormat(total)}</p> <p>Total: ${currencyFormat(total)}</p>
<button>Checkout</button> <Button text={"Checkout"} />
</div> </div>
); );
} }
@ -85,9 +89,10 @@ function CartItem({ item, cart, setCart }) {
</div> </div>
<div> <div>
<p>total: ${currencyFormat(qty * price)} </p> <p>total: ${currencyFormat(qty * price)} </p>
<button onClick={() => removeFromCart(item, cart, setCart)}> <Button
Remove From Cart onClick={() => removeFromCart(item, cart, setCart)}
</button> text={"Remove From Cart"}
/>
</div> </div>
</div> </div>
</div> </div>
@ -96,13 +101,19 @@ function CartItem({ item, cart, setCart }) {
function QuantityInput({ item, cart, setCart }) { function QuantityInput({ item, cart, setCart }) {
function handleChange(e) { function handleChange(e) {
const newQty = e.target.value; const newQty = Number(e.target.value);
let obj = { ...cart }; let obj = { ...cart };
obj[item.id].qty = newQty; if (newQty !== 0) {
obj[item.id].qty = newQty;
} else {
obj[item.id].qty = 1;
}
setCart(obj); setCart(obj);
} }
return <input value={item.qty} onChange={handleChange} />; return (
<input value={item.qty} onChange={handleChange} min="1" type="number" />
);
} }
function increaseQty(item, cart, setCart) { function increaseQty(item, cart, setCart) {

View file

@ -10,7 +10,6 @@ export default function Store() {
return ( return (
<div> <div>
<h1>Smig.Tech Store</h1>
<ProductCollection <ProductCollection
loading={loading} loading={loading}
items={items} items={items}

View file

@ -1,6 +1,10 @@
.btn { .btn {
padding: 1rem; padding: 1rem;
margin: 1rem; margin: 1rem;
font-size: 1rem;
border-radius: 0.5rem;
border: none;
cursor: pointer;
} }
.action { .action {

View file

@ -12,18 +12,22 @@ export default function Main() {
function Default() { function Default() {
return ( return (
<div className={styles.container}> <>
<h1 className={styles.mainHeading}> <div className={styles.container}>
Our products help you skill up faster <h1 className={styles.mainHeading}>
</h1> Our products help <span className={styles["heading-color"]}>you</span>{" "}
<p> </h1>
Trying to pivot into tech? There&apos;s a lot to figure out. We can help <p className={styles["sub-heading"]}>
you navigate the path with our products. Fast results and guaranteed Keep engineers happy using working technology. Fast results and
growth. guaranteed value from day one.
</p> </p>
<Link to="/store"> <Link to="/store">
<Button text={"Start shopping now!"} styles={"action"} /> <Button text={"Start shopping now!"} />
</Link> </Link>
</div> <div>
<img src="/hero.jpg" alt="" className={styles["hero-img"]} />
</div>
</div>
</>
); );
} }

View file

@ -5,6 +5,29 @@ main {
.container { .container {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
justify-content: start; justify-content: center;
align-items: center; align-items: center;
height: 100vh;
}
.mainHeading {
font-size: 4rem;
margin: 0;
}
.sub-heading {
font-size: 1.5rem;
}
.heading-color {
color: #0e6c96;
}
.hero-img {
margin-top: 100px;
width: 100%;
max-height: 800px;
vertical-align: middle;
object-fit: contain;
float: left;
} }

View file

@ -1,35 +1,42 @@
import styles from "./navbar.module.css"; import styles from "./navbar.module.css";
import { Link } from "react-router-dom"; import { Link } from "react-router-dom";
import PropTypes from "prop-types"; import PropTypes from "prop-types";
import ShoppingCartIcon from "@mui/icons-material/ShoppingCart";
export default function Navbar({ cartItems }) { export default function Navbar({ cartItems }) {
const sumCartItems = Object.keys(cartItems).length; const sumCartItems = Object.keys(cartItems).length;
return ( return (
<nav className={styles.container}> <nav className={styles.container}>
<h1>Smig.Tech</h1> <h1 className={styles["nav-heading"]}>Hobby Tech</h1>
<Nav /> <Nav sumCartItems={sumCartItems} />
{sumCartItems > 0 ? (
<Link to="bag">
{" "}
<h1>{sumCartItems}</h1>
</Link>
) : (
<img src="/shopping_cart_icon.svg" />
)}
</nav> </nav>
); );
} }
function Nav() { function Nav({ sumCartItems }) {
return ( return (
<ul className={styles.nav}> <ul className={styles.nav}>
<li> <li>
<Link to="/">home</Link> <Link to="/" className={styles.link}>
home
</Link>
</li> </li>
<li> <li>
<Link to="store">shop</Link> <Link to="store" className={styles.link}>
shop
</Link>
</li> </li>
<Link to="bag" className={styles.link}>
{sumCartItems > 0 ? (
<div className={styles["cart-icon-container"]}>
<div className={styles["cart-icon-circle"]}></div>
<ShoppingCartIcon fontSize="large" />
</div>
) : (
<ShoppingCartIcon fontSize="large" />
)}
</Link>
</ul> </ul>
); );
} }
@ -37,3 +44,7 @@ function Nav() {
Navbar.propTypes = { Navbar.propTypes = {
cartItems: PropTypes.object, cartItems: PropTypes.object,
}; };
Nav.propTypes = {
sumCartItems: PropTypes.number,
};

View file

@ -15,3 +15,28 @@
margin-left: auto; margin-left: auto;
align-self: center; align-self: center;
} }
.link {
text-decoration: none;
font-size: 1.5rem;
color: #0e374e;
}
.nav-heading {
color: #0e374e;
}
.cart-icon-container {
position: relative;
}
.cart-icon-circle {
background: #85d5f4;
border-radius: 50%;
height: 20px;
width: 20px;
position: absolute;
top: 7px;
left: 10px;
opacity: 60%;
}

View file

@ -11,7 +11,10 @@ export default function ProductCollection({ loading, items, cart, setCart }) {
return ( return (
<div key={index} className={styles.card}> <div key={index} className={styles.card}>
<Products item={item} cart={cart} setCart={setCart} /> <Products item={item} cart={cart} setCart={setCart} />
<Link to={item.id}> More Info</Link> <Link to={item.id} className={styles.link}>
{" "}
More Info
</Link>
</div> </div>
); );
}) })

View file

@ -12,5 +12,18 @@
justify-content: end; justify-content: end;
padding: 1.5rem; padding: 1.5rem;
margin: 1.5rem; margin: 1.5rem;
background: gray; background: #e2f3fc;
border-radius: 1rem;
text-align: center;
}
.link {
text-decoration: none;
color: #0e374e;
font-weight: 600;
transition: font-weight 500ms;
}
.link:hover {
font-weight: 900;
} }

View file

@ -1,4 +1,5 @@
import { useParams, useOutletContext, Link } from "react-router-dom"; import { useParams, useOutletContext, Link } from "react-router-dom";
import Button from "./button";
import Products from "./products"; import Products from "./products";
import styles from "./productDetails.module.css"; import styles from "./productDetails.module.css";
@ -15,18 +16,23 @@ export default function ProductDetails() {
<div className={styles.container}> <div className={styles.container}>
{item ? ( {item ? (
<div className={styles.card}> <div className={styles.card}>
<Link to="/store">Back</Link> <Link to="/store" className={styles.link}>
Back
</Link>
<Products item={item} cart={cart} setCart={setCart} /> <Products item={item} cart={cart} setCart={setCart} />
<button <Button
onClick={() => { onClick={() => {
cart[item.id] cart[item.id]
? removeFromCart(item, cart, setCart) ? removeFromCart(item, cart, setCart)
: addToCart(item, cart, setCart); : addToCart(item, cart, setCart);
}} }}
> text={cart[item.id] ? "Remove from Cart" : "Add to Cart"}
{cart[item.id] ? "Remove from Cart" : "Add to Cart"} />
</button> {Object.keys(cart).length > 0 ? (
<Link to="/bag">View Cart</Link> <Link to="/bag" className={styles.link}>
View Cart
</Link>
) : null}
</div> </div>
) : ( ) : (
<HandleInvalidItem /> <HandleInvalidItem />

View file

@ -4,6 +4,7 @@
justify-content: center; justify-content: center;
flex-wrap: wrap; flex-wrap: wrap;
align-items: stretch; align-items: stretch;
text-align: center;
} }
.card { .card {
display: flex; display: flex;
@ -13,4 +14,16 @@
/*flex: 1;*/ /*flex: 1;*/
padding: 1.5rem; padding: 1.5rem;
margin: 1.5rem; margin: 1.5rem;
border-radius: 1rem;
}
.link {
text-decoration: none;
color: #0e374e;
font-weight: 600;
transition: font-weight 500ms;
}
.link:hover {
font-weight: 900;
} }

View file

@ -4,7 +4,7 @@ import styles from "./products.module.css";
import { currencyFormat } from "../utils/currency"; import { currencyFormat } from "../utils/currency";
export default function Products({ item, cart, setCart }) { export default function Products({ item }) {
return ( return (
<> <>
<img src={item.image} alt={item.title} className={styles.img} /> <img src={item.image} alt={item.title} className={styles.img} />
@ -16,6 +16,4 @@ export default function Products({ item, cart, setCart }) {
Products.propTypes = { Products.propTypes = {
item: PropTypes.object, item: PropTypes.object,
cart: PropTypes.object,
setCart: PropTypes.func,
}; };

View file

@ -3,6 +3,14 @@
justify-content: space-between; justify-content: space-between;
} }
.empty-cart {
width: 100%;
display: flex;
justify-content: center;
align-items: flex-start;
margin-top: 0.5rem;
}
.summary { .summary {
margin-right: 3rem; margin-right: 3rem;
padding: 1rem; padding: 1rem;

View file

@ -2,6 +2,7 @@
font-family: Inter, system-ui, sans-serif; font-family: Inter, system-ui, sans-serif;
line-height: 1.5; line-height: 1.5;
font-weight: 400; font-weight: 400;
font-size: 18px;
/*color-scheme: light dark;*/ /*color-scheme: light dark;*/
/*color: rgba(255, 255, 255, 0.87);*/ /*color: rgba(255, 255, 255, 0.87);*/
@ -18,6 +19,18 @@ body {
display: flex; display: flex;
} }
/* Chrome, Safari, Edge, Opera */
input::-webkit-outer-spin-button,
input::-webkit-inner-spin-button {
-webkit-appearance: none;
margin: 0;
}
/* Firefox */
input[type="number"] {
-moz-appearance: textfield;
}
.roboto-condensed-fnt { .roboto-condensed-fnt {
font-family: "Roboto Condensed", sans-serif; font-family: "Roboto Condensed", sans-serif;
font-optical-sizing: auto; font-optical-sizing: auto;