mirror of
https://github.com/lemeow125/Borrowing-TrackerFrontend.git
synced 2025-05-18 12:28:15 +08:00
Added conditional rendering to dashboard page and restrict certain pages select user types
This commit is contained in:
parent
0e4c1b9f31
commit
3d20af24c9
9 changed files with 646 additions and 468 deletions
|
@ -15,6 +15,7 @@ import {
|
|||
PatchEquipmentType,
|
||||
EquipmentLogListType,
|
||||
EquipmentInstanceLogListType,
|
||||
UserType,
|
||||
} from "../Types/Types";
|
||||
|
||||
const debug = true;
|
||||
|
@ -135,7 +136,7 @@ export async function UserAPI() {
|
|||
return instance
|
||||
.get("api/v1/accounts/users/me/", config)
|
||||
.then((response) => {
|
||||
return response.data;
|
||||
return response.data as UserType;
|
||||
})
|
||||
.catch(() => {
|
||||
console.log("Error retrieving user data");
|
||||
|
|
261
src/Components/DashboardPage/TechnicianButtons.tsx
Normal file
261
src/Components/DashboardPage/TechnicianButtons.tsx
Normal file
|
@ -0,0 +1,261 @@
|
|||
import { useQueries } from "@tanstack/react-query";
|
||||
import styles from "../../styles";
|
||||
import { EquipmentsAPI, EquipmentInstancesAPI, UserAPI } from "../API/API";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { Button } from "@mui/material";
|
||||
import FormatListBulletedIcon from "@mui/icons-material/FormatListBulleted";
|
||||
import AddToQueueIcon from "@mui/icons-material/AddToQueue";
|
||||
import NoteAddIcon from "@mui/icons-material/NoteAdd";
|
||||
import NoteIcon from "@mui/icons-material/Note";
|
||||
import { colors } from "../../styles";
|
||||
import ScienceIcon from "@mui/icons-material/Science";
|
||||
import ColorizeIcon from "@mui/icons-material/Colorize";
|
||||
import { Dispatch, SetStateAction } from "react";
|
||||
|
||||
type props = {
|
||||
SetAddSKUModalOpen: Dispatch<SetStateAction<boolean>>;
|
||||
SetAddItemModalOpen: Dispatch<SetStateAction<boolean>>;
|
||||
};
|
||||
export default function TechnicianButtons(props: props) {
|
||||
const navigate = useNavigate();
|
||||
const queries = useQueries({
|
||||
queries: [
|
||||
{
|
||||
queryKey: ["equipments"],
|
||||
queryFn: EquipmentsAPI,
|
||||
},
|
||||
{
|
||||
queryKey: ["equipment_instances"],
|
||||
queryFn: EquipmentInstancesAPI,
|
||||
},
|
||||
{
|
||||
queryKey: ["user"],
|
||||
queryFn: UserAPI,
|
||||
},
|
||||
],
|
||||
});
|
||||
return (
|
||||
<>
|
||||
<p
|
||||
style={{
|
||||
...styles.text_dark,
|
||||
...styles.text_L,
|
||||
}}
|
||||
>
|
||||
Equipments
|
||||
</p>
|
||||
<div
|
||||
style={{
|
||||
...styles.flex_row,
|
||||
...{
|
||||
alignSelf: "center",
|
||||
justifyContent: "center",
|
||||
flexWrap: "wrap",
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Button
|
||||
style={{
|
||||
...styles.flex_column,
|
||||
...{
|
||||
alignSelf: "center",
|
||||
justifyContent: "center",
|
||||
flexWrap: "wrap",
|
||||
display:
|
||||
queries[2].data && queries[2].data.is_technician
|
||||
? "initial"
|
||||
: "none",
|
||||
},
|
||||
}}
|
||||
onClick={() => {
|
||||
navigate("/view/equipment_instances");
|
||||
}}
|
||||
>
|
||||
<FormatListBulletedIcon
|
||||
style={{
|
||||
height: 64,
|
||||
width: 64,
|
||||
fill: colors.font_dark,
|
||||
marginLeft: "1rem",
|
||||
marginRight: "1rem",
|
||||
}}
|
||||
/>
|
||||
<p
|
||||
style={{
|
||||
...styles.text_dark,
|
||||
...styles.text_M,
|
||||
}}
|
||||
>
|
||||
View All
|
||||
</p>
|
||||
</Button>
|
||||
<Button
|
||||
style={{
|
||||
...styles.flex_column,
|
||||
...{
|
||||
alignSelf: "center",
|
||||
justifyContent: "center",
|
||||
flexWrap: "wrap",
|
||||
},
|
||||
}}
|
||||
onClick={() => {
|
||||
props.SetAddItemModalOpen(true);
|
||||
}}
|
||||
>
|
||||
<AddToQueueIcon
|
||||
style={{
|
||||
height: 64,
|
||||
width: 64,
|
||||
fill: colors.font_dark,
|
||||
marginLeft: "1rem",
|
||||
marginRight: "1rem",
|
||||
}}
|
||||
/>
|
||||
<p
|
||||
style={{
|
||||
...styles.text_dark,
|
||||
...styles.text_M,
|
||||
}}
|
||||
>
|
||||
Add Item
|
||||
</p>
|
||||
</Button>
|
||||
<Button
|
||||
style={{
|
||||
...styles.flex_column,
|
||||
...{
|
||||
alignSelf: "center",
|
||||
justifyContent: "center",
|
||||
flexWrap: "wrap",
|
||||
},
|
||||
}}
|
||||
onClick={() => {
|
||||
props.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>
|
||||
<Button
|
||||
style={{
|
||||
...styles.flex_column,
|
||||
...{
|
||||
alignSelf: "center",
|
||||
justifyContent: "center",
|
||||
flexWrap: "wrap",
|
||||
},
|
||||
}}
|
||||
onClick={() => {
|
||||
navigate("/view/equipments");
|
||||
}}
|
||||
>
|
||||
<NoteIcon
|
||||
style={{
|
||||
height: 64,
|
||||
width: 64,
|
||||
fill: colors.font_dark,
|
||||
marginLeft: "1rem",
|
||||
marginRight: "1rem",
|
||||
}}
|
||||
/>
|
||||
<p
|
||||
style={{
|
||||
...styles.text_dark,
|
||||
...styles.text_M,
|
||||
}}
|
||||
>
|
||||
View SKUs
|
||||
</p>
|
||||
</Button>
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
...styles.flex_row,
|
||||
...{
|
||||
alignSelf: "center",
|
||||
justifyContent: "center",
|
||||
flexWrap: "wrap",
|
||||
},
|
||||
}}
|
||||
>
|
||||
<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");
|
||||
}}
|
||||
/>
|
||||
<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,
|
||||
}}
|
||||
>
|
||||
Miscellaneous
|
||||
</p>
|
||||
</Button>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
94
src/Components/DashboardPage/TechnicianLogs.tsx
Normal file
94
src/Components/DashboardPage/TechnicianLogs.tsx
Normal file
|
@ -0,0 +1,94 @@
|
|||
import { Button } from "@mui/material";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import ManageSearchIcon from "@mui/icons-material/ManageSearch";
|
||||
import styles from "../../styles";
|
||||
import { colors } from "../../styles";
|
||||
|
||||
export default function TechnicianLogs() {
|
||||
const navigate = useNavigate();
|
||||
return (
|
||||
<>
|
||||
<p
|
||||
style={{
|
||||
...styles.text_dark,
|
||||
...styles.text_L,
|
||||
}}
|
||||
>
|
||||
Logs
|
||||
</p>
|
||||
<div
|
||||
style={{
|
||||
...styles.flex_row,
|
||||
...{
|
||||
alignSelf: "center",
|
||||
justifyContent: "center",
|
||||
flexWrap: "wrap",
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Button
|
||||
style={{
|
||||
...styles.flex_column,
|
||||
...{
|
||||
alignSelf: "center",
|
||||
justifyContent: "center",
|
||||
flexWrap: "wrap",
|
||||
},
|
||||
}}
|
||||
onClick={() => {
|
||||
navigate("/view/equipments/logs");
|
||||
}}
|
||||
>
|
||||
<ManageSearchIcon
|
||||
style={{
|
||||
height: 64,
|
||||
width: 64,
|
||||
fill: colors.font_dark,
|
||||
marginLeft: "1rem",
|
||||
marginRight: "1rem",
|
||||
}}
|
||||
/>
|
||||
<p
|
||||
style={{
|
||||
...styles.text_dark,
|
||||
...styles.text_M,
|
||||
}}
|
||||
>
|
||||
SKU Logs
|
||||
</p>
|
||||
</Button>
|
||||
<Button
|
||||
style={{
|
||||
...styles.flex_column,
|
||||
...{
|
||||
alignSelf: "center",
|
||||
justifyContent: "center",
|
||||
flexWrap: "wrap",
|
||||
},
|
||||
}}
|
||||
onClick={() => {
|
||||
navigate("/view/equipment_instances/logs");
|
||||
}}
|
||||
>
|
||||
<ManageSearchIcon
|
||||
style={{
|
||||
height: 64,
|
||||
width: 64,
|
||||
fill: colors.font_dark,
|
||||
marginLeft: "1rem",
|
||||
marginRight: "1rem",
|
||||
}}
|
||||
/>
|
||||
<p
|
||||
style={{
|
||||
...styles.text_dark,
|
||||
...styles.text_M,
|
||||
}}
|
||||
>
|
||||
Item Logs
|
||||
</p>
|
||||
</Button>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
180
src/Components/DashboardPage/TechnicianWidgets.tsx
Normal file
180
src/Components/DashboardPage/TechnicianWidgets.tsx
Normal file
|
@ -0,0 +1,180 @@
|
|||
import { useQueries } from "@tanstack/react-query";
|
||||
import styles from "../../styles";
|
||||
import { EquipmentsAPI, EquipmentInstancesAPI, UserAPI } from "../API/API";
|
||||
|
||||
export default function TechnicianWidgets() {
|
||||
const queries = useQueries({
|
||||
queries: [
|
||||
{
|
||||
queryKey: ["equipments"],
|
||||
queryFn: EquipmentsAPI,
|
||||
},
|
||||
{
|
||||
queryKey: ["equipment_instances"],
|
||||
queryFn: EquipmentInstancesAPI,
|
||||
},
|
||||
{
|
||||
queryKey: ["user"],
|
||||
queryFn: UserAPI,
|
||||
},
|
||||
],
|
||||
});
|
||||
return (
|
||||
<div style={styles.flex_column}>
|
||||
<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" },
|
||||
}}
|
||||
>
|
||||
SKUs in Database
|
||||
</p>
|
||||
|
||||
<p
|
||||
style={{
|
||||
...styles.text_dark,
|
||||
...styles.text_L,
|
||||
}}
|
||||
>
|
||||
{queries[0].data ? queries[0].data.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" },
|
||||
}}
|
||||
>
|
||||
Items in Database
|
||||
</p>
|
||||
|
||||
<p
|
||||
style={{
|
||||
...styles.text_dark,
|
||||
...styles.text_L,
|
||||
}}
|
||||
>
|
||||
{queries[1].data ? queries[1].data.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" },
|
||||
}}
|
||||
>
|
||||
Functional Items
|
||||
</p>
|
||||
|
||||
<p
|
||||
style={{
|
||||
...styles.text_dark,
|
||||
...styles.text_L,
|
||||
}}
|
||||
>
|
||||
{queries[1].data
|
||||
? queries[1].data.filter(
|
||||
(equipment) => equipment.status == "WORKING"
|
||||
).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 Items
|
||||
</p>
|
||||
|
||||
<p
|
||||
style={{
|
||||
...styles.text_dark,
|
||||
...styles.text_L,
|
||||
}}
|
||||
>
|
||||
{queries[1].data
|
||||
? queries[1].data.filter(
|
||||
(equipment) => equipment.status == "BROKEN"
|
||||
).length
|
||||
: 0}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
21
src/Components/RestrictedComponent/RestrictedComponent.tsx
Normal file
21
src/Components/RestrictedComponent/RestrictedComponent.tsx
Normal file
|
@ -0,0 +1,21 @@
|
|||
import React from "react";
|
||||
import { UserAPI } from "../API/API";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
|
||||
type props = {
|
||||
allow_only: string;
|
||||
children: React.ReactNode;
|
||||
};
|
||||
export default function RestrictedComponent(props: props) {
|
||||
const user = useQuery({ queryKey: ["user"], queryFn: UserAPI });
|
||||
if (props.allow_only === "Teacher") {
|
||||
if (user.data && user.data.is_teacher) {
|
||||
return <>{props.children}</>;
|
||||
}
|
||||
} else if (props.allow_only === "Technician") {
|
||||
if (user.data && user.data.is_technician) {
|
||||
return <>{props.children}</>;
|
||||
}
|
||||
}
|
||||
return <></>;
|
||||
}
|
46
src/Components/RestrictedPage/RestrictedPage.tsx
Normal file
46
src/Components/RestrictedPage/RestrictedPage.tsx
Normal file
|
@ -0,0 +1,46 @@
|
|||
import { useEffect } from "react";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { UserAPI } from "../API/API";
|
||||
import { toast } from "react-toastify";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
|
||||
type props = {
|
||||
allow_only: string;
|
||||
};
|
||||
export default function RestrictedPage(props: props) {
|
||||
const navigate = useNavigate();
|
||||
const user = useQuery({ queryKey: ["user"], queryFn: UserAPI });
|
||||
useEffect(() => {
|
||||
if (props.allow_only == "Teacher") {
|
||||
if (user.data && !user.data.is_teacher) {
|
||||
navigate("/");
|
||||
toast("You are not a teacher!", {
|
||||
position: "bottom-center",
|
||||
autoClose: 2000,
|
||||
hideProgressBar: false,
|
||||
closeOnClick: true,
|
||||
pauseOnHover: true,
|
||||
draggable: true,
|
||||
progress: undefined,
|
||||
theme: "light",
|
||||
});
|
||||
}
|
||||
} else if (props.allow_only == "Technician") {
|
||||
if (user.data && !user.data.is_technician) {
|
||||
navigate("/");
|
||||
toast("You are not a technician!", {
|
||||
position: "bottom-center",
|
||||
autoClose: 2000,
|
||||
hideProgressBar: false,
|
||||
closeOnClick: true,
|
||||
pauseOnHover: true,
|
||||
draggable: true,
|
||||
progress: undefined,
|
||||
theme: "light",
|
||||
});
|
||||
}
|
||||
}
|
||||
}, [navigate, props.allow_only, user.data]);
|
||||
|
||||
return <></>;
|
||||
}
|
|
@ -96,3 +96,13 @@ export type EquipmentInstanceLogType = {
|
|||
};
|
||||
|
||||
export type EquipmentInstanceLogListType = Array<EquipmentInstanceLogType>;
|
||||
|
||||
export type UserType = {
|
||||
username: string;
|
||||
email: string;
|
||||
avatar: string;
|
||||
first_name: string;
|
||||
last_name: string;
|
||||
is_teacher: boolean;
|
||||
is_technician: boolean;
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue