admin-dashboard-web/src/Pages/UserProfile/index.js

332 lines
9.4 KiB
JavaScript

import {
Button,
Card,
Col,
Form,
Input,
Row,
Select,
Space,
Table,
Upload,
notification,
} from "antd";
import { useContext, useState } from "react";
import {
Constants,
EncodeStringToBase64,
FormatDatetime,
MyAvatar,
SentMessagesCommands,
WebSocketContext,
getConnectionStatusItem,
getUserSessionFromLocalStorage,
handleUnauthorizedStatus,
isEmailValid,
} from "../../utils";
import { Link } from "react-router-dom";
import { useTranslation } from "react-i18next";
export default function UserProfile() {
const webSocketContext = useContext(WebSocketContext);
const [notificationApi, notificationContextHolder] =
notification.useNotification();
const { t, i18n } = useTranslation();
const [oldPassword, setOldPassword] = useState("");
const [newPassword, setNewPassword] = useState("");
const [repeatedNewPassword, setRepeatedNewPassword] = useState("");
const getTableColumns = () => {
return [
{
title: t("userProfile.column.userAgent"),
dataIndex: "userAgent",
key: "userAgent",
},
{
title: t("userProfile.column.connectionStatus"),
dataIndex: "connectionStatus",
key: "connectionStatus",
},
{
title: t("userProfile.column.lastUsed"),
dataIndex: "lastUsed",
key: "lastUsed",
},
{
title: t("userProfile.column.expiresAt"),
dataIndex: "expiresAt",
key: "expiresAt",
},
{
title: t("userProfile.column.action"),
dataIndex: "action",
key: "action",
render: (_, record) => {
return (
<Space size="middle">
<Link
href="#"
onClick={() => {
fetch(`${Constants.API_ADDRESS}/user/session/${record.key}`, {
method: "DELETE",
headers: {
"Content-Type": "application/json",
"X-Authorization": getUserSessionFromLocalStorage(),
},
})
.then((res) => handleUnauthorizedStatus(res.status))
.catch((err) => {
console.error(err);
});
}}
>
{t("userProfile.column.action.signOut")}
</Link>
</Space>
);
},
},
];
};
const getTableItems = () => {
let items = [];
webSocketContext.User.Sessions.sort(
(a, b) => b.ConnectionStatus - a.ConnectionStatus
);
webSocketContext.User.Sessions.forEach((session) => {
items.push({
key: session.IdForDeletion,
userAgent: session.UserAgent,
connectionStatus: getConnectionStatusItem(session.ConnectionStatus),
lastUsed: FormatDatetime(session.LastUsed),
expiresAt: FormatDatetime(session.ExpiresAt),
});
});
return items;
};
const beforeUpload = (file) => {
if (file.size > Constants.MAX_AVATAR_SIZE) {
notificationApi["error"]({
message: t("userProfile.changeAvatarError.notification.message"),
description: t(
"userProfile.changeAvatarError.notification.description",
{ MAX_AVATAR_SIZE: Constants.MAX_AVATAR_SIZE / 1024 / 1024 }
),
});
return false;
}
return true;
};
const isButtonDisabled = () => {
if (
!isEmailValid(webSocketContext.UserProfileStateEmail) ||
webSocketContext.UserProfileStateUsername.length <
Constants.GLOBALS.MIN_USERNAME_LENGTH
) {
return true;
}
if (
webSocketContext.UserProfileStateUsername !==
webSocketContext.User.Username ||
webSocketContext.UserProfileStateEmail !== webSocketContext.User.Email ||
(oldPassword !== "" &&
newPassword !== "" &&
newPassword === repeatedNewPassword)
) {
return false;
}
return true;
};
const handleOnSubmit = () => {
const changes = {};
if (
webSocketContext.User.Username !==
webSocketContext.UserProfileStateUsername
) {
changes.username = webSocketContext.UserProfileStateUsername;
}
if (
webSocketContext.User.Email !== webSocketContext.UserProfileStateEmail
) {
changes.email = webSocketContext.UserProfileStateEmail;
}
if (
oldPassword !== "" &&
newPassword !== "" &&
newPassword === repeatedNewPassword
) {
changes.oldPassword = EncodeStringToBase64(oldPassword);
changes.newPassword = EncodeStringToBase64(newPassword);
}
webSocketContext.SendSocketMessage(SentMessagesCommands.UpdateUserProfile, {
changes: changes,
});
};
return (
<>
{notificationContextHolder}
<h1 style={{ fontWeight: "bold" }}>
{t("userProfile.header.yourProfile")}
</h1>
<Card>
<Form layout="vertical">
<Row>
<Col span={4}>
<Upload
accept={Constants.ACCEPTED_FILE_TYPES.join(",")}
action={Constants.API_ADDRESS + "/user/avatar"}
maxCount={1}
showUploadList={false}
beforeUpload={beforeUpload}
headers={{
"X-Authorization": getUserSessionFromLocalStorage(),
}}
>
<MyAvatar
avatarWidth={200}
allUsers={webSocketContext.AllUsers}
userId={webSocketContext.User.Id}
/>
</Upload>
</Col>
<Col span={4} offset={16}>
<Form.Item label={t("userProfile.form.language")}>
<Select
style={{ width: "100%" }}
defaultValue={i18n.language}
options={[
{
value: "en",
label: "English",
},
{
value: "de",
label: "Deutsch",
},
]}
onChange={(e) => i18n.changeLanguage(e)}
/>
</Form.Item>
</Col>
</Row>
<Form.Item
label={t("userProfile.form.username")}
hasFeedback
validateStatus={
webSocketContext.UserProfileStateUsername.length <
Constants.GLOBALS.MIN_USERNAME_LENGTH && "error"
}
>
<Input
value={webSocketContext.UserProfileStateUsername}
onChange={(e) =>
webSocketContext.setUserProfileStateUsername(e.target.value)
}
minLength={Constants.GLOBALS.MIN_USERNAME_LENGTH}
maxLength={Constants.GLOBALS.MAX_USERNAME_LENGTH}
/>
</Form.Item>
<Form.Item
label={t("userProfile.form.email")}
hasFeedback
validateStatus={
!isEmailValid(webSocketContext.UserProfileStateEmail) && "error"
}
>
<Input
type="email"
value={webSocketContext.UserProfileStateEmail}
onChange={(e) =>
webSocketContext.setUserProfileStateEmail(e.target.value)
}
/>
</Form.Item>
<Form.Item
label={t("userProfile.form.oldPassword")}
hasFeedback
validateStatus={
oldPassword !== "" &&
oldPassword.length < Constants.GLOBALS.MIN_PASSWORD_LENGTH &&
"error"
}
>
<Input.Password
value={oldPassword}
onChange={(e) => setOldPassword(e.target.value)}
minLength={Constants.GLOBALS.MIN_PASSWORD_LENGTH}
maxLength={Constants.GLOBALS.MAX_PASSWORD_LENGTH}
/>
</Form.Item>
<Form.Item
label={t("userProfile.form.newPassword")}
hasFeedback
validateStatus={
newPassword !== "" &&
newPassword.length < Constants.GLOBALS.MIN_PASSWORD_LENGTH &&
"error"
}
>
<Input.Password
value={newPassword}
onChange={(e) => setNewPassword(e.target.value)}
minLength={Constants.GLOBALS.MIN_PASSWORD_LENGTH}
maxLength={Constants.GLOBALS.MAX_PASSWORD_LENGTH}
/>
</Form.Item>
<Form.Item
label={t("userProfile.form.repeatNewPassword")}
hasFeedback
validateStatus={newPassword !== repeatedNewPassword && "error"}
>
<Input.Password
value={repeatedNewPassword}
onChange={(e) => setRepeatedNewPassword(e.target.value)}
minLength={Constants.GLOBALS.MIN_PASSWORD_LENGTH}
maxLength={Constants.GLOBALS.MAX_PASSWORD_LENGTH}
/>
</Form.Item>
<Form.Item style={{ margin: 0 }}>
<Button
type="primary"
htmlType="submit"
onClick={() => handleOnSubmit()}
disabled={isButtonDisabled()}
>
{t("buttonSave")}
</Button>
</Form.Item>
</Form>
</Card>
<br />
<h1 style={{ fontWeight: "bold" }}>
{t("userProfile.header.yourSessions")} (
{webSocketContext.User.Sessions.length})
</h1>
<Table columns={getTableColumns()} dataSource={getTableItems()} />
</>
);
}