user avatar

main
alex 2023-05-18 22:03:06 +02:00
parent 71f0abf37b
commit b89f40f622
4 changed files with 205 additions and 20 deletions

View File

@ -2,14 +2,18 @@ import {
AppstoreOutlined, AppstoreOutlined,
LogoutOutlined, LogoutOutlined,
SnippetsOutlined, SnippetsOutlined,
UserOutlined,
} from "@ant-design/icons"; } from "@ant-design/icons";
import { Badge, Divider, Menu } from "antd"; import { Badge, Divider, Menu } from "antd";
import Sider from "antd/es/layout/Sider"; import Sider from "antd/es/layout/Sider";
import { useContext, useEffect, useState } from "react"; import { useContext, useEffect, useState } from "react";
import { useLocation, useNavigate } from "react-router-dom"; import { useLocation, useNavigate } from "react-router-dom";
import PropTypes from "prop-types"; import PropTypes from "prop-types";
import { Constants, UseUserSession, WebSocketContext } from "../../utils"; import {
Constants,
MyAvatar,
UseUserSession,
WebSocketContext,
} from "../../utils";
export default function SideMenu({ setUserSession }) { export default function SideMenu({ setUserSession }) {
const { userSession } = UseUserSession(); const { userSession } = UseUserSession();
@ -87,8 +91,16 @@ export default function SideMenu({ setUserSession }) {
key: "/users", key: "/users",
}, },
{ {
label: webSocketContext.User.Username, label: " " + webSocketContext.User.Username,
icon: <UserOutlined />, icon: (
<MyAvatar
avatar={
webSocketContext.AllUsers.find(
(user) => user.Id === webSocketContext.User.Id
)?.Avatar
}
/>
),
key: "/user-profile", key: "/user-profile",
}, },
{ {

View File

@ -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 { useContext } from "react";
import { Constants, FormatDatetime, WebSocketContext } from "../../utils"; import {
Constants,
FormatDatetime,
MyAvatar,
WebSocketContext,
getConnectionStatusItem,
getUserSessionFromLocalStorage,
} from "../../utils";
const columns = [ const columns = [
{ {
@ -37,9 +44,7 @@ const columns = [
method: "DELETE", method: "DELETE",
headers: { headers: {
"Content-Type": "application/json", "Content-Type": "application/json",
"X-Authorization": JSON.parse( "X-Authorization": getUserSessionFromLocalStorage(),
localStorage.getItem("session")
),
}, },
}).catch((err) => { }).catch((err) => {
console.error(err); console.error(err);
@ -68,12 +73,7 @@ export default function UserProfile() {
items.push({ items.push({
key: session.IdForDeletion, key: session.IdForDeletion,
userAgent: session.UserAgent, userAgent: session.UserAgent,
connectionStatus: connectionStatus: getConnectionStatusItem(session.ConnectionStatus),
session.ConnectionStatus === 0 ? (
<Badge status="error" text="Offline" />
) : (
<Badge status="success" text="Online" />
),
lastUsed: FormatDatetime(session.LastUsed), lastUsed: FormatDatetime(session.LastUsed),
expiresAt: FormatDatetime(session.ExpiresAt), expiresAt: FormatDatetime(session.ExpiresAt),
}); });
@ -82,8 +82,60 @@ export default function UserProfile() {
return items; 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 ( return (
<> <>
<h1 style={{ fontWeight: "bold" }}>Your Profile</h1>
<Card>
<Upload
accept={Constants.ACCEPTED_FILE_TYPES.join(",")}
action={Constants.API_ADDRESS + "/user/avatar"}
maxCount={1}
showUploadList={false}
beforeUpload={beforeUpload}
headers={{
"X-Authorization": getUserSessionFromLocalStorage(),
}}
>
<MyAvatar
avatar={
webSocketContext.AllUsers.find(
(user) => user.Id === webSocketContext.User.Id
)?.Avatar
}
avatarWidth={200}
/>
</Upload>
<Form layout="vertical">
<Form.Item label="Username">
<Input value={webSocketContext.User.Username} />
</Form.Item>
<Form.Item label="E-Mail">
<Input value={webSocketContext.User.Email} />
</Form.Item>
<Form.Item>
<Button type="primary" htmlType="submit">
Submit
</Button>
</Form.Item>
</Form>
</Card>
<br />
<h1 style={{ fontWeight: "bold" }}> <h1 style={{ fontWeight: "bold" }}>
Your Sessions ({webSocketContext.User.Sessions.length}) Your Sessions ({webSocketContext.User.Sessions.length})
</h1> </h1>

View File

@ -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() { export default function Users() {
return <Button>Test</Button>; 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: (
<Popover
placement="right"
trigger={"hover"}
content={<MyAvatar avatar={user.Avatar} avatarWidth={256} />}
>
<>
<MyAvatar avatar={user.Avatar} />
</>
</Popover>
),
connectionStatus: getConnectionStatusItem(user.ConnectionStatus),
username: user.Username,
});
});
return items;
};
return (
<>
<h1 style={{ fontWeight: "bold" }}>
All users ({webSocketContext.AllUsers.length})
</h1>
<Table columns={columns} dataSource={getTableItems()} />
</>
);
} }

View File

@ -1,3 +1,5 @@
import { UserOutlined } from "@ant-design/icons";
import { Avatar, Badge } from "antd";
import { createContext, useEffect, useRef, useState } from "react"; import { createContext, useEffect, useRef, useState } from "react";
import { useNavigate } from "react-router-dom"; import { useNavigate } from "react-router-dom";
@ -12,6 +14,7 @@ export const Constants = {
}, },
TEXT_EMPTY_PLACEHOLDER: "-/-", TEXT_EMPTY_PLACEHOLDER: "-/-",
API_ADDRESS: "http://localhost:8080/v1", API_ADDRESS: "http://localhost:8080/v1",
STATIC_CONTENT_ADDRESS: "http://localhost:8080/",
WS_ADDRESS: "ws://localhost:8080/ws", WS_ADDRESS: "ws://localhost:8080/ws",
ROUTE_PATHS: { ROUTE_PATHS: {
GROUP_TASKS: "/group-tasks", GROUP_TASKS: "/group-tasks",
@ -30,6 +33,8 @@ export const Constants = {
MIN_PASSWORD_LENGTH: 6, MIN_PASSWORD_LENGTH: 6,
MAX_PASSWORD_LENGTH: 64, 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() { export function UseUserSession() {
const getUserSession = () => { const getUserSession = () => {
return JSON.parse(localStorage.getItem("session")); return getUserSessionFromLocalStorage();
}; };
const [userSession, setUserSession] = useState(getUserSession()); const [userSession, setUserSession] = useState(getUserSession());
@ -58,6 +63,10 @@ export function UseUserSession() {
}; };
} }
export function getUserSessionFromLocalStorage() {
return JSON.parse(localStorage.getItem("session"));
}
/** /**
* websocket * websocket
*/ */
@ -65,10 +74,12 @@ let l = "loading...";
let webSocketContextPreview = { let webSocketContextPreview = {
User: { User: {
Id: "",
Username: l, Username: l,
Email: l, Email: l,
Sessions: [], Sessions: [],
}, },
AllUsers: [],
ConnectionBadgeStatus: "error", ConnectionBadgeStatus: "error",
ConnectedWebSocketUsersCount: 0, ConnectedWebSocketUsersCount: 0,
CategoryGroups: [], CategoryGroups: [],
@ -89,6 +100,7 @@ const ReceivedMessagesCommands = {
ReloadingGroupTasks: 7, ReloadingGroupTasks: 7,
GroupTasksReloaded: 8, GroupTasksReloaded: 8,
UpdateUserSessions: 9, UpdateUserSessions: 9,
UpdateAllUsersUserAvatar: 10,
}; };
// commands sent to the backend server // commands sent to the backend server
@ -112,6 +124,7 @@ export function WebSocketProvider({
const [connectedWebSocketUsersCount, setConnectedWebSocketUsersCount] = const [connectedWebSocketUsersCount, setConnectedWebSocketUsersCount] =
useState(0); useState(0);
const [user, setUser] = useState(webSocketContextPreview.User); const [user, setUser] = useState(webSocketContextPreview.User);
const [allUsers, setAllUsers] = useState(webSocketContextPreview.AllUsers);
const [categoryGroups, setCategoryGroups] = useState( const [categoryGroups, setCategoryGroups] = useState(
webSocketContextPreview.CategoryGroups webSocketContextPreview.CategoryGroups
); );
@ -145,12 +158,22 @@ export function WebSocketProvider({
switch (cmd) { switch (cmd) {
case ReceivedMessagesCommands.InitUserSocketConnection: case ReceivedMessagesCommands.InitUserSocketConnection:
setUser(body.User); setUser(body.User);
setAllUsers(body.AllUsers);
setCategoryGroups(body.CategoryGroups); setCategoryGroups(body.CategoryGroups);
setGroupTasks(body.GroupTasks); setGroupTasks(body.GroupTasks);
setGroupTasksSteps(body.GroupTasksSteps); setGroupTasksSteps(body.GroupTasksSteps);
break; break;
case ReceivedMessagesCommands.UpdateConnectedUsers: 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; break;
case ReceivedMessagesCommands.NewGroupTaskStarted: case ReceivedMessagesCommands.NewGroupTaskStarted:
setGroupTasks((arr) => [...arr, body]); setGroupTasks((arr) => [...arr, body]);
@ -207,7 +230,17 @@ export function WebSocketProvider({
case ReceivedMessagesCommands.UpdateUserSessions: case ReceivedMessagesCommands.UpdateUserSessions:
setUser((arr) => ({ ...arr, Sessions: body })); setUser((arr) => ({ ...arr, Sessions: body }));
break; 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); console.error("unknown command", cmd);
break; break;
} }
@ -257,6 +290,7 @@ export function WebSocketProvider({
CategoryGroups: categoryGroups, CategoryGroups: categoryGroups,
GroupTasks: groupTasks, GroupTasks: groupTasks,
User: user, User: user,
AllUsers: allUsers,
SendSocketMessage: SendSocketMessage, SendSocketMessage: SendSocketMessage,
GroupTasksSteps: groupTasksSteps, GroupTasksSteps: groupTasksSteps,
setGroupTasksSteps: setGroupTasksSteps, setGroupTasksSteps: setGroupTasksSteps,
@ -318,3 +352,22 @@ export function GetDuration(startTime, endTime) {
return result.trim(); return result.trim();
} }
export function getConnectionStatusItem(connectionStatus) {
return connectionStatus === 0 ? (
<Badge status="error" text="Offline" />
) : (
<Badge status="success" text="Online" />
);
}
export function MyAvatar({ avatarWidth, avatar }) {
return avatar !== undefined && avatar !== "" ? (
<Avatar
size={avatarWidth}
src={Constants.STATIC_CONTENT_ADDRESS + "avatars/" + avatar}
/>
) : (
<Avatar size={avatarWidth} icon={<UserOutlined />} />
);
}