From 2fdaa6d61d963522e0c07676f3d10d1da3a8cb53 Mon Sep 17 00:00:00 2001
From: JAN VOJACEK <vojacekjan@hotmail.com>
Date: Mon, 30 May 2022 12:19:25 +0200
Subject: [PATCH] Display errors from manage pages properly through error
 reducer

---
 client/src/components/Error.tsx               |  58 +--
 .../src/routes/AdminRoutes/ManageGateways.tsx | 374 +++++++++++-------
 client/src/routes/AdminRoutes/ManageUsers.tsx | 311 +++++++++------
 client/src/store/reducers/errorReducer.ts     |  22 +-
 4 files changed, 466 insertions(+), 299 deletions(-)

diff --git a/client/src/components/Error.tsx b/client/src/components/Error.tsx
index bb50ef9..558bb2b 100644
--- a/client/src/components/Error.tsx
+++ b/client/src/components/Error.tsx
@@ -1,29 +1,39 @@
 import { useDispatch } from "react-redux";
-import { cleanError } from "../store/reducers/errorReducer"
-const Error = ({ errorMessage }: { errorMessage: [] }) => {
-    const dispatch = useDispatch();
-    console.log(errorMessage)
-    return (
-        <div style={{
-            display: "flex",
-            justifyContent: "center",
-            alignItems: "center",
-            position: "fixed",
-            zIndex: 99999,
-            width: "100%",
-            height: "100%",
-            background: "#e5e5e5d1"
-        }}
-            onClick={() => {
-                dispatch(cleanError());
-            }}
-        >
-            {
-                //   errorMessage.map((err, index) => <p key={index} style={{ color: "red", padding: 40, background: "white", borderRadius: 12 }}>{err}</p>)
-            }
+import { cleanError, ErrorStateAlert } from "../store/reducers/errorReducer";
 
-        </div>
-    );
+const Error = ({ errorMessage }: { errorMessage: Array<ErrorStateAlert> }) => {
+  const dispatch = useDispatch();
+  return (
+    <div
+      style={{
+        display: "flex",
+        justifyContent: "center",
+        alignItems: "center",
+        position: "fixed",
+        zIndex: 99999,
+        width: "100%",
+        height: "100%",
+        background: "#e5e5e5d1",
+      }}
+      onClick={() => {
+        dispatch(cleanError());
+      }}
+    >
+      {errorMessage.map((err, index) => (
+        <p
+          key={index}
+          style={{
+            color: "red",
+            padding: 40,
+            background: "white",
+            borderRadius: 12,
+          }}
+        >
+          {err.message}
+        </p>
+      ))}
+    </div>
+  );
 };
 
 export default Error;
diff --git a/client/src/routes/AdminRoutes/ManageGateways.tsx b/client/src/routes/AdminRoutes/ManageGateways.tsx
index 7db3d56..58bdc5f 100644
--- a/client/src/routes/AdminRoutes/ManageGateways.tsx
+++ b/client/src/routes/AdminRoutes/ManageGateways.tsx
@@ -1,167 +1,237 @@
-import React, { useState, useEffect } from 'react'
-import AdminContainer from "../../admin-components/AdminContainer"
-import { GLOBAL_URL } from '../../GLOBAL_URL'
+import React, { useState, useEffect } from "react";
+import AdminContainer from "../../admin-components/AdminContainer";
+import { GLOBAL_URL } from "../../GLOBAL_URL";
+import { useDispatch } from "react-redux";
+import { setError } from "../../store/reducers/errorReducer";
+
 interface GateWayCreateInterface {
-    name: string;
-    password?: string;
-    confirmedPassword?: string;
-    description: string;
-    creator?: string
-    createdAt?: any,
-    _id?: string
+  name: string;
+  password?: string;
+  confirmedPassword?: string;
+  description: string;
+  creator?: string;
+  createdAt?: any;
+  _id?: string;
 }
 const AdminCreateGateway = () => {
-    const [listOfGateways, setListOfGateways] = useState<GateWayCreateInterface[]>([])
-    const [fetchChange, setFetchChange] = useState<boolean>(false)
-    const [gatewayData, setGatewayData] = useState<GateWayCreateInterface>({
+  const [listOfGateways, setListOfGateways] = useState<
+    GateWayCreateInterface[]
+  >([]);
+  const dispatch = useDispatch();
+  const [fetchChange, setFetchChange] = useState<boolean>(false);
+  const [gatewayData, setGatewayData] = useState<GateWayCreateInterface>({
+    name: "",
+    password: "",
+    confirmedPassword: "",
+    description: "",
+  });
+
+  const formData = (e: React.ChangeEvent<HTMLInputElement>) => {
+    setGatewayData({ ...gatewayData, [e.target.name]: e.target.value });
+  };
+  const createGateWay = async (e: any) => {
+    e.preventDefault();
+    const {
+      name,
+      password,
+      confirmedPassword,
+      description,
+    }: GateWayCreateInterface = gatewayData;
+    try {
+      if (!name) throw new Error("Unique name is mising");
+      if (!description) throw new Error("Description is mandatory");
+      if (!password) throw new Error("Password is mandatory");
+      if (!description) throw new Error("Description is mandatory");
+      if (password !== confirmedPassword)
+        throw new Error("Passwords must match!");
+
+      //Fetch call na backend
+      const token: string | null = localStorage.getItem("token");
+      const response: Response = await fetch(`${GLOBAL_URL}/gateway/create/`, {
+        method: "POST",
+        headers: {
+          "Content-type": "application/json",
+          Authorization: `Bearer ${token}_dr_dick`,
+        },
+        body: JSON.stringify({
+          name,
+          description,
+          password,
+        }),
+      });
+      const data: any = await response.json();
+      if (data.statusCode >= 400) throw new Error(data.message);
+      setFetchChange(!fetchChange);
+      setGatewayData({
         name: "",
         password: "",
         confirmedPassword: "",
-        description: ""
-    })
-    const [showError, setShowError] = useState<boolean>(false)
-    const [errorMessage, setErrorMessage] = useState<string>("")
-
-    const formData = (e: React.ChangeEvent<HTMLInputElement>) => {
-        setGatewayData({ ...gatewayData, [e.target.name]: e.target.value })
+        description: "",
+      });
+    } catch (error: any) {
+      if (error) {
+        dispatch(setError(error.message));
+      }
     }
-    const createGateWay = async (e: any) => {
-        e.preventDefault();
-        const { name, password, confirmedPassword, description }: GateWayCreateInterface = gatewayData;
-        try {
-            if (!name) throw new Error("Unique name is mising");
-            if (!description) throw new Error("Description is mandatory");
-            if (!password) throw new Error("Password is mandatory");
-            if (!description) throw new Error("Description is mandatory");
-            if (password !== confirmedPassword) throw new Error("Passwords must match!")
+  };
 
-            //Fetch call na backend
-            const token: string | null = localStorage.getItem("token");
-            const response: Response = await fetch(`${GLOBAL_URL}/gateway/create/`, {
-                method: "POST",
-                headers: {
-                    "Content-type": "application/json",
-                    Authorization: `Bearer ${token}`,
-                },
-                body: JSON.stringify({
-                    name,
-                    description,
-                    password
-                })
-            })
-            const data: any = await response.json();
-            console.log(data)
-            if (data.status) throw new Error(data.message);
-            setFetchChange(!fetchChange)
-            setGatewayData({
-                name: "",
-                password: "",
-                confirmedPassword: "",
-                description: ""
-            })
-        } catch (error: any) {
-            if (error) {
-                setShowError(true);
-                setErrorMessage(error.message)
-                setTimeout(() => {
-                    setShowError(false);
-                    setErrorMessage("");
-                }, 2000)
-            }
-        }
-    }
+  const getAllGateways = async () => {
+    const token: string | null = localStorage.getItem("token");
+    const response: Response = await fetch(`${GLOBAL_URL}/gateway/all/`, {
+      method: "GET",
+      headers: {
+        "Content-type": "application/json",
+        Authorization: `Bearer ${token}`,
+      },
+    });
+    const data: GateWayCreateInterface[] = await response.json();
+    setListOfGateways(data);
+  };
 
-    const getAllGateways = async () => {
-
-        const token: string | null = localStorage.getItem("token");
-        const response: Response = await fetch(`${GLOBAL_URL}/gateway/all/`, {
-            method: "GET",
+  const deleteGateWay = async (index: number) => {
+    const conf = window.confirm(
+      `Do you really want to delete ${listOfGateways[index].name}`
+    );
+    if (conf) {
+      const token: string | null = localStorage.getItem("token");
+      try {
+        const response: Response = await fetch(
+          GLOBAL_URL + `/gateway/delete/${listOfGateways[index]._id}`,
+          {
+            method: "DELETE",
             headers: {
-                "Content-type": "application/json",
-                Authorization: `Bearer ${token}`,
-            }
-        })
-        const data: GateWayCreateInterface[] = await response.json();
-        setListOfGateways(data);
-    }
-
-    const deleteGateWay = async (index: number) => {
-        const conf = window.confirm(`Do you really want to delete ${listOfGateways[index].name}`);
-        if (conf) {
-            const token: string | null = localStorage.getItem("token");
-            try {
-                const response: Response = await fetch(GLOBAL_URL + `/gateway/delete/${listOfGateways[index]._id}`, {
-                    method: "DELETE",
-                    headers: {
-                        "Content-type": "application/json",
-                        Authorization: `Bearer ${token}`,
-                    },
-                })
-                const data: any = await response.json();
-                if (data.error) throw new Error(data.message);
-                setFetchChange(!fetchChange);
-            } catch (error: any) {
-                console.log(error);
-                // dispatch(setError([error]))
-            }
-        }
+              "Content-type": "application/json",
+              Authorization: `Bearer ${token}`,
+            },
+          }
+        );
+        const data: any = await response.json();
+        if (data.error) throw new Error(data.message);
+        setFetchChange(!fetchChange);
+      } catch (error: any) {
+        dispatch(setError(error.message));
+      }
     }
-    useEffect(() => {
-        getAllGateways()
-    }, [fetchChange]);
+  };
+  useEffect(() => {
+    getAllGateways();
+  }, [fetchChange]);
 
-    return (
-        <AdminContainer>
-            <h1>Create new GateWay</h1>
-            <form autoComplete="false" onSubmit={createGateWay} >
-                <div className="form-group row">
-                    <label htmlFor="uniqueName" className="col-sm-2 col-form-label">Unique Name</label>
-                    <div className="col-sm-10">
-                        <input onChange={formData} value={gatewayData.name} type="text" name="name" placeholder="Some really cool gateway" />
-                    </div>
-                </div>
-                <div className="form-group row">
-                    <label htmlFor="inputPassword3" className="col-sm-2 col-form-label">Password</label>
-                    <div className="col-sm-10">
-                        <input onChange={formData} value={gatewayData.password} type="password" className="form-control" name="password" placeholder="Password" />
-                    </div>
-                </div>
-                <div className="form-group row">
-                    <label htmlFor="inputPassword3" className="col-sm-2 col-form-label">Confirm password</label>
-                    <div className="col-sm-10">
-                        <input onChange={formData} value={gatewayData.confirmedPassword} type="password" className="form-control" name="confirmedPassword" placeholder="Password" />
-                    </div>
-                </div>
-                <div className="form-group row">
-                    <label htmlFor="inputPassword3" className="col-sm-2 col-form-label">Detailed purpose of Gateway / Description</label>
-                    <div className="col-sm-10">
-                        <input onChange={formData} value={gatewayData.description} className="form-control" name="description" placeholder={"Please, be super descriptive what is the purpose of the new gateway"}></input>
-                    </div>
-                </div>
+  return (
+    <AdminContainer>
+      <h1>Create new GateWay</h1>
+      <form autoComplete="false" onSubmit={createGateWay}>
+        <div className="form-group row">
+          <label htmlFor="uniqueName" className="col-sm-2 col-form-label">
+            Unique Name
+          </label>
+          <div className="col-sm-10">
+            <input
+              onChange={formData}
+              value={gatewayData.name}
+              type="text"
+              name="name"
+              placeholder="Some really cool gateway"
+            />
+          </div>
+        </div>
+        <div className="form-group row">
+          <label htmlFor="inputPassword3" className="col-sm-2 col-form-label">
+            Password
+          </label>
+          <div className="col-sm-10">
+            <input
+              onChange={formData}
+              value={gatewayData.password}
+              type="password"
+              className="form-control"
+              name="password"
+              placeholder="Password"
+            />
+          </div>
+        </div>
+        <div className="form-group row">
+          <label htmlFor="inputPassword3" className="col-sm-2 col-form-label">
+            Confirm password
+          </label>
+          <div className="col-sm-10">
+            <input
+              onChange={formData}
+              value={gatewayData.confirmedPassword}
+              type="password"
+              className="form-control"
+              name="confirmedPassword"
+              placeholder="Password"
+            />
+          </div>
+        </div>
+        <div className="form-group row">
+          <label htmlFor="inputPassword3" className="col-sm-2 col-form-label">
+            Detailed purpose of Gateway / Description
+          </label>
+          <div className="col-sm-10">
+            <input
+              onChange={formData}
+              value={gatewayData.description}
+              className="form-control"
+              name="description"
+              placeholder={
+                "Please, be super descriptive what is the purpose of the new gateway"
+              }
+            ></input>
+          </div>
+        </div>
 
-                <div className="form-group row">
-                    <div className="col-sm-10">
-                        <button type="submit" className="btn btn-primary">Create new GateWay {gatewayData.name}</button>
-                    </div>
-                    {showError && <p className='btn-danger'>{errorMessage}</p>}
-                </div>
-            </form>
-            <hr />
-            <div className="listOfUsers" style={{ display: "flex", flexDirection: "row", flexWrap: "wrap" }}>
-                {listOfGateways.map((gateway: GateWayCreateInterface, index) => (
-                    <div key={index} className="card" style={{ width: "23rem", margin: 10 }}>
-                        <div className="card-body">
-                            <h5 className="card-header">{gateway.name}</h5>
-                            <p className="card-text"> <strong>Description: </strong> {gateway.description}</p>
-                            <p className="card-text"><strong>Created by:</strong>{gateway.creator} <span style={{ fontSize: 10 }}>{new Date(gateway.createdAt).toDateString()}</span></p>
-                            <p className="card-text"><strong>Status: </strong> <span style={{ color: "green" }}>Online</span></p>
-                            <p className="btn btn-danger" onClick={() => { deleteGateWay(index) }}>Delete</p>
-                        </div>
-                    </div>
-                ))}
+        <div className="form-group row">
+          <div className="col-sm-10">
+            <button type="submit" className="btn btn-primary">
+              Create new GateWay {gatewayData.name}
+            </button>
+          </div>
+        </div>
+      </form>
+      <hr />
+      <div
+        className="listOfUsers"
+        style={{ display: "flex", flexDirection: "row", flexWrap: "wrap" }}
+      >
+        {listOfGateways.map((gateway: GateWayCreateInterface, index) => (
+          <div
+            key={index}
+            className="card"
+            style={{ width: "23rem", margin: 10 }}
+          >
+            <div className="card-body">
+              <h5 className="card-header">{gateway.name}</h5>
+              <p className="card-text">
+                {" "}
+                <strong>Description: </strong> {gateway.description}
+              </p>
+              <p className="card-text">
+                <strong>Created by:</strong>
+                {gateway.creator}{" "}
+                <span style={{ fontSize: 10 }}>
+                  {new Date(gateway.createdAt).toDateString()}
+                </span>
+              </p>
+              <p className="card-text">
+                <strong>Status: </strong>{" "}
+                <span style={{ color: "green" }}>Online</span>
+              </p>
+              <p
+                className="btn btn-danger"
+                onClick={() => {
+                  deleteGateWay(index);
+                }}
+              >
+                Delete
+              </p>
             </div>
-        </AdminContainer>
-    )
-}
+          </div>
+        ))}
+      </div>
+    </AdminContainer>
+  );
+};
 
-export default AdminCreateGateway
\ No newline at end of file
+export default AdminCreateGateway;
diff --git a/client/src/routes/AdminRoutes/ManageUsers.tsx b/client/src/routes/AdminRoutes/ManageUsers.tsx
index 417291d..705072d 100644
--- a/client/src/routes/AdminRoutes/ManageUsers.tsx
+++ b/client/src/routes/AdminRoutes/ManageUsers.tsx
@@ -7,136 +7,205 @@ import { authUserFailed } from "../../store/reducers/auth";
 import { setError } from "../../store/reducers/errorReducer";
 import { GLOBAL_URL } from "../../GLOBAL_URL";
 const AdminPanel = () => {
-    const dispatch = useDispatch();
-    let user: UserInterface = useSelector((data: any) => {
-        return data.auth.user;
-    })
-    const [listenForChange, setListenForChange] = useState<boolean>(false)
-    const [users, setUsers] = useState<UserInterface[]>([])
+  const dispatch = useDispatch();
+  let user: UserInterface = useSelector((data: any) => {
+    return data.auth.user;
+  });
+  const [listenForChange, setListenForChange] = useState<boolean>(false);
+  const [users, setUsers] = useState<UserInterface[]>([]);
 
-    useEffect(() => {
-        getAllUsers();
-        // eslint-disable-next-line react-hooks/exhaustive-deps
-    }, [listenForChange]);
-    //Fetch all users - Admin required
-    const getAllUsers = async () => {
-        try {
-            const token: string | null = localStorage.getItem("token");
-            const response: Response = await fetch(GLOBAL_URL + "/users/all", {
-                method: "get",
-                headers: {
-                    "Content-type": "application/json",
-                    Authorization: `Bearer ${token}`,
-                },
-            })
-            const data: any = await response.json();
-            if (data.statusCode === 401) {
-                dispatch(authUserFailed());
-            }
-            setUsers(data);
-
-        } catch (error: any) {
-            if (error) {
-                dispatch(setError(error.message));
-            }
-        }
+  useEffect(() => {
+    getAllUsers();
+    // eslint-disable-next-line react-hooks/exhaustive-deps
+  }, [listenForChange]);
+  //Fetch all users - Admin required
+  const getAllUsers = async () => {
+    try {
+      const token: string | null = localStorage.getItem("token");
+      const response: Response = await fetch(GLOBAL_URL + "/users/all", {
+        method: "get",
+        headers: {
+          "Content-type": "application/json",
+          Authorization: `Bearer ${token}`,
+        },
+      });
+      const data: any = await response.json();
+      if (data.statusCode === 401) {
+        dispatch(authUserFailed());
+      }
+      setUsers(data);
+    } catch (error: any) {
+      if (error) {
+        dispatch(setError(error.message));
+      }
     }
+  };
 
-    const updateUser = async (index: number, action: boolean) => {
-        const token: string | null = localStorage.getItem("token");
-        try {
-            const response: Response = await fetch(GLOBAL_URL + `/users/update/${users[index]._id}`, {
-                method: "PATCH",
-                headers: {
-                    "Content-type": "application/json",
-                    Authorization: `Bearer ${token}`,
-                },
-                body: JSON.stringify({
-                    isUserApproved: action
-                })
-            })
-            const data: any = await response.json();
-            if (!data) throw new Error("User could not be updated");
-            setListenForChange(!listenForChange);
-        } catch (error: any) {
-            dispatch(setError([error]))
+  const updateUser = async (index: number, action: boolean) => {
+    const token: string | null = localStorage.getItem("token");
+    try {
+      const response: Response = await fetch(
+        GLOBAL_URL + `/users/update/${users[index]._id}`,
+        {
+          method: "PATCH",
+          headers: {
+            "Content-type": "application/json",
+            Authorization: `Bearer ${token}`,
+          },
+          body: JSON.stringify({
+            isUserApproved: action,
+          }),
         }
+      );
+      const data: any = await response.json();
+      if (!data) throw new Error("User could not be updated");
+      setListenForChange(!listenForChange);
+    } catch (error: any) {
+      dispatch(setError(error.message));
     }
-    const deleteUser = async (index: number) => {
-        const conf = window.confirm(`Do you really want to delete ${users[index].email}`);
-        if (conf) {
-            const token: string | null = localStorage.getItem("token");
-            try {
-                const response: Response = await fetch(GLOBAL_URL + `/users/delete/${users[index]._id}`, {
-                    method: "DELETE",
-                    headers: {
-                        "Content-type": "application/json",
-                        Authorization: `Bearer ${token}`,
-                    },
-                })
-                const data: any = await response.json();
-                if (data.error) throw new Error(data.message);
-                setListenForChange(!listenForChange);
-            } catch (error: any) {
-                dispatch(setError([error]))
-            }
-        }
+  };
+  const deleteUser = async (index: number) => {
+    const conf = window.confirm(
+      `Do you really want to delete ${users[index].email}`
+    );
+    if (conf) {
+      const token: string | null = localStorage.getItem("token");
+      try {
+        const response: Response = await fetch(
+          GLOBAL_URL + `/users/delete/${users[index]._id}`,
+          {
+            method: "DELETE",
+            headers: {
+              "Content-type": "application/json",
+              Authorization: `Bearer ${token}`,
+            },
+          }
+        );
+        const data: any = await response.json();
+        if (data.error) throw new Error(data.message);
+        setListenForChange(!listenForChange);
+      } catch (error: any) {
+        dispatch(setError(error.message));
+      }
     }
+  };
 
-
-    return (
-        <AdminContainer>
-            <div className="listOfUsers" style={{ display: "flex", flexDirection: "row", flexWrap: "wrap" }}>
-                {
-                    users.map((userRegular: UserInterface, index) => (
-                        <div key={index} className="card text-center" style={{ width: "23rem", margin: 10 }}>
-                            <div className="card-body">
-                                <h5 className="card-header">{userRegular.name} {userRegular.surname}</h5>
-                                <ul className="list-group list-group-flush">
-                                    <li className="list-group-item">@ {userRegular.email}</li>
-                                    <li className="list-group-item" style={{ fontSize: 11 }}>{new Date(userRegular.lastLoggedIn).toLocaleString()}</li>
-                                    <li className="list-group-item">Approved: <span style={userRegular.isUserApproved ? { color: "green" } : { color: "red" }}>{userRegular.isUserApproved ? "Approved" : "Not approved"}</span></li>
-                                    <li className="list-group-item">Auth Level: <span style={userRegular.authLevel === "iotadmin" ? { color: "#ff8227", fontWeight: "bold" } : { color: "green" }}>{userRegular.authLevel === "iotadmin" ? "Administrator" : "Regular user"}</span></li>
-                                </ul>
-                                <br />
-                                <div className="row">
-                                    {user.email !== userRegular.email &&
-                                        <>
-                                            {!userRegular.isUserApproved &&
-                                                <div className="col-sm-4">
-                                                    <div className="btn btn-primary btn-success" onClick={() => { updateUser(index, true) }}>Approve</div>
-                                                </div>}
-                                            {userRegular.isUserApproved && <div className="col-sm-4">
-                                                <div className="btn btn-primary btn-warning" onClick={() => { updateUser(index, false) }}>Disapprove</div>
-                                            </div>}
-
-                                        </>
-                                    }
-                                    {
-                                        user.email === userRegular.email &&
-                                        <div>
-
-                                            <ul className="list-group list-group-flush">
-                                                <li className="list-group-item" onClick={() => {
-                                                    dispatch(authUserFailed())
-                                                }}>
-                                                    <span style={{ color: "red" }} className="nav-link btn btn-sm btn-outline-secondary">Log-out</span>
-                                                </li>
-                                            </ul>
-
-                                        </div>
-                                    }
-                                    {user.email !== userRegular.email && <div className="col-sm-4">
-                                        <div className="btn btn-primary btn-danger" onClick={() => { deleteUser(index) }}>Delete</div>
-                                    </div>}
-
-                                </div>
-                            </div>
+  return (
+    <AdminContainer>
+      <div
+        className="listOfUsers"
+        style={{ display: "flex", flexDirection: "row", flexWrap: "wrap" }}
+      >
+        {users.map((userRegular: UserInterface, index) => (
+          <div
+            key={index}
+            className="card text-center"
+            style={{ width: "23rem", margin: 10 }}
+          >
+            <div className="card-body">
+              <h5 className="card-header">
+                {userRegular.name} {userRegular.surname}
+              </h5>
+              <ul className="list-group list-group-flush">
+                <li className="list-group-item">@ {userRegular.email}</li>
+                <li className="list-group-item" style={{ fontSize: 11 }}>
+                  {new Date(userRegular.lastLoggedIn).toLocaleString()}
+                </li>
+                <li className="list-group-item">
+                  Approved:{" "}
+                  <span
+                    style={
+                      userRegular.isUserApproved
+                        ? { color: "green" }
+                        : { color: "red" }
+                    }
+                  >
+                    {userRegular.isUserApproved ? "Approved" : "Not approved"}
+                  </span>
+                </li>
+                <li className="list-group-item">
+                  Auth Level:{" "}
+                  <span
+                    style={
+                      userRegular.authLevel === "iotadmin"
+                        ? { color: "#ff8227", fontWeight: "bold" }
+                        : { color: "green" }
+                    }
+                  >
+                    {userRegular.authLevel === "iotadmin"
+                      ? "Administrator"
+                      : "Regular user"}
+                  </span>
+                </li>
+              </ul>
+              <br />
+              <div className="row">
+                {user.email !== userRegular.email && (
+                  <>
+                    {!userRegular.isUserApproved && (
+                      <div className="col-sm-4">
+                        <div
+                          className="btn btn-primary btn-success"
+                          onClick={() => {
+                            updateUser(index, true);
+                          }}
+                        >
+                          Approve
+                        </div>
+                      </div>
+                    )}
+                    {userRegular.isUserApproved && (
+                      <div className="col-sm-4">
+                        <div
+                          className="btn btn-primary btn-warning"
+                          onClick={() => {
+                            updateUser(index, false);
+                          }}
+                        >
+                          Disapprove
                         </div>
-                    ))
-                }
+                      </div>
+                    )}
+                  </>
+                )}
+                {user.email === userRegular.email && (
+                  <div>
+                    <ul className="list-group list-group-flush">
+                      <li
+                        className="list-group-item"
+                        onClick={() => {
+                          dispatch(authUserFailed());
+                        }}
+                      >
+                        <span
+                          style={{ color: "red" }}
+                          className="nav-link btn btn-sm btn-outline-secondary"
+                        >
+                          Log-out
+                        </span>
+                      </li>
+                    </ul>
+                  </div>
+                )}
+                {user.email !== userRegular.email && (
+                  <div className="col-sm-4">
+                    <div
+                      className="btn btn-primary btn-danger"
+                      onClick={() => {
+                        deleteUser(index);
+                      }}
+                    >
+                      Delete
+                    </div>
+                  </div>
+                )}
+              </div>
             </div>
-        </AdminContainer>);
+          </div>
+        ))}
+      </div>
+    </AdminContainer>
+  );
 };
 
 export default AdminPanel;
diff --git a/client/src/store/reducers/errorReducer.ts b/client/src/store/reducers/errorReducer.ts
index 25d0a8a..72110b6 100644
--- a/client/src/store/reducers/errorReducer.ts
+++ b/client/src/store/reducers/errorReducer.ts
@@ -1,5 +1,20 @@
 import { createSlice } from "@reduxjs/toolkit";
-export const errorSlice = createSlice({
+
+export interface ErrorStateAlert {
+  message: string;
+}
+
+export interface ErrorState {
+  alerts: Array<ErrorStateAlert>;
+  show: boolean;
+}
+
+export type ErrorReducers = {
+  setError: (state: ErrorState, action: { payload: string }) => void;
+  cleanError: (state: ErrorState) => void;
+};
+
+export const errorSlice = createSlice<ErrorState, ErrorReducers, string>({
   name: "alert",
   initialState: {
     alerts: [],
@@ -7,7 +22,10 @@ export const errorSlice = createSlice({
   },
   reducers: {
     setError: (state, action) => {
-      state.alerts = action.payload;
+      console.log(state, action);
+      state.alerts.push({
+        message: action.payload ?? "Unknown error occurred",
+      });
       state.show = true;
     },
     cleanError: (state) => {