Add user info page and add equipment status to pdf preview

This commit is contained in:
Keannu Bernasol 2024-01-14 21:02:04 +08:00
parent c80908d8f1
commit 3850a61403
8 changed files with 262 additions and 3 deletions

View file

@ -23,6 +23,7 @@ import TransactionPage from "./Pages/TransactionPage/TransactionPage";
import EquipmentInstanceTallyPage from "./Pages/EquipmentTallyPage/EquipmentTallyPage"; import EquipmentInstanceTallyPage from "./Pages/EquipmentTallyPage/EquipmentTallyPage";
import TransactionReportPage from "./Pages/TransactionReportPage/TransactionReportPage"; import TransactionReportPage from "./Pages/TransactionReportPage/TransactionReportPage";
import ManageEquipmentPage from "./Pages/ManageEquipmentPage/ManageEquipmentPage"; import ManageEquipmentPage from "./Pages/ManageEquipmentPage/ManageEquipmentPage";
import UserInfoPage from "./Pages/UserInfoPage/UserInfoPage";
const queryClient = new QueryClient(); const queryClient = new QueryClient();
const router = createHashRouter([ const router = createHashRouter([
@ -184,6 +185,16 @@ const router = createHashRouter([
), ),
errorElement: <ErrorPage />, errorElement: <ErrorPage />,
}, },
{
path: "/view/user/",
element: (
<>
<Revalidator />
<UserInfoPage />
</>
),
errorElement: <ErrorPage />,
},
]); ]);
export default function App() { export default function App() {

View file

@ -21,6 +21,7 @@ import {
TransactionType, TransactionType,
ClearanceType, ClearanceType,
TransactionCreateType, TransactionCreateType,
PatchUserType,
} from "../Types/Types"; } from "../Types/Types";
const debug = false; const debug = false;
@ -148,6 +149,19 @@ export async function UserAPI() {
}); });
} }
export async function UserUpdateAPI(user: PatchUserType) {
const config = await GetConfig();
return instance
.patch("api/v1/accounts/users/me/", user, config)
.then((response) => {
return [true, response.data as UserType];
})
.catch((error) => {
console.log("Error updating user info");
return [false, ParseError(error)];
});
}
export function ActivationAPI(activation: ActivationType) { export function ActivationAPI(activation: ActivationType) {
return instance return instance
.post("api/v1/accounts/users/activation/", activation) .post("api/v1/accounts/users/activation/", activation)

View file

@ -39,7 +39,7 @@ export default function Drawer() {
backgroundColor: colors.header_color, backgroundColor: colors.header_color,
}} }}
> >
<div style={styles.flex_row}> <div style={styles.flex_row} onClick={() => navigate("/view/user")}>
<AccountCircleIcon <AccountCircleIcon
style={{ style={{
width: "48px", width: "48px",

View file

@ -26,6 +26,7 @@ export default function RegisterModal() {
username: "", username: "",
email: "", email: "",
course: "", course: "",
section: "",
password: "", password: "",
confirm_password: "", confirm_password: "",
}); });
@ -166,6 +167,17 @@ export default function RegisterModal() {
</div> </div>
</RadioGroup> </RadioGroup>
</FormControl> </FormControl>
<TextField
id="outlined-helperText"
label="Section"
style={styles.input_form}
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
setUser({ ...user, section: e.target.value });
setError("");
}}
value={user.username}
placeholder={"Enter current section"}
/>
<TextField <TextField
id="outlined-helperText" id="outlined-helperText"
label="Username" label="Username"
@ -268,6 +280,7 @@ export default function RegisterModal() {
email: "", email: "",
password: "", password: "",
confirm_password: "", confirm_password: "",
section: "",
course: "", course: "",
}); });
} else { } else {

View file

@ -268,6 +268,7 @@ export default function TransactionPDF(props: props) {
</Text> </Text>
{props.transaction.equipments.map((equipment) => ( {props.transaction.equipments.map((equipment) => (
<Text <Text
key={equipment.id}
style={{ style={{
color: colors.form_dark, color: colors.form_dark,
textAlign: "left", textAlign: "left",
@ -278,7 +279,7 @@ export default function TransactionPDF(props: props) {
padding: 3, padding: 3,
}} }}
> >
{` - ${equipment.name} (ID:${equipment.id})`} {` - ${equipment.name} (ID:${equipment.id}) (${equipment.status})`}
</Text> </Text>
))} ))}
{/* total Equipment */} {/* total Equipment */}

View file

@ -107,6 +107,15 @@ export type UserType = {
last_name: string; last_name: string;
is_teacher: boolean; is_teacher: boolean;
is_technician: boolean; is_technician: boolean;
course: string;
section: string;
};
export type PatchUserType = {
first_name?: string;
last_name?: string;
course?: string;
section?: string;
}; };
export type TransactionType = { export type TransactionType = {

View file

@ -29,7 +29,6 @@ export default function Dashboard() {
> >
<StudentDashboard /> <StudentDashboard />
<StudentTransactionListView /> <StudentTransactionListView />
</div> </div>
</RestrictedComponent> </RestrictedComponent>
<RestrictedComponent allow_only={"Teacher"}> <RestrictedComponent allow_only={"Teacher"}>

View file

@ -0,0 +1,212 @@
import Header from "../../Components/Header/Header";
import styles from "../../styles";
import RestrictedComponent from "../../Components/RestrictedComponent/RestrictedComponent";
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
import { UserAPI, UserUpdateAPI } from "../../Components/API/API";
import CircularProgress from "@mui/material/CircularProgress/CircularProgress";
import { useEffect, useState } from "react";
import { toast } from "react-toastify";
import {
FormControlLabel,
FormLabel,
Radio,
RadioGroup,
TextField,
} from "@mui/material";
export default function UserInfoPage() {
const queryClient = useQueryClient();
const User = useQuery({ queryKey: ["user"], queryFn: UserAPI });
const [user, setUser] = useState({
first_name: "",
last_name: "",
username: "",
email: "",
course: "",
section: "",
});
const [error, setError] = useState("");
const mutation = useMutation({
mutationFn: async () => {
const data = await UserUpdateAPI(user);
if (data[0] != true) {
setError(JSON.stringify(data[1]));
return Promise.reject(new Error(JSON.stringify(data[1])));
}
return data;
},
onSuccess: (data) => {
queryClient.invalidateQueries({
queryKey: ["user"],
});
setError("Updated successfully");
toast(`User info updated successfuly`, {
position: "top-right",
autoClose: 2000,
hideProgressBar: false,
closeOnClick: true,
pauseOnHover: true,
draggable: true,
progress: undefined,
theme: "light",
});
if (data && User.data) {
setUser({
first_name: User.data.first_name,
last_name: User.data.last_name,
username: User.data.username,
email: User.data.email,
course: User.data.course,
section: User.data.section,
});
}
},
});
useEffect(() => {
if (User.data) {
setUser(User.data);
}
}, [User.data]);
if (User.isLoading) {
return (
<div style={styles.background}>
<Header label={"Transactions"} />
<div
style={{
...styles.flex_column,
...{
alignItems: "center",
justifyContent: "center",
paddingTop: "64px",
},
}}
>
<CircularProgress style={{ height: "128px", width: "128px" }} />
<p
style={{
...styles.text_dark,
...styles.text_L,
}}
>
Loading
</p>
</div>
</div>
);
}
return (
<div style={styles.background}>
<Header label={"Dashboard"} />
<div style={{ position: "relative", zIndex: 999, marginTop: 80 }}>
<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"}
/>
<p>{JSON.stringify(User.data)}</p>
</div>
<RestrictedComponent allow_only={"Student"}>
<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("");
}}
>
<div
style={{
...styles.flex_column,
...{
overflowY: "scroll",
maxHeight: "128px",
},
}}
>
<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>
<TextField
id="outlined-helperText"
label="Section"
style={styles.input_form}
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
setUser({ ...user, section: e.target.value });
setError("");
}}
value={user.username}
placeholder={"Enter current section"}
/>
</RestrictedComponent>
<p
style={{
...styles.text_dark_red,
...styles.text_S,
flex: 1,
textAlign: "center",
marginLeft: 15,
}}
>
{error}
</p>
<button
onClick={() => mutation.mutate()}
style={{
borderRadius: 16,
justifyContent: "center",
alignItems: "center",
background: "#FBB217",
height: "40px",
width: "20vw",
}}
>
Update
</button>
</div>
);
}