mirror of
https://gitea.smigz.com/smiggiddy/odin-codeprojects.git
synced 2024-12-26 14:20:43 -05:00
basic functionality complete
This commit is contained in:
parent
81d70ec032
commit
f34aa95bfe
9 changed files with 98 additions and 37 deletions
|
@ -1,16 +1,14 @@
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { Outlet, useParams } from "react-router-dom";
|
import { Outlet } from "react-router-dom";
|
||||||
import Main from "./components/main";
|
|
||||||
import "./App.css";
|
import "./App.css";
|
||||||
import Navbar from "./components/navbar";
|
import Navbar from "./components/navbar";
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
const { path } = useParams();
|
const [cart, setCart] = useState({});
|
||||||
const [cartItems, setCartItems] = useState(0);
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Navbar cartItems={cartItems} />
|
<Navbar cartItems={cart} />
|
||||||
{path === "cart" ? <Outlet /> : path === "store" ? <Outlet /> : <Main />}
|
<Outlet context={[cart, setCart]} />
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,20 @@
|
||||||
import PropTypes from "prop-types";
|
import PropTypes from "prop-types";
|
||||||
|
import styles from "./css/cart.module.css";
|
||||||
|
import { useOutletContext } from "react-router-dom";
|
||||||
|
|
||||||
|
const Cart = () => {
|
||||||
|
const [cart, setCart] = useOutletContext();
|
||||||
|
|
||||||
|
const cartItems = Object.keys(cart);
|
||||||
|
|
||||||
const Cart = (props) => {
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div>
|
<div>
|
||||||
{props.cart ? (
|
{cart ? (
|
||||||
<div>
|
<div>
|
||||||
<h2>Cart</h2>
|
<h2>Cart</h2>
|
||||||
{props.cart.map((item) => (
|
{cartItems.map((item, index) => (
|
||||||
<CartItem item={item} key={item.id} />
|
<CartItem item={cart[item]} key={index} />
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
|
@ -20,15 +26,16 @@ const Cart = (props) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
function CartItem({ item }) {
|
function CartItem({ item }) {
|
||||||
const { name, price, img, qty } = item;
|
const { title, price, image, qty } = item;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div className={styles.container}>
|
||||||
<img src={img} alt={name} />
|
<img src={image} alt={title} />
|
||||||
<h3>{name}</h3>
|
<h3>{title}</h3>
|
||||||
<p>Qty: {qty}</p>
|
<p>Qty: {qty}</p>
|
||||||
<p>{price}</p>
|
<p>Price: {price}</p>
|
||||||
<p>{price * qty}</p>
|
<p>Total: {price * qty}</p>
|
||||||
|
<p>{item.id}</p>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,20 @@
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import ProductCollection from "./components/productCollection";
|
import ProductCollection from "./components/productCollection";
|
||||||
|
import { useOutletContext } from "react-router-dom";
|
||||||
|
|
||||||
export default function Store(props) {
|
export default function Store() {
|
||||||
|
const [cart, setCart] = useOutletContext();
|
||||||
const { items, loading } = useFakeStoreAPI();
|
const { items, loading } = useFakeStoreAPI();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<h1>Smig.Tech Coaching Store</h1>
|
<h1>Smig.Tech Coaching Store</h1>
|
||||||
<ProductCollection loading={loading} items={items} />
|
<ProductCollection
|
||||||
|
loading={loading}
|
||||||
|
items={items}
|
||||||
|
cart={cart}
|
||||||
|
setCart={setCart}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -19,14 +27,19 @@ function useFakeStoreAPI() {
|
||||||
fetch("https://fakestoreapi.com/products?limit=5", { mode: "cors" })
|
fetch("https://fakestoreapi.com/products?limit=5", { mode: "cors" })
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
if (response.status >= 400) {
|
if (response.status >= 400) {
|
||||||
return { error: "unable to fetch items" };
|
throw new Error("unable to fetch items");
|
||||||
}
|
}
|
||||||
return response.json();
|
return response.json();
|
||||||
})
|
})
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
const arr = [];
|
const arr = [];
|
||||||
response.forEach((item) => {
|
response.forEach((item) => {
|
||||||
arr.push({ title: item.title, price: item.price, image: item.image });
|
arr.push({
|
||||||
|
title: item.title,
|
||||||
|
price: item.price,
|
||||||
|
image: item.image,
|
||||||
|
id: crypto.randomUUID(),
|
||||||
|
});
|
||||||
});
|
});
|
||||||
setItems(arr);
|
setItems(arr);
|
||||||
})
|
})
|
||||||
|
|
|
@ -3,11 +3,20 @@ import { Link } from "react-router-dom";
|
||||||
import PropTypes from "prop-types";
|
import PropTypes from "prop-types";
|
||||||
|
|
||||||
export default function Navbar({ cartItems }) {
|
export default function Navbar({ cartItems }) {
|
||||||
|
const sumCartItems = Object.keys(cartItems).length;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<nav className={styles.nav}>
|
<nav className={styles.nav}>
|
||||||
<h1>Smig.Tech</h1>
|
<h1>Smig.Tech</h1>
|
||||||
<Nav />
|
<Nav />
|
||||||
{cartItems ? <h1>{cartItems}</h1> : <button>I'm Ready</button>}
|
{sumCartItems > 0 ? (
|
||||||
|
<Link to="bag">
|
||||||
|
{" "}
|
||||||
|
<h1>{sumCartItems}</h1>
|
||||||
|
</Link>
|
||||||
|
) : (
|
||||||
|
<button>I'm Ready</button>
|
||||||
|
)}
|
||||||
</nav>
|
</nav>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -26,5 +35,5 @@ function Nav() {
|
||||||
}
|
}
|
||||||
|
|
||||||
Navbar.propTypes = {
|
Navbar.propTypes = {
|
||||||
cartItems: PropTypes.number,
|
cartItems: PropTypes.object,
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,12 +1,16 @@
|
||||||
import Product from "./products";
|
import Product from "./products";
|
||||||
import PropTypes from "prop-types";
|
import PropTypes from "prop-types";
|
||||||
|
|
||||||
export default function ProductCollection({ loading, items }) {
|
import styles from "./productCollection.module.css";
|
||||||
|
|
||||||
|
export default function ProductCollection({ loading, items, cart, setCart }) {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div className={styles.container}>
|
||||||
{!loading
|
{!loading
|
||||||
? items.map((item, index) => {
|
? items.map((item, index) => {
|
||||||
return <Product item={item} key={index} />;
|
return (
|
||||||
|
<Product item={item} key={index} cart={cart} setCart={setCart} />
|
||||||
|
);
|
||||||
})
|
})
|
||||||
: null}
|
: null}
|
||||||
</div>
|
</div>
|
||||||
|
@ -16,4 +20,6 @@ export default function ProductCollection({ loading, items }) {
|
||||||
ProductCollection.propTypes = {
|
ProductCollection.propTypes = {
|
||||||
loading: PropTypes.bool,
|
loading: PropTypes.bool,
|
||||||
items: PropTypes.array,
|
items: PropTypes.array,
|
||||||
|
cart: PropTypes.object,
|
||||||
|
setCart: PropTypes.func,
|
||||||
};
|
};
|
||||||
|
|
|
@ -2,16 +2,33 @@ import PropTypes from "prop-types";
|
||||||
|
|
||||||
import styles from "./products.module.css";
|
import styles from "./products.module.css";
|
||||||
|
|
||||||
export default function Product({ item }) {
|
export default function Product({ item, cart, setCart }) {
|
||||||
return (
|
return (
|
||||||
<div className={styles.card}>
|
<div className={styles.card}>
|
||||||
<img src={item.image} alt={item.title} className={styles.img} />
|
<img src={item.image} alt={item.title} className={styles.img} />
|
||||||
<p>{item.title}</p>
|
<p>{item.title}</p>
|
||||||
<p>${item.price}</p>
|
<p>${item.price}</p>
|
||||||
|
<button
|
||||||
|
onClick={() => {
|
||||||
|
let obj = { ...cart };
|
||||||
|
if (obj[item.id]) {
|
||||||
|
obj[item.id].qty += 1;
|
||||||
|
} else {
|
||||||
|
obj[item.id] = item;
|
||||||
|
obj[item.id].qty = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
setCart(obj);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Add to Cart
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Product.propTypes = {
|
Product.propTypes = {
|
||||||
item: PropTypes.object,
|
item: PropTypes.object,
|
||||||
|
cart: PropTypes.object,
|
||||||
|
setCart: PropTypes.func,
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,11 +1,15 @@
|
||||||
.card {
|
.card {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
max-width: 350px;
|
max-width: calc(100% / 5);
|
||||||
justify-content: center;
|
justify-content: end;
|
||||||
align-items: center;
|
/*flex: 1;*/
|
||||||
|
padding: 1.5rem;
|
||||||
|
margin: 1.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.img {
|
.img {
|
||||||
max-width: 250px;
|
width: 100%;
|
||||||
|
height: auto;
|
||||||
|
vertical-align: middle;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,10 +3,12 @@ import { Link } from "react-router-dom";
|
||||||
function ErrorPage() {
|
function ErrorPage() {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<h1>Oh no, this route doesn't exist!</h1>
|
<h1>Oh no, this route doesn't exist!</h1>
|
||||||
<Link to="/">
|
<p>
|
||||||
You can go back to the home page by clicking here, though!
|
You can go back to the home page by clicking
|
||||||
</Link>
|
<Link to="/">here</Link>
|
||||||
|
though!
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import App from "./App";
|
import App from "./App";
|
||||||
import Cart from "./Cart";
|
import Cart from "./Cart";
|
||||||
|
import Main from "./components/main";
|
||||||
import Store from "./Store";
|
import Store from "./Store";
|
||||||
import ErrorPage from "./errorPage";
|
import ErrorPage from "./errorPage";
|
||||||
|
|
||||||
|
@ -10,12 +11,16 @@ const routes = [
|
||||||
errorElement: <ErrorPage />,
|
errorElement: <ErrorPage />,
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
path: ":path",
|
path: "/",
|
||||||
element: <Store />,
|
element: <Main />,
|
||||||
index: true,
|
index: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: "store/:path",
|
path: "store",
|
||||||
|
element: <Store />,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "bag",
|
||||||
element: <Cart />,
|
element: <Cart />,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|
Loading…
Reference in a new issue