mirror of
https://gitea.smigz.com/smiggiddy/odin-codeprojects.git
synced 2024-12-27 06:40:42 -05:00
adding more logic and components
This commit is contained in:
parent
9a7596b2a8
commit
da6d76e598
10 changed files with 109 additions and 83 deletions
|
@ -5,13 +5,30 @@ import { useOutletContext } from "react-router-dom";
|
||||||
export default function Store() {
|
export default function Store() {
|
||||||
const [cart, setCart, items, setItems] = useOutletContext();
|
const [cart, setCart, items, setItems] = useOutletContext();
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
const url = 'https://fakestoreapi.com/products?limit=5'
|
|
||||||
|
|
||||||
console.table(items)
|
useFakeStoreAPIData(items, setItems, loading, setLoading);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h1>Smig.Tech Coaching Store</h1>
|
||||||
|
<ProductCollection
|
||||||
|
loading={loading}
|
||||||
|
items={items}
|
||||||
|
cart={cart}
|
||||||
|
setCart={setCart}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function useFakeStoreAPIData(items, setItems, loading, setLoading) {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (items === null) {
|
if (items !== null) {
|
||||||
|
setLoading(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
fetch(url, { mode: "cors" })
|
fetch("https://fakestoreapi.com/products?limit=5", { mode: "cors" })
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
if (response.status >= 400) {
|
if (response.status >= 400) {
|
||||||
throw new Error("unable to fetch items");
|
throw new Error("unable to fetch items");
|
||||||
|
@ -32,51 +49,5 @@ export default function Store() {
|
||||||
})
|
})
|
||||||
.catch((error) => console.log(error))
|
.catch((error) => console.log(error))
|
||||||
.finally(() => setLoading(false));
|
.finally(() => setLoading(false));
|
||||||
} else {
|
}, [items, setItems, loading, setLoading]);
|
||||||
setLoading(false);
|
|
||||||
}
|
}
|
||||||
}, []);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<h1>Smig.Tech Coaching Store</h1>
|
|
||||||
<ProductCollection
|
|
||||||
loading={loading}
|
|
||||||
items={items}
|
|
||||||
cart={cart}
|
|
||||||
setCart={setCart}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// function useFakeStoreAPI() {
|
|
||||||
// const [items, setItems] = useState(null);
|
|
||||||
// const [loading, setLoading] = useState(true);
|
|
||||||
|
|
||||||
// useEffect(() => {
|
|
||||||
// fetch("https://fakestoreapi.com/products?limit=5", { mode: "cors" })
|
|
||||||
// .then((response) => {
|
|
||||||
// if (response.status >= 400) {
|
|
||||||
// throw new Error("unable to fetch items");
|
|
||||||
// }
|
|
||||||
// return response.json();
|
|
||||||
// })
|
|
||||||
// .then((response) => {
|
|
||||||
// const arr = [];
|
|
||||||
// response.forEach((item) => {
|
|
||||||
// arr.push({
|
|
||||||
// title: item.title,
|
|
||||||
// price: item.price,
|
|
||||||
// image: item.image,
|
|
||||||
// id: crypto.randomUUID(),
|
|
||||||
// });
|
|
||||||
// });
|
|
||||||
// setItems(arr);
|
|
||||||
// })
|
|
||||||
// .catch((error) => console.log(error))
|
|
||||||
// .finally(() => setLoading(false));
|
|
||||||
// }, []);
|
|
||||||
|
|
||||||
// return { items, loading };
|
|
||||||
// }
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ export default function Navbar({ cartItems }) {
|
||||||
const sumCartItems = Object.keys(cartItems).length;
|
const sumCartItems = Object.keys(cartItems).length;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<nav className={styles.nav}>
|
<nav className={styles.container}>
|
||||||
<h1>Smig.Tech</h1>
|
<h1>Smig.Tech</h1>
|
||||||
<Nav />
|
<Nav />
|
||||||
{sumCartItems > 0 ? (
|
{sumCartItems > 0 ? (
|
||||||
|
|
|
@ -1,11 +1,17 @@
|
||||||
nav {
|
.container {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
padding: 0 1rem;
|
padding: 0 1rem;
|
||||||
|
/*position: relative;*/
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav {
|
.nav {
|
||||||
display: flex;
|
display: flex;
|
||||||
list-style-type: none;
|
list-style-type: none;
|
||||||
gap: 20px;
|
gap: 20px;
|
||||||
|
/*position: absolute;*/
|
||||||
|
/*right: 4vw;*/
|
||||||
|
padding-right: 1rem;
|
||||||
|
margin-left: auto;
|
||||||
|
align-self: center;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import Product from "./products";
|
import { Link } from "react-router-dom";
|
||||||
|
import Products from "./products";
|
||||||
import PropTypes from "prop-types";
|
import PropTypes from "prop-types";
|
||||||
|
|
||||||
import styles from "./productCollection.module.css";
|
import styles from "./productCollection.module.css";
|
||||||
|
|
||||||
export default function ProductCollection({ loading, items, cart, setCart }) {
|
export default function ProductCollection({ loading, items, cart, setCart }) {
|
||||||
|
@ -9,7 +9,10 @@ export default function ProductCollection({ loading, items, cart, setCart }) {
|
||||||
{!loading
|
{!loading
|
||||||
? items.map((item, index) => {
|
? items.map((item, index) => {
|
||||||
return (
|
return (
|
||||||
<Product item={item} key={index} cart={cart} setCart={setCart} />
|
<div key={index} className={styles.card}>
|
||||||
|
<Products item={item} cart={cart} setCart={setCart} />
|
||||||
|
<Link to={item.id}> More Info</Link>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
: null}
|
: null}
|
||||||
|
|
16
shopping-cart/src/components/productCollection.module.css
Normal file
16
shopping-cart/src/components/productCollection.module.css
Normal file
|
@ -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% / 4);
|
||||||
|
justify-content: end;
|
||||||
|
/*flex: 1;*/
|
||||||
|
padding: 1.5rem;
|
||||||
|
margin: 1.5rem;
|
||||||
|
}
|
47
shopping-cart/src/components/productDetails.jsx
Normal file
47
shopping-cart/src/components/productDetails.jsx
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
import { useParams, useOutletContext } from "react-router-dom";
|
||||||
|
import Products from "./products";
|
||||||
|
import PropTypes from "prop-types";
|
||||||
|
|
||||||
|
import styles from "./productCollection.module.css";
|
||||||
|
|
||||||
|
export default function ProductDetails() {
|
||||||
|
const [cart, setCart, items, setItems] = useOutletContext();
|
||||||
|
|
||||||
|
const { id } = useParams();
|
||||||
|
const item = items.filter((item) => item.id === id)[0];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={styles.container}>
|
||||||
|
{item ? (
|
||||||
|
<div className={styles.card}>
|
||||||
|
<Products item={item} cart={cart} setCart={setCart} />
|
||||||
|
<button
|
||||||
|
onClick={() => {
|
||||||
|
addToCart(item, cart, setCart);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Add to Cart
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
setCart(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
ProductDetails.propTypes = {
|
||||||
|
item: PropTypes.object,
|
||||||
|
cart: PropTypes.object,
|
||||||
|
setCart: PropTypes.func,
|
||||||
|
};
|
|
@ -2,32 +2,17 @@ import PropTypes from "prop-types";
|
||||||
|
|
||||||
import styles from "./products.module.css";
|
import styles from "./products.module.css";
|
||||||
|
|
||||||
export default function Product({ item, cart, setCart }) {
|
export default function Products({ 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 = {
|
Products.propTypes = {
|
||||||
item: PropTypes.object,
|
item: PropTypes.object,
|
||||||
cart: PropTypes.object,
|
cart: PropTypes.object,
|
||||||
setCart: PropTypes.func,
|
setCart: PropTypes.func,
|
||||||
|
|
|
@ -1,13 +1,3 @@
|
||||||
.card {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
max-width: calc(100% / 5);
|
|
||||||
justify-content: end;
|
|
||||||
/*flex: 1;*/
|
|
||||||
padding: 1.5rem;
|
|
||||||
margin: 1.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.img {
|
.img {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: auto;
|
height: auto;
|
||||||
|
|
3
shopping-cart/src/css/cart.module.css
Normal file
3
shopping-cart/src/css/cart.module.css
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
.container {
|
||||||
|
display: flex;
|
||||||
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
import App from "./App";
|
import App from "./App";
|
||||||
import Cart from "./Cart";
|
import Cart from "./Cart";
|
||||||
import Main from "./components/main";
|
import Main from "./components/main";
|
||||||
|
import ProductDetails from "./components/productDetails";
|
||||||
import Store from "./Store";
|
import Store from "./Store";
|
||||||
import ErrorPage from "./errorPage";
|
import ErrorPage from "./errorPage";
|
||||||
|
|
||||||
|
@ -19,6 +20,10 @@ const routes = [
|
||||||
path: "store",
|
path: "store",
|
||||||
element: <Store />,
|
element: <Store />,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: "store/:id",
|
||||||
|
element: <ProductDetails />,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: "bag",
|
path: "bag",
|
||||||
element: <Cart />,
|
element: <Cart />,
|
||||||
|
|
Loading…
Reference in a new issue