diff --git a/src/Components/SideMenu/index.js b/src/Components/SideMenu/index.js
index 8450832..0aea869 100644
--- a/src/Components/SideMenu/index.js
+++ b/src/Components/SideMenu/index.js
@@ -2,14 +2,18 @@ import {
AppstoreOutlined,
LogoutOutlined,
SnippetsOutlined,
- UserOutlined,
} from "@ant-design/icons";
import { Badge, Divider, Menu } from "antd";
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, UseUserSession, WebSocketContext } from "../../utils";
+import {
+ Constants,
+ MyAvatar,
+ UseUserSession,
+ WebSocketContext,
+} from "../../utils";
export default function SideMenu({ setUserSession }) {
const { userSession } = UseUserSession();
@@ -87,8 +91,16 @@ export default function SideMenu({ setUserSession }) {
key: "/users",
},
{
- label: webSocketContext.User.Username,
- icon: ,
+ label: " " + webSocketContext.User.Username,
+ icon: (
+ user.Id === webSocketContext.User.Id
+ )?.Avatar
+ }
+ />
+ ),
key: "/user-profile",
},
{
diff --git a/src/Pages/UserProfile/index.js b/src/Pages/UserProfile/index.js
index 0982c32..6c6276e 100644
--- a/src/Pages/UserProfile/index.js
+++ b/src/Pages/UserProfile/index.js
@@ -1,6 +1,13 @@
-import { Badge, Space, Table } from "antd";
+import { Button, Card, Form, Input, Space, Table, Upload, message } from "antd";
import { useContext } from "react";
-import { Constants, FormatDatetime, WebSocketContext } from "../../utils";
+import {
+ Constants,
+ FormatDatetime,
+ MyAvatar,
+ WebSocketContext,
+ getConnectionStatusItem,
+ getUserSessionFromLocalStorage,
+} from "../../utils";
const columns = [
{
@@ -37,9 +44,7 @@ const columns = [
method: "DELETE",
headers: {
"Content-Type": "application/json",
- "X-Authorization": JSON.parse(
- localStorage.getItem("session")
- ),
+ "X-Authorization": getUserSessionFromLocalStorage(),
},
}).catch((err) => {
console.error(err);
@@ -68,12 +73,7 @@ export default function UserProfile() {
items.push({
key: session.IdForDeletion,
userAgent: session.UserAgent,
- connectionStatus:
- session.ConnectionStatus === 0 ? (
-
- ) : (
-
- ),
+ connectionStatus: getConnectionStatusItem(session.ConnectionStatus),
lastUsed: FormatDatetime(session.LastUsed),
expiresAt: FormatDatetime(session.ExpiresAt),
});
@@ -82,8 +82,60 @@ export default function UserProfile() {
return items;
};
+ const beforeUpload = (file) => {
+ if (file.size > Constants.MAX_AVATAR_SIZE) {
+ message.error(
+ `Image must be smaller than ${
+ Constants.MAX_AVATAR_SIZE / 1024 / 1024
+ } MB`
+ );
+ return false;
+ }
+ return true;
+ };
+
return (
<>
+ Your Profile
+
+
+
+ user.Id === webSocketContext.User.Id
+ )?.Avatar
+ }
+ avatarWidth={200}
+ />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Your Sessions ({webSocketContext.User.Sessions.length})
diff --git a/src/Pages/Users/index.js b/src/Pages/Users/index.js
index c55a187..54f7966 100644
--- a/src/Pages/Users/index.js
+++ b/src/Pages/Users/index.js
@@ -1,5 +1,73 @@
-import { Button } from "antd";
+import { Popover, Table } from "antd";
+import {
+ MyAvatar,
+ WebSocketContext,
+ getConnectionStatusItem,
+} from "../../utils";
+import { useContext } from "react";
+
+const columns = [
+ {
+ title: "Avatar",
+ dataIndex: "avatar",
+ key: "avatar",
+ },
+ {
+ title: "Username",
+ dataIndex: "username",
+ key: "username",
+ },
+ {
+ title: "Connection status",
+ dataIndex: "connectionStatus",
+ key: "connectionStatus",
+ },
+ {
+ title: "Last online",
+ dataIndex: "lastOnline",
+ key: "lastOnline",
+ },
+];
export default function Users() {
- return ;
+ const webSocketContext = useContext(WebSocketContext);
+
+ const getTableItems = () => {
+ let items = [];
+
+ webSocketContext.AllUsers.sort(
+ (a, b) => b.ConnectionStatus - a.ConnectionStatus
+ );
+
+ webSocketContext.AllUsers.forEach((user) => {
+ items.push({
+ key: user.Id,
+ avatar: (
+ }
+ >
+ <>
+
+ >
+
+ ),
+ connectionStatus: getConnectionStatusItem(user.ConnectionStatus),
+ username: user.Username,
+ });
+ });
+
+ return items;
+ };
+
+ return (
+ <>
+
+ All users ({webSocketContext.AllUsers.length})
+
+
+
+ >
+ );
}
diff --git a/src/utils.js b/src/utils.js
index 1284fe7..d47ba0b 100644
--- a/src/utils.js
+++ b/src/utils.js
@@ -1,3 +1,5 @@
+import { UserOutlined } from "@ant-design/icons";
+import { Avatar, Badge } from "antd";
import { createContext, useEffect, useRef, useState } from "react";
import { useNavigate } from "react-router-dom";
@@ -12,6 +14,7 @@ export const Constants = {
},
TEXT_EMPTY_PLACEHOLDER: "-/-",
API_ADDRESS: "http://localhost:8080/v1",
+ STATIC_CONTENT_ADDRESS: "http://localhost:8080/",
WS_ADDRESS: "ws://localhost:8080/ws",
ROUTE_PATHS: {
GROUP_TASKS: "/group-tasks",
@@ -30,6 +33,8 @@ export const Constants = {
MIN_PASSWORD_LENGTH: 6,
MAX_PASSWORD_LENGTH: 64,
},
+ MAX_AVATAR_SIZE: 5 * 1024 * 1024,
+ ACCEPTED_FILE_TYPES: ["image/png", "image/jpeg", "image/jpg"],
};
/**
@@ -37,7 +42,7 @@ export const Constants = {
*/
export function UseUserSession() {
const getUserSession = () => {
- return JSON.parse(localStorage.getItem("session"));
+ return getUserSessionFromLocalStorage();
};
const [userSession, setUserSession] = useState(getUserSession());
@@ -58,6 +63,10 @@ export function UseUserSession() {
};
}
+export function getUserSessionFromLocalStorage() {
+ return JSON.parse(localStorage.getItem("session"));
+}
+
/**
* websocket
*/
@@ -65,10 +74,12 @@ let l = "loading...";
let webSocketContextPreview = {
User: {
+ Id: "",
Username: l,
Email: l,
Sessions: [],
},
+ AllUsers: [],
ConnectionBadgeStatus: "error",
ConnectedWebSocketUsersCount: 0,
CategoryGroups: [],
@@ -89,6 +100,7 @@ const ReceivedMessagesCommands = {
ReloadingGroupTasks: 7,
GroupTasksReloaded: 8,
UpdateUserSessions: 9,
+ UpdateAllUsersUserAvatar: 10,
};
// commands sent to the backend server
@@ -112,6 +124,7 @@ export function WebSocketProvider({
const [connectedWebSocketUsersCount, setConnectedWebSocketUsersCount] =
useState(0);
const [user, setUser] = useState(webSocketContextPreview.User);
+ const [allUsers, setAllUsers] = useState(webSocketContextPreview.AllUsers);
const [categoryGroups, setCategoryGroups] = useState(
webSocketContextPreview.CategoryGroups
);
@@ -145,12 +158,22 @@ export function WebSocketProvider({
switch (cmd) {
case ReceivedMessagesCommands.InitUserSocketConnection:
setUser(body.User);
+ setAllUsers(body.AllUsers);
setCategoryGroups(body.CategoryGroups);
setGroupTasks(body.GroupTasks);
setGroupTasksSteps(body.GroupTasksSteps);
break;
case ReceivedMessagesCommands.UpdateConnectedUsers:
- setConnectedWebSocketUsersCount(body);
+ setConnectedWebSocketUsersCount(body.WebSocketUsersCount);
+ setAllUsers((arr) => {
+ const newArr = [...arr];
+
+ newArr[
+ arr.findIndex((arr1) => arr1.Id === body.UserId)
+ ].ConnectionStatus = body.ConnectionStatus;
+
+ return newArr;
+ });
break;
case ReceivedMessagesCommands.NewGroupTaskStarted:
setGroupTasks((arr) => [...arr, body]);
@@ -207,7 +230,17 @@ export function WebSocketProvider({
case ReceivedMessagesCommands.UpdateUserSessions:
setUser((arr) => ({ ...arr, Sessions: body }));
break;
- case ReceivedMessagesCommands.default:
+ case ReceivedMessagesCommands.UpdateAllUsersUserAvatar:
+ setAllUsers((arr) => {
+ const newArr = [...arr];
+
+ newArr[arr.findIndex((arr1) => arr1.Id === body.UserId)].Avatar =
+ body.Avatar;
+
+ return newArr;
+ });
+ break;
+ default:
console.error("unknown command", cmd);
break;
}
@@ -257,6 +290,7 @@ export function WebSocketProvider({
CategoryGroups: categoryGroups,
GroupTasks: groupTasks,
User: user,
+ AllUsers: allUsers,
SendSocketMessage: SendSocketMessage,
GroupTasksSteps: groupTasksSteps,
setGroupTasksSteps: setGroupTasksSteps,
@@ -318,3 +352,22 @@ export function GetDuration(startTime, endTime) {
return result.trim();
}
+
+export function getConnectionStatusItem(connectionStatus) {
+ return connectionStatus === 0 ? (
+
+ ) : (
+
+ );
+}
+
+export function MyAvatar({ avatarWidth, avatar }) {
+ return avatar !== undefined && avatar !== "" ? (
+
+ ) : (
+ } />
+ );
+}