user avatar
parent
71f0abf37b
commit
b89f40f622
|
@ -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: <UserOutlined />,
|
||||
label: " " + webSocketContext.User.Username,
|
||||
icon: (
|
||||
<MyAvatar
|
||||
avatar={
|
||||
webSocketContext.AllUsers.find(
|
||||
(user) => user.Id === webSocketContext.User.Id
|
||||
)?.Avatar
|
||||
}
|
||||
/>
|
||||
),
|
||||
key: "/user-profile",
|
||||
},
|
||||
{
|
||||
|
|
|
@ -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 ? (
|
||||
<Badge status="error" text="Offline" />
|
||||
) : (
|
||||
<Badge status="success" text="Online" />
|
||||
),
|
||||
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 (
|
||||
<>
|
||||
<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" }}>
|
||||
Your Sessions ({webSocketContext.User.Sessions.length})
|
||||
</h1>
|
||||
|
|
|
@ -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 <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()} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
59
src/utils.js
59
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 ? (
|
||||
<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 />} />
|
||||
);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue