Просмотр исходного кода

Account delete, mock user stats UI

binwiederhier 3 лет назад
Родитель
Сommit
8752680233
3 измененных файлов с 114 добавлено и 31 удалено
  1. 3 1
      server/server.go
  2. 95 16
      web/src/components/Account.js
  3. 16 14
      web/src/components/App.js

+ 3 - 1
server/server.go

@@ -36,6 +36,7 @@ import (
 
 /*
 	TODO
+		return rate limit information in account stats
 		expire tokens
 		auto-refresh tokens from UI
 		reserve topics
@@ -48,7 +49,8 @@ import (
 		- Pricing
 		- change email
 		-
-
+		Polishing:
+			aria-label for everything
 
 
 */

+ 95 - 16
web/src/components/Account.js

@@ -1,5 +1,7 @@
 import * as React from 'react';
-import {Stack, useMediaQuery} from "@mui/material";
+import {useState} from 'react';
+import {LinearProgress, Stack, useMediaQuery} from "@mui/material";
+import Tooltip from '@mui/material/Tooltip';
 import Typography from "@mui/material/Typography";
 import EditIcon from '@mui/icons-material/Edit';
 import Container from "@mui/material/Container";
@@ -7,24 +9,26 @@ import Card from "@mui/material/Card";
 import Button from "@mui/material/Button";
 import {useTranslation} from "react-i18next";
 import session from "../app/Session";
-import {useEffect, useState} from "react";
+import DeleteOutlineIcon from '@mui/icons-material/DeleteOutline';
 import theme from "./theme";
-import {validUrl} from "../app/utils";
 import Dialog from "@mui/material/Dialog";
 import DialogTitle from "@mui/material/DialogTitle";
 import DialogContent from "@mui/material/DialogContent";
 import TextField from "@mui/material/TextField";
 import DialogActions from "@mui/material/DialogActions";
-import userManager from "../app/UserManager";
 import api from "../app/Api";
 import routes from "./routes";
+import IconButton from "@mui/material/IconButton";
+import {NavLink, useOutletContext} from "react-router-dom";
+import Box from "@mui/material/Box";
 
 const Account = () => {
     return (
         <Container maxWidth="md" sx={{marginTop: 3, marginBottom: 3}}>
             <Stack spacing={3}>
                 <Basics/>
-
+                <Stats/>
+                <Delete/>
             </Stack>
         </Container>
     );
@@ -38,14 +42,84 @@ const Basics = () => {
                 Account
             </Typography>
             <PrefGroup>
-                <Pref labelId={"username"} title={"Username"}>{session.username()}</Pref>
+                <Username/>
                 <ChangePassword/>
+            </PrefGroup>
+        </Card>
+    );
+};
+
+const Stats = () => {
+    const { t } = useTranslation();
+    const { account } = useOutletContext();
+    return (
+        <Card sx={{p: 3}} aria-label={t("xxxxxxxxx")}>
+            <Typography variant="h5" sx={{marginBottom: 2}}>
+                {t("Usage")}
+            </Typography>
+            <PrefGroup>
+                <Pref labelId={"accountType"} title={t("Account type")}>
+                    <div>
+                        {account?.role === "admin"
+                            ? <>Unlimited <Tooltip title={"You are Admin"}><span style={{cursor: "default"}}>👑</span></Tooltip></>
+                            : "Free"}
+                    </div>
+                </Pref>
+                <Pref labelId={"dailyMessages"} title={t("Daily messages")}>
+                    <div>
+                        <Typography variant="body2" sx={{float: "left"}}>123</Typography>
+                        <Typography variant="body2" sx={{float: "right"}}>of 1000</Typography>
+                    </div>
+                    <LinearProgress variant="determinate" value={10} />
+                </Pref>
+                <Pref labelId={"attachmentStorage"} title={t("Attachment storage")}>
+                    <div>
+                        <Typography variant="body2" sx={{float: "left"}}>15 MB used</Typography>
+                        <Typography variant="body2" sx={{float: "right"}}>of 150 MB</Typography>
+                    </div>
+                    <LinearProgress variant="determinate" value={40} />
+                </Pref>
+                <Pref labelId={"emailLimits"} title={t("Emails sent")}>
+                    <div>
+                        <Typography variant="body2" sx={{float: "left"}}>2</Typography>
+                        <Typography variant="body2" sx={{float: "right"}}>of 15</Typography>
+                    </div>
+                    <LinearProgress variant="determinate" value={20} />
+                </Pref>
+            </PrefGroup>
+        </Card>
+    );
+};
+
+const Delete = () => {
+    const { t } = useTranslation();
+    return (
+        <Card sx={{p: 3}} aria-label={t("xxxxxxxxx")}>
+            <Typography variant="h5" sx={{marginBottom: 2}}>
+                {t("Delete account")}
+            </Typography>
+            <PrefGroup>
                 <DeleteAccount/>
             </PrefGroup>
         </Card>
     );
 };
 
+const Username = () => {
+    const { t } = useTranslation();
+    const { account } = useOutletContext();
+    return (
+        <Pref labelId={"username"} title={t("Username")} description={t("Hey, that's you ❤")}>
+            <div>
+                {session.username()}
+                {account?.role === "admin"
+                    ? <>{" "}<Tooltip title={"You are Admin"}><span style={{cursor: "default"}}>👑</span></Tooltip></>
+                    : ""}
+            </div>
+        </Pref>
+    )
+};
+
 const ChangePassword = () => {
     const { t } = useTranslation();
     const [dialogKey, setDialogKey] = useState(0);
@@ -69,10 +143,13 @@ const ChangePassword = () => {
         }
     };
     return (
-        <Pref labelId={labelId} title={"Password"}>
-            <Button variant="outlined" startIcon={<EditIcon />} onClick={handleDialogOpen}>
-                Change password
-            </Button>
+        <Pref labelId={labelId} title={t("Password")} description={t("Change your account password")}>
+            <div>
+                <Typography color="gray" sx={{float: "left", fontSize: "0.7rem", lineHeight: "3.5"}}>⬤⬤⬤⬤⬤⬤⬤⬤⬤⬤</Typography>
+                <IconButton onClick={handleDialogOpen} aria-label={t("xxxxxxxx")}>
+                    <EditIcon/>
+                </IconButton>
+            </div>
             <ChangePasswordDialog
                 key={`changePasswordDialog${dialogKey}`}
                 open={dialogOpen}
@@ -152,10 +229,12 @@ const DeleteAccount = () => {
         }
     };
     return (
-        <Pref labelId={labelId} title={t("Delete account")} description={t("This will permanently delete your account, including all data that is stored on the server.")}>
-            <Button variant="outlined" startIcon={<EditIcon />} onClick={handleDialogOpen}>
-                Delete account
-            </Button>
+        <Pref labelId={labelId} title={t("Delete account")} description={t("Permanently delete your account")}>
+            <div>
+                <Button fullWidth={false} variant="outlined" color="error" startIcon={<DeleteOutlineIcon />} onClick={handleDialogOpen}>
+                    Delete account
+                </Button>
+            </div>
             <DeleteAccountDialog
                 key={`deleteAccountDialog${dialogKey}`}
                 open={dialogOpen}
@@ -176,12 +255,12 @@ const DeleteAccountDialog = (props) => {
             <DialogTitle>{t("Delete account")}</DialogTitle>
             <DialogContent>
                 <Typography variant="body1">
-                    {t("This will permanently delete your account, including all data that is stored on the server. If you really want to proceed, please type {{username}} in the text box below.")}
+                    {t("This will permanently delete your account, including all data that is stored on the server. If you really want to proceed, please type '{{username}}' in the text box below.", { username: session.username()})}
                 </Typography>
                 <TextField
                     margin="dense"
                     id="account-delete-confirm"
-                    label={t("Type '{{username}}' to delete account")}
+                    label={t("Type '{{username}}' to delete account", { username: session.username()})}
                     aria-label={t("xxxx")}
                     type="text"
                     value={username}

+ 16 - 14
web/src/components/App.js

@@ -81,6 +81,7 @@ const Layout = () => {
     const [mobileDrawerOpen, setMobileDrawerOpen] = useState(false);
     const [notificationsGranted, setNotificationsGranted] = useState(notifier.granted());
     const [sendDialogOpenMode, setSendDialogOpenMode] = useState("");
+    const [account, setAccount] = useState(null);
     const users = useLiveQuery(() => userManager.all());
     const subscriptions = useLiveQuery(() => subscriptionManager.all());
     const newNotificationsCount = subscriptions?.reduce((prev, cur) => prev + cur.new, 0) || 0;
@@ -95,24 +96,25 @@ const Layout = () => {
 
     useEffect(() => {
         (async () => {
-            const account = await api.getAccountSettings("http://localhost:2586", session.token());
-            if (account) {
-                if (account.language) {
-                    await i18n.changeLanguage(account.language);
+            const acc = await api.getAccountSettings("http://localhost:2586", session.token());
+            if (acc) {
+                setAccount(acc);
+                if (acc.language) {
+                    await i18n.changeLanguage(acc.language);
                 }
-                if (account.notification) {
-                    if (account.notification.sound) {
-                        await prefs.setSound(account.notification.sound);
+                if (acc.notification) {
+                    if (acc.notification.sound) {
+                        await prefs.setSound(acc.notification.sound);
                     }
-                    if (account.notification.delete_after) {
-                        await prefs.setDeleteAfter(account.notification.delete_after);
+                    if (acc.notification.delete_after) {
+                        await prefs.setDeleteAfter(acc.notification.delete_after);
                     }
-                    if (account.notification.min_priority) {
-                        await prefs.setMinPriority(account.notification.min_priority);
+                    if (acc.notification.min_priority) {
+                        await prefs.setMinPriority(acc.notification.min_priority);
                     }
                 }
-                if (account.subscriptions) {
-                    await subscriptionManager.syncFromRemote(account.subscriptions);
+                if (acc.subscriptions) {
+                    await subscriptionManager.syncFromRemote(acc.subscriptions);
                 }
             }
         })();
@@ -135,7 +137,7 @@ const Layout = () => {
             />
             <Main>
                 <Toolbar/>
-                <Outlet context={{ subscriptions, selected }}/>
+                <Outlet context={{ account, subscriptions, selected }}/>
             </Main>
             <Messaging
                 selected={selected}