added cart and store components

This commit is contained in:
Mike 2024-10-13 11:41:36 -04:00
parent 556a7f8fe2
commit 81d70ec032
13 changed files with 254 additions and 54 deletions

View file

@ -8,8 +8,10 @@
"name": "shopping-cart", "name": "shopping-cart",
"version": "0.0.0", "version": "0.0.0",
"dependencies": { "dependencies": {
"prop-types": "^15.8.1",
"react": "^18.3.1", "react": "^18.3.1",
"react-dom": "^18.3.1" "react-dom": "^18.3.1",
"react-router-dom": "^6.27.0"
}, },
"devDependencies": { "devDependencies": {
"@eslint/js": "^9.11.1", "@eslint/js": "^9.11.1",
@ -980,6 +982,15 @@
"@jridgewell/sourcemap-codec": "^1.4.14" "@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": { "node_modules/@rollup/rollup-android-arm-eabi": {
"version": "4.24.0", "version": "4.24.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.24.0.tgz", "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", "version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
"integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
"dev": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">=0.10.0" "node": ">=0.10.0"
@ -3578,7 +3588,6 @@
"version": "15.8.1", "version": "15.8.1",
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
"integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
"dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"loose-envify": "^1.4.0", "loose-envify": "^1.4.0",
@ -3625,7 +3634,6 @@
"version": "16.13.1", "version": "16.13.1",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
"dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/react-refresh": { "node_modules/react-refresh": {
@ -3638,6 +3646,38 @@
"node": ">=0.10.0" "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": { "node_modules/reflect.getprototypeof": {
"version": "1.0.6", "version": "1.0.6",
"resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.6.tgz", "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.6.tgz",

View file

@ -10,8 +10,10 @@
"preview": "vite preview" "preview": "vite preview"
}, },
"dependencies": { "dependencies": {
"prop-types": "^15.8.1",
"react": "^18.3.1", "react": "^18.3.1",
"react-dom": "^18.3.1" "react-dom": "^18.3.1",
"react-router-dom": "^6.27.0"
}, },
"devDependencies": { "devDependencies": {
"@eslint/js": "^9.11.1", "@eslint/js": "^9.11.1",

View file

@ -1,15 +1,16 @@
import { useState } from "react"; import { useState } from "react";
import "./App.css"; import { Outlet, useParams } from "react-router-dom";
import Main from "./components/main"; import Main from "./components/main";
import "./App.css";
import Navbar from "./components/navbar"; import Navbar from "./components/navbar";
function App() { function App() {
const [count, setCount] = useState(0); const { path } = useParams();
const [cartItems, setCartItems] = useState(0);
return ( return (
<> <>
<Navbar /> <Navbar cartItems={cartItems} />
<Main /> {path === "cart" ? <Outlet /> : path === "store" ? <Outlet /> : <Main />}
</> </>
); );
} }

View file

@ -1,22 +1,26 @@
import PropTypes from "prop-types";
const Cart = (props) => { const Cart = (props) => {
return ( return (
<section> <>
<div>
{props.cart ? ( {props.cart ? (
<div> <div>
<h2>Cart</h2> <h2>Cart</h2>
{props.cart.map((item) => {props.cart.map((item) => (
<CartItem item={item} qty={item.qty} /> <CartItem item={item} key={item.id} />
))}
</div>
) : (
<h2>Your cart is empty</h2>
)} )}
</div> </div>
) : (<h2>Your cart is empty</h2>)} </>
);
};
</section> function CartItem({ item }) {
) const { name, price, img, qty } = item;
}
function CartItem({item, qty}) {
const {name, price, img} = item;
return ( return (
<div> <div>
@ -26,5 +30,15 @@ function CartItem({item, qty}) {
<p>{price}</p> <p>{price}</p>
<p>{price * qty}</p> <p>{price * qty}</p>
</div> </div>
) );
} }
CartItem.propTypes = {
item: PropTypes.object,
};
Cart.propTypes = {
cart: PropTypes.array,
};
export default Cart;

View 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 };
}

View file

@ -3,14 +3,20 @@ import styles from "./main.module.css";
export default function Main(props) { export default function Main(props) {
return ( return (
<main> <main>
<div> <Default />
<h1 className={styles.mainHeading}>We help you skill up faster</h1>
<p>
Trying to pivot into tech? There&apos;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>
</main> </main>
); );
} }
function Default() {
return (
<div>
<h1 className={styles.mainHeading}>We help you skill up faster</h1>
<p>
Trying to pivot into tech? There&apos;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>
);
}

View file

@ -1,11 +1,13 @@
import styles from "./navbar.module.css"; 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 ( return (
<nav className={styles.nav}> <nav className={styles.nav}>
<h1>Smig.Tech</h1> <h1>Smig.Tech</h1>
<Nav /> <Nav />
<button>I&apos;m Ready</button> {cartItems ? <h1>{cartItems}</h1> : <button>I&apos;m Ready</button>}
</nav> </nav>
); );
} }
@ -13,8 +15,16 @@ export default function Navbar(props) {
function Nav() { function Nav() {
return ( return (
<ul className={styles.nav}> <ul className={styles.nav}>
<li>home</li> <li>
<li>shop</li> <Link to="/">home</Link>
</li>
<li>
<Link to="store">shop</Link>
</li>
</ul> </ul>
); );
} }
Navbar.propTypes = {
cartItems: PropTypes.number,
};

View 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,
};

View 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,
};

View file

@ -0,0 +1,11 @@
.card {
display: flex;
flex-direction: column;
max-width: 350px;
justify-content: center;
align-items: center;
}
.img {
max-width: 250px;
}

View 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;

View file

@ -1,10 +1,13 @@
import { StrictMode } from 'react' import { StrictMode } from "react";
import { createRoot } from 'react-dom/client' import { createRoot } from "react-dom/client";
import App from './App.jsx' import "./index.css";
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> <StrictMode>
<App /> <RouterProvider router={router} />
</StrictMode>, </StrictMode>,
) );

View 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;