Merge branch 'feature/additional_styles' of https://git.keannu1.duckdns.org/keannu125/Borrowing-TrackerFrontend into feature/additional_styles

This commit is contained in:
Prince Kurt Laurence 2024-01-09 12:33:44 +08:00
commit 353e28e962
35 changed files with 1895 additions and 1016 deletions

View file

@ -4,7 +4,7 @@
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>CITC Equipment Tracker</title>
<title>CSM Equipment Tracker</title>
</head>
<body>
<div id="root"></div>

45
package-lock.json generated
View file

@ -23,12 +23,15 @@
"react-redux": "^8.1.3",
"react-router-dom": "^6.18.0",
"react-toastify": "^9.1.3",
"react-virtuoso": "^4.6.2",
"react-window": "^1.8.10",
"reactjs-popup": "^2.0.6",
"styled-components": "^6.1.1"
},
"devDependencies": {
"@types/react": "^18.2.15",
"@types/react-dom": "^18.2.7",
"@types/react-window": "^1.8.8",
"@typescript-eslint/eslint-plugin": "^6.0.0",
"@typescript-eslint/parser": "^6.0.0",
"@vitejs/plugin-react": "^4.0.3",
@ -1761,6 +1764,15 @@
"@types/react": "*"
}
},
"node_modules/@types/react-window": {
"version": "1.8.8",
"resolved": "https://registry.npmjs.org/@types/react-window/-/react-window-1.8.8.tgz",
"integrity": "sha512-8Ls660bHR1AUA2kuRvVG9D/4XpRC6wjAaPT9dil7Ckc76eP9TKWZwwmgfq8Q1LANX3QNDnoU4Zp48A3w+zK69Q==",
"dev": true,
"dependencies": {
"@types/react": "*"
}
},
"node_modules/@types/scheduler": {
"version": "0.16.5",
"resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.5.tgz",
@ -3372,6 +3384,11 @@
"resolved": "https://registry.npmjs.org/media-engine/-/media-engine-1.0.3.tgz",
"integrity": "sha512-aa5tG6sDoK+k70B9iEX1NeyfT8ObCKhNDs6lJVpwF6r8vhUfuKMslIcirq6HIUYuuUYLefcEQOn9bSBOvawtwg=="
},
"node_modules/memoize-one": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.2.1.tgz",
"integrity": "sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q=="
},
"node_modules/merge2": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
@ -3895,6 +3912,34 @@
"react-dom": ">=16.6.0"
}
},
"node_modules/react-virtuoso": {
"version": "4.6.2",
"resolved": "https://registry.npmjs.org/react-virtuoso/-/react-virtuoso-4.6.2.tgz",
"integrity": "sha512-vvlqvzPif+MvBrJ09+hJJrVY0xJK9yran+A+/1iwY78k0YCVKsyoNPqoLxOxzYPggspNBNXqUXEcvckN29OxyQ==",
"engines": {
"node": ">=10"
},
"peerDependencies": {
"react": ">=16 || >=17 || >= 18",
"react-dom": ">=16 || >=17 || >= 18"
}
},
"node_modules/react-window": {
"version": "1.8.10",
"resolved": "https://registry.npmjs.org/react-window/-/react-window-1.8.10.tgz",
"integrity": "sha512-Y0Cx+dnU6NLa5/EvoHukUD0BklJ8qITCtVEPY1C/nL8wwoZ0b5aEw8Ff1dOVHw7fCzMt55XfJDd8S8W8LCaUCg==",
"dependencies": {
"@babel/runtime": "^7.0.0",
"memoize-one": ">=3.1.1 <6"
},
"engines": {
"node": ">8.0.0"
},
"peerDependencies": {
"react": "^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0",
"react-dom": "^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0"
}
},
"node_modules/reactjs-popup": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/reactjs-popup/-/reactjs-popup-2.0.6.tgz",

View file

