mirror of
https://gitea.smigz.com/smiggiddy/odin-codeprojects.git
synced 2024-12-26 14:20:43 -05:00
added cart and store components
This commit is contained in:
parent
556a7f8fe2
commit
81d70ec032
13 changed files with 254 additions and 54 deletions
48
shopping-cart/package-lock.json
generated
48
shopping-cart/package-lock.json
generated
|
@ -8,8 +8,10 @@
|
|||
"name": "shopping-cart",
|
||||
"version": "0.0.0",
|
||||
"dependencies": {
|
||||
"prop-types": "^15.8.1",
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1"
|
||||
"react-dom": "^18.3.1",
|
||||
"react-router-dom": "^6.27.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^9.11.1",
|
||||
|
@ -980,6 +982,15 @@
|
|||
"@jridgewell/sourcemap-codec": "^1.4.14"
|
||||
}
|
||||
},
|
||||
"node_modules/@remix-run/router": {
|
||||
"version": "1.20.0",
|
||||
"resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.20.0.tgz",
|
||||
"integrity": "sha512-mUnk8rPJBI9loFDZ+YzPGdeniYK+FTmRD1TMCz7ev2SNIozyKKpnGgsxO34u6Z4z/t0ITuu7voi/AshfsGsgFg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@rollup/rollup-android-arm-eabi": {
|
||||
"version": "4.24.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.24.0.tgz",
|
||||
|
@ -3328,7 +3339,6 @@
|
|||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
||||
"integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
|
@ -3578,7 +3588,6 @@
|
|||
"version": "15.8.1",
|
||||
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
|
||||
"integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.4.0",
|
||||
|
@ -3625,7 +3634,6 @@
|
|||
"version": "16.13.1",
|
||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
||||
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/react-refresh": {
|
||||
|
@ -3638,6 +3646,38 @@
|
|||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-router": {
|
||||
"version": "6.27.0",
|
||||
"resolved": "https://registry.npmjs.org/react-router/-/react-router-6.27.0.tgz",
|
||||
"integrity": "sha512-YA+HGZXz4jaAkVoYBE98VQl+nVzI+cVI2Oj/06F5ZM+0u3TgedN9Y9kmMRo2mnkSK2nCpNQn0DVob4HCsY/WLw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@remix-run/router": "1.20.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=16.8"
|
||||
}
|
||||
},
|
||||
"node_modules/react-router-dom": {
|
||||
"version": "6.27.0",
|
||||
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.27.0.tgz",
|
||||
"integrity": "sha512-+bvtFWMC0DgAFrfKXKG9Fc+BcXWRUO1aJIihbB79xaeq0v5UzfvnM5houGUm1Y461WVRcgAQ+Clh5rdb1eCx4g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@remix-run/router": "1.20.0",
|
||||
"react-router": "6.27.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=16.8",
|
||||
"react-dom": ">=16.8"
|
||||
}
|
||||
},
|
||||
"node_modules/reflect.getprototypeof": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.6.tgz",
|
||||
|
|
|
@ -10,8 +10,10 @@
|
|||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"prop-types": "^15.8.1",
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1"
|
||||
"react-dom": "^18.3.1",
|
||||
"react-router-dom": "^6.27.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^9.11.1",
|
||||
|
|
|
@ -1,15 +1,16 @@
|
|||
import { useState } from "react";
|
||||
import "./App.css";
|
||||
import { Outlet, useParams } from "react-router-dom";
|
||||
import Main from "./components/main";
|
||||
import "./App.css";
|
||||
import Navbar from "./components/navbar";
|
||||
|
||||
function App() {
|
||||
const [count, setCount] = useState(0);
|
||||
|
||||
const { path } = useParams();
|
||||
const [cartItems, setCartItems] = useState(0);
|
||||
return (
|
||||
<>
|
||||
<Navbar />
|
||||
<Main />
|
||||
<Navbar cartItems={cartItems} />
|
||||
{path === "cart" ? <Outlet /> : path === "store" ? <Outlet /> : <Main />}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,30 +1,44 @@
|
|||
import PropTypes from "prop-types";
|
||||
|
||||
const Cart = (props) => {
|
||||
return (
|
||||
<section>
|
||||
{props.cart ? (
|
||||
<div>
|
||||
<h2>Cart</h2>
|
||||
{props.cart.map((item) =>
|
||||
<CartItem item={item} qty={item.qty} />
|
||||
)}
|
||||
</div>
|
||||
) : (<h2>Your cart is empty</h2>)}
|
||||
|
||||
</section>
|
||||
)
|
||||
return (
|
||||
<>
|
||||
<div>
|
||||
{props.cart ? (
|
||||
<div>
|
||||
<h2>Cart</h2>
|
||||
{props.cart.map((item) => (
|
||||
<CartItem item={item} key={item.id} />
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
<h2>Your cart is empty</h2>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
function CartItem({ item }) {
|
||||
const { name, price, img, qty } = item;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<img src={img} alt={name} />
|
||||
<h3>{name}</h3>
|
||||
<p>Qty: {qty}</p>
|
||||
<p>{price}</p>
|
||||
<p>{price * qty}</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
CartItem.propTypes = {
|
||||
item: PropTypes.object,
|
||||
};
|
||||
|
||||
function CartItem({item, qty}) {
|
||||
const {name, price, img} = item;
|
||||
Cart.propTypes = {
|
||||
cart: PropTypes.array,
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<img src={img} alt={name} />
|
||||
<h3>{name}</h3>
|
||||
<p>Qty: {qty}</p>
|
||||
<p>{price}</p>
|
||||
<p>{price * qty}</p>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
export default Cart;
|
||||
|
|
38
shopping-cart/src/Store.jsx
Normal file
38
shopping-cart/src/Store.jsx
Normal file
|
@ -0,0 +1,38 @@
|
|||
import { useEffect, useState } from "react";
|
||||
import ProductCollection from "./components/productCollection";
|
||||
|
||||
export default function Store(props) {
|
||||
const { items, loading } = useFakeStoreAPI();
|
||||
return (
|
||||
<div>
|
||||
<h1>Smig.Tech Coaching Store</h1>
|
||||
<ProductCollection loading={loading} items={items} />
|
||||
</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) {
|
||||
return { 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 });
|
||||
});
|
||||
setItems(arr);
|
||||
})
|
||||
.catch((error) => console.log(error))
|
||||
.finally(() => setLoading(false));
|
||||
}, []);
|
||||
|
||||
return { items, loading };
|
||||
}
|
|
@ -3,14 +3,20 @@ import styles from "./main.module.css";
|
|||
export default function Main(props) {
|
||||
return (
|
||||
<main>
|
||||
<div>
|
||||
<h1 className={styles.mainHeading}>We help you skill up faster</h1>
|
||||
<p>
|
||||
Trying to pivot into tech? There's a lot to figure out. We can
|
||||
help you navigate the path. Fast results and guaranteed growth.
|
||||
</p>
|
||||
<button>BOOK INTRO CALL</button>
|
||||
</div>
|
||||
<Default />
|
||||
</main>
|
||||
);
|
||||
}
|
||||
|
||||
function Default() {
|
||||
return (
|
||||
<div>
|
||||
<h1 className={styles.mainHeading}>We help you skill up faster</h1>
|
||||
<p>
|
||||
Trying to pivot into tech? There's a lot to figure out. We can help
|
||||
you navigate the path. Fast results and guaranteed growth.
|
||||
</p>
|
||||
<button>BOOK INTRO CALL</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
import styles from "./navbar.module.css";
|
||||
import { Link } from "react-router-dom";
|
||||
import PropTypes from "prop-types";
|
||||
|
||||
export default function Navbar(props) {
|
||||
export default function Navbar({ cartItems }) {
|
||||
return (
|
||||
<nav className={styles.nav}>
|
||||
<h1>Smig.Tech</h1>
|
||||
<Nav />
|
||||
<button>I'm Ready</button>
|
||||
{cartItems ? <h1>{cartItems}</h1> : <button>I'm Ready</button>}
|
||||
</nav>
|
||||
);
|
||||
}
|
||||
|
@ -13,8 +15,16 @@ export default function Navbar(props) {
|
|||
function Nav() {
|
||||
return (
|
||||
<ul className={styles.nav}>
|
||||
<li>home</li>
|
||||
<li>shop</li>
|
||||
<li>
|
||||
<Link to="/">home</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link to="store">shop</Link>
|
||||
</li>
|
||||
</ul>
|
||||
);
|
||||
}
|
||||
|
||||
Navbar.propTypes = {
|
||||
cartItems: PropTypes.number,
|
||||
};
|
||||
|
|
19
shopping-cart/src/components/productCollection.jsx
Normal file
19
shopping-cart/src/components/productCollection.jsx
Normal file
|
@ -0,0 +1,19 @@
|
|||
import Product from "./products";
|
||||
import PropTypes from "prop-types";
|
||||
|
||||
export default function ProductCollection({ loading, items }) {
|
||||
return (
|
||||
<div>
|
||||
{!loading
|
||||
? items.map((item, index) => {
|
||||
return <Product item={item} key={index} />;
|
||||
})
|
||||
: null}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
ProductCollection.propTypes = {
|
||||
loading: PropTypes.bool,
|
||||
items: PropTypes.array,
|
||||
};
|
17
shopping-cart/src/components/products.jsx
Normal file
17
shopping-cart/src/components/products.jsx
Normal file
|
@ -0,0 +1,17 @@
|
|||
import PropTypes from "prop-types";
|
||||
|
||||
import styles from "./products.module.css";
|
||||
|
||||
export default function Product({ item }) {
|
||||
return (
|
||||
<div className={styles.card}>
|
||||
<img src={item.image} alt={item.title} className={styles.img} />
|
||||
<p>{item.title}</p>
|
||||
<p>${item.price}</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Product.propTypes = {
|
||||
item: PropTypes.object,
|
||||
};
|
11
shopping-cart/src/components/products.module.css
Normal file
11
shopping-cart/src/components/products.module.css
Normal file
|
@ -0,0 +1,11 @@
|
|||
.card {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
max-width: 350px;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.img {
|
||||
max-width: 250px;
|
||||
}
|
14
shopping-cart/src/errorPage.jsx
Normal file
14
shopping-cart/src/errorPage.jsx
Normal file
|
@ -0,0 +1,14 @@
|
|||
import { Link } from "react-router-dom";
|
||||
|
||||
function ErrorPage() {
|
||||
return (
|
||||
<div>
|
||||
<h1>Oh no, this route doesn't exist!</h1>
|
||||
<Link to="/">
|
||||
You can go back to the home page by clicking here, though!
|
||||
</Link>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default ErrorPage;
|
|
@ -1,10 +1,13 @@
|
|||
import { StrictMode } from 'react'
|
||||
import { createRoot } from 'react-dom/client'
|
||||
import App from './App.jsx'
|
||||
import './index.css'
|
||||
import { StrictMode } from "react";
|
||||
import { createRoot } from "react-dom/client";
|
||||
import "./index.css";
|
||||
import { createBrowserRouter, RouterProvider } from "react-router-dom";
|
||||
import routes from "./routes";
|
||||
|
||||
createRoot(document.getElementById('root')).render(
|
||||
const router = createBrowserRouter(routes);
|
||||
|
||||
createRoot(document.getElementById("root")).render(
|
||||
<StrictMode>
|
||||
<App />
|
||||
<RouterProvider router={router} />
|
||||
</StrictMode>,
|
||||
)
|
||||
);
|
||||
|
|
25
shopping-cart/src/routes.jsx
Normal file
25
shopping-cart/src/routes.jsx
Normal file
|
@ -0,0 +1,25 @@
|
|||
import App from "./App";
|
||||
import Cart from "./Cart";
|
||||
import Store from "./Store";
|
||||
import ErrorPage from "./errorPage";
|
||||
|
||||
const routes = [
|
||||
{
|
||||
path: "/",
|
||||
element: <App />,
|
||||
errorElement: <ErrorPage />,
|
||||
children: [
|
||||
{
|
||||
path: ":path",
|
||||
element: <Store />,
|
||||
index: true,
|
||||
},
|
||||
{
|
||||
path: "store/:path",
|
||||
element: <Cart />,
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
export default routes;
|
Loading…
Reference in a new issue