diff --git a/src/Components/API/API.tsx b/src/Components/API/API.tsx index 667ad12..322f794 100644 --- a/src/Components/API/API.tsx +++ b/src/Components/API/API.tsx @@ -11,6 +11,7 @@ import { AddEquipmentType, AddEquipmentInstanceType, EquipmentInstanceType, + PatchEquipmentInstanceType, } from "../Types/Types"; const instance = axios.create({ @@ -190,6 +191,47 @@ export async function EquipmentCreateAPI(equipment: AddEquipmentType) { // Equipment Instances APIs +export async function EquipmentInstanceAPI(id: number) { + const config = await GetConfig(); + return instance + .get(`api/v1/equipments/equipment_instances/${id}`, config) + .then((response) => { + return response.data as EquipmentInstanceType; + }) + .catch(() => { + console.log("Error retrieving equipment"); + }); +} + +export async function EquipmentInstanceUpdateAPI( + item: PatchEquipmentInstanceType, + id: number +) { + const config = await GetConfig(); + return instance + .patch(`api/v1/equipments/equipment_instances/${id}/`, item, config) + .then((response) => { + return [true, response.data as EquipmentInstanceType]; + }) + .catch((error) => { + console.log("Error updating equipment instance"); + return [false, ParseError(error)]; + }); +} + +export async function EquipmentInstanceRemoveAPI(id: number) { + const config = await GetConfig(); + return instance + .delete(`api/v1/equipments/equipment_instances/${id}/`, config) + .then((response) => { + return [true, response.data]; + }) + .catch((error) => { + console.log("Error updating equipment instance"); + return [false, ParseError(error)]; + }); +} + export async function EquipmentInstancesAPI() { const config = await GetConfig(); return instance diff --git a/src/Components/EditItemModal/EditItemModal.tsx b/src/Components/EditItemModal/EditItemModal.tsx new file mode 100644 index 0000000..bdcb36f --- /dev/null +++ b/src/Components/EditItemModal/EditItemModal.tsx @@ -0,0 +1,297 @@ +import { useEffect, useState } from "react"; +import styles from "../../styles"; +import { colors } from "../../styles"; +import TextField from "@mui/material/TextField"; +import EditIcon from "@mui/icons-material/Edit"; +import Button from "../Button/Button"; +import { toast } from "react-toastify"; +import { + EquipmentInstanceAPI, + EquipmentInstanceRemoveAPI, + EquipmentInstanceUpdateAPI, +} from "../API/API"; +import RadioGroup from "@mui/material/RadioGroup"; +import FormControlLabel from "@mui/material/FormControlLabel"; +import FormControl from "@mui/material/FormControl"; +import FormLabel from "@mui/material/FormLabel"; +import Radio from "@mui/material/Radio"; +import { useMutation, useQueryClient } from "@tanstack/react-query"; +import { useQuery } from "@tanstack/react-query"; +import { CircularProgress } from "@mui/material"; +import React from "react"; + +export default function EditItemModal(props: { + id: number; + setOpen: React.Dispatch>; +}) { + const queryClient = useQueryClient(); + const [item, setItem] = useState({ + remarks: "", + status: "", + }); + const [error, setError] = useState(""); + + const equipment = useQuery({ + queryKey: ["equipment_instance", props.id], + queryFn: () => EquipmentInstanceAPI(Number(props.id)), + }); + + useEffect(() => { + if (equipment.data) { + setItem({ + ...item, + remarks: equipment.data.remarks, + status: equipment.data.status, + }); + } + }, [equipment.data]); + + const update_mutation = useMutation({ + mutationFn: async () => { + const data = await EquipmentInstanceUpdateAPI(item, props.id); + if (data[0] != true) { + return Promise.reject(new Error(JSON.stringify(data[1]))); + } + return data; + }, + onSuccess: (data) => { + queryClient.invalidateQueries({ queryKey: ["equipment_instances"] }); + queryClient.invalidateQueries({ + queryKey: ["equipment_instance", props.id], + }); + setError("Updated successfully"); + toast( + `Item updated successfuly, ${ + typeof data[1] == "object" ? "ID:" + data[1].id : "" + }`, + { + position: "top-right", + autoClose: 2000, + hideProgressBar: false, + closeOnClick: true, + pauseOnHover: true, + draggable: true, + progress: undefined, + theme: "light", + } + ); + if (typeof data[1] == "object") { + setItem({ + ...item, + remarks: data[1].remarks, + status: data[1].status, + }); + } + }, + onError: (error) => { + setError(JSON.stringify(error)); + }, + }); + + const delete_mutation = useMutation({ + mutationFn: async () => { + const data = await EquipmentInstanceRemoveAPI(props.id); + if (data[0] != true) { + return Promise.reject(new Error(JSON.stringify(data[1]))); + } + return data; + }, + onSuccess: (data) => { + queryClient.invalidateQueries({ queryKey: ["equipment_instances"] }); + queryClient.invalidateQueries({ + queryKey: ["equipment_instance", props.id], + }); + setError("Deleted successfully"); + toast("Item deleted successfuly", { + position: "top-right", + autoClose: 2000, + hideProgressBar: false, + closeOnClick: true, + pauseOnHover: true, + draggable: true, + progress: undefined, + theme: "light", + }); + props.setOpen(false); + if (typeof data[1] == "object") { + setItem({ + ...item, + remarks: data[1].remarks, + status: data[1].status, + }); + } + }, + onError: (error) => { + setError(JSON.stringify(error)); + }, + }); + + if (equipment.isLoading) { + return ( +
+ +

+ Loading +

+
+ ); + } + return ( + <> +
+ +

Edit Item

+
+ +
+ +
+

+ Associated SKU: +

+

+ {equipment.data?.equipment_name} + {" (SKU #" + equipment.data?.equipment + ")"} +

+
+ + + Item Status + + ) => { + setItem({ ...item, status: e.target.value }); + setError(""); + }} + > +
+ } + label="Working" + style={styles.text_dark} + /> + } + label="Broken" + style={styles.text_dark} + /> + } + label="Under Maintenance" + style={styles.text_dark} + /> + } + label="Decomissioned" + style={styles.text_dark} + /> +
+
+
+ ) => { + setItem({ ...item, remarks: e.target.value }); + setError(""); + }} + value={item.remarks} + placeholder={"Optionally add a brief description of the item"} + /> +
+

