Skip to content
Draft
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
17 changes: 14 additions & 3 deletions backend/sql/create_tables.sql
Original file line number Diff line number Diff line change
Expand Up @@ -159,10 +159,21 @@ CREATE MATERIALIZED VIEW stock
AS
SELECT
item.name
,item.category
,sum(trans_items.quantity) as quantity
,item.category
,sum(
CASE
WHEN transaction.trans_type = 'donation' THEN trans_items.quantity
ELSE trans_items.quantity * -1
END
)
as quantity
FROM trans_items
JOIN item
ON trans_items.item_id = item.item_id
GROUP BY item.name, item.category
JOIN transaction
ON trans_items.trans_id = transaction.trans_id
GROUP BY item.name, item.category
WITH DATA;

--Adding extention for fuzzy searching
CREATE EXTENSION pg_trgm;
15 changes: 11 additions & 4 deletions backend/sql/dummy_data2.sql
Original file line number Diff line number Diff line change
Expand Up @@ -37,19 +37,26 @@ WHERE email = 'johndoe@example.com';
INSERT INTO Transaction (person_id, date, trans_type, site)
VALUES ((SELECT MAX(person_id) FROM Person), NOW(), 'donation', 1),
-- Add old transaction with goods that have been expiring.
((SELECT MIN(person_id) FROM Person), NOW() - INTERVAL '3 weeks', 'donation', 1);
((SELECT MIN(person_id) FROM Person), NOW() - INTERVAL '3 weeks', 'donation', 1),
-- Other Transaction types
((SELECT MIN(person_id) FROM Person), NOW(), 'purchase', 1),
((SELECT MAX(person_id) FROM Person), NOW(), 'throw out', 1);

-- Insert test data for Trans_items
INSERT INTO Trans_items (trans_id, item_id, quantity, expiration)
VALUES ((SELECT MIN(trans_id) FROM Transaction), 4, 5, NOW() + INTERVAL '1 week'),
((SELECT MIN(trans_id) FROM Transaction), 3, 10, NOW() + INTERVAL '2 weeks'),
-- Donate goods that expired 3 weeks ago, 1 week ago, and 1 week from now.
-- Old apples
((SELECT MAX(trans_id) FROM Transaction), 1, 7, NOW() - INTERVAL '3 weeks'),
((SELECT MAX(trans_id)-2 FROM Transaction), 1, 7, NOW() - INTERVAL '3 weeks'),
-- Old oranges
((SELECT MAX(trans_id) FROM Transaction), 2, 7, NOW() - INTERVAL '1 week'),
((SELECT MAX(trans_id)-2 FROM Transaction), 2, 7, NOW() - INTERVAL '1 week'),
-- Nearly old Milk
((SELECT MAX(trans_id) FROM Transaction), 3, 7, NOW() + INTERVAL '1 day');
((SELECT MAX(trans_id)-2 FROM Transaction), 3, 7, NOW() + INTERVAL '1 day'),
-- purchase trans item
((SELECT MAX(trans_id)-1 FROM Transaction), 3, 2, null),
-- throw out for trans item
((SELECT MAX(trans_id) FROM Transaction), 3, 1, null);

-- Insert test data for Shelf_contents
INSERT INTO Shelf_contents (trans_item_id, shelf_id, store_date, quantity)
Expand Down
1 change: 1 addition & 0 deletions backend/src/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ app.get('/wastemanagement', summaryRouter);
app.get('/soontoexpire', summaryRouter);

app.get('/stock', stockRouter);
app.get('/available', stockRouter);

