Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
node_modules/
41 changes: 41 additions & 0 deletions FrontEnd/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
/.pnp
.pnp.*
.yarn/*
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/versions

# testing
/coverage

# next.js
/.next/
/out/

# production
/build

# misc
.DS_Store
*.pem

# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.pnpm-debug.log*

# env files (can opt-in for committing if needed)
.env*

# vercel
.vercel

# typescript
*.tsbuildinfo
next-env.d.ts
36 changes: 36 additions & 0 deletions FrontEnd/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app).

## Getting Started

First, run the development server:

```bash
npm run dev
# or
yarn dev
# or
pnpm dev
# or
bun dev
```

Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.

You can start editing the page by modifying `app/page.js`. The page auto-updates as you edit the file.

This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel.

## Learn More

To learn more about Next.js, take a look at the following resources:

- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.

You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome!

## Deploy on Vercel

The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.

Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details.
132 changes: 132 additions & 0 deletions FrontEnd/app/components/NavBar.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
"use client";
import { useDispatch } from "react-redux";
import { useEffect } from "react";
import { getProducts, setFilter } from "../store/slices/apiSlice";

export const NavBar = () => {
useEffect(() => {
if (typeof window !== "undefined") {
import("bootstrap/dist/js/bootstrap.esm.js");
}
}, []);
const dispatch = useDispatch();

const search = (e) => {
dispatch(getProducts({ query: e.target.value }));
};

const sortByCat = (e) => {
dispatch(setFilter({ category: e.target.id }));
dispatch(getProducts({ category: e.target.id }));
};

const sortByPrice = (e) => {
dispatch(setFilter({ price: e.target.id }));
dispatch(getProducts({ price: e.target.id }));
};

return (
<div className="container text-center p-2">
<nav className="input-group">
<input
className="form-control"
onChange={search}
placeholder="Search for a product"
type="text"
/>
<div className="dropdown">
<button
className="btn btn-secondary dropdown-toggle"
type="button"
id="dropdownMenu2"
data-bs-toggle="dropdown"
aria-haspopup="true"
aria-expanded="false"
>
Category
</button>
<div className="dropdown-menu" aria-labelledby="dropdownMenu2">
<button
id="Home"
onClick={sortByCat}
className="dropdown-item"
type="button"
>
Home
</button>
<button
id="Sports"
onClick={sortByCat}
className="dropdown-item"
type="button"
>
Sports
</button>
<button
id="Health"
onClick={sortByCat}
className="dropdown-item"
type="button"
>
Health
</button>
<button
id="Music"
onClick={sortByCat}
className="dropdown-item"
type="button"
>
Music
</button>
<button
id="Baby"
onClick={sortByCat}
className="dropdown-item"
type="button"
>
Baby
</button>
<button
id="Electronics"
onClick={sortByCat}
className="dropdown-item"
type="button"
>
Electronics
</button>
</div>
</div>
<div className="dropdown">
<button
className="btn btn-secondary dropdown-toggle"
type="button"
id="dropdownMenu2"
data-bs-toggle="dropdown"
aria-haspopup="true"
aria-expanded="false"
>
Price
</button>
<div className="dropdown-menu" aria-labelledby="dropdownMenu2">
<button
id="highest"
onClick={sortByPrice}
className="dropdown-item"
type="button"
>
High to low
</button>
<button
id="lowest"
onClick={sortByPrice}
className="dropdown-item"
type="button"
>
Low to high
</button>
</div>
</div>
</nav>
</div>
);
};
32 changes: 32 additions & 0 deletions FrontEnd/app/components/PageNav.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
"use client";
import { useState, useEffect } from "react";
import { useSelector, useDispatch } from "react-redux";
import { getProducts } from "../store/slices/apiSlice";

export const PageNav = () => {
const [pages, setPages] = useState([]);
const dispatch = useDispatch();
const { products } = useSelector((state) => state.products);

const numberOfPages = Math.ceil(products.totalCount / 9);
let pagesArray = [];

useEffect(() => {
for (let i = 0; i < numberOfPages; i++) {
pagesArray.push(i + 1);
}
setPages(pagesArray);
}, [products]);

useEffect(() => {
console.log(pages);
}, [pages]);
// return page list, handle page navigation
return (
<div className="input-group">
{pages.map((number) => {
<button className="btn btn-link">{number}</button>;
})}
</div>
);
};
81 changes: 81 additions & 0 deletions FrontEnd/app/components/ProductList.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
"use client";
import { useState, useEffect } from "react";
import { useSelector, useDispatch } from "react-redux";
import { getProducts } from "../store/slices/apiSlice";

export const ProductList = () => {
const dispatch = useDispatch();
const [productList, setProductList] = useState([]);
const [pages, setPages] = useState([]);
const { products } = useSelector((state) => state.products);

const numberOfPages = Math.ceil(products.totalCount / 9);
let pagesArray = [];

const changePage = (e) => {
dispatch(getProducts({ page: e.target.id }));
};

useEffect(() => {
dispatch(getProducts());
}, []);

useEffect(() => {
if (products) {
setProductList(products.products);
}
}, [products]);

useEffect(() => {
for (let i = 0; i < numberOfPages; i++) {
pagesArray.push(i + 1);
}
setPages(pagesArray);
}, [products]);

useEffect(() => {
console.log(pages);
}, [pages]);

return (
<div className="container">
<div className="row">
{productList && productList.length > 0 ? (
productList.map((product) => (
<div className="col-12 col-sm-6 col-md-4" key={product._id}>
<div className="card">
<div className="card-body">
<p>Category: {product.category}</p>
<p>Price: {product.price}</p>
{/* Used <img> instead of <Image> to avoid nextJS domain restrictions */}
<img
className="img-fluid"
height={50}
width={50}
alt="product image"
src={product.image}
/>
<p>{product.name}</p>
</div>
</div>
</div>
))
) : (
<p>No products available</p>
)}
</div>
<div className="input-group justify-content-center">
{pages.map((number) => (
<button
onClick={changePage}
id={number}
key={number}
className="btn btn-link"
>
{number}
</button>
))}
</div>
</div>
);
};
Binary file added FrontEnd/app/favicon.ico
Binary file not shown.
42 changes: 42 additions & 0 deletions FrontEnd/app/globals.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
:root {
--background: #ffffff;
--foreground: #171717;
}

@media (prefers-color-scheme: dark) {
:root {
--background: #0a0a0a;
--foreground: #ededed;
}
}

html,
body {
max-width: 100vw;
overflow-x: hidden;
}

body {
color: var(--foreground);
background: var(--background);
font-family: Arial, Helvetica, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}

* {
box-sizing: border-box;
padding: 0;
margin: 0;
}

a {
color: inherit;
text-decoration: none;
}

@media (prefers-color-scheme: dark) {
html {
color-scheme: dark;
}
}
14 changes: 14 additions & 0 deletions FrontEnd/app/layout.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
"use client";
import { Provider } from "react-redux";
import store from "./store/configureStore";
import "bootstrap/dist/css/bootstrap.min.css";

export default function RootLayout({ children }) {
return (
<html lang="en">
<Provider store={store}>
<body className="text-center">{children}</body>
</Provider>
</html>
);
}
11 changes: 11 additions & 0 deletions FrontEnd/app/page.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { ProductList } from "./components/ProductList";
import { NavBar } from "./components/NavBar";

export default function Home() {
return (
<main>
<NavBar />
<ProductList />
</main>
);
}
Loading