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
66 changes: 64 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,64 @@
# assignment-03
check canvas for instructions
# RetailHub Dashboard

RetailHub Dashboard is a web application designed to provide a comprehensive overview of key metrics and data visualization for retail businesses.

## Features

- **Dashboard Overview:** View key metrics such as weekly sales, new users, item orders, bug reports, employees, and vendors all returned from our prisma db tables.
- **Customized Graphs:** Visualize data using customized bar charts, pie charts, line charts, and area charts.
- **Data Management:** Add, update, and delete categories and items through the web interface.

- **Responsive Design:** User-friendly interface optimized for desktop and mobile devices.

## Authentication and Middleware

- **Auth0 Authentication:** Authentication has been implemented using Auth0 to secure inventory access and handle POST requests.
- **Middleware:** A middleware named `/verify` has been created to handle GET and POST requests to interact with our Prisma database.

## External Weather API Integration

The RetailHub Dashboard includes integration with an external weather API to provide information about the weather conditions of the store location.

## Custom Components

Custom components have been created using Material-UI (MUI) to enhance the functionality and aesthetics of the RetailHub Dashboard.

## Tests

Tests have been added in the `test` folder to ensure the functionality and reliability of the RetailHub Dashboard.

## Accessibility

Accessibility has been maintained for all the working pages of the RetailHub Dashboard, ensuring usability for all users, including those with disabilities.

## Light House Report

The Light House report for this project is available in PDF form in the `client/src/assets` folder.

## Code Structure and Naming Conventions

The codebase follows industry standards with well-maintained variable names and folder structure for clarity and consistency.

## API Endpoints

- `GET /dashboard-data`: Fetches data for populating the dashboard graphs.
- `GET /categories`: Retrieves a list of all categories.
- `POST /categories`: Adds a new category.
- `PUT /categories/:id`: Updates an existing category.
- `DELETE /categories/:id`: Deletes a category.
- `GET /items/:categoryId`: Retrieves items by category.
- `POST /items`: Adds a new item.
- `PUT /items/:id`: Updates an existing item.
- `DELETE /items/:id`: Deletes an item.

## Database Schema

The database schema includes two main tables:

- **User:** Stores user details such as username, email, and password.
- **Category:** Stores different types of categories with their descriptions and emojis.
- **Item:** Stores unique items belonging to a category, including item name, description, price, quantity, and category ID.

## Conclusion

The RetailHub Dashboard offers a robust solution for retail businesses, providing comprehensive insights, intuitive data visualization, and seamless data management. With its user-friendly interface, responsive design, and adherence to industry standards, this dashboard empowers retailers to make informed decisions and drive business growth. We welcome feedback, contributions, and suggestions for further improvements to enhance the RetailHub experience.
6 changes: 3 additions & 3 deletions api/.env
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
DATABASE_URL=mysql://root:123456@localhost:3306/tododb
AUTH0_AUDIENCE=https://api.todos
AUTH0_ISSUER=https://neu.us.auth0.com/
DATABASE_URL=mysql://root:Rishi_14@127.0.0.1:3306/project
AUTH0_AUDIENCE=https://api.retailhub
AUTH0_ISSUER=https://rishabhkumar.us.auth0.com/
2 changes: 2 additions & 0 deletions api/.gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
node_modules
# Keep environment variables out of version control
.env
203 changes: 199 additions & 4 deletions api/index.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as dotenv from "dotenv";
dotenv.config();
import express from "express";
import pkg from "@prisma/client";
import { PrismaClient } from "@prisma/client";
import morgan from "morgan";
import cors from "cors";
import { auth } from "express-oauth2-jwt-bearer";
Expand All @@ -20,16 +20,211 @@ app.use(express.urlencoded({ extended: true }));
app.use(express.json());
app.use(morgan("dev"));

const { PrismaClient } = pkg;
const prisma = new PrismaClient();
const dataArea = [
{ name: "January", uv: 400, pv: 240, amt: 240 },
{ name: "February", uv: 300, pv: 139, amt: 221 },
{ name: "March", uv: 200, pv: 980, amt: 229 },
{ name: "April", uv: 278, pv: 390, amt: 200 },
{ name: "May", uv: 189, pv: 480, amt: 218 },
{ name: "June", uv: 239, pv: 380, amt: 250 },
{ name: "July", uv: 349, pv: 430, amt: 210 },
];

const dataPie = [
{ name: "Category A", value: 400, color: "#8884d8" },
{ name: "Category B", value: 300, color: "#81c99c" },
{ name: "Category C", value: 200, color: "#edb852" },
{ name: "Category H", value: 120, color: "#e91e63" },
];

const dataBar = [
{ category: "Category A", value1: 150, value2: 200, value3: 120 },
{ category: "Category B", value1: 250, value2: 100, value3: 180 },
{ category: "Category C", value1: 100, value2: 300, value3: 150 },
{ category: "Category D", value1: 200, value2: 150, value3: 220 },
{ category: "Category E", value1: 180, value2: 120, value3: 250 },
];