app.get('/checkout_success', function(req, res, next) {
res.render('checkout_success', { title: 'Success' });
Expand Down
43 changes: 40 additions & 3 deletions backend/src/routes/stock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,50 @@ router.get('/stock', ensureAuthenticated, function (req: any, res: any) {
const errors = [];
res.post('Unauthenticated');
} else {
stock.findAll().then((cur_stock: typeof stock[]) => {
if(req.query.item !== undefined) {
const filter = ` word_similarity('${req.query.item}', name) > 0.5 ORDER BY name <->> '${req.query.item}'`;
stock.findAll({
where: Sequelize.literal(filter),
}).then((cur_stock: typeof stock[]) => {
if (cur_stock == null) {
res.send("No Items Found");
} else {
res.json(cur_stock);
}
});
} else {
stock.findAll().then((cur_stock: typeof stock[]) => {
if (cur_stock == null) {
console.log("THIS IS ERROR " + cur_stock);
} else {
res.json(JSON.stringify(cur_stock));
res.json(cur_stock);
}
});
});
}
}
});

router.get('/available', ensureAuthenticated, function (req: any, res: any) {
if (!req.isAuthenticated()) {
const errors = [];
res.post('Unauthenticated');
} else {
console.log(req.query);
if(req.query.item !== undefined) {
stock.findOne({
where: {
name: req.query.item
},
}).then((cur_stock: typeof stock[]) => {
if (cur_stock == null) {
res.send("No Items Found");
} else {
res.send(cur_stock);
}
});
} else {
res.send("bad request");
}
}
});

Expand Down
122 changes: 122 additions & 0 deletions frontend/src/Components/Stock/StockChart.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
import React, { useState } from "react";
import { Table, TableBody, TableHead, TableRow, TableContainer, Paper, TableCell, Grid, ToggleButton, ToggleButtonGroup, } from "@mui/material";
import { Box } from "@mui/system";
// import StockBarChart from "./StockChart"

type StockProps = {
sortedStockList: {
name: string;
category: string;
quantity: number;
}[];
};


const Stock = ({ sortedStockList }: StockProps) => {
const [alignment, setAlignment] = useState("table"); //Used for the purpose of MUI toggle button

// eslint-disable-next-line @typescript-eslint/no-unused-vars
const [activeComponent, setActiveComponent] = useState<string>("tables");
const [tableVisibility, setTableVisibility] = useState<boolean>(true); //based on boolean data visibility changes, Tables have default visibility
// const [chartVisibility, setChartVisibility] = useState<boolean>(false); //based on boolean data visibility changes,Chart is initially not visible

const handleAlignmentChange = (
event: React.MouseEvent<HTMLElement>,
newAlignment: string
) => {
setAlignment(newAlignment);
};

/**
* Sets tables as active component and makes the tables visible
*/
function handleTablesClick() {
setActiveComponent("tables");
setTableVisibility(true);
// setChartVisibility(false);
}
/**
* Sets tables as active component and makes the chart visible
*/
function handleChartClick() {
setActiveComponent("chart");
setTableVisibility(false);
// setChartVisibility(true);
}
return (
<div>
<ToggleButtonGroup
color="primary"
fullWidth
value={alignment}
exclusive
onChange={handleAlignmentChange}
aria-label="Platform"
sx={{ marginBottom: 2 }}>
<ToggleButton value="table" onClick={handleTablesClick}>
Table
</ToggleButton>
<ToggleButton value="chart" onClick={handleChartClick}>
Chart
</ToggleButton>
</ToggleButtonGroup>
{tableVisibility && ( // if tableVisibility state is set true, the following tables will be visible.
<Grid item xs={10} md={6} mt={4}>
<strong>Stock</strong>
<br />
{/* Total Checkout: {purchaseTotal} | Total Quantity Checked Out:{" "}
{purchaseQuantityTotal} */}
{/*Purchase Table*/}
<Box
style={{ maxHeight: "40vh", overflow: "auto" }}
sx={{
boxShadow: "0px -1px 10px #eeeeee",
border: "solid 0.1px #e6e6e6",
borderRadius: "5px",
marginTop: "1rem",
}}>
<TableContainer component={Paper} style={{}}>
<Table>
<TableHead
sx={{
"& th": { color: "white", backgroundColor: "#8C2332" },
}}>
<TableRow>
<TableCell>#</TableCell>
<TableCell>
<strong>Name</strong>
</TableCell>
<TableCell>
<strong>category</strong>
</TableCell>
<TableCell>
<strong>Quantity</strong>
</TableCell>
</TableRow>
</TableHead>
<TableBody>
{sortedStockList.map((row, index) => (
<TableRow
key={index}
style={
index % 2
? { background: "#fcfcfc" }
: { background: "white" }
}>
<TableCell>{index + 1}</TableCell>
<TableCell>{row.name}</TableCell>
<TableCell>{row.category}</TableCell>
<TableCell>{row.quantity}</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</TableContainer>
</Box>
</Grid>
)}
</div>
);
}

export default Stock;
47 changes: 41 additions & 6 deletions frontend/src/pages/stock.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,49 @@
import React from "react";
// import { useAppSelector,useAppDispatch } from '../hooks'
// import { login } from '../redux-features/user';
import React, { useEffect, useState } from "react";
import StockChart from "../Components/Stock/StockChart";
import axiosInstance from "../util/axiosInstance";

type cur_stock = {
name: string;
category: string;
quantity: number;
};

const Stock = () => {
const [stockList, setStockList] = useState<cur_stock[]>([]);
const [sortedStockList, setSortedStockList] = useState<cur_stock[]>([]);
// const [sortedExpiredFeedList, setSortedExpiredFeedList] = useState<cur_stock[]>(
// []
// );
useEffect(() => {
axiosInstance.get<cur_stock[]>("stock").then((res: any) => {
setStockList(res);
});
}, []);

useEffect(() => {
if (stockList.length > 0) {
setSortedStockList(
stockList.sort()
);

// sort feeds by latest date to oldest future expiring date
// setSortedExpiredFeedList(
// feedList.sort((a, b) => {
// return (
// new Date(b.expiry_date).getTime() -
// new Date(a.expiry_date).getTime()
// );
// })
// );
}
}, [stockList]);

return (
<div>
stock
</div>);
<StockChart
sortedStockList={sortedStockList}
// sortedExpiredFeedList={sortedExpiredFeedList}
/>
);
};

export default Stock;