import { Button, Card, Col, Form, Input, Popconfirm, Row, Select, Space, Table, Tooltip, Typography, Upload, notification, } from "antd"; import { useEffect, useState } from "react"; import { Constants, EncodeStringToBase64, FormatDatetime, getConnectionStatusItem, getUserSessionFromLocalStorage, hasPermission, isEmailValid, myFetch, } from "../../utils"; import { Link } from "react-router-dom"; import { useTranslation } from "react-i18next"; import { CopyOutlined, EyeInvisibleOutlined, EyeOutlined, FileTextOutlined, KeyOutlined, } from "@ant-design/icons"; import { MyUserAvatar } from "../../Components/MyAvatar"; import { useUserProfileContext } from "../../Contexts/UserProfileContext"; import { useWebSocketContext } from "../../Contexts/WebSocketContext"; import { useAppContext } from "../../Contexts/AppContext"; import { useSideBarContext } from "../../Contexts/SideBarContext"; import { SentMessagesCommands } from "../../Handlers/WebSocketMessageHandler"; export default function UserProfile() { const webSocketContext = useWebSocketContext(); const appContext = useAppContext(); const sideBarContext = useSideBarContext(); const userProfileContext = useUserProfileContext(); const [notificationApi, notificationContextHolder] = notification.useNotification(); const { t, i18n } = useTranslation(); const [username, setUsername] = useState(Constants.LOADING); const [email, setEmail] = useState(Constants.LOADING); const [oldPassword, setOldPassword] = useState(""); const [newPassword, setNewPassword] = useState(""); const [repeatedNewPassword, setRepeatedNewPassword] = useState(""); const [newApiKeyName, setNewApikeyName] = useState(""); const [showApiKeyPassword, setShowApiKeyPassword] = useState(false); const getSessionTableColumns = () => { 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.title"), dataIndex: "action", key: "action", render: (_, record) => { return ( myFetch(`/user/session/${record.key}`, "DELETE")} > {t("userProfile.column.action.signOut")} ); }, }, ]; }; const getApiKeyTableColumns = () => { return [ { title: t("userProfile.column.name"), dataIndex: "name", key: "name", }, { title: t("userProfile.column.token"), dataIndex: "token", key: "token", render: (text) => ( {showApiKeyPassword ? text : "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"} {showApiKeyPassword ? ( setShowApiKeyPassword(false)} /> ) : ( setShowApiKeyPassword(true)} /> )} {showApiKeyPassword && ( { navigator.clipboard.writeText(text); setShowApiKeyPassword(false); notificationApi["info"]({ message: t( "userProfile.button.copyToClipboard.notification" ), }); }} /> )} ), }, { title: t("userProfile.column.usageCount"), dataIndex: "usageCount", key: "usageCount", }, { title: t("userProfile.column.lastUsed"), dataIndex: "lastUsed", key: "lastUsed", }, { title: t("userProfile.column.createdAt"), dataIndex: "createdAt", key: "createdAt", }, { title: t("userProfile.column.action.title"), dataIndex: "action", key: "action", render: (_, record) => ( webSocketContext.SendSocketMessage( SentMessagesCommands.DeleteUserApiKey, { Id: record.key } ) } > {t("userProfile.column.deleteApiKey.link")} ), }, ]; }; const getApiKeyTableItems = () => { let items = []; userProfileContext.apiKeys.forEach((apiKey) => { items.push({ key: apiKey.Id, name: apiKey.Name, token: apiKey.Token, usageCount: apiKey.UsageCount, createdAt: FormatDatetime(apiKey.CreatedAt), lastUsed: FormatDatetime(apiKey.LastUsed), }); }); return items; }; const getSessionTableItems = () => { let items = []; userProfileContext.sessions.sort( (a, b) => b.ConnectionStatus - a.ConnectionStatus ); userProfileContext.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(email) || sideBarContext.username.length < Constants.GLOBALS.MIN_USERNAME_LENGTH ) { return true; } if ( username !== sideBarContext.username || email !== userProfileContext.email || (oldPassword !== "" && newPassword !== "" && newPassword === repeatedNewPassword) ) { return false; } return true; }; const handleOnSubmit = () => { const changes = {}; if (sideBarContext.username !== username) { changes.username = username; } if (userProfileContext.email !== email) { changes.email = email; } if ( oldPassword !== "" && newPassword !== "" && newPassword === repeatedNewPassword ) { changes.oldPassword = EncodeStringToBase64(oldPassword); changes.newPassword = EncodeStringToBase64(newPassword); } webSocketContext.SendSocketMessage(SentMessagesCommands.UpdateUserProfile, { changes: changes, }); }; const onCreateNewApiKeyConfirm = () => { webSocketContext.SendSocketMessage( SentMessagesCommands.CreateNewUserApiKey, { Name: newApiKeyName } ); setNewApikeyName(""); }; useEffect(() => { myFetch("/user/profile", "GET").then((data) => { userProfileContext.setEmail(data.Email); userProfileContext.setSessions(data.Sessions); userProfileContext.setApiKeys(data.ApiKeys); setEmail(data.Email); }); }, []); useEffect( () => setUsername(sideBarContext.username), [sideBarContext.username] ); useEffect( () => setEmail(userProfileContext.email), [userProfileContext.email] ); return ( <> {notificationContextHolder} {t("userProfile.header.yourProfile")}
setUsername(e.target.value)} minLength={Constants.GLOBALS.MIN_USERNAME_LENGTH} maxLength={Constants.GLOBALS.MAX_USERNAME_LENGTH} /> setEmail(e.target.value)} /> setOldPassword(e.target.value)} minLength={Constants.GLOBALS.MIN_PASSWORD_LENGTH} maxLength={Constants.GLOBALS.MAX_PASSWORD_LENGTH} /> setNewPassword(e.target.value)} minLength={Constants.GLOBALS.MIN_PASSWORD_LENGTH} maxLength={Constants.GLOBALS.MAX_PASSWORD_LENGTH} /> setRepeatedNewPassword(e.target.value)} minLength={Constants.GLOBALS.MIN_PASSWORD_LENGTH} maxLength={Constants.GLOBALS.MAX_PASSWORD_LENGTH} />

{t("userProfile.header.yourSessions")} ( {userProfileContext.sessions.length}) {hasPermission( appContext.userPermissions, Constants.PERMISSIONS.USER_PROFILE.API_KEYS ) && ( <> {" "}
{t("userProfile.header.yourApiKeys")} ( {userProfileContext.apiKeys.length}){" "} setNewApikeyName(e.target.value)} /> } okText={t("userProfile.button.createApiKey.popconfirm.okText")} cancelText={t("common.button.cancel")} onConfirm={() => onCreateNewApiKeyConfirm()} >
)} ); }