@ -25,12 +25,15 @@
"react-redux": "^8.1.3",
"react-router-dom": "^6.18.0",
"react-toastify": "^9.1.3",
"react-virtuoso": "^4.6.2",
"react-window": "^1.8.10",
"reactjs-popup": "^2.0.6",
"styled-components": "^6.1.1"
},
"devDependencies": {
"@types/react": "^18.2.15",
"@types/react-dom": "^18.2.7",
"@types/react-window": "^1.8.8",
"@typescript-eslint/eslint-plugin": "^6.0.0",
"@typescript-eslint/parser": "^6.0.0",
"@vitejs/plugin-react": "^4.0.3",

View file

@ -22,6 +22,7 @@ import AddTransactionPage from "./Pages/AddTransactionPage/AddTransactionPage";
import TransactionPage from "./Pages/TransactionPage/TransactionPage";
import EquipmentInstanceTallyPage from "./Pages/EquipmentTallyPage/EquipmentTallyPage";
import TransactionReportPage from "./Pages/TransactionReportPage/TransactionReportPage";
import ManageEquipmentPage from "./Pages/ManageEquipmentPage/ManageEquipmentPage";
const queryClient = new QueryClient();
const router = createHashRouter([
@ -67,6 +68,17 @@ const router = createHashRouter([
),
errorElement: <ErrorPage />,
},
{
path: "/view/ManageEquipment",
element: (
<>
<Revalidator />
<RestrictedPage allow_only="Technician" />
<ManageEquipmentPage />
</>
),
errorElement: <ErrorPage />,
},
{
path: "/view/equipment_instances/filter/:filter_by",
element: (

View file

@ -27,7 +27,7 @@ const debug = false;
let backendURL;
if (debug) {
backendURL = "http://localhost:8000/";
backendURL = "http://localhost:8092/";
} else {
backendURL = "https://csm-backend.keannu1.duckdns.org/";
}

View file

@ -1,7 +1,6 @@
import styles from "../../../styles";
import { Button } from "@mui/material";
import AddBoxIcon from "@mui/icons-material/AddBox";
import { colors } from "../../../styles";
import { useNavigate } from "react-router-dom";
export default function StudentDashboard() {
const navigate = useNavigate();
@ -17,7 +16,7 @@ export default function StudentDashboard() {
justifyContent: "center",
flexWrap: "wrap",
marginTop: "40px",
width: "100%"
},
@ -28,11 +27,10 @@ export default function StudentDashboard() {
...styles.flex_column,
...{
alignSelf: "center",
justifyContent: "center",
flexWrap: "wrap",
backgroundColor: "#CCDDFF",
paddingInline: "90px",
borderRadius: "20px"
borderRadius: "20px",
paddingInline: "100px",
width: "100%",
},
}}
onClick={() => {
@ -43,9 +41,8 @@ export default function StudentDashboard() {
<p
style={{
...styles.text_dark_blue,
...styles.text_M,
fontSize: "15px"
fontSize: "15px",
}}
>
CLICK TO REQUEST BORROW ITEMS

View file

@ -1,6 +1,6 @@
import { useQuery } from "@tanstack/react-query";
import { TransactionsByStudentAPI } from "../../API/API";
import styles from "../../../styles";
import styles, { colors } from "../../../styles";
import CircularProgress from "@mui/material/CircularProgress/CircularProgress";
import React, { useState } from "react";
import TransactionEntry from "../../TransactionEntry/TransactionEntry";
@ -39,10 +39,11 @@ export default function StudentTransactionListView() {
);
}
return (
<div >
<div style={{ width: "100%" }}>
<div style={{
marginTop: "60px",
marginTop: "60px",
width: "85%",
marginInline: "6.5%"
}}>
<TransactionFilterMenu filter={filter} setFilter={setFilter} />
<div style={{ marginTop: "16px" }} />
@ -69,12 +70,43 @@ export default function StudentTransactionListView() {
}}
transaction={transaction}
/>
<button
style={{
borderTop: "2px solid rgba(160, 160, 160, 0.20)",
padding: "7px",
margin: "0px",
backgroundColor: colors.header_color,
width: 550,
alignSelf: "center",
borderRadius: "0px 0px 7px 7px",
}}
onClick={() => {
navigate(`/view/transaction/${transaction.id}`, {
replace: true,
state: { id: transaction.id },
});
}}
>
<p
style={{
...styles.text_gray,
...styles.text_S,
padding: "0px",
margin: "0px",
}}
>
TAP TO VIEW
</p>
</button>
</React.Fragment>
))
) : (
<></>
)}
</div>
</div>
</div>
);

View file

@ -1,14 +1,16 @@
import { useQuery } from "@tanstack/react-query";
import { TransactionsByTeacherAPI } from "../../API/API";
import styles from "../../../styles";
import styles, { colors } from "../../../styles";
import CircularProgress from "@mui/material/CircularProgress/CircularProgress";
import React, { useState } from "react";
import TransactionEntry from "../../TransactionEntry/TransactionEntry";
import TransactionFilterMenu from "../../TransactionFilterMenu/TransactionFilterMenu";
import Popup from "reactjs-popup";
import EditTransactionModal from "../../EditTransactionModal/EditTransactionModal";
import { useNavigate } from "react-router-dom";
export default function TeacherTransactionListView() {
const navigate = useNavigate();
const [EditTransactionOpen, SetEditTransactionOpen] = useState(false);
const [SelectedTransaction, SetSelectedTransaction] = useState(0);
const transactions = useQuery({
@ -48,7 +50,7 @@ export default function TeacherTransactionListView() {
<div
style={{
...styles.flex_column,
...{ height: "50vh", overflowY: "scroll" },
...{ height: "50vh", overflowY: "scroll", width: "100%", gap: "-15px", },
}}
>
{transactions.data ? (
@ -69,6 +71,35 @@ export default function TeacherTransactionListView() {
}}
transaction={transaction}
/>
<button
style={{
borderTop: "2px solid rgba(160, 160, 160, 0.20)",
padding: "7px",
margin: "0px",
backgroundColor: colors.header_color,
width: 550,
alignSelf: "center",
borderRadius: "0px 0px 7px 7px",
}}
onClick={() => {
navigate(`/view/transaction/${transaction.id}`, {
replace: true,
state: { id: transaction.id },
});
}}
>
<p
style={{
...styles.text_gray,
...styles.text_S,
padding: "0px",
margin: "0px",
}}
>
TAP TO VIEW
</p>
</button>
</React.Fragment>
))
) : (
@ -76,6 +107,7 @@ export default function TeacherTransactionListView() {
)}
</div>
</div>
<Popup
open={EditTransactionOpen}
onClose={() => SetEditTransactionOpen(false)}

View file

@ -68,7 +68,7 @@ export default function TechnicianEquipmentButtons() {
View All
</p>
</Button>
{/* <Button
<Button
style={{
...styles.flex_column,
...{
@ -98,8 +98,8 @@ export default function TechnicianEquipmentButtons() {
>
Add Item
</p>
</Button> */}
{/* <Button
</Button>
<Button
style={{
...styles.flex_column,
...{
@ -129,7 +129,7 @@ export default function TechnicianEquipmentButtons() {
>
Add SKU
</p>
</Button> */}
</Button>
<Button
style={{
...styles.flex_column,
@ -204,7 +204,7 @@ export default function TechnicianEquipmentButtons() {
Transactions
</p>
</Button>
{/* <Button
<Button
style={{
...styles.flex_column,
...{
@ -265,9 +265,9 @@ export default function TechnicianEquipmentButtons() {
>
Miscellaneous
</p>
</Button> */}
</Button>
</div>
{/* <Popup
<Popup
open={addSKUmodalOpen}
onClose={() => SetAddSKUModalOpen(false)}
modal
@ -285,8 +285,8 @@ export default function TechnicianEquipmentButtons() {
}}
>
<AddSKUModal />
</Popup> */}
{/* <Popup
</Popup>
<Popup
open={additemmodalOpen}
onClose={() => SetAddItemModalOpen(false)}
modal
@ -304,7 +304,7 @@ export default function TechnicianEquipmentButtons() {
}}
>
<AddItemModal />
</Popup> */}
</Popup>
</>
);
}

View file

@ -0,0 +1,125 @@
import styles from "../../../styles";
import { useNavigate } from "react-router-dom";
import AssessmentIcon from "@mui/icons-material/Assessment";
import equipment from "../../../assets/Equipment.svg";
import transaction from "../../../assets/Transaction.svg";
export default function TechnicianNavigation() {
const navigate = useNavigate();
return (
<>
<div
style={{
display: "flex",
flexDirection: "column",
alignItems: "center",
gap: "24px",
alignSelf: "stretch",
paddingBottom: "5rem"
}}
>
<div
style={{
display: "flex",
flexDirection: "column",
alignItems: "center",
gap: "24px",
width: "100%",
maxWidth: "800px",
}}
>
<p
style={{
overflow: "hidden",
color: "#0E410D",
fontSize: "24px",
fontWeight: 700,
display: "-webkit-box",
width: "100%",
maxWidth: "807px",
flex: 1,
textAlign: "left",
marginLeft: "1rem",
}}
>
Feature
</p>
<button
style={{
display: "flex",
width: "100%",
height: "85px",
padding: "15px 30px",
alignItems: "center",
gap: "15px",
borderRadius: "12px",
border: "1px solid #6877FF",
background: "#DDEDFF",
}}
onClick={() => {
navigate("/view/transactions");
}}
>
<img src={transaction} alt="Manage Transaction" />
<p style={{ ...styles.text_normal, fontSize: 20, margin: "10" }}>
Manage Transactions
</p>
</button>
<button
style={{
display: "flex",
width: "100%",
height: "85px",
padding: "15px 30px",
alignItems: "center",
gap: "15px",
borderRadius: "12px",
border: "1px solid #E3BD91",
background: "#E8D3BB",
}}
onClick={() => {
navigate("/view/ManageEquipment");
}}
>
<img src={equipment} alt="Manage Equipment" />
<p style={{ ...styles.text_normal, fontSize: 20, margin: "10" }}>
Manage Equipments
</p>
</button>
<button
style={{
display: "flex",
width: "100%",
height: "85px",
padding: "15px 30px",
alignItems: "center",
gap: "15px",
borderRadius: "12px",
border: "1px solid #FFCBA5",
background: "#FFEDAF",
}}
onClick={() => {
navigate("/view/transactions/report");
}}
>
<AssessmentIcon
style={{
height: 48,
width: 48,
fill: "brown",
}}
/>
<p style={{ ...styles.text_normal, fontSize: 20, margin: "10" }}>
Generate Report
</p>
</button>
</div>
</div>
</>
);
}

View file

@ -6,7 +6,6 @@ import {
UserAPI,
TransactionsAPI,
} from "../../API/API";
import CircularProgress from "@mui/material/CircularProgress";
import moment from "moment";
export default function TechnicianWidgets() {
@ -34,22 +33,6 @@ export default function TechnicianWidgets() {
},
],
});
const isLoading = queries.some((result) => result.isLoading);
if (isLoading) {
return (
<>
<CircularProgress style={{ height: "128px", width: "128px" }} />
<p
style={{
...styles.text_dark,
...styles.text_L,
}}
>
Loading
</p>
</>
);
}
return (
<div style={styles.flex_column}>
<div
@ -64,226 +47,404 @@ export default function TechnicianWidgets() {
>
<div
style={{
paddingLeft: "16px",
paddingRight: "16px",
margin: "16px",
borderRadius: 16,
backgroundColor: "#a6a6a6",
alignSelf: "center",
justifyContent: "center",
width: "16rem",
display: "flex",
flexDirection: "column",
alignItems: "center",
gap: "24px",
width: "100%",
maxWidth: "800px",
}}
>
<p
style={{
...styles.text_dark,
...styles.text_M,
...{ float: "left", position: "absolute" },
overflow: "hidden",
color: "#0E410D",
fontSize: "24px",
fontWeight: 700,
display: "-webkit-box",
width: "100%",
maxWidth: "807px",
flex: 1,
textAlign: "left",
marginLeft: "1rem",
marginBottom: -15,
}}
>
Pending Equipments
</p>
<p
style={{
...styles.text_dark,
...styles.text_L,
}}
>
{queries[1].data?.filter(
(equipment) => equipment.status == "Pending"
).length || 0}
Summary
</p>
</div>
{/* Blue Capsule */}
<div
className="capsule"
style={{
paddingLeft: "16px",
paddingRight: "16px",
margin: "16px",
borderRadius: 16,
backgroundColor: "#a6a6a6",
alignSelf: "center",
justifyContent: "center",
width: "16rem",
background: "#DDEDF3",
margin: 30,
paddingTop: 50,
}}
>
<p
<div
style={{
...styles.text_dark,
...styles.text_M,
...{ float: "left", position: "absolute" },
display: "flex",
justifyContent: "center",
alignItems: "center",
gap: "15px",
}}
>
Equipments in Inventory
</p>
{/* Transactions all */}
<div
style={{
display: "flex",
width: "202px",
height: "245px",
padding: "25px 10px",
flexDirection: "column",
justifyContent: "space-between",
alignItems: "center",
borderRadius: "15px",
background: "#FFF",
boxShadow: "0px 4px 4px 0px rgba(0, 0, 0, 0.25)",
}}
>
<p
style={{
...styles.text_dark,
...styles.text_normal,
fontWeight: "400",
}}
>
Total Transactions Today
</p>
<p
style={{
...styles.text_dark,
...styles.text_L,
margin: 0,
}}
>
{queries[3].data?.filter((transaction) =>
moment(transaction.timestamp, "MM-DD-YYYY hh:mm A").isBetween(
todayStartOfDay,
todayEndOfDay
)
).length || "0"}
</p>
<p
style={{
...styles.text_dark,
...styles.text_normal,
fontWeight: "400",
}}
>
Total Transactions this Month
</p>
<p
style={{
...styles.text_dark,
...styles.text_L,
margin: 0,
}}
>
{queries[3].data?.filter((transaction) =>
moment(transaction.timestamp, "MM-DD-YYYY hh:mm A").isBetween(
thisMonthStart,
thisMonthEnd
)
).length || "Loading..."}
</p>
</div>
<div
style={{
display: "flex",
width: "40%",
flexDirection: "column",
justifyContent: "center",
alignItems: "center",
gap: "15px",
alignSelf: "stretch",
}}
>
<div
style={{
display: "flex",
height: "88px",
width: "100%",
flexDirection: "column",
justifyContent: "center",
alignItems: "center",
alignSelf: "stretch",
borderRadius: "15px",
background: "#FFF",
boxShadow: "0px 4px 4px 0px rgba(0, 0, 0, 0.25)",
}}
>
<p
style={{
...styles.text_dark,
...styles.text_L,
margin: "0",
}}
>
{queries[3].data?.filter(
(transaction) =>
transaction.transaction_status == "Approved"
).length || 0}
</p>
<p
style={{
...styles.text_dark,
...styles.text_S,
margin: "0",
fontWeight: "400",
}}
>
Pending Request
</p>
</div>
<div
style={{
display: "flex",
height: "88px",
width: "100%",
flexDirection: "column",
justifyContent: "center",
alignItems: "center",
alignSelf: "stretch",
borderRadius: "15px",
background: "#FFF",
boxShadow: "0px 4px 4px 0px rgba(0, 0, 0, 0.25)",
}}
>
<p
style={{
...styles.text_dark,
...styles.text_L,
margin: "0",
}}
>
{queries[3].data?.filter(
(transaction) =>
transaction.transaction_status == "Borrowed"
).length || 0}
</p>
<p
style={{
...styles.text_dark,
...styles.text_S,
margin: "0",
fontWeight: "400",
}}
>
On Borrow
</p>
</div>
<div
style={{
display: "flex",
height: "88px",
width: "100%",
flexDirection: "column",
justifyContent: "center",
alignItems: "center",
alignSelf: "stretch",
borderRadius: "15px",
background: "#FFF",
boxShadow: "0px 4px 4px 0px rgba(0, 0, 0, 0.25)",
}}
>
<p
style={{
...styles.text_dark,
...styles.text_L,
margin: "0",
}}
>
{queries[3].data?.filter(
(transaction) =>
transaction.transaction_status == "Finalized"
).length || 0}
</p>
<p
style={{
...styles.text_dark,
...styles.text_S,
margin: "0",
fontWeight: "400",
}}
>
Success
</p>
</div>
</div>
</div>
<p
style={{
...styles.text_dark,
...styles.text_L,
margin: "0",
fontWeight: 700,
...styles.text_normal,
}}
>
{queries[1].data?.length || 0}
Borrowing Transaction
</p>
</div>
</div>
<div
style={{
...styles.flex_row,
...{
alignSelf: "center",
justifyContent: "center",
flexWrap: "wrap",
},
}}
>
{/* Yellow Capsule */}
<div
className="capsule"
style={{
paddingLeft: "16px",
paddingRight: "16px",
margin: "16px",
borderRadius: 16,
backgroundColor: "#a6a6a6",
alignSelf: "center",
justifyContent: "center",
width: "16rem",
background: "#FCF2E7",
paddingTop: 50,
margin: 30,
}}
>
<p
<div
style={{
...styles.text_dark,
...styles.text_M,
...{ float: "left", position: "absolute" },
display: "flex",
justifyContent: "center",
alignItems: "center",
gap: "15px",
}}
>
Available Equipments
</p>
{/* Pending Req */}
<div
style={{
display: "flex",
width: "202px",
height: "193px",
padding: "25px 10px",
flexDirection: "column",
justifyContent: "space-between",
alignItems: "center",
borderRadius: "15px",
background: "#FFF",
boxShadow: "0px 4px 4px 0px rgba(0, 0, 0, 0.25)",
}}
>
<p
style={{
...styles.text_dark,
...styles.text_L,
}}
>
{queries[1].data?.length || "Loading..."}
</p>
<p
style={{
...styles.text_dark,
...styles.text_L,
}}
>
{queries[1].data?.filter(
(equipment) => equipment.status == "Available"
).length || 0}
</p>
</div>
<div
style={{
paddingLeft: "16px",
paddingRight: "16px",
margin: "16px",
borderRadius: 16,
backgroundColor: "#a6a6a6",
alignSelf: "center",
justifyContent: "center",
width: "16rem",
}}
>
<p
style={{
...styles.text_dark,
...styles.text_M,
...{ float: "left", position: "absolute" },
}}
>
Broken Equipments
</p>
<p
style={{
...styles.text_dark,
...styles.text_M,
fontWeight: "400",
}}
>
Total Equipment
</p>
</div>
<div
style={{
display: "flex",
width: "40%",
flexDirection: "column",
justifyContent: "center",
alignItems: "center",
gap: "15px",
alignSelf: "stretch",
}}
>
<div
style={{
display: "flex",
height: "100%",
width: "100%",
flexDirection: "column",
justifyContent: "center",
alignItems: "center",
alignSelf: "stretch",
borderRadius: "15px",
background: "#FFF",
boxShadow: "0px 4px 4px 0px rgba(0, 0, 0, 0.25)",
}}
>
<p
style={{
...styles.text_dark,
...styles.text_S,
margin: "0",
fontWeight: "400",
}}
>
Available
</p>
<p
style={{
...styles.text_dark,
...styles.text_L,
margin: 0,
}}
>
{queries[1].data?.filter(
(equipment) => equipment.status == "Available"
).length || "Loading..."}
</p>
<p
style={{
...styles.text_dark,
...styles.text_L,
}}
>
{queries[1].data?.filter(
(equipment) => equipment.status == "Broken"
).length || 0}
</p>
</div>
</div>
<div
style={{
...styles.flex_row,
...{
alignSelf: "center",
justifyContent: "center",
flexWrap: "wrap",
},
}}
>
<div
style={{
paddingLeft: "16px",
paddingRight: "16px",
margin: "16px",
borderRadius: 16,
backgroundColor: "#a6a6a6",
alignSelf: "center",
justifyContent: "center",
width: "16rem",
}}
>
<p
style={{
...styles.text_dark,
...styles.text_M,
...{ float: "left", position: "absolute" },
}}
>
Total Transactions Today
</p>
<p
style={{
...styles.text_dark,
...styles.text_S,
margin: "0",
fontWeight: "400",
}}
>
Pending
</p>
<p
style={{
...styles.text_dark,
...styles.text_L,
margin: 0,
}}
>
{queries[1].data?.filter(
(equipment) => equipment.status == "Pending"
).length || 0}
</p>
<p
style={{
...styles.text_dark,
...styles.text_L,
}}
>
{queries[3].data?.filter((transaction) =>
moment(transaction.timestamp, "MM-DD-YYYY hh:mm A").isBetween(
todayStartOfDay,
todayEndOfDay
)
).length || 0}
</p>
</div>
<div
style={{
paddingLeft: "16px",
paddingRight: "16px",
margin: "16px",
borderRadius: 16,
backgroundColor: "#a6a6a6",
alignSelf: "center",
justifyContent: "center",
width: "16rem",
}}
>
<p
style={{
...styles.text_dark,
...styles.text_M,
...{ float: "left", position: "absolute" },
}}
>
Total Transactions this Month
</p>
<p
style={{
...styles.text_dark,
...styles.text_S,
margin: "0",
fontWeight: "400",
color: "#a44141",
}}
>
Broken
</p>
<p
style={{
...styles.text_dark,
...styles.text_L,
margin: "0",
color: "#a44141",
}}
>
{queries[1].data?.filter(
(equipment) => equipment.status == "Broken"
).length || 0}
</p>
</div>
</div>
</div>
<p
style={{
...styles.text_dark,
...styles.text_L,
margin: "0",
fontWeight: 700,
...styles.text_normal,
}}
>
{queries[3].data?.filter((transaction) =>
moment(transaction.timestamp, "MM-DD-YYYY hh:mm A").isBetween(
thisMonthStart,
thisMonthEnd
)
).length || 0}
Equipment Tracking
</p>
</div>
</div>

View file

@ -1,5 +1,5 @@
import { useState } from "react";
import styles, { colors } from "../../styles";
import styles from "../../styles";
import MenuIcon from "@mui/icons-material/Menu";
import SidebarModal from "../Drawer/Drawer";
import { Drawer } from "@mui/material";
@ -10,26 +10,32 @@ export interface props {
export default function Header(props: props) {
const [SidebarOpen, SetSidebarOpen] = useState(false);
return (
<div>
<div
style={{
position: "sticky",
position: "fixed",
top: 0,
zIndex: 1000,
backgroundColor: colors.header_color,
width: "100%",
display: "flex",
flexDirection: "row",
padding: "10px 25px",
justifyContent: "space-between",
alignItems: "center",
alignSelf: "stretch",
background: "#B2DFAB",
zIndex: 1000, // Ensure it's above other elements
}}
>
<div
style={{
flex: 1,
alignSelf: "center",
display: "flex",
flex: "1 0 0",
}}
>
<MenuIcon
style={{
height: "64px",
width: "64px",
height: "48px",
width: "48px",
float: "left",
marginLeft: "8px",
}}
@ -38,9 +44,33 @@ export default function Header(props: props) {
}}
/>
</div>
<p style={{ ...styles.text_light, ...styles.text_L, ...{ flex: 1 } }}>
{props.label}
</p>
<div
style={{
display: "flex",
justifyContent: "space-between",
alignItems: "center",
flex: "1 0 0",
alignSelf: "stretch",
}}
>
<p style={{ ...styles.text_light, fontSize: 24, textAlign: "center", flex: 1, margin: "0px" }}>{props.label}</p>
</div>
<div
style={{
display: "flex",
justifyContent: "space-between",
alignItems: "center",
flex: "1 0 0",
alignSelf: "stretch",
}}
>
</div>
</div>
<div style={{ flex: 1 }} />
<Drawer open={SidebarOpen} onClose={() => SetSidebarOpen(false)}>
<SidebarModal />

View file

@ -6,14 +6,14 @@ import InputAdornment from "@mui/material/InputAdornment";
import IconButton from "@mui/material/IconButton";
import Visibility from "@mui/icons-material/Visibility";
import VisibilityOff from "@mui/icons-material/VisibilityOff";
import LoginIcon from "@mui/icons-material/Login";
import Checkbox from "@mui/material/Checkbox";
import Button from "../Button/Button";
import { useNavigate } from "react-router-dom";
import { LoginAPI } from "../API/API";
import { useDispatch } from "react-redux";
import { auth_toggle } from "../Plugins/Redux/Slices/AuthSlice/AuthSlice";
import { toast } from "react-toastify";
import Logo_dako from "../../assets/Logo_dako.png"
export default function LoginModal() {
const navigate = useNavigate();
const [showPassword, setShowPassword] = useState(false);
@ -28,25 +28,41 @@ export default function LoginModal() {
<>
<div
style={{
...styles.flex_row,
...styles.flex_column,
...{
alignItems: "center",
justifyContent: "center",
overflowY: "scroll",
},
}}
>
<LoginIcon
style={{
height: 64,
width: 64,
fill: colors.font_dark,
}}
<img
style={{ width: "10rem", height: "auto", alignSelf: "center" }}
src={Logo_dako}
/>
<p style={{ ...styles.text_dark, ...styles.text_L }}>Welcome back!</p>
<p
style={{
...styles.text_normal,
fontSize: 16,
margin: "0",
marginTop: 15,
}}
>
Welcome back!
</p>
<p style={{ ...styles.text_normal, fontSize: 20, margin: "10" }}>
Sign In to Continue
</p>
</div>
<div style={styles.flex_column}>
<div style={{flex: 1, backgroundColor: "pink", margin: "20px"}}>
<p style={{ ...styles.text_dark_red, ...styles.text_S, flex: 1, textAlign: "left", marginLeft: 15}}>{error}</p>
</div>
<div style={{...styles.flex_column, marginTop: 30,
marginBottom: 20,
marginInline: 10,
}}>
<TextField
id="outlined-helperText"
label="Username"
@ -113,33 +129,45 @@ export default function LoginModal() {
backgroundColor: colors.button_border,
width: "100%",
height: "2px",
marginBottom: 8,
}}
/>
<p style={{ ...styles.text_dark, ...styles.text_S }}>{error}</p>
<Button
type={"dark"}
label={"Login"}
onClick={async () => {
const status = await LoginAPI(user, remember_session);
if (status === true) {
await dispatch(auth_toggle());
navigate("/dashboard");
toast("Logged in", {
position: "top-right",
autoClose: 2000,
hideProgressBar: false,
closeOnClick: true,
pauseOnHover: true,
draggable: true,
progress: undefined,
theme: "light",
});
} else {
setError("Invalid login");
}
marginBottom: "40px"
}}
/>
<div style={{ margin: "10px", }}>
<button
onClick={async () => {
const status = await LoginAPI(user, remember_session);
if (status === true) {
await dispatch(auth_toggle());
navigate("/dashboard");
toast("Logged in", {
position: "top-right",
autoClose: 2000,
hideProgressBar: false,
closeOnClick: true,
pauseOnHover: true,
draggable: true,
progress: undefined,
theme: "light",
});
} else {
setError("Invalid login");
}
}}
style={{
display: "flex",
padding: "25px 38px",
justifyContent: "center",
alignItems: "center",
background: "#FBB217",
height: "40px",
width: "100%",
}}
>
Login
</button>
</div>
</>
);
}

View file

@ -1,13 +1,11 @@
import { useState } from "react";
import styles from "../../styles";
import { colors } from "../../styles";
import styles, { colors } from "../../styles";
import TextField from "@mui/material/TextField";
import InputAdornment from "@mui/material/InputAdornment";
import IconButton from "@mui/material/IconButton";
import Visibility from "@mui/icons-material/Visibility";
import VisibilityOff from "@mui/icons-material/VisibilityOff";
import { AppRegistration } from "@mui/icons-material";
import Button from "../Button/Button";
import Logo_dako from "../../assets/Logo_dako.png";
import { useNavigate } from "react-router-dom";
import { RegisterAPI } from "../API/API";
import { toast } from "react-toastify";
@ -34,216 +32,263 @@ export default function RegisterModal() {
const [error, setError] = useState("");
return (
<>
<div
style={{
...styles.flex_row,
...{
alignItems: "center",
justifyContent: "center",
overflowY: "scroll",
},
}}
>
<AppRegistration
<div className="custom-scrollbar">
<div
style={{
height: 64,
width: 64,
fill: colors.font_dark,
...styles.flex_column,
...{
alignItems: "center",
justifyContent: "center",
overflow: "auto",
scrollbarWidth: "thin",
WebkitOverflowScrolling: "touch",
},
}}
/>
<p style={{ ...styles.text_dark, ...styles.text_L }}>Get Started</p>
</div>
>
<img
style={{ width: "10rem", height: "auto", alignSelf: "center" }}
src={Logo_dako}
/>
<div style={styles.flex_column}>
<TextField
id="outlined-helperText"
label="First Name"
style={styles.input_form}
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
setUser({ ...user, first_name: e.target.value });
setError("");
}}
value={user.first_name}
placeholder={"Enter your first name"}
/>
<TextField
id="outlined-helperText"
label="Last Name"
style={styles.input_form}
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
setUser({ ...user, last_name: e.target.value })
}
value={user.last_name}
placeholder={"Enter your last name"}
/>
<TextField
id="outlined-helperText"
label="Email"
style={styles.input_form}
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
setUser({ ...user, email: e.target.value })
}
value={user.email}
placeholder={"Enter your email"}
/>
<FormControl style={{ marginTop: "8px" }}>
<FormLabel style={styles.text_dark} id="status-selection">
Course
</FormLabel>
<RadioGroup
aria-labelledby="demo-radio-buttons-group-label"
value={user.course}
defaultValue="BS Chemistry"
name="radio-buttons-group"
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
setUser({ ...user, course: e.target.value });
setError("");
<p
style={{
...styles.text_normal,
fontSize: 24,
margin: "0",
marginTop: 15,
}}
>
<div
style={{
...styles.flex_column,
...{ overflowY: "scroll", maxHeight: "72px" },
Create an Account
</p>
<p style={{ ...styles.text_normal, fontSize: 16, margin: "10" }}>
Enter required fields
</p>
</div>
<div style={{ flex: 1, backgroundColor: "pink", margin: "10px" }}>
<p
style={{
...styles.text_dark_red,
...styles.text_S,
flex: 1,
textAlign: "left",
marginLeft: 15,
}}
>
{error}
</p>
</div>
<div
style={{
...styles.flex_column,
marginTop: 30,
marginBottom: 55,
marginInline: 10,
}}
>
<TextField
id="outlined-helperText"
label="First Name"
style={styles.input_form}
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
setUser({ ...user, first_name: e.target.value });
setError("");
}}
value={user.first_name}
placeholder={"Enter your first name"}
/>
<TextField
id="outlined-helperText"
label="Last Name"
style={styles.input_form}
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
setUser({ ...user, last_name: e.target.value })
}
value={user.last_name}
placeholder={"Enter your last name"}
/>
<TextField
id="outlined-helperText"
label="Email"
style={styles.input_form}
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
setUser({ ...user, email: e.target.value })
}
value={user.email}
placeholder={"Enter your email"}
/>
<FormControl style={{ marginTop: "8px" }}>
<FormLabel style={styles.text_dark} id="status-selection">
Course
</FormLabel>
<RadioGroup
aria-labelledby="demo-radio-buttons-group-label"
value={user.course}
defaultValue="BS Chemistry"
name="radio-buttons-group"
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
setUser({ ...user, course: e.target.value });
setError("");
}}
>
<FormControlLabel
value="BS Chemistry"
control={<Radio />}
label="BS Chemistry"
style={styles.text_dark}
/>
<FormControlLabel
value="BS Food Technology"
control={<Radio />}
label="BS Food Technology"
style={styles.text_dark}
/>
<FormControlLabel
value="BS Applied Physics"
control={<Radio />}
label="BS Applied Physics"
style={styles.text_dark}
/>
<FormControlLabel
value="BS Environmental Science"
control={<Radio />}
label="BS Environmental Science"
style={styles.text_dark}
/>
</div>
</RadioGroup>
</FormControl>
<TextField
id="outlined-helperText"
label="Username"
style={styles.input_form}
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
setUser({ ...user, username: e.target.value });
setError("");
}}
value={user.username}
placeholder={"Enter username"}
/>
<TextField
id="outlined-helperText"
type={showPassword ? "text" : "password"}
style={styles.input_form}
InputProps={{
endAdornment: (
<InputAdornment position="end">
<IconButton
aria-label="toggle password visibility"
onClick={() => setShowPassword(!showPassword)}
edge="end"
>
{showPassword ? <VisibilityOff /> : <Visibility />}
</IconButton>
</InputAdornment>
),
}}
label="Password"
placeholder={"Enter password"}
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
setUser({ ...user, password: e.target.value })
}
value={user.password}
/>
<TextField
id="outlined-helperText"
type={showPassword ? "text" : "password"}
style={styles.input_form}
InputProps={{
endAdornment: (
<InputAdornment position="end">
<IconButton
aria-label="toggle password visibility"
onClick={() => setShowPassword(!showPassword)}
edge="end"
>
{showPassword ? <VisibilityOff /> : <Visibility />}
</IconButton>
</InputAdornment>
),
}}
label="Confirm Password"
placeholder={"Re-enter password"}
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
setUser({ ...user, confirm_password: e.target.value });
setError("");
}}
value={user.confirm_password}
/>
</div>
<p style={{ ...styles.text_dark, ...styles.text_M }}>{error}</p>
<div
style={{
backgroundColor: colors.button_border,
marginTop: "16px",
width: "100%",
height: "2px",
marginBottom: 8,
}}
/>
<Button
type={"dark"}
label={"Register"}
onClick={async () => {
if (user.password !== user.confirm_password) {
setError("Passwords do not match");
} else {
const status = await RegisterAPI(user);
if (status[0]) {
setError(
"Registration successful. Please activate your account using the email provided"
);
toast("Registration successful", {
position: "top-right",
autoClose: 2000,
hideProgressBar: false,
closeOnClick: true,
pauseOnHover: true,
draggable: true,
progress: undefined,
theme: "light",
});
setTimeout(() => {
navigate(0);
}, 3000);
setUser({
first_name: "",
last_name: "",
username: "",
email: "",
password: "",
confirm_password: "",
course: "",
});
} else {
setError(JSON.stringify(status[1]));
<div
style={{
...styles.flex_column,
...{ overflowY: "scroll", maxHeight: "72px" },
}}
>
<FormControlLabel
value="BS Chemistry"
control={<Radio />}
label="BS Chemistry"
style={styles.text_dark}
/>
<FormControlLabel
value="BS Food Technology"
control={<Radio />}
label="BS Food Technology"
style={styles.text_dark}
/>
<FormControlLabel
value="BS Applied Physics"
control={<Radio />}
label="BS Applied Physics"
style={styles.text_dark}
/>
<FormControlLabel
value="BS Environmental Science"
control={<Radio />}
label="BS Environmental Science"
style={styles.text_dark}
/>
</div>
</RadioGroup>
</FormControl>
<TextField
id="outlined-helperText"
label="Username"
style={styles.input_form}
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
setUser({ ...user, username: e.target.value });
setError("");
}}
value={user.username}
placeholder={"Enter username"}
/>
<TextField
id="outlined-helperText"
type={showPassword ? "text" : "password"}
style={styles.input_form}
InputProps={{
endAdornment: (
<InputAdornment position="end">
<IconButton
aria-label="toggle password visibility"
onClick={() => setShowPassword(!showPassword)}
edge="end"
>
{showPassword ? <VisibilityOff /> : <Visibility />}
</IconButton>
</InputAdornment>
),
}}
label="Password"
placeholder={"Enter password"}
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
setUser({ ...user, password: e.target.value })
}
}
}}
/>
value={user.password}
/>
<TextField
id="outlined-helperText"
type={showPassword ? "text" : "password"}
style={styles.input_form}
InputProps={{
endAdornment: (
<InputAdornment position="end">
<IconButton
aria-label="toggle password visibility"
onClick={() => setShowPassword(!showPassword)}
edge="end"
>
{showPassword ? <VisibilityOff /> : <Visibility />}
</IconButton>
</InputAdornment>
),
}}
label="Confirm Password"
placeholder={"Re-enter password"}
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
setUser({ ...user, confirm_password: e.target.value });
setError("");
}}
value={user.confirm_password}
/>
</div>
<div
style={{
backgroundColor: colors.button_border,
height: "2px",
margin: "20px",
marginBottom: "40px",
}}
/>
<div style={{ margin: "10px" }}>
<button
onClick={async () => {
if (user.password !== user.confirm_password) {
setError("Passwords do not match");
} else {
const status = await RegisterAPI(user);
if (status[0]) {
setError(
"Registration successful. Please activate your account using the email provided"
);
toast("Registration successful", {
position: "top-right",
autoClose: 2000,
hideProgressBar: false,
closeOnClick: true,
pauseOnHover: true,
draggable: true,
progress: undefined,
theme: "light",
});
setTimeout(() => {
navigate(0);
}, 3000);
setUser({
first_name: "",
last_name: "",
username: "",
email: "",
password: "",
confirm_password: "",
course: "",
});
} else {
setError(JSON.stringify(status[1]));
}
}
}}
style={{
display: "flex",
padding: "25px 38px",
justifyContent: "center",
alignItems: "center",
background: "#FBB217",
height: "40px",
width: "100%",
}}
>
Register
</button>
</div>
</div>
</>
);
}

