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 ( -
{ - dispatch(cleanError()); - }} - > - { - // errorMessage.map((err, index) =>

{err}

) - } +import { cleanError, ErrorStateAlert } from "../store/reducers/errorReducer"; -
- ); +const Error = ({ errorMessage }: { errorMessage: Array }) => { + const dispatch = useDispatch(); + return ( +
{ + dispatch(cleanError()); + }} + > + {errorMessage.map((err, index) => ( +

+ {err.message} +

+ ))} +
+ ); }; 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([]) - const [fetchChange, setFetchChange] = useState(false) - const [gatewayData, setGatewayData] = useState({ + const [listOfGateways, setListOfGateways] = useState< + GateWayCreateInterface[] + >([]); + const dispatch = useDispatch(); + const [fetchChange, setFetchChange] = useState(false); + const [gatewayData, setGatewayData] = useState({ + name: "", + password: "", + confirmedPassword: "", + description: "", + }); + + const formData = (e: React.ChangeEvent) => { + 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(false) - const [errorMessage, setErrorMessage] = useState("") - - const formData = (e: React.ChangeEvent) => { - 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 ( - -

Create new GateWay

-
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
+ return ( + +

Create new GateWay

+ +
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
-
-
- -
- {showError &&

{errorMessage}

} -
- -
-
- {listOfGateways.map((gateway: GateWayCreateInterface, index) => ( -
-
-
{gateway.name}
-

Description: {gateway.description}

-

Created by:{gateway.creator} {new Date(gateway.createdAt).toDateString()}

-

Status: Online

-

{ deleteGateWay(index) }}>Delete

-
-
- ))} +
+
+ +
+
+ +
+
+ {listOfGateways.map((gateway: GateWayCreateInterface, index) => ( +
+
+
{gateway.name}
+

+ {" "} + Description: {gateway.description} +

+

+ Created by: + {gateway.creator}{" "} + + {new Date(gateway.createdAt).toDateString()} + +

+

+ Status: {" "} + Online +

+

{ + deleteGateWay(index); + }} + > + Delete +

- - ) -} +
+ ))} +
+ + ); +}; -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(false) - const [users, setUsers] = useState([]) + const dispatch = useDispatch(); + let user: UserInterface = useSelector((data: any) => { + return data.auth.user; + }); + const [listenForChange, setListenForChange] = useState(false); + const [users, setUsers] = useState([]); - 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 ( - -
- { - users.map((userRegular: UserInterface, index) => ( -
-
-
{userRegular.name} {userRegular.surname}
-
    -
  • @ {userRegular.email}
  • -
  • {new Date(userRegular.lastLoggedIn).toLocaleString()}
  • -
  • Approved: {userRegular.isUserApproved ? "Approved" : "Not approved"}
  • -
  • Auth Level: {userRegular.authLevel === "iotadmin" ? "Administrator" : "Regular user"}
  • -
-
-
- {user.email !== userRegular.email && - <> - {!userRegular.isUserApproved && -
-
{ updateUser(index, true) }}>Approve
-
} - {userRegular.isUserApproved &&
-
{ updateUser(index, false) }}>Disapprove
-
} - - - } - { - user.email === userRegular.email && -
- -
    -
  • { - dispatch(authUserFailed()) - }}> - Log-out -
  • -
- -
- } - {user.email !== userRegular.email &&
-
{ deleteUser(index) }}>Delete
-
} - -
-
+ return ( + +
+ {users.map((userRegular: UserInterface, index) => ( +
+
+
+ {userRegular.name} {userRegular.surname} +
+
    +
  • @ {userRegular.email}
  • +
  • + {new Date(userRegular.lastLoggedIn).toLocaleString()} +
  • +
  • + Approved:{" "} + + {userRegular.isUserApproved ? "Approved" : "Not approved"} + +
  • +
  • + Auth Level:{" "} + + {userRegular.authLevel === "iotadmin" + ? "Administrator" + : "Regular user"} + +
  • +
+
+
+ {user.email !== userRegular.email && ( + <> + {!userRegular.isUserApproved && ( +
+
{ + updateUser(index, true); + }} + > + Approve +
+
+ )} + {userRegular.isUserApproved && ( +
+
{ + updateUser(index, false); + }} + > + Disapprove
- )) - } +
+ )} + + )} + {user.email === userRegular.email && ( +
+
    +
  • { + dispatch(authUserFailed()); + }} + > + + Log-out + +
  • +
+
+ )} + {user.email !== userRegular.email && ( +
+
{ + deleteUser(index); + }} + > + Delete +
+
+ )} +
- ); +
+ ))} +
+
+ ); }; 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; + show: boolean; +} + +export type ErrorReducers = { + setError: (state: ErrorState, action: { payload: string }) => void; + cleanError: (state: ErrorState) => void; +}; + +export const errorSlice = createSlice({ 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) => {