const dataLine = [
{ month: "Jan", users: 100, sessions: 220, revenue: 350 },
{ month: "Feb", users: 150, sessions: 300, revenue: 400 },
{ month: "Mar", users: 200, sessions: 400, revenue: 500 },
{ month: "Apr", users: 250, sessions: 500, revenue: 600 },
{ month: "May", users: 300, sessions: 600, revenue: 700 },
];

// this is a public endpoint because it doesn't have the requireAuth middleware
app.get("/ping", (req, res) => {
res.send("pong");
});

// add your endpoints below this line
app.get("/dashboard-data", (req, res) => {
res.json({
dataArea,
dataPie,
dataBar,
dataLine,
});
});

// Categories Endpoints

// GET: list of all categories
app.get("/categories", async (req, res) => {
const categories = await prisma.category.findMany();
res.status(200).json(categories);
});

// POST: creates new category
app.post("/categories", async (req, res) => {
const { category_name, category_description, emoji } = req.body;
const newCategory = await prisma.category.create({
data: {
category_name,
category_description,
emoji,
},
});
res.status(201).json(newCategory);
});

// GET: return Category with :id
app.get("/categories/:id", async (req, res) => {
const categoryId = parseInt(req.params.id);
const category = await prisma.category.findUnique({
where: { id: categoryId },
});

if (category) {
res.status(200).json(category);
} else {
res.status(404).send(`Category id ${categoryId} not found`);
}
});

// PUT: updates Category name, description, or symbol with :id
app.put("/categories/:id", async (req, res) => {
const categoryId = parseInt(req.params.id);
const { category_name, category_description, emoji } = req.body; // Use correct keys
const updatedCategory = await prisma.category.update({
where: { id: categoryId },
data: { category_name, category_description, emoji }, // Use correct keys
});
res.status(200).json(updatedCategory);
});

// DELETE: deletes Category with :id
app.delete("/categories/:id", async (req, res) => {
const categoryId = parseInt(req.params.id);
await prisma.category.delete({
where: { id: categoryId },
});
res.status(204).send();
});

// Items Endpoints

// GET: list of items by category
app.get("/items/:categoryId", async (req, res) => {
const categoryId = parseInt(req.params.categoryId);
const items = await prisma.item.findMany({
where: { categoryId },
});
res.status(200).json(items);
});

// POST: creates new item
app.post("/items", async (req, res) => {
const { item_name, item_description, price, categoryId } = req.body;

try {
const newItem = await prisma.item.create({
data: {
item_name,
item_description,
price,
quantity: 0,
category: { connect: { id: categoryId } },
},
});
res.status(201).json(newItem);
} catch (error) {
if (error.code === "P2002" && error.meta?.target === "Item_item_name_key") {
// Handle unique constraint violation gracefully
res.status(400).json({
error: "Item name already exists. Please choose a different name.",
});
} else {
console.error("Error adding item:", error);
res.status(500).json({ error: "Failed to add item" });
}
}
});

// GET: return Item with :id
app.get("/items/:id", async (req, res) => {
const itemId = parseInt(req.params.id);
const item = await prisma.item.findUnique({
where: { id: itemId },
});

if (item) {
res.status(200).json(item);
} else {
res.status(404).send(`Item id ${itemId} not found`);
}
});

// PUT: updates Item description or price with :id
app.put("/items/:id", async (req, res) => {
const itemId = parseInt(req.params.id);
const { item_description, price } = req.body;
const updatedItem = await prisma.item.update({
where: { id: itemId },
data: { item_description, price },
});
res.status(200).json(updatedItem);
});

// DELETE: deletes Item with :id
app.delete("/items/:id", async (req, res) => {
const itemId = parseInt(req.params.id);
await prisma.item.delete({
where: { id: itemId },
});
res.status(204).send();
});

// this endpoint is used by the client to verify the user status and to make sure the user is registered in our database once they signup with Auth0
// if not registered in our database we will create it.
// if the user is already registered we will return the user information
app.post("/verify-user", requireAuth, async (req, res) => {
const auth0Id = req.auth.payload.sub;
const email = req.auth.payload[`${process.env.AUTH0_AUDIENCE}/email`];
const name = req.auth.payload[`${process.env.AUTH0_AUDIENCE}/name`];

const user = await prisma.user.findFirst({
where: {
auth0Id: auth0Id,
},
});

if (user) {
res.json(user);
} else {
const newUser = await prisma.user.create({
data: {
email,
auth0Id,
name,
},
});

res.json(newUser);
}
});

// Starts HTTP Server
app.listen(8000, () => {
console.log("Server running on http://localhost:8000 🎉 🚀");
});
Loading