2022-12-16 04:07:04 +01:00
import * as React from 'react' ;
2022-12-17 19:49:32 +01:00
import { useState } from 'react' ;
import { LinearProgress , Stack , useMediaQuery } from "@mui/material" ;
import Tooltip from '@mui/material/Tooltip' ;
2022-12-16 04:07:04 +01:00
import Typography from "@mui/material/Typography" ;
import EditIcon from '@mui/icons-material/Edit' ;
import Container from "@mui/material/Container" ;
import Card from "@mui/material/Card" ;
import Button from "@mui/material/Button" ;
import { useTranslation } from "react-i18next" ;
import session from "../app/Session" ;
2022-12-17 19:49:32 +01:00
import DeleteOutlineIcon from '@mui/icons-material/DeleteOutline' ;
2022-12-16 04:07:04 +01:00
import theme from "./theme" ;
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 api from "../app/Api" ;
import routes from "./routes" ;
2022-12-17 19:49:32 +01:00
import IconButton from "@mui/material/IconButton" ;
import { NavLink , useOutletContext } from "react-router-dom" ;
import Box from "@mui/material/Box" ;
2022-12-16 04:07:04 +01:00
const Account = ( ) => {
return (
< Container maxWidth = "md" sx = { { marginTop : 3 , marginBottom : 3 } } >
< Stack spacing = { 3 } >
< Basics / >
2022-12-17 19:49:32 +01:00
< Stats / >
< Delete / >
2022-12-16 04:07:04 +01:00
< / S t a c k >
< / C o n t a i n e r >
) ;
} ;
const Basics = ( ) => {
const { t } = useTranslation ( ) ;
return (
< Card sx = { { p : 3 } } aria - label = { t ( "xxxxxxxxx" ) } >
< Typography variant = "h5" sx = { { marginBottom : 2 } } >
Account
< / T y p o g r a p h y >
< PrefGroup >
2022-12-17 19:49:32 +01:00
< Username / >
2022-12-16 04:07:04 +01:00
< ChangePassword / >
2022-12-17 19:49:32 +01:00
< / P r e f G r o u p >
< / C a r d >
) ;
} ;
const Stats = ( ) => {
const { t } = useTranslation ( ) ;
const { account } = useOutletContext ( ) ;
2022-12-17 21:17:52 +01:00
const admin = account ? . role === "admin"
const accountType = account ? . plan ? . name ? ? "Free" ;
2022-12-17 19:49:32 +01:00
return (
< Card sx = { { p : 3 } } aria - label = { t ( "xxxxxxxxx" ) } >
< Typography variant = "h5" sx = { { marginBottom : 2 } } >
{ t ( "Usage" ) }
< / T y p o g r a p h y >
< PrefGroup >
< Pref labelId = { "accountType" } title = { t ( "Account type" ) } >
< div >
{ account ? . role === "admin"
? < > Unlimited < Tooltip title = { "You are Admin" } > < span style = { { cursor : "default" } } > 👑 < / s p a n > < / T o o l t i p > < / >
2022-12-17 21:17:52 +01:00
: accountType }
2022-12-17 19:49:32 +01:00
< / d i v >
< / P r e f >
< Pref labelId = { "dailyMessages" } title = { t ( "Daily messages" ) } >
< div >
< Typography variant = "body2" sx = { { float : "left" } } > 123 < / T y p o g r a p h y >
< Typography variant = "body2" sx = { { float : "right" } } > of 1000 < / T y p o g r a p h y >
< / d i v >
< LinearProgress variant = "determinate" value = { 10 } / >
< / P r e f >
< Pref labelId = { "attachmentStorage" } title = { t ( "Attachment storage" ) } >
< div >
< Typography variant = "body2" sx = { { float : "left" } } > 15 MB used < / T y p o g r a p h y >
< Typography variant = "body2" sx = { { float : "right" } } > of 150 MB < / T y p o g r a p h y >
< / d i v >
< LinearProgress variant = "determinate" value = { 40 } / >
< / P r e f >
< Pref labelId = { "emailLimits" } title = { t ( "Emails sent" ) } >
< div >
< Typography variant = "body2" sx = { { float : "left" } } > 2 < / T y p o g r a p h y >
< Typography variant = "body2" sx = { { float : "right" } } > of 15 < / T y p o g r a p h y >
< / d i v >
< LinearProgress variant = "determinate" value = { 20 } / >
< / P r e f >
< / P r e f G r o u p >
< / C a r d >
) ;
} ;
const Delete = ( ) => {
const { t } = useTranslation ( ) ;
return (
< Card sx = { { p : 3 } } aria - label = { t ( "xxxxxxxxx" ) } >
< Typography variant = "h5" sx = { { marginBottom : 2 } } >
{ t ( "Delete account" ) }
< / T y p o g r a p h y >
< PrefGroup >
2022-12-16 04:07:04 +01:00
< DeleteAccount / >
< / P r e f G r o u p >
< / C a r d >
) ;
} ;
2022-12-17 19:49:32 +01:00
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" } } > 👑 < / s p a n > < / T o o l t i p > < / >
: "" }
< / d i v >
< / P r e f >
)
} ;
2022-12-16 04:07:04 +01:00
const ChangePassword = ( ) => {
const { t } = useTranslation ( ) ;
const [ dialogKey , setDialogKey ] = useState ( 0 ) ;
const [ dialogOpen , setDialogOpen ] = useState ( false ) ;
const labelId = "prefChangePassword" ;
const handleDialogOpen = ( ) => {
setDialogKey ( prev => prev + 1 ) ;
setDialogOpen ( true ) ;
} ;
const handleDialogCancel = ( ) => {
setDialogOpen ( false ) ;
} ;
const handleDialogSubmit = async ( newPassword ) => {
try {
await api . changePassword ( "http://localhost:2586" , session . token ( ) , newPassword ) ;
setDialogOpen ( false ) ;
console . debug ( ` [Account] Password changed ` ) ;
} catch ( e ) {
console . log ( ` [Account] Error changing password ` , e ) ;
// TODO show error
}
} ;
return (
2022-12-17 19:49:32 +01:00
< 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" } } > ⬤ ⬤ ⬤ ⬤ ⬤ ⬤ ⬤ ⬤ ⬤ ⬤ < / T y p o g r a p h y >
< IconButton onClick = { handleDialogOpen } aria - label = { t ( "xxxxxxxx" ) } >
< EditIcon / >
< / I c o n B u t t o n >
< / d i v >
2022-12-16 04:07:04 +01:00
< ChangePasswordDialog
key = { ` changePasswordDialog ${ dialogKey } ` }
open = { dialogOpen }
onCancel = { handleDialogCancel }
onSubmit = { handleDialogSubmit }
/ >
< / P r e f >
)
} ;
const ChangePasswordDialog = ( props ) => {
const { t } = useTranslation ( ) ;
const [ newPassword , setNewPassword ] = useState ( "" ) ;
const [ confirmPassword , setConfirmPassword ] = useState ( "" ) ;
const fullScreen = useMediaQuery ( theme . breakpoints . down ( 'sm' ) ) ;
const changeButtonEnabled = ( ( ) => {
return newPassword . length > 0 && newPassword === confirmPassword ;
} ) ( ) ;
return (
< Dialog open = { props . open } onClose = { props . onCancel } fullScreen = { fullScreen } >
< DialogTitle > Change password < / D i a l o g T i t l e >
< DialogContent >
< TextField
margin = "dense"
id = "new-password"
label = { t ( "New password" ) }
aria - label = { t ( "xxxx" ) }
type = "password"
value = { newPassword }
onChange = { ev => setNewPassword ( ev . target . value ) }
fullWidth
variant = "standard"
/ >
< TextField
margin = "dense"
id = "confirm"
label = { t ( "Confirm password" ) }
aria - label = { t ( "xxx" ) }
type = "password"
value = { confirmPassword }
onChange = { ev => setConfirmPassword ( ev . target . value ) }
fullWidth
variant = "standard"
/ >
< / D i a l o g C o n t e n t >
< DialogActions >
< Button onClick = { props . onCancel } > { t ( "Cancel" ) } < / B u t t o n >
< Button onClick = { ( ) => props . onSubmit ( newPassword ) } disabled = { ! changeButtonEnabled } > { t ( "Change password" ) } < / B u t t o n >
< / D i a l o g A c t i o n s >
< / D i a l o g >
) ;
} ;
const DeleteAccount = ( ) => {
const { t } = useTranslation ( ) ;
const [ dialogKey , setDialogKey ] = useState ( 0 ) ;
const [ dialogOpen , setDialogOpen ] = useState ( false ) ;
const labelId = "prefDeleteAccount" ;
const handleDialogOpen = ( ) => {
setDialogKey ( prev => prev + 1 ) ;
setDialogOpen ( true ) ;
} ;
const handleDialogCancel = ( ) => {
setDialogOpen ( false ) ;
} ;
const handleDialogSubmit = async ( newPassword ) => {
try {
await api . deleteAccount ( "http://localhost:2586" , session . token ( ) ) ;
setDialogOpen ( false ) ;
console . debug ( ` [Account] Account deleted ` ) ;
// TODO delete local storage
session . reset ( ) ;
window . location . href = routes . app ;
} catch ( e ) {
console . log ( ` [Account] Error deleting account ` , e ) ;
// TODO show error
}
} ;
return (
2022-12-17 19:49:32 +01:00
< 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
< / B u t t o n >
< / d i v >
2022-12-16 04:07:04 +01:00
< DeleteAccountDialog
key = { ` deleteAccountDialog ${ dialogKey } ` }
open = { dialogOpen }
onCancel = { handleDialogCancel }
onSubmit = { handleDialogSubmit }
/ >
< / P r e f >
)
} ;
const DeleteAccountDialog = ( props ) => {
const { t } = useTranslation ( ) ;
const [ username , setUsername ] = useState ( "" ) ;
const fullScreen = useMediaQuery ( theme . breakpoints . down ( 'sm' ) ) ;
const buttonEnabled = username === session . username ( ) ;
return (
< Dialog open = { props . open } onClose = { props . onCancel } fullScreen = { fullScreen } >
< DialogTitle > { t ( "Delete account" ) } < / D i a l o g T i t l e >
< DialogContent >
< Typography variant = "body1" >
2022-12-17 19:49:32 +01:00
{ 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 ( ) } ) }
2022-12-16 04:07:04 +01:00
< / T y p o g r a p h y >
< TextField
margin = "dense"
id = "account-delete-confirm"
2022-12-17 19:49:32 +01:00
label = { t ( "Type '{{username}}' to delete account" , { username : session . username ( ) } ) }
2022-12-16 04:07:04 +01:00
aria - label = { t ( "xxxx" ) }
type = "text"
value = { username }
onChange = { ev => setUsername ( ev . target . value ) }
fullWidth
variant = "standard"
/ >
< / D i a l o g C o n t e n t >
< DialogActions >
< Button onClick = { props . onCancel } > { t ( "prefs_users_dialog_button_cancel" ) } < / B u t t o n >
< Button onClick = { props . onSubmit } color = "error" disabled = { ! buttonEnabled } > { t ( "Permanently delete account" ) } < / B u t t o n >
< / D i a l o g A c t i o n s >
< / D i a l o g >
) ;
} ;
// FIXME duplicate code
const PrefGroup = ( props ) => {
return (
< div role = "table" >
{ props . children }
< / d i v >
)
} ;
const Pref = ( props ) => {
return (
< div
role = "row"
style = { {
display : "flex" ,
flexDirection : "row" ,
marginTop : "10px" ,
marginBottom : "20px" ,
} }
>
< div
role = "cell"
id = { props . labelId }
aria - label = { props . title }
style = { {
flex : '1 0 40%' ,
display : 'flex' ,
flexDirection : 'column' ,
justifyContent : 'center' ,
paddingRight : '30px'
} }
>
< div > < b > { props . title } < / b > < / d i v >
{ props . description && < div > < em > { props . description } < / e m > < / d i v > }
< / d i v >
< div
role = "cell"
style = { {
flex : '1 0 calc(60% - 50px)' ,
display : 'flex' ,
flexDirection : 'column' ,
justifyContent : 'center'
} }
>
{ props . children }
< / d i v >
< / d i v >
) ;
} ;
export default Account ;