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>
) : ( ) : (
<div className={styles["empty-cart"]}>
<h2>Your cart is empty</h2> <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 };
if (newQty !== 0) {
obj[item.id].qty = newQty; 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}> <div className={styles.container}>
<h1 className={styles.mainHeading}> <h1 className={styles.mainHeading}>
Our products help you skill up faster Our products help <span className={styles["heading-color"]}>you</span>{" "}
</h1> </h1>
<p> <p className={styles["sub-heading"]}>
Trying to pivot into tech? There&apos;s a lot to figure out. We can help Keep engineers happy using working technology. Fast results and
you navigate the path with our products. Fast results and guaranteed guaranteed value from day one.
growth.
</p> </p>
<Link to="/store"> <Link to="/store">
<Button text={"Start shopping now!"} styles={"action"} /> <Button text={"Start shopping now!"} />
</Link> </Link>
<div>
<img src="/hero.jpg" alt="" className={styles["hero-img"]} />
</div> </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;