{error}

+
+
+
+ + ); +} diff --git a/src/Components/Types/Types.tsx b/src/Components/Types/Types.tsx index 3f263ce..bab625f 100644 --- a/src/Components/Types/Types.tsx +++ b/src/Components/Types/Types.tsx @@ -45,6 +45,11 @@ export type AddEquipmentInstanceType = { remarks?: string; }; +export type PatchEquipmentInstanceType = { + status: string; + remarks?: string; +}; + export type EquipmentInstanceType = { id: number; equipment: string; diff --git a/src/Pages/EquipmentInstancesListPage/EquipmentInstancesListPage.tsx b/src/Pages/EquipmentInstancesListPage/EquipmentInstancesListPage.tsx index b56d28e..654c049 100644 --- a/src/Pages/EquipmentInstancesListPage/EquipmentInstancesListPage.tsx +++ b/src/Pages/EquipmentInstancesListPage/EquipmentInstancesListPage.tsx @@ -11,8 +11,13 @@ import TableHead from "@mui/material/TableHead"; import TableRow from "@mui/material/TableRow"; import Paper from "@mui/material/Paper"; import { colors } from "../../styles"; +import EditItemModal from "../../Components/EditItemModal/EditItemModal"; +import { useState } from "react"; +import Popup from "reactjs-popup"; export default function EquipmentInstancesListPage() { + const [editmodalOpen, SetEditModalOpen] = useState(false); + const [selectedItem, SetSelectedItem] = useState(0); const equipment_instances = useQuery({ queryKey: ["equipment_instances"], queryFn: EquipmentInstancesAPI, @@ -88,7 +93,8 @@ export default function EquipmentInstancesListPage() { key={equipment.id} sx={{ "&:last-child td, &:last-child th": { border: 0 } }} onClick={() => { - console.log("HEH"); + SetSelectedItem(equipment.id); + SetEditModalOpen(true); }} > @@ -129,6 +135,25 @@ export default function EquipmentInstancesListPage() {
+ SetEditModalOpen(false)} + modal + position={"top center"} + contentStyle={{ + width: "512px", + borderRadius: 16, + borderColor: "grey", + borderStyle: "solid", + borderWidth: 1, + padding: 16, + alignContent: "center", + justifyContent: "center", + textAlign: "center", + }} + > + + ); }