View file

@ -1,6 +1,6 @@
import { colors } from "../../styles";
export default function StatusTextColor(status: string) {
export function StatusTextColor(status: string) {
if (
status === "Pending Approval" ||
status === "Returned: Pending Checking"
@ -11,8 +11,25 @@ export default function StatusTextColor(status: string) {
status === "Finalized" ||
status === "Borrowed"
) {
return colors.dark_green;
return colors.darkgreen;
} else {
return colors.red;
}
}
export function StatusBGColor(status: string) {
if (
status === "Pending Approval" ||
status === "Returned: Pending Checking"
) {
return colors.lightorange;
} else if (
status === "Approved" ||
status === "Finalized" ||
status === "Borrowed"
) {
return colors.lightgreen;
} else {
return colors.lightred;
}
}

View file

@ -1,13 +1,13 @@
import styles from "../../styles";
import { colors } from "../../styles";
import { TransactionType } from "../Types/Types";
import StatusTextColor from "../StatusTextColor/StatusTextColor";
import { StatusTextColor } from "../StatusTextColor/StatusTextColor";
import CircleSharpIcon from '@mui/icons-material/CircleSharp';
export interface props {
transaction: TransactionType;
onClick?: React.MouseEventHandler<HTMLButtonElement>;
}
export default function TransactionEntry(props: props) {
@ -18,11 +18,12 @@ export default function TransactionEntry(props: props) {
style={{
alignSelf: "center",
justifySelf: "center",
width: "584px",
backgroundColor: colors.header_color,
borderRadius: 16,
margin: "10px",
borderRadius: "7px 7px 0px 0px",
marginTop: "10px",
paddingTop: "15px",
width: "100%",
maxWidth: "550px"
}}
onClick={props.onClick}
@ -105,28 +106,7 @@ export default function TransactionEntry(props: props) {
{/* //GIWALA */}
<div
style={{
borderTop: "2px solid rgba(160, 160, 160, 0.20)",
padding: "7px",
margin: "0px",
}}>
<p
style={{
...styles.text_gray,
...styles.text_S,
padding: "0px",
margin: "0px"
}}
>
TAP TO VIEW
</p>
</div>

View file

@ -41,10 +41,11 @@ export default function TransactionFilterMenu(props: props) {
alignSelf: "center",
justifyContent: "center",
flexWrap: "wrap",
width: "100%"
},
}}
>
<FormControl sx={{ width: "384px" }}>
<FormControl sx={{ width: "550px", marginInline: "30px" }}>
<InputLabel style={{ backgroundColor: "white", padding: 0 }}>
Filter Transactions
</InputLabel>

View file

@ -1,161 +1,355 @@
import { Document, Page, Text, View } from "@react-pdf/renderer";
import { Document, Page, Text, View, Image } from "@react-pdf/renderer";
import { TransactionType } from "../Types/Types";
import { colors } from "../../styles";
import StatusTextColor from "../StatusTextColor/StatusTextColor";
import {
StatusTextColor,
StatusBGColor,
} from "../StatusTextColor/StatusTextColor";
import ustplogo from "../../assets/ustp-logo.png";
type props = {
transaction: TransactionType | null;
transaction: TransactionType;
};
export default function TransactionPDF(props: props) {
return (
<Document>
<Page size={"A4"}>
<Page size={{ width: 8.5 * 72, height: 10 * 90 }}>
{/* Whole Page */}
<View
style={{
alignSelf: "center",
justifyContent: "center",
width: "512px",
backgroundColor: colors.header_color,
borderRadius: 16,
margin: "8px",
padding: "8px",
display: "flex",
flexDirection: "column",
width: "90%",
height: "100%",
alignItems: "flex-end",
marginLeft: "auto", // Align to the right edge
marginRight: "auto",
padding: "20 0",
gap: 10,
}}
>
<View style={{ display: "flex", flexDirection: "row" }}>
<Text
{/* Header */}
<View
style={{
display: "flex",
flexDirection: "row",
alignItems: "center",
justifyContent: "center",
alignSelf: "stretch",
}}
>
<Image
src={ustplogo}
style={{
color: colors.font_dark,
fontSize: 16,
textAlign: "left",
flex: 1,
width: 60,
height: 60,
position: "absolute",
left: 10,
top: 0,
}}
>
Transaction ID: {props.transaction?.id}
</Text>
<Text
style={{
color: colors.font_dark,
fontSize: 16,
textAlign: "right",
flex: 1,
}}
>
{props.transaction?.timestamp}
</Text>
</View>
<View style={{ paddingVertical: 8 }}></View>
<View style={{ display: "flex", flexDirection: "row" }}>
<View style={{ flex: 1 }}>
/>
<View style={{ alignItems: "center" }}>
<Text
style={{
color: colors.font_dark,
fontSize: 16,
textAlign: "left",
margin: 0,
color: colors.form_dark,
fontSize: 11,
textAlign: "center",
margin: "2 5 2 5",
}}
>
Borrower: {props.transaction?.borrower.name}{" "}
{`(ID:${props.transaction?.borrower.id})`}
Department of Chemistry (Laboratory)
</Text>
<Text
style={{
color: colors.font_dark,
fontSize: 16,
textAlign: "left",
margin: 0,
color: colors.form_dark,
fontSize: 10,
textAlign: "center",
padding: "5 0 5 0",
}}
>
{`(${props.transaction?.borrower.course})`}
University of Science and Technology of Southern Philippines{" "}
{"\n"}
Lapasan Cagayan de Oro City {"\n"}
</Text>
<Text
style={{
color: colors.font_dark,
fontSize: 16,
textAlign: "left",
margin: 0,
color: colors.form_dark,
fontSize: 11,
padding: "5 0 5 0",
}}
>
Teacher: {props.transaction?.teacher.name}{" "}
{`(ID:${props.transaction?.teacher.id})`}
</Text>
<Text
style={{
color: colors.font_dark,
fontSize: 16,
textAlign: "left",
margin: 0,
}}
>
Subject: {props.transaction?.subject}
</Text>
<Text
style={{
color: colors.font_dark,
fontSize: 16,
textAlign: "left",
margin: 0,
marginTop: 8,
flexWrap: "wrap",
}}
>
Remarks: {props.transaction?.remarks}
</Text>
<Text
style={{
color: colors.font_dark,
fontSize: 16,
textAlign: "left",
margin: 0,
marginTop: 8,
flexWrap: "wrap",
}}
>
Consumables: {props.transaction?.consumables}
BORROWER'S SLIP
</Text>
</View>
<View style={{ flex: 1 }}>
<Text
style={{
color: colors.font_dark,
textAlign: "right",
fontSize: 16,
margin: 0,
flexWrap: "wrap",
}}
>
Equipments:
</Text>
</View>
{/* Status */}
<View
style={{
alignSelf: "stretch",
alignContent: "center",
justifyContent: "center",
backgroundColor: StatusBGColor(
props.transaction.transaction_status
),
borderRadius: 16,
padding: "8px",
}}
>
<Text
style={{
color: StatusTextColor(props.transaction.transaction_status),
textAlign: "right",
fontSize: 16,
}}
>
Status: {`${props.transaction.transaction_status}`}
</Text>
</View>
{/* Transaction ID */}
<View
style={{
display: "flex",
flexDirection: "row",
alignItems: "center",
justifyContent: "center",
alignSelf: "stretch",
}}
>
<Text
style={{
color: colors.form_dark,
fontSize: 20,
textAlign: "right",
}}
>
Transaction ID: #{props.transaction.id}
</Text>
</View>
<View
style={{
display: "flex",
alignSelf: "stretch",
}}
>
<Text
style={{
color: colors.form_title,
borderBottom: "1px solid #A2A2A2",
}}
>
Borrower Details
</Text>
</View>
{/* Top Details */}
<View
style={{
display: "flex",
flexDirection: "row",
gap: 5,
alignSelf: "stretch",
justifyContent: "space-between",
}}
>
{/* Borrower Details */}
<View
style={{
display: "flex",
flexDirection: "row",
gap: 5,
alignSelf: "stretch",
padding: "0px 5px",
}}
>
<View style={{ display: "flex", flexDirection: "column" }}>
{props.transaction?.equipments.map((equipment) => (
<Text
style={{
color: colors.form_dark,
fontSize: 16,
textAlign: "left",
margin: 0,
}}
>
Name:{" "}
<Text style={{ textDecoration: "underline" }}>
{props.transaction.borrower.name}
</Text>{" "}
</Text>
<Text
style={{
color: colors.form_dark,
fontSize: 14,
textAlign: "left",
margin: 0,
}}
>
Course:{" "}
<Text
style={{
color: colors.font_dark,
textAlign: "right",
fontSize: 12,
margin: 0,
marginTop: 2,
flexWrap: "wrap",
}}
>
{` - ${equipment.name} (ID:${equipment.id})`}
</Text>
))}
style={{ textDecoration: "underline" }}
>{`${props.transaction.borrower.course}`}</Text>{" "}
{"\n"}
{/* Section: <Text style={{ textDecoration: "underline" }}>{props.transaction.section}</Text> */}
</Text>
</View>
</View>
<View style={{ display: "flex", flexDirection: "column" }}>
<Text
style={{
color: colors.form_dark,
fontSize: 14,
textAlign: "left",
}}
>
Timestamp:{" "}
<Text style={{ textDecoration: "underline" }}>
{props.transaction.timestamp}
</Text>
{"\n"}
Lab instructor:{" "}
<Text style={{ textDecoration: "underline" }}>
{props.transaction.teacher.name}
</Text>{" "}
</Text>
<Text
style={{
color: colors.form_dark,
fontSize: 14,
textAlign: "left",
}}
>
Subject:{" "}
<Text style={{ textDecoration: "underline" }}>
{props.transaction.subject}
</Text>
</Text>
</View>
</View>
<View style={{ alignContent: "center", justifyContent: "center" }}>
{/* Equipment Section */}
<View
style={{
display: "flex",
gap: 5,
alignSelf: "stretch",
marginTop: "10"
}}
>
<Text
style={{
color: StatusTextColor(
props.transaction?.transaction_status || "Pending"
),
textAlign: "center",
fontSize: 16,
color: colors.form_title,
borderBottom: "1px solid #A2A2A2",
}}
>
{`${props.transaction?.transaction_status}`}
Selected Equipment
</Text>
{props.transaction.equipments.map((equipment) => (
<Text
style={{
color: colors.form_dark,
textAlign: "left",
fontSize: 14,
margin: 0,
marginTop: 2,
flexWrap: "wrap",
padding: 3,
}}
>
{` - ${equipment.name} (ID:${equipment.id})`}
</Text>
))}
{/* total Equipment */}
<View style={{ borderTop: "1px", marginTop: 5, width: "150px" }}>
<Text
style={{
color: colors.form_dark,
textAlign: "left",
fontSize: 14,
margin: 0,
flexWrap: "wrap",
}}
>
Total Equipment: {props.transaction.equipments.length}
</Text>
</View>
{/* Consumables Area */}
<View style={{ marginTop: "5" , marginBottom: 10}}>
<Text
style={{
color: colors.form_title,
borderBottom: "1px solid #A2A2A2",
}}
>
Consumables
</Text>
<Text
style={{
color: colors.form_dark,
textAlign: "left",
fontSize: 14,
flexWrap: "wrap",
padding: 3,
}}
>
{props.transaction?.consumables}
</Text>
</View>
</View>
{/* Members here */}
<View style={{
display: "flex",
gap: 5,
alignSelf: "stretch",}}>
<Text
style={{
color: colors.form_title,
borderBottom: "1px solid #A2A2A2",
}}
>
Members
</Text>
<Text
style={{
fontSize: 16,
margin: 0,
marginTop: 8,
}}
>
{props.transaction?.additional_members}
</Text>
{/* Remarks */}
</View>
<View style={{ display: "flex", flexDirection: "column", alignSelf: "stretch" }}>
<View style={{ padding: "10 0" }}>
<Text
style={{
color: colors.form_title,
marginTop: 10,
borderBottom: "1px solid #A2A2A2",
padding: "5 0",
}}
>
Remarks
</Text>
</View>
<Text
style={{
color: colors.form_dark,
fontSize: 14,
margin: 0,
marginTop: 8,
}}
>
{props.transaction.remarks}
</Text>
</View>
</View>
</Page>
</Document>

View file

@ -110,6 +110,7 @@ export type UserType = {
};
export type TransactionType = {
additional_members: string;
id: number;
borrower: {
id: number;

View file

@ -3,7 +3,6 @@ import styles from "../../styles";
import { colors } from "../../styles";
import TextField from "@mui/material/TextField";
import AddToQueueIcon from "@mui/icons-material/AddToQueue";
import Button from "../../Components/Button/Button";
import { toast } from "react-toastify";
import {
AvailableEquipmentInstancesAPI,
@ -20,6 +19,10 @@ import {
CircularProgress,
MenuItem,
OutlinedInput,
Autocomplete,
Alert,
Stack
} from "@mui/material";
import React from "react";
import Header from "../../Components/Header/Header";
@ -32,10 +35,10 @@ export default function AddTransactionPage() {
equipments: [] as number[],
teacher: 0,
subject: "",
remarks: " ",
remarks: "",
transaction_status: "Pending Approval",
consumables: " ",
additional_members: " ",
consumables: "",
additional_members: "",
borrower: 0,
});
/*
@ -109,6 +112,7 @@ export default function AddTransactionPage() {
alignItems: "center",
justifyContent: "center",
overflowY: "scroll",
marginTop: 64
},
}}
>
@ -124,31 +128,58 @@ export default function AddTransactionPage() {
<p style={{ ...styles.text_dark, ...styles.text_L }}>Borrowing Form</p>
</div>
<div style={{...styles.flex_column, marginLeft: "1rem", marginRight: "1rem"}}>
<div
style={{
...styles.flex_column,
marginLeft: "1rem",
marginRight: "1rem",
}}
>
<FormControl style={{ marginTop: "8px" }}>
<FormLabel style={{...styles.text_dark, ...styles.bform_label2}}>Items Requested</FormLabel>
<Select
<FormLabel
style={{
...{ ...styles.text_dark, ...styles.bform_label2 },
...{ marginLeft: "4px", marginBottom: "8px", textAlign: "left" },
}}
>
Items Requested
</FormLabel>
<Autocomplete
multiple
value={transaction.equipments}
onChange={(event) =>
id="equipment-autocomplete"
options={equipments.data?.sort((a, b) => a.id - b.id) || []}
getOptionLabel={(option) =>
`${option.equipment_name} (ID:${option.id})`
}
value={
equipments.data?.filter((equipment) =>
transaction.equipments.includes(equipment.id)
) || []
}
onChange={(_event, newValue) => {
SetTransaction({
...transaction,
equipments: event.target.value as number[],
})
}
input={<OutlinedInput />}
>
{equipments.data
?.filter((equipment) => equipment.status == "Available")
.map((equipment) => (
<MenuItem key={equipment.id} value={equipment.id}>
{`${equipment.equipment_name} (ID:${equipment.id})`}
</MenuItem>
))}
</Select>
equipments: newValue.map((item) => item.id),
});
}}
renderInput={(params) => (
<TextField
{...params}
variant="outlined"
label="Items Requested"
/>
)}
/>
</FormControl>
<FormControl style={{ marginTop: "8px" }}>
<FormLabel style={{...styles.text_dark, ...styles.bform_label2}}>Assigned Teacher</FormLabel>
<FormLabel
style={{
...styles.text_dark,
...{ marginLeft: "4px", marginBottom: "4px", textAlign: "left" },
}}
>
Assigned Teacher
</FormLabel>
<Select
value={transaction.teacher}
onChange={(event) =>
@ -157,9 +188,7 @@ export default function AddTransactionPage() {
teacher: event.target.value as number,
})
}
label={"Assigned Teacher"}
input={<OutlinedInput />}
>
{teachers.data?.map((teacher) => (
<MenuItem key={teacher.id} value={teacher.id}>
@ -169,7 +198,14 @@ export default function AddTransactionPage() {
</Select>
</FormControl>
<FormControl style={{ marginTop: "8px" }}>
<FormLabel style={{...styles.text_dark, ...styles.bform_label}}>Subject</FormLabel>
<FormLabel
style={{
...styles.text_dark,
...{ marginLeft: "4px", marginBottom: "4px", textAlign: "left" },
}}
>
Subject
</FormLabel>
<TextField
style={styles.input_form}
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
@ -180,21 +216,16 @@ export default function AddTransactionPage() {
placeholder={"The subject requiring the equipments"}
/>
</FormControl>
<FormControl style={{ marginTop: "8px" }}>
<FormLabel style={{...styles.text_dark, ...styles.bform_label}}>Remarks</FormLabel>
<TextField
multiline
style={styles.input_form}
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
SetTransaction({ ...transaction, remarks: e.target.value });
setError("");
<FormLabel
style={{
...styles.text_dark,
...{ marginLeft: "4px", marginBottom: "4px", textAlign: "left" },
}}
value={transaction.remarks}
placeholder={"Optionally add a brief description of the request"}
/>
</FormControl>
<FormControl style={{ marginTop: "8px" }}>
<FormLabel style={{...styles.text_dark, ...styles.bform_label}}>Consumables</FormLabel>
>
Consumables
</FormLabel>
<TextField
multiline
style={styles.input_form}
@ -203,11 +234,20 @@ export default function AddTransactionPage() {
setError("");
}}
value={transaction.consumables}
placeholder={"Write down any consumables here"}
placeholder={
"ex. Filter Papers, Acids, Solvent, Cleaning Agents"
}
/>
</FormControl>
<FormControl style={{ marginTop: "8px" }}>
<FormLabel style={{...styles.text_dark, ...styles.bform_label}}>Additional Members</FormLabel>
<FormLabel
style={{
...styles.text_dark,
...{ marginLeft: "4px", marginBottom: "4px", textAlign: "left" },
}}
>
Additional Members
</FormLabel>
<TextField
multiline
style={styles.input_form}
@ -220,24 +260,63 @@ export default function AddTransactionPage() {
}}
value={transaction.additional_members}
placeholder={
"Write down any additional members borrowing on behalf of this transaction"
"1. Full Name ex. (Daniel John Padilla)\n2. Kathryn Bernardo \n3. ..."
}
/>
</FormControl>
<FormControl style={{ marginTop: "8px" }}>
<FormLabel
style={{
...styles.text_dark,
...{ marginLeft: "4px", marginBottom: "4px", textAlign: "left" },
}}
>
Remarks (optional)
</FormLabel>
<TextField
multiline
style={styles.input_form}
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
SetTransaction({ ...transaction, remarks: e.target.value });
setError("");
}}
value={transaction.remarks}
placeholder={"Add a brief description of the request or N/A."}
/>
</FormControl>
</div>
<p style={{ ...styles.text_dark, ...styles.text_M }}>{error}</p>
<div
style={{
backgroundColor: colors.button_border,
marginTop: "16px",
display: "flex",
flex: 1,
alignContent: "center",
width: "100%",
height: "2px",
marginBottom: 8,
marginTop: "1rem"
}}
/>
<Button
type={"dark"}
label={"Create Transaction"}
>
<Stack
sx={{
width: "100%",
}}
spacing={2}
>
<Alert
icon={false}
severity="warning"
sx={{ alignItems: "center", justifyContent: "center" }}
>
NOTE: please be reminded that borrowing of lab apparatus can only be
made once. Further requests of additional apparatus will not be
entertained.
</Alert>
</Stack>
</div>
<p style={{ ...styles.text_dark, ...styles.text_M }}>{error}</p>
<button
onClick={async () => {
console.log(JSON.stringify(transaction));
const data = await TransactionCreateAPI(transaction);
@ -269,7 +348,22 @@ export default function AddTransactionPage() {
setError(JSON.stringify(data[1]));
}
}}
/>
style={{
display: "flex",
padding: "25px 38px",
justifyContent: "center",
alignItems: "center",
background: "#A7DA96",
height: "40px",
width: "100%",
marginTop: "1rem",
marginBottom: "1rem",
}}
>
<p style={{ ...styles.text_light, ...styles.text_M, ...{ flex: 1 } }}>Create Transaction</p>
</button>
</div>
);
}

View file

@ -2,40 +2,40 @@ import Header from "../../Components/Header/Header";
import styles from "../../styles";
import RestrictedComponent from "../../Components/RestrictedComponent/RestrictedComponent";
import TechnicianWidgets from "../../Components/DashboardPage/Technician/TechnicianWidgets";
import TechnicianEquipmentButtons from "../../Components/DashboardPage/Technician/TechnicianEquipmentButtons";
import TechnicianLogButtons from "../../Components/DashboardPage/Technician/TechnicianLogButtons";
import StudentTransactionListView from "../../Components/DashboardPage/Student/StudentTransactionListView";
import StudentDashboard from "../../Components/DashboardPage/Student/StudentDashboard";
import TechnicianNavigation from "../../Components/DashboardPage/Technician/TechnicianNavigation";
import TeacherTransactionListView from "../../Components/DashboardPage/Teacher/TeacherTransactionListView";
export default function Dashboard() {
return (
<div style={styles.background}>
<Header label={"Dashboard"} />
<RestrictedComponent allow_only={"Technician"}>
<TechnicianWidgets />
<TechnicianEquipmentButtons />
<TechnicianLogButtons />
</RestrictedComponent>
<RestrictedComponent allow_only={"Student"}>
<div
style={{
...styles.flex_column,
...{
flexWrap: "wrap",
justifyContent: "center",
marginLeft: "16px",
marginRight: "16px",
},
}}
>
<StudentDashboard />
<StudentTransactionListView />
</div>
</RestrictedComponent>
<RestrictedComponent allow_only={"Teacher"}>
<TeacherTransactionListView />
</RestrictedComponent>
<div style={{ position: "relative", zIndex: 999, marginTop: 80 }}>
<RestrictedComponent allow_only={"Technician"}>
<TechnicianWidgets />
<TechnicianNavigation />
</RestrictedComponent>
<RestrictedComponent allow_only={"Student"}>
<div
style={{
...styles.flex_row,
...{
flexWrap: "wrap",
justifyContent: "center",
marginLeft: "16px",
marginRight: "16px",
},
}}
>
<StudentDashboard />
<StudentTransactionListView />
</div>
</RestrictedComponent>
<RestrictedComponent allow_only={"Teacher"}>
<TeacherTransactionListView />
</RestrictedComponent>
</div>
</div>
);
}

View file

@ -16,22 +16,14 @@ import { useState } from "react";
import Popup from "reactjs-popup";
import Autocomplete from "@mui/material/Autocomplete";
import SearchIcon from "@mui/icons-material/Search";
import AddItemModal from "../../Components/AddItemModal/AddItemModal";
import AddToQueueIcon from "@mui/icons-material/AddToQueue";
import ScienceIcon from "@mui/icons-material/Science";
import ColorizeIcon from "@mui/icons-material/Colorize";
import { Button } from "@mui/material";
import { useNavigate } from "react-router-dom";
export default function EquipmentInstancesListPage() {
const [editmodalOpen, SetEditModalOpen] = useState(false);
const [selectedItem, SetSelectedItem] = useState(0);
const [additemmodalOpen, SetAddItemModalOpen] = useState(false);
const navigate = useNavigate();
const equipment_instances = useQuery({
queryKey: ["equipment_instances"],
@ -81,195 +73,81 @@ export default function EquipmentInstancesListPage() {
width: "100%",
minHeight: "100%",
minWidth: "100%",
flexWrap: "wrap",
}}
>
{/* ADDED/INSERTED BUTTON,POPUP, TWO CATEGORY BUTTONS*/}
<Button
<div
style={{
...styles.flex_column,
...{
alignSelf: "center",
justifyContent: "center",
flexWrap: "wrap",
},
}}
onClick={() => {
SetAddItemModalOpen(true);
...styles.flex_row,
...{ alignItems: "center", justifySelf: "flex-start" },
}}
>
<AddToQueueIcon
<SearchIcon
style={{
height: 64,
width: 64,
height: 32,
width: 32,
fill: colors.font_dark,
marginLeft: "1rem",
marginRight: "1rem",
}}
/>
<p
style={{
...styles.text_dark,
...styles.text_M,
<Autocomplete
sx={{
display: "inline-block",
"& input": {
width: "256x",
bgcolor: "background.paper",
color: (theme) =>
theme.palette.getContrastText(theme.palette.background.paper),
},
}}
>
Add Item
</p>
</Button>
<Popup
open={additemmodalOpen}
onClose={() => SetAddItemModalOpen(false)}
modal
position={"top center"}
contentStyle={{
width: "32rem",
borderRadius: 16,
borderColor: "grey",
borderStyle: "solid",
borderWidth: 1,
padding: 16,
alignContent: "center",
justifyContent: "center",
textAlign: "center",
}}
>
<AddItemModal />
</Popup>
<Button
style={{
...styles.flex_column,
...{
alignSelf: "center",
justifyContent: "center",
flexWrap: "wrap",
},
}}
>
<ScienceIcon
style={{
height: 64,
width: 64,
fill: colors.font_dark,
marginLeft: "1rem",
marginRight: "1rem",
}}
onClick={() => {
navigate("/view/equipment_instances/filter/Glassware");
value={filter}
onChange={(_event, newValue) => {
setFilter(newValue);
}}
freeSolo
id="custom-input-demo"
options={["Available", "Broken", "Glassware", "Miscellaneous"]}
renderInput={(params) => (
<div ref={params.InputProps.ref}>
<input type="text" {...params.inputProps} />
</div>
)}
/>
<p
style={{
...styles.text_dark,
...styles.text_M,
}}
>
Glassware
</p>
</Button>
<Button
style={{
...styles.flex_column,
...{
alignSelf: "center",
justifyContent: "center",
flexWrap: "wrap",
},
}}
>
<ColorizeIcon
style={{
height: 64,
width: 64,
fill: colors.font_dark,
marginLeft: "1rem",
marginRight: "1rem",
}}
onClick={() => {
navigate("/view/equipment_instances/filter/Miscellaneous");
}}
/>
<p
style={{
...styles.text_dark,
...styles.text_M,
...{ marginLeft: "4px" },
}}
>
Miscellaneous
Results Found:{" "}
{
equipment_instances?.data?.filter((equipment) =>
filter !== null
? // If filter is not null, we filter if it matches any criteria
equipment.equipment_name
.toLowerCase()
.includes(filter.toLowerCase()) ||
equipment.category
.toLowerCase()
.includes(filter.toLowerCase()) ||
equipment.last_updated
.toLowerCase()
.includes(filter?.toLowerCase()) ||
equipment.status.toLowerCase() == filter.toLowerCase()
: // If filter keyword is null then we just pass through everything as if we did not filter at all
true
).length
}
</p>
</Button>
<div style={{ alignSelf: "flex-start", paddingLeft: "32px" }}>
<div
style={{
...styles.flex_row,
...{ alignItems: "center", justifySelf: "flex-start" },
}}
>
<SearchIcon
style={{
height: 32,
width: 32,
fill: colors.font_dark,
marginLeft: "1rem",
marginRight: "1rem",
}}
/>
<Autocomplete
sx={{
display: "inline-block",
"& input": {
width: "256x",
bgcolor: "background.paper",
color: (theme) =>
theme.palette.getContrastText(
theme.palette.background.paper
),
},
}}
value={filter}
onChange={(_event, newValue) => {
setFilter(newValue);
}}
freeSolo
id="custom-input-demo"
options={["Available", "Broken", "Glassware", "Miscellaneous"]}
renderInput={(params) => (
<div ref={params.InputProps.ref}>
<input type="text" {...params.inputProps} />
</div>
)}
/>
<p
style={{
...styles.text_M,
...styles.text_dark,
...{ marginLeft: "4px" },
}}
>
Results Found:{" "}
{
equipment_instances?.data?.filter((equipment) =>
filter !== null
? // If filter is not null, we filter if it matches any criteria
equipment.equipment_name
.toLowerCase()
.includes(filter.toLowerCase()) ||
equipment.category
.toLowerCase()
.includes(filter.toLowerCase()) ||
equipment.last_updated
.toLowerCase()
.includes(filter?.toLowerCase()) ||
equipment.status.toLowerCase() == filter.toLowerCase()
: // If filter keyword is null then we just pass through everything as if we did not filter at all
true
).length
}
</p>
</div>
</div>
<div style={{ alignSelf: "flex-start", paddingLeft: "32px" }}></div>
<TableContainer
style={{ width: "90%", overflowY: "scroll", marginTop: "2rem" }}
component={Paper}

View file

@ -64,68 +64,67 @@ export default function EquipmentListPage() {
display: "flex",
alignItems: "center",
justifyContent: "center",
height: "100%",
height: "80%",
width: "100%",
minHeight: "100%",
minHeight: "80%",
minWidth: "100%",
flexWrap: "wrap",
}}
}}>
<div style={{width: "90%", marginTop: "3rem"}}>
<Button
style={{
...styles.flex_column,
...{
alignSelf: "flex-start",
justifyContent: "center",
flexWrap: "wrap",
},
}}
onClick={() => {
SetAddSKUModalOpen(true);
}}
>
<NoteAddIcon
style={{
height: 64,
width: 64,
fill: colors.font_dark,
marginLeft: "1rem",
marginRight: "1rem",
}}
/>
<p
style={{
...styles.text_dark,
...styles.text_M,
}}
>
Add SKU
</p>
</Button>
</div>
>
<Button
style={{
...styles.flex_column,
...{
alignSelf: "center",
justifyContent: "center",
flexWrap: "wrap",
},
}}
onClick={() => {
SetAddSKUModalOpen(true);
<Popup
open={addSKUmodalOpen}
onClose={() => SetAddSKUModalOpen(false)}
modal
position={"top center"}
contentStyle={{
width: "32rem",
borderRadius: 16,
borderColor: "grey",
borderStyle: "solid",
borderWidth: 1,
padding: 16,
alignContent: "center",
justifyContent: "center",
textAlign: "center",
}}
>
<NoteAddIcon
style={{
height: 64,
width: 64,
fill: colors.font_dark,
marginLeft: "1rem",
marginRight: "1rem",
}}
/>
<p
style={{
...styles.text_dark,
...styles.text_M,
}}
>
Add SKU
</p>
</Button>
<Popup
open={addSKUmodalOpen}
onClose={() => SetAddSKUModalOpen(false)}
modal
position={"top center"}
contentStyle={{
width: "32rem",
borderRadius: 16,
borderColor: "grey",
borderStyle: "solid",
borderWidth: 1,
padding: 16,
alignContent: "center",
justifyContent: "center",
textAlign: "center",
}}
>
<AddSKUModal />
</Popup>
<AddSKUModal />
</Popup>
<TableContainer
style={{ width: "90%", overflowY: "scroll", marginTop: "2rem" }}

View file

@ -65,79 +65,75 @@ export default function EquipmentTallyPage() {
width: "100%",
minHeight: "100%",
minWidth: "100%",
flexWrap: "wrap",
}}
>
<div style={{ alignSelf: "flex-start", paddingLeft: "32px" }}>
<div
<div
style={{
...styles.flex_row,
...{ alignItems: "center", justifySelf: "flex-start" },
}}
>
<SearchIcon
style={{
...styles.flex_row,
...{ alignItems: "center", justifySelf: "flex-start" },
height: 32,
width: 32,
fill: colors.font_dark,
marginLeft: "1rem",
marginRight: "1rem",
}}
/>
<Autocomplete
sx={{
display: "inline-block",
"& input": {
width: "256x",
bgcolor: "background.paper",
color: (theme) =>
theme.palette.getContrastText(theme.palette.background.paper),
},
}}
value={filter}
onChange={(_event, newValue) => {
setFilter(newValue);
}}
freeSolo
id="custom-input-demo"
options={["Glassware", "Miscellaneous"]}
renderInput={(params) => (
<div ref={params.InputProps.ref}>
<input type="text" {...params.inputProps} />
</div>
)}
/>
<p
style={{
...styles.text_M,
...styles.text_dark,
...{ marginLeft: "4px" },
}}
>
<SearchIcon
style={{
height: 32,
width: 32,
fill: colors.font_dark,
marginLeft: "1rem",
marginRight: "1rem",
}}
/>
<Autocomplete
sx={{
display: "inline-block",
"& input": {
width: "256x",
bgcolor: "background.paper",
color: (theme) =>
theme.palette.getContrastText(
theme.palette.background.paper
),
},
}}
value={filter}
onChange={(_event, newValue) => {
setFilter(newValue);
}}
freeSolo
id="custom-input-demo"
options={["Glassware", "Miscellaneous"]}
renderInput={(params) => (
<div ref={params.InputProps.ref}>
<input type="text" {...params.inputProps} />
</div>
)}
/>
<p
style={{
...styles.text_M,
...styles.text_dark,
...{ marginLeft: "4px" },
}}
>
Results Found:{" "}
{
equipments?.data?.filter((equipment) =>
filter !== null
? // If filter is not null, we filter if it matches any criteria
equipment.name
.toLowerCase()
.includes(filter.toLowerCase()) ||
equipment.category
.toLowerCase()
.includes(filter.toLowerCase()) ||
equipment.last_updated
.toLowerCase()
.includes(filter?.toLowerCase()) ||
equipment.category.toLowerCase() == filter.toLowerCase()
: // If filter keyword is null then we just pass through everything as if we did not filter at all
true
).length
}
</p>
</div>
Results Found:{" "}
{
equipment_instances?.data?.filter((equipment) =>
filter !== null
? // If filter is not null, we filter if it matches any criteria
equipment.equipment_name
.toLowerCase()
.includes(filter.toLowerCase()) ||
equipment.category
.toLowerCase()
.includes(filter.toLowerCase()) ||
equipment.last_updated
.toLowerCase()
.includes(filter?.toLowerCase()) ||
equipment.status.toLowerCase() == filter.toLowerCase()
: // If filter keyword is null then we just pass through everything as if we did not filter at all
true
).length
}
</p>
</div>
<div style={{ alignSelf: "flex-start", paddingLeft: "32px" }}></div>
<TableContainer
style={{ width: "90%", overflowY: "scroll", marginTop: "2rem" }}
component={Paper}

View file

@ -37,6 +37,7 @@ export default function LandingPage() {
minHeight: "100%",
minWidth: "100%",
flexWrap: "wrap",
backgroundColor: "#F2FAF4"
}}
>
<div style={{ height: "auto", flex: 1, flexWrap: "wrap" }}>
@ -51,19 +52,26 @@ export default function LandingPage() {
>
<div
style={{
minWidth: "30vw",
minWidth: "80%",
borderRadius: 4,
borderColor: "grey",
borderStyle: "solid",
borderWidth: 1,
padding: 16,
margin: 64,
marginLeft: "1.2rem",
paddingBottom: "16vh",
paddingTop: "16vh",
paddingTop: "15vh",
backgroundColor: "white",
boxShadow: "0px 4px 4px 0px rgba(0, 0, 0, 0.25)",
maxWidth: "35vw",
}}
>
<p style={{ ...styles.text_dark, ...styles.text_L }}>
CSM Inventory
Welcome!
</p>
<p style={{ ...styles.text_dark, ...styles.text_M }}>
CSM Borrowing and Inventory
<br />
Monitoring and Management System
</p>

View file

@ -0,0 +1,20 @@
import Header from "../../Components/Header/Header";
import styles from "../../styles";
import RestrictedComponent from "../../Components/RestrictedComponent/RestrictedComponent";
import TechnicianEquipmentButtons from "../../Components/DashboardPage/Technician/TechnicianEquipmentButtons";
import TechnicianLogButtons from "../../Components/DashboardPage/Technician/TechnicianLogButtons";
export default function ManageEquipmentPage() {
return (
<div style={styles.background}>
<Header label={"Equipment Management"} />
<div style={{ position: "relative", zIndex: 999, marginTop: 80 , alignContent: "center", height: "100%"}}>
<RestrictedComponent allow_only={"Technician"}>
<TechnicianEquipmentButtons />
<TechnicianLogButtons />
</RestrictedComponent>
</div>
</div>
);
}

View file

@ -53,6 +53,7 @@ export default function TransactionPage() {
alignContent: "center",
justifyContent: "center",
alignItems: "center",
marginTop: 64
}}
>
<PDFDownloadLink

View file

@ -16,8 +16,10 @@ import { useState } from "react";
import EditTransactionModal from "../../Components/EditTransactionModal/EditTransactionModal";
import EditItemInstanceModal from "../../Components/EditItemInstanceModal/EditItemInstanceModal";
import SearchIcon from "@mui/icons-material/Search";
import { useNavigate } from "react-router-dom";
export default function TransactionsListPage() {
const navigate = useNavigate();
const [EditTransactionOpen, SetEditTransactionOpen] = useState(false);
const [SelectedTransaction, SetSelectedTransaction] = useState(0);
const [EditEquipmentsOpen, SetEditEquipmentsOpen] = useState(false);
@ -68,6 +70,8 @@ export default function TransactionsListPage() {
minHeight: "100%",
minWidth: "100%",
flexWrap: "wrap",
marginTop: 60,
paddingBottom: 20,
},
...styles.flex_column,
}}
@ -143,6 +147,9 @@ export default function TransactionsListPage() {
transaction.teacher.name
.toLowerCase()
.includes(filter.toLowerCase()) ||
transaction.additional_members
.toLowerCase()
.includes(filter.toLowerCase()) ||
transaction.remarks
.toLowerCase()
.includes(filter?.toLowerCase()) ||
@ -176,7 +183,13 @@ export default function TransactionsListPage() {
Consumables
</TableCell>
<TableCell align="center" style={styles.text_light}>
Equipments
Additional Members
</TableCell>
<TableCell align="center" style={styles.text_light}>
Additional Members
</TableCell>
<TableCell align="center" style={styles.text_light}>
Actions
</TableCell>
</TableRow>
</TableHead>
@ -189,6 +202,9 @@ export default function TransactionsListPage() {
transaction.borrower.name
.toLowerCase()
.includes(filter.toLowerCase()) ||
transaction.additional_members
.toLowerCase()
.includes(filter.toLowerCase()) ||
transaction.teacher.name
.toLowerCase()
.includes(filter.toLowerCase()) ||
@ -313,6 +329,28 @@ export default function TransactionsListPage() {
>
{transaction.consumables}
</TableCell>
<TableCell
align="center"
component="th"
scope="row"
style={{ ...styles.text_S }}
sx={{
maxWidth: "64px",
flexWrap: "wrap",
wordWrap: "break-word",
}}
onClick={() => {
if (
transaction.transaction_status != "Finalized" &&
transaction.transaction_status != "Rejected"
) {
SetSelectedTransaction(transaction.id);
SetEditTransactionOpen(true);
}
}}
>
{transaction.additional_members}
</TableCell>
<TableCell align="center">
<p style={{ ...styles.text_M, ...styles.text_dark }}>
Involved Items: {transaction.equipments.length}
@ -403,6 +441,46 @@ export default function TransactionsListPage() {
</Table>
</TableContainer>
</TableCell>
<TableCell
align="center"
component="th"
scope="row"
style={{ ...styles.text_S }}
sx={{
maxWidth: "64px",
flexWrap: "wrap",
wordWrap: "break-word",
}}
>
<button
style={{
borderTop: "2px solid rgba(160, 160, 160, 0.20)",
padding: "7px",
margin: "0px",
backgroundColor: colors.dandelion,
width: "auto",
alignSelf: "center",
borderRadius: "7px",
}}
onClick={() => {
navigate(`/view/transaction/${transaction.id}`, {
replace: true,
state: { id: transaction.id },
});
}}
>
<p
style={{
...styles.text_S,
padding: "0px",
margin: "0px",
}}
>
Tap To View {"\n"} or Print
</p>
</button>
</TableCell>
</TableRow>
))
) : (

36
src/assets/Equipment.svg Normal file
View file

@ -0,0 +1,36 @@
<svg width="37" height="37" viewBox="0 0 37 37" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="37" height="37" fill="#1E1E1E"/>
<g id="Dashboard">
<rect width="1440" height="1024" transform="translate(-199 -581)" fill="#F2FAF4"/>
<g id="Body" clip-path="url(#clip0_50_13)">
<rect width="1151" height="919" transform="translate(-199 -581)" fill="#F2FAF4"/>
<g id="Left">
<g id="Buttons">
<g id="Main">
<rect x="-23" y="-23.5" width="799" height="84" rx="11.5" fill="#E8D3BB"/>
<rect x="-23" y="-23.5" width="799" height="84" rx="11.5" stroke="#FFAC92"/>
<g id="Icon">
<g id="Group">
<path id="Vector" d="M10.9742 22.2765C12.8259 22.2765 14.5125 23.3215 15.4659 25.0815C16.0525 26.1632 17.2259 26.8232 18.5092 26.8232C19.7742 26.8232 20.9475 26.1632 21.5342 25.0815C22.4875 23.3215 24.1742 22.2765 26.0259 22.2765H33.3409H36.1092L34.3309 6.03317C33.9825 2.73317 31.1042 0.166504 27.8042 0.166504H9.19587C5.89587 0.166504 3.01754 2.73317 2.6692 6.03317L0.890869 22.2765H3.6592H10.9742ZM23.9909 14.9432L19.4809 19.4715C19.5542 19.3982 19.6092 19.3248 19.6459 19.2515C19.3892 19.6182 18.9675 19.8382 18.5092 19.8382C18.1242 19.8382 17.7942 19.6915 17.5375 19.4532V19.4715L13.0092 14.9432C12.4775 14.4115 12.4775 13.5498 13.0092 12.9998C13.5409 12.4682 14.4209 12.4682 14.9525 12.9998L17.1342 15.1815V7.16984C17.1342 6.39984 17.7392 5.79484 18.5092 5.79484C19.2609 5.79484 19.8842 6.39984 19.8842 7.16984V15.1632L22.0475 12.9998C22.5792 12.4682 23.4592 12.4682 23.9909 12.9998C24.5225 13.5498 24.5225 14.4115 23.9909 14.9432Z" fill="url(#paint0_linear_50_13)"/>
<path id="Vector_2" d="M36.7875 28.473L36.4025 25.0264H33.6341H26.0258C25.2008 25.0264 24.4125 25.5397 23.9541 26.4014C22.8725 28.363 20.7825 29.573 18.5091 29.573C16.2175 29.573 14.1275 28.363 13.0641 26.4014C12.5875 25.5397 11.7991 25.0264 10.9741 25.0264H3.34746H0.597458L0.212457 28.473C-0.0442093 30.838 0.634124 33.1297 2.08246 34.7247C3.29246 36.0814 4.94246 36.833 6.72079 36.833H30.2791C32.0575 36.833 33.7075 36.0814 34.9175 34.7247C36.3658 33.1297 37.0441 30.838 36.7875 28.473Z" fill="url(#paint1_linear_50_13)"/>
</g>
</g>
</g>
</g>
</g>
</g>
</g>
<defs>
<linearGradient id="paint0_linear_50_13" x1="18.5" y1="0.166504" x2="18.5" y2="26.8232" gradientUnits="userSpaceOnUse">
<stop stop-color="#CB9C65"/>
<stop offset="1" stop-color="#693A03"/>
</linearGradient>
<linearGradient id="paint1_linear_50_13" x1="18.5" y1="25.0264" x2="18.5" y2="36.833" gradientUnits="userSpaceOnUse">
<stop stop-color="#CB9C65"/>
<stop offset="1" stop-color="#693A03"/>
</linearGradient>
<clipPath id="clip0_50_13">
<rect width="1151" height="919" fill="white" transform="translate(-199 -581)"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 2.6 KiB

BIN
src/assets/Profile-Icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 783 B

View file

@ -0,0 +1,9 @@
<svg width="37" height="45" viewBox="0 0 37 45" fill="none" xmlns="http://www.w3.org/2000/svg">
<path id="Vector" d="M30.1524 0.5H6.84758C3.35639 0.5 0.5 3.24998 0.5 6.65998V38.318C0.5 41.728 3.35639 44.5 6.84758 44.5H30.1524C33.6663 44.5 36.5 41.728 36.5 38.318V6.65998C36.5 3.24998 33.6663 0.5 30.1524 0.5ZM9.18266 32.246H27.8173C28.7695 32.246 29.5176 32.994 29.5176 33.896C29.5176 34.798 28.7695 35.546 27.8173 35.546H9.18266C8.25319 35.546 7.4824 34.798 7.4824 33.896C7.4824 32.994 8.25319 32.246 9.18266 32.246ZM7.4824 22.588C7.4824 21.686 8.25319 20.938 9.18266 20.938H27.8173C28.7695 20.938 29.5176 21.686 29.5176 22.588C29.5176 23.512 28.7695 24.238 27.8173 24.238H9.18266C8.25319 24.238 7.4824 23.512 7.4824 22.588ZM27.8173 12.93H9.18266C8.25319 12.93 7.4824 12.204 7.4824 11.28C7.4824 10.378 8.25319 9.62999 9.18266 9.62999H27.8173C28.7695 9.62999 29.5176 10.378 29.5176 11.28C29.5176 12.204 28.7695 12.93 27.8173 12.93Z" fill="url(#paint0_linear_121_218)"/>
<defs>
<linearGradient id="paint0_linear_121_218" x1="18.5" y1="0.499999" x2="31" y2="40" gradientUnits="userSpaceOnUse">
<stop stop-color="#417BBE"/>
<stop offset="1" stop-color="#3A389F"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
src/assets/ustp-logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

View file

@ -82,3 +82,40 @@ button:focus-visible {
background-color: #f9f9f9;
}
}
.custom-scrollbar {
overflow-y: scroll;
max-height: 800px;
scrollbar-width: thin; /* For Firefox */
-webkit-overflow-scrolling: touch; /* For smooth scrolling on iOS */
-ms-overflow-style: none; /* For IE */
scrollbar-color: transparent transparent; /* For WebKit */
}
.custom-scrollbar::-webkit-scrollbar {
width: 6px; /* Adjust the width as needed */
}
.custom-scrollbar::-webkit-scrollbar-thumb {
background-color: #c4c4c4; /* Color of the thumb */
border-radius: 3px; /* Rounded corners of the thumb */
}
.custom-scrollbar::-webkit-scrollbar-track {
background-color: #f0f0f0; /* Color of the track */
}
.capsule {
display: flex;
width: 374px;
padding: 10px;
justify-content: center;
align-items: center;
align-content: center;
gap: 30px;
flex-wrap: wrap;
border-radius: 6px;
border: 1px dashed #000;
background: #DDEDFF;
}

View file

@ -1,5 +1,5 @@
export const colors = {
background: "#FFFFFF",
background: "#F2FAF4",
header_color: "#b2dfab",
font_dark: "#2e482e",
font_light: "#0e410d",
@ -11,9 +11,20 @@ export const colors = {
green: "#80b28a",
gray: "#8F8F8F",
dark_green: "#17561D",
dark_blue: "#19639D"
dark_blue: "#19639D",
font_dark_red: "#570404",
dandelion: "#FBB217",
lightgreen: "#D9FFD8",
darkgreen: "#00360C",
lightorange: "#FEFFCD",
lightred: "#ECC4B8",
form_dark: "#000000",
form_title: "#1E1A4D"
};
const styles: { [key: string]: React.CSSProperties } = {
@ -30,7 +41,16 @@ const styles: { [key: string]: React.CSSProperties } = {
overflowY: "scroll",
},
text_normal: {
color: colors.font_dark,
fontWeight: "500",
},
text_dark_red: {
color: colors.font_dark_red,
fontWeight: "bold",
},
text_dark: {
color: colors.font_dark,
fontWeight: "bold",