diff --git a/src/App.js b/src/App.js
index 89cf7e2..0376d49 100644
--- a/src/App.js
+++ b/src/App.js
@@ -2,11 +2,52 @@ import { useState } from "react";
import "antd/dist/reset.css";
import "./App.css";
import Login from "./Pages/Login";
-import { Layout, message, notification } from "antd";
-import { UseUserSession, WebSocketProvider } from "./utils";
+import { Layout, notification } from "antd";
+import { UseUserSession } from "./utils";
import DashboardLayout from "./Components/DashboardLayout";
+import WebSocketProvider from "./Contexts/WebSocketContext";
+import SideBarProvider from "./Contexts/SideBarContext";
+import { AppProvider } from "./Contexts/AppContext";
export default function App() {
+ const { userSession, setUserSession } = UseUserSession();
+ const [isWebSocketReady, setIsWebSocketReady] = useState(true);
+
+ if (!userSession) {
+ return ;
+ }
+
+ console.info(
+ "\n %c Admin Dashboard %c v0.1.0 %c \n",
+ "background-color: #555;color: #fff;padding: 3px 2px 3px 3px;border-radius: 3px 0 0 3px;font-family: DejaVu Sans,Verdana,Geneva,sans-serif;text-shadow: 0 1px 0 rgba(1, 1, 1, 0.3)",
+ "background-color: #bc81e0;background-image: linear-gradient(90deg, #e67e22, #9b59b6);color: #fff;padding: 3px 3px 3px 2px;border-radius: 0 3px 3px 0;font-family: DejaVu Sans,Verdana,Geneva,sans-serif;text-shadow: 0 1px 0 rgba(1, 1, 1, 0.3)",
+ "background-color: transparent"
+ );
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
+
+/*export default function App() {
const [notificationApi, notificationContextHolder] =
notification.useNotification();
const { userSession, setUserSession } = UseUserSession();
@@ -26,6 +67,7 @@ export default function App() {
return (
{notificationContextHolder}
+
);
-}
+} */
-const ReconnectingView = ({ webSocketIsReady }) => {
+const ReconnectingView = ({ isWebSocketReady }) => {
return (
{
right: 0,
bottom: 0,
backgroundColor: "rgba(0, 0, 0, 0.8)",
- display: webSocketIsReady ? "none" : "block",
+ display: isWebSocketReady ? "none" : "block",
justifyContent: "center",
alignItems: "center",
zIndex: 9999,
diff --git a/src/Components/AppRoutes/index.js b/src/Components/AppRoutes/index.js
index 04b051e..6a07580 100644
--- a/src/Components/AppRoutes/index.js
+++ b/src/Components/AppRoutes/index.js
@@ -11,11 +11,12 @@ import Scanners from "../../Pages/Scanners";
import AdminAreaRoles from "../../Pages/AdminArea/Roles";
import AdminAreaLogs from "../../Pages/AdminArea/Logs";
import AllUsers from "../../Pages/AllUsers";
-import { useContext } from "react";
import GroupTasks from "../../Pages/GroupTasks/Overview";
import GroupTasksHistory from "../../Pages/GroupTasks/History";
import PageNotFound from "../../Pages/PageNotFound";
import EquipmentDocumentationOverview from "../../Pages/EquipmentDocumentation";
+import { UserProfileProvider } from "../../Contexts/UserProfileContext";
+import { UsersProvider } from "../../Contexts/UsersContext";
export default function AppRoutes() {
// const webSocketContext = useContext(WebSocketContext);
@@ -79,9 +80,23 @@ export default function AppRoutes() {
} />
-
} />
+
+
+
+ }
+ />
- } />
+
+
+
+ }
+ />
} />
diff --git a/src/Components/MyAvatar/index.js b/src/Components/MyAvatar/index.js
index 84c237a..77b63b0 100644
--- a/src/Components/MyAvatar/index.js
+++ b/src/Components/MyAvatar/index.js
@@ -58,3 +58,16 @@ export function MyAvatar({
return ;
}
+
+export function MyUserAvatar({ avatar, size = "default" }) {
+ if (avatar === "") {
+ return } />;
+ }
+
+ return (
+
+ );
+}
diff --git a/src/Components/MyTypography/index.js b/src/Components/MyTypography/index.js
index 462a47b..19ba0ad 100644
--- a/src/Components/MyTypography/index.js
+++ b/src/Components/MyTypography/index.js
@@ -1,7 +1,6 @@
import { EditOutlined } from "@ant-design/icons";
import { Input, Typography } from "antd";
import { useState } from "react";
-import { Constants } from "../../utils";
export default function MyTypography({ value, setValue, maxLength }) {
const [editing, setEditing] = useState(false);
diff --git a/src/Components/SideMenu/index.js b/src/Components/SideMenu/index.js
index 442f033..3310e69 100644
--- a/src/Components/SideMenu/index.js
+++ b/src/Components/SideMenu/index.js
@@ -14,15 +14,11 @@ import Sider from "antd/es/layout/Sider";
import { useContext, useEffect, useState } from "react";
import { useLocation, useNavigate } from "react-router-dom";
import PropTypes from "prop-types";
-import {
- Constants,
- WebSocketContext,
- getUserId,
- hasOnePermission,
- hasPermission,
-} from "../../utils";
+import { Constants, hasOnePermission, hasPermission } from "../../utils";
import { useTranslation } from "react-i18next";
-import { MyAvatar } from "../MyAvatar";
+import { MyUserAvatar } from "../MyAvatar";
+import { useSideBarContext } from "../../Contexts/SideBarContext";
+import { useAppContext } from "../../Contexts/AppContext";
export default function SideMenu({
userSession,
@@ -30,9 +26,10 @@ export default function SideMenu({
isSideMenuCollapsed,
setIsSideMenuCollapsed,
}) {
+ const appContext = useAppContext();
+ const sidebarContext = useSideBarContext();
const location = useLocation();
const [selectedKeys, setSelectedKeys] = useState("/");
- const webSocketContext = useContext(WebSocketContext);
const { t } = useTranslation();
useEffect(() => setSelectedKeys(location.pathname), [location.pathname]);
@@ -40,13 +37,17 @@ export default function SideMenu({
const navigate = useNavigate();
const getCurrentUsedScannerName = () => {
- const scannerName = webSocketContext.Scanners.find(
+ /*const scannerName = webSocketContext.Scanners.find(
(scanner) => scanner.UsedByUserId === getUserId()
)?.Name;
return scannerName === undefined
? t("sideMenu.adminArea.noScannerSelected")
- : scannerName;
+ : scannerName; */
+
+ // TODO: handle scanner name
+
+ return Constants.LOADING;
};
const getFirstMenuItems = () => {
@@ -57,19 +58,19 @@ export default function SideMenu({
key: "/",
},
];
- /*
+
if (
hasPermission(
- webSocketContext.User.Permissions,
+ appContext.userPermissions,
Constants.PERMISSIONS.EQUIPMENT_DOCUMENTATION.VIEW
)
- ) { */
- items.push({
- label: t("sideMenu.equipmentDocumentation"),
- icon: ,
- key: "/equipment-documentation",
- });
- //}
+ ) {
+ items.push({
+ label: t("sideMenu.equipmentDocumentation"),
+ icon: ,
+ key: "/equipment-documentation",
+ });
+ }
let groupTasks = {
label: t("sideMenu.groupTasks.menuCategory"),
@@ -85,7 +86,7 @@ export default function SideMenu({
if (
hasPermission(
- webSocketContext.User.Permissions,
+ appContext.userPermissions,
Constants.PERMISSIONS.GROUP_TASKS.HISTORY
)
) {
@@ -104,7 +105,7 @@ export default function SideMenu({
if (
hasOnePermission(
- webSocketContext.User.Permissions,
+ appContext.userPermissions,
Constants.PERMISSIONS.ADMIN_AREA.ROLES.CREATE_NEW_ROLE,
Constants.PERMISSIONS.ADMIN_AREA.ROLES.UPDATE_ROLE,
Constants.PERMISSIONS.ADMIN_AREA.ROLES.DELETE_ROLE,
@@ -121,7 +122,7 @@ export default function SideMenu({
if (
hasOnePermission(
- webSocketContext.User.Permissions,
+ appContext.userPermissions,
Constants.PERMISSIONS.ADMIN_AREA.ROLES.CREATE_NEW_ROLE,
Constants.PERMISSIONS.ADMIN_AREA.ROLES.UPDATE_ROLE,
Constants.PERMISSIONS.ADMIN_AREA.ROLES.DELETE_ROLE,
@@ -137,7 +138,7 @@ export default function SideMenu({
if (
hasPermission(
- webSocketContext.User.Permissions,
+ appContext.userPermissions,
Constants.PERMISSIONS.ADMIN_AREA.LOGS
)
) {
@@ -155,11 +156,13 @@ export default function SideMenu({
};
const getSecondMenuItems = () => {
+ console.log("getSecondMenuItems", sidebarContext.connectionBadgeStatus);
+
let items = [];
if (
hasPermission(
- webSocketContext.User.Permissions,
+ appContext.userPermissions,
Constants.PERMISSIONS.SCANNER.USE_SCANNERS
)
) {
@@ -174,9 +177,9 @@ export default function SideMenu({
{
icon: (
- ),
+ label: ` ${appContext.username}`,
+ icon: ,
key: "/user-profile",
},
{
@@ -216,6 +214,11 @@ export default function SideMenu({
return items;
};
+ console.log(
+ "sidebarContext.connectionBadgeStatus",
+ sidebarContext.connectionBadgeStatus
+ );
+
return (
useContext(AppContext);
+
+export function AppProvider({ children }) {
+ const [username, setUsername] = useState(Constants.LOADING);
+ const [avatar, setAvatar] = useState("");
+ const [userPermissions, setUserPermissions] = useState([]);
+ const [availableGroupTasks, setAvailableGroupTasks] = useState([]);
+
+ return (
+
+ {children}
+
+ );
+}
diff --git a/src/Contexts/SideBarContext.js b/src/Contexts/SideBarContext.js
new file mode 100644
index 0000000..7595972
--- /dev/null
+++ b/src/Contexts/SideBarContext.js
@@ -0,0 +1,32 @@
+import { createContext, useContext, useState } from "react";
+
+const preview = {
+ connectionBadgeStatus: "",
+ connectedUsers: 0,
+ selectedScanner: "",
+};
+
+const SideBarContext = createContext(preview);
+
+export const useSideBarContext = () => useContext(SideBarContext);
+
+export default function SideBarProvider({ children }) {
+ const [connectionBadgeStatus, setConnectionBadgeStatus] = useState("error");
+ const [connectedUsers, setConnectedUsers] = useState(0);
+ const [selectedScanner, setSelectedScanner] = useState("");
+
+ return (
+
+ {children}
+
+ );
+}
diff --git a/src/Contexts/UserProfileContext.js b/src/Contexts/UserProfileContext.js
new file mode 100644
index 0000000..ca85951
--- /dev/null
+++ b/src/Contexts/UserProfileContext.js
@@ -0,0 +1,26 @@
+import { createContext, useContext, useState } from "react";
+import { Constants } from "../utils";
+
+// only for tab completion
+const preview = {
+ id: Constants.LOADING,
+ avatar: "",
+ username: Constants.LOADING,
+ email: Constants.LOADING,
+ sessions: [],
+ apiKeys: [],
+};
+
+const UserProfileContext = createContext({ userProfile: preview });
+
+export const useUserProfileContext = () => useContext(UserProfileContext);
+
+export function UserProfileProvider({ children }) {
+ const [userProfile, setUserProfile] = useState(preview);
+
+ return (
+
+ {children}
+
+ );
+}
diff --git a/src/Contexts/UsersContext.js b/src/Contexts/UsersContext.js
new file mode 100644
index 0000000..f3ba0c7
--- /dev/null
+++ b/src/Contexts/UsersContext.js
@@ -0,0 +1,32 @@
+import { createContext, useContext, useState } from "react";
+
+const preview = {
+ roleId: "",
+ users: [],
+ roles: [],
+};
+
+const UsersContext = createContext(preview);
+
+export const useUsersContext = () => useContext(UsersContext);
+
+export function UsersProvider({ children }) {
+ const [roleId, setRoleId] = useState("");
+ const [users, setUsers] = useState([]);
+ const [roles, setRoles] = useState([]);
+
+ return (
+
+ {children}
+
+ );
+}
diff --git a/src/Contexts/WebSocketContext.js b/src/Contexts/WebSocketContext.js
new file mode 100644
index 0000000..9a3ae3b
--- /dev/null
+++ b/src/Contexts/WebSocketContext.js
@@ -0,0 +1,100 @@
+import { createContext, useContext, useEffect, useRef, useState } from "react";
+import { Constants, ReceivedMessagesCommands, myFetch } from "../utils";
+import { useSideBarContext } from "./SideBarContext";
+import { useAppContext } from "./AppContext";
+import { message } from "antd";
+
+const WebSocketContext = createContext(null);
+
+export const useWebSocketContext = () => useContext(WebSocketContext);
+
+export default function WebSocketProvider({
+ children,
+ userSession,
+ setUserSession,
+ isWebSocketReady,
+ setIsWebSocketReady,
+}) {
+ const ws = useRef(null);
+ const appContext = useAppContext();
+ const sideBarContext = useSideBarContext();
+
+ const connect = () => {
+ ws.current = new WebSocket(`${Constants.WS_ADDRESS}?auth=${userSession}`);
+
+ ws.current.onopen = () => {
+ console.log("connected");
+ sideBarContext.setConnectionBadgeStatus("success");
+ setIsWebSocketReady(true);
+
+ myFetch("/user/", "GET").then((data) => {
+ console.log("user info", data);
+
+ appContext.setUsername(data.Username);
+ appContext.setAvatar(data.Avatar);
+ appContext.setUserPermissions(data.Permissions);
+ appContext.setAvailableGroupTasks(data.AvailableGroupTasks);
+ });
+ };
+
+ ws.current.onmessage = (event) => {
+ const data = JSON.parse(event.data);
+ console.log("received message", data);
+
+ const cmd = data.Cmd;
+ const body = data.Body;
+
+ switch (cmd) {
+ case ReceivedMessagesCommands.UpdateConnectedUsers:
+ sideBarContext.setConnectedUsers(body.WebSocketUsersCount);
+ break;
+ }
+ };
+
+ ws.current.onclose = (event) => {
+ setIsWebSocketReady(false);
+ sideBarContext.setConnectionBadgeStatus("error");
+ console.warn("closed", event);
+
+ // custom code defined by the backend server
+ if (event.code === 4001 || event.code === 4002) {
+ //Unauthorized || SessionClosed
+
+ setUserSession();
+ window.location.href = "/";
+ return;
+ }
+
+ if (event.reason.code === 1005) return;
+
+ console.warn("reconnecting...");
+
+ setTimeout(() => connect(), 1000);
+ };
+ };
+
+ const SendSocketMessage = (cmd, body) => {
+ if (isWebSocketReady) {
+ ws.current.send(JSON.stringify({ Cmd: cmd, Body: body }));
+ } else {
+ /*notificationApi["error"]({
+ message: `Websocket is not ready`,
+ description: `Please check your internet connection`,
+ }); */
+
+ message.error(`Websocket is not ready`);
+ }
+ };
+
+ useEffect(() => {
+ connect();
+
+ return () => ws.current.close();
+ }, []);
+
+ return (
+
+ {children}
+
+ );
+}
diff --git a/src/Handlers/WebSocketMessageHandler.js b/src/Handlers/WebSocketMessageHandler.js
new file mode 100644
index 0000000..b52cd90
--- /dev/null
+++ b/src/Handlers/WebSocketMessageHandler.js
@@ -0,0 +1 @@
+export function handleWebSocketMessage(message) {}
diff --git a/src/Pages/AllUsers/index.js b/src/Pages/AllUsers/index.js
index 09d693c..7ec9222 100644
--- a/src/Pages/AllUsers/index.js
+++ b/src/Pages/AllUsers/index.js
@@ -12,20 +12,25 @@ import {
Constants,
FormatDatetime,
SentMessagesCommands,
- WebSocketContext,
getConnectionStatusItem,
hasOnePermission,
hasPermission,
+ myFetch,
} from "../../utils";
-import { useContext, useState } from "react";
+import { useEffect, useState } from "react";
import { Link } from "react-router-dom";
import { UserAddOutlined } from "@ant-design/icons";
import CreateUserModal from "./CreateUserModal";
import { useTranslation } from "react-i18next";
import { MyAvatar } from "../../Components/MyAvatar";
+import { useUsersContext } from "../../Contexts/UsersContext";
+import { useAppContext } from "../../Contexts/AppContext";
+import { useWebSocketContext } from "../../Contexts/WebSocketContext";
export default function AllUsers() {
- const webSocketContext = useContext(WebSocketContext);
+ const webSocketContext = useWebSocketContext();
+ const appContext = useAppContext();
+ const usersContext = useUsersContext();
const { t } = useTranslation();
const [selectedRoleId, setSelectedRoleId] = useState("");
const [notificationApi, notificationContextHolder] =
@@ -63,7 +68,7 @@ export default function AllUsers() {
if (
hasOnePermission(
- webSocketContext.User.Permissions,
+ appContext.userPermissions,
Constants.PERMISSIONS.ALL_USERS.ACTION.CHANGE_ROLE,
Constants.PERMISSIONS.ALL_USERS.ACTION.DELETE_USER,
Constants.PERMISSIONS.ALL_USERS.ACTION.DEACTIVATE_USER
@@ -75,17 +80,16 @@ export default function AllUsers() {
render: (_, record) => (
{hasPermission(
- webSocketContext.User.Permissions,
+ appContext.userPermissions,
Constants.PERMISSIONS.ALL_USERS.ACTION.CHANGE_ROLE
) &&
- (webSocketContext.AllRoles.find(
- (role) => role.Id === webSocketContext.User.RoleId
+ (usersContext.roles.find(
+ (role) => role.Id === usersContext.roleId
).SortingOrder <
- webSocketContext.AllRoles.find(
- (role) => role.Id === record._roleId
- ).SortingOrder ||
- webSocketContext.AllRoles.find(
- (role) => role.Id === webSocketContext.User.RoleId
+ usersContext.roles.find((role) => role.Id === record._roleId)
+ .SortingOrder ||
+ usersContext.roles.find(
+ (role) => role.Id === usersContext.roleId
).Master) && (
user.Id === record.key
- ).RoleId,
+ usersContext.users.find((user) => user.Id === record.key)
+ .RoleId,
}}
description={