fixed login, removed old makeStyles call
This commit is contained in:
parent
c6f9c8894c
commit
b68ff85578
@ -1,54 +0,0 @@
|
|||||||
import React, {useCallback, useContext, useState} from 'react';
|
|
||||||
import {Box} from "@mui/material";
|
|
||||||
import {LocaleContext} from "shared/locale";
|
|
||||||
|
|
||||||
/*
|
|
||||||
const useStyles = makeStyles((theme) => ({
|
|
||||||
languageFlag: {
|
|
||||||
margin: theme.spacing(0.2),
|
|
||||||
cursor: "pointer",
|
|
||||||
border: 0,
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
*/
|
|
||||||
|
|
||||||
export default function LanguageSelection(props) {
|
|
||||||
|
|
||||||
const api = props.api;
|
|
||||||
// const classes = useStyles();
|
|
||||||
const classes = {};
|
|
||||||
const [languages, setLanguages] = useState(null);
|
|
||||||
const {translate: L, setLanguageByCode} = useContext(LocaleContext);
|
|
||||||
|
|
||||||
const onSetLanguage = useCallback((code) => {
|
|
||||||
setLanguageByCode(api, code).then((res) => {
|
|
||||||
if (!res.success) {
|
|
||||||
alert(res.msg);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
let flags = [];
|
|
||||||
if (languages === null) {
|
|
||||||
api.getLanguages().then((res) => {
|
|
||||||
if (res.success) {
|
|
||||||
setLanguages(res.languages);
|
|
||||||
} else {
|
|
||||||
setLanguages({});
|
|
||||||
alert(res.msg);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
for (const language of Object.values(languages)) {
|
|
||||||
let key = `lang-${language.code}`;
|
|
||||||
flags.push(<button type={"button"} title={language.name} onClick={() => onSetLanguage(language.code)}
|
|
||||||
key={key} className={classes.languageFlag} >
|
|
||||||
<img alt={key} src={`/img/icons/lang/${language.code}.gif`} />
|
|
||||||
</button>);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return <Box mt={1}>
|
|
||||||
{L("general.language") + ": "} { flags }
|
|
||||||
</Box>
|
|
||||||
}
|
|
@ -1,310 +0,0 @@
|
|||||||
import {
|
|
||||||
Box,
|
|
||||||
Button,
|
|
||||||
Checkbox, CircularProgress, Container,
|
|
||||||
FormControlLabel,
|
|
||||||
Grid,
|
|
||||||
Link,
|
|
||||||
TextField,
|
|
||||||
Typography
|
|
||||||
} from "@mui/material";
|
|
||||||
|
|
||||||
import {Alert} from '@mui/lab';
|
|
||||||
import React, {useCallback, useContext, useEffect, useState} from "react";
|
|
||||||
import ReplayIcon from '@mui/icons-material';
|
|
||||||
import LanguageSelection from "../elements/language-selection";
|
|
||||||
import {decodeText, encodeText, getParameter, removeParameter} from "shared/util";
|
|
||||||
import Icon from "shared/elements/icon";
|
|
||||||
import {LocaleContext} from "shared/locale";
|
|
||||||
|
|
||||||
/*
|
|
||||||
const useStyles = makeStyles((theme) => ({
|
|
||||||
paper: {
|
|
||||||
marginTop: theme.spacing(8),
|
|
||||||
display: 'flex',
|
|
||||||
flexDirection: 'column',
|
|
||||||
alignItems: 'center',
|
|
||||||
},
|
|
||||||
avatar: {
|
|
||||||
margin: theme.spacing(2),
|
|
||||||
width: "60px",
|
|
||||||
height: "60px"
|
|
||||||
},
|
|
||||||
form: {
|
|
||||||
width: '100%', // Fix IE 11 issue.
|
|
||||||
marginTop: theme.spacing(1),
|
|
||||||
},
|
|
||||||
submit: {
|
|
||||||
margin: theme.spacing(3, 0, 2),
|
|
||||||
},
|
|
||||||
logo: {
|
|
||||||
marginRight: theme.spacing(3)
|
|
||||||
},
|
|
||||||
headline: {
|
|
||||||
width: "100%",
|
|
||||||
},
|
|
||||||
container: {
|
|
||||||
marginTop: theme.spacing(5),
|
|
||||||
paddingBottom: theme.spacing(1),
|
|
||||||
borderColor: theme.palette.primary.main,
|
|
||||||
borderStyle: "solid",
|
|
||||||
borderWidth: 1,
|
|
||||||
borderRadius: 5
|
|
||||||
},
|
|
||||||
buttons2FA: {
|
|
||||||
marginTop: theme.spacing(1),
|
|
||||||
marginBottom: theme.spacing(1),
|
|
||||||
},
|
|
||||||
error2FA: {
|
|
||||||
marginTop: theme.spacing(2),
|
|
||||||
marginBottom: theme.spacing(2),
|
|
||||||
"& > div": {
|
|
||||||
fontSize: 16
|
|
||||||
},
|
|
||||||
"& > button": {
|
|
||||||
marginTop: theme.spacing(1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
*/
|
|
||||||
|
|
||||||
export default function LoginForm(props) {
|
|
||||||
|
|
||||||
const api = props.api;
|
|
||||||
// const classes = useStyles();
|
|
||||||
const classes = {};
|
|
||||||
let [username, setUsername] = useState("");
|
|
||||||
let [password, setPassword] = useState("");
|
|
||||||
let [rememberMe, setRememberMe] = useState(true);
|
|
||||||
let [isLoggingIn, setLoggingIn] = useState(false);
|
|
||||||
let [emailConfirmed, setEmailConfirmed] = useState(null);
|
|
||||||
let [tfaCode, set2FACode] = useState("");
|
|
||||||
let [tfaState, set2FAState] = useState(0); // 0: not sent, 1: sent, 2: retry
|
|
||||||
let [tfaError, set2FAError] = useState("");
|
|
||||||
let [error, setError] = useState("");
|
|
||||||
let [loaded, setLoaded] = useState(false);
|
|
||||||
|
|
||||||
const {translate: L, currentLocale, requestModules} = useContext(LocaleContext);
|
|
||||||
|
|
||||||
const onUpdateLocale = useCallback(() => {
|
|
||||||
requestModules(api, ["general", "account"], currentLocale).then(data => {
|
|
||||||
setLoaded(true);
|
|
||||||
if (!data.success) {
|
|
||||||
alert(data.msg);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}, [currentLocale]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
onUpdateLocale();
|
|
||||||
}, [currentLocale]);
|
|
||||||
|
|
||||||
const onLogin = useCallback(() => {
|
|
||||||
if (!isLoggingIn) {
|
|
||||||
setError("");
|
|
||||||
setLoggingIn(true);
|
|
||||||
removeParameter("success");
|
|
||||||
api.login(username, password, rememberMe).then((res) => {
|
|
||||||
set2FAState(0);
|
|
||||||
setLoggingIn(false);
|
|
||||||
setPassword("");
|
|
||||||
if (!res.success) {
|
|
||||||
setEmailConfirmed(res.emailConfirmed);
|
|
||||||
setError(res.msg);
|
|
||||||
} else {
|
|
||||||
props.onLogin();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}, [api, isLoggingIn, password, props, rememberMe, username]);
|
|
||||||
|
|
||||||
const onSubmit2FA = useCallback(() => {
|
|
||||||
setLoggingIn(true);
|
|
||||||
props.onTotp2FA(tfaCode, (res) => {
|
|
||||||
setLoggingIn(false);
|
|
||||||
});
|
|
||||||
}, [tfaCode, props]);
|
|
||||||
|
|
||||||
const onCancel2FA = useCallback(() => {
|
|
||||||
props.onLogout();
|
|
||||||
}, [props]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!api.loggedIn || !api.user) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let twoFactor = api.user["2fa"];
|
|
||||||
if (!twoFactor || !twoFactor.confirmed ||
|
|
||||||
twoFactor.authenticated || twoFactor.type !== "fido") {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tfaState === 0) {
|
|
||||||
set2FAState(1);
|
|
||||||
set2FAError("");
|
|
||||||
navigator.credentials.get({
|
|
||||||
publicKey: {
|
|
||||||
challenge: encodeText(window.atob(twoFactor.challenge)),
|
|
||||||
allowCredentials: [{
|
|
||||||
id: encodeText(window.atob(twoFactor.credentialID)),
|
|
||||||
type: "public-key",
|
|
||||||
}],
|
|
||||||
userVerification: "discouraged",
|
|
||||||
},
|
|
||||||
}).then((res) => {
|
|
||||||
let credentialID = res.id;
|
|
||||||
let clientDataJson = decodeText(res.response.clientDataJSON);
|
|
||||||
let authData = window.btoa(decodeText(res.response.authenticatorData));
|
|
||||||
let signature = window.btoa(decodeText(res.response.signature));
|
|
||||||
props.onKey2FA(credentialID, clientDataJson, authData, signature, res => {
|
|
||||||
if (!res.success) {
|
|
||||||
set2FAState(2);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}).catch(e => {
|
|
||||||
set2FAState(2);
|
|
||||||
set2FAError(e.toString());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}, [api.loggedIn, api.user, tfaState, props]);
|
|
||||||
|
|
||||||
const createForm = () => {
|
|
||||||
|
|
||||||
// 2FA
|
|
||||||
if (api.loggedIn && api.user["2fa"]) {
|
|
||||||
return <>
|
|
||||||
<div>{L("account.2fa_title")}: {api.user["2fa"].type}</div>
|
|
||||||
{ api.user["2fa"].type === "totp" ?
|
|
||||||
<TextField
|
|
||||||
variant="outlined" margin="normal"
|
|
||||||
id="code" label={L("account.6_digit_code")} name="code"
|
|
||||||
autoComplete="code"
|
|
||||||
required fullWidth autoFocus
|
|
||||||
value={tfaCode} onChange={(e) => set2FACode(e.target.value)}
|
|
||||||
/> : <>
|
|
||||||
{L("account.2fa_text")}
|
|
||||||
<Box mt={2} textAlign={"center"}>
|
|
||||||
{tfaState !== 2
|
|
||||||
? <CircularProgress/>
|
|
||||||
: <div className={classes.error2FA}>
|
|
||||||
<div>{L("general.something_went_wrong")}:<br />{tfaError}</div>
|
|
||||||
<Button onClick={() => set2FAState(0)}
|
|
||||||
variant={"outlined"} color={"secondary"} size={"small"}>
|
|
||||||
<ReplayIcon /> {L("general.retry")}
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
</Box>
|
|
||||||
</>
|
|
||||||
}
|
|
||||||
{
|
|
||||||
error ? <Alert severity="error">{error}</Alert> : <></>
|
|
||||||
}
|
|
||||||
<Grid container spacing={2} className={classes.buttons2FA}>
|
|
||||||
<Grid item xs={6}>
|
|
||||||
<Button
|
|
||||||
fullWidth variant="contained"
|
|
||||||
color="inherit" size={"medium"}
|
|
||||||
disabled={isLoggingIn}
|
|
||||||
onClick={onCancel2FA}>
|
|
||||||
{L("general.go_back")}
|
|
||||||
</Button>
|
|
||||||
</Grid>
|
|
||||||
<Grid item xs={6}>
|
|
||||||
<Button
|
|
||||||
type="submit" fullWidth variant="contained"
|
|
||||||
color="primary" size={"medium"}
|
|
||||||
disabled={isLoggingIn || api.user["2fa"].type !== "totp"}
|
|
||||||
onClick={onSubmit2FA}>
|
|
||||||
{isLoggingIn ?
|
|
||||||
<>{L("general.submitting")}… <CircularProgress size={15}/></> :
|
|
||||||
L("general.submit")
|
|
||||||
}
|
|
||||||
</Button>
|
|
||||||
</Grid>
|
|
||||||
</Grid>
|
|
||||||
</>
|
|
||||||
}
|
|
||||||
|
|
||||||
return <>
|
|
||||||
<TextField
|
|
||||||
variant="outlined" margin="normal"
|
|
||||||
id="username" label={L("account.username")} name="username"
|
|
||||||
autoComplete="username" disabled={isLoggingIn}
|
|
||||||
required fullWidth autoFocus
|
|
||||||
value={username} onChange={(e) => setUsername(e.target.value)}
|
|
||||||
/>
|
|
||||||
<TextField
|
|
||||||
variant="outlined" margin="normal"
|
|
||||||
name="password" label={L("account.password")} type="password" id="password"
|
|
||||||
autoComplete="current-password"
|
|
||||||
required fullWidth disabled={isLoggingIn}
|
|
||||||
value={password} onChange={(e) => setPassword(e.target.value)}
|
|
||||||
/>
|
|
||||||
<FormControlLabel
|
|
||||||
control={<Checkbox value="remember" color="primary"/>}
|
|
||||||
label={L("account.remember_me")}
|
|
||||||
checked={rememberMe} onClick={(e) => setRememberMe(!rememberMe)}
|
|
||||||
/>
|
|
||||||
{
|
|
||||||
error
|
|
||||||
? <Alert severity="error">
|
|
||||||
{error}
|
|
||||||
{emailConfirmed === false
|
|
||||||
? <> <Link href={"/resendConfirmEmail"}>Click here</Link> to resend the confirmation email.</>
|
|
||||||
: <></>
|
|
||||||
}
|
|
||||||
</Alert>
|
|
||||||
: (successMessage
|
|
||||||
? <Alert severity="success">{successMessage}</Alert>
|
|
||||||
: <></>)
|
|
||||||
}
|
|
||||||
<Button
|
|
||||||
type={"submit"} fullWidth variant={"contained"}
|
|
||||||
color={"primary"} className={classes.submit}
|
|
||||||
size={"large"}
|
|
||||||
disabled={isLoggingIn}
|
|
||||||
onClick={onLogin}>
|
|
||||||
{isLoggingIn ?
|
|
||||||
<>{L("account.signing_in")}… <CircularProgress size={15}/></> :
|
|
||||||
L("account.sign_in")
|
|
||||||
}
|
|
||||||
</Button>
|
|
||||||
<Grid container>
|
|
||||||
<Grid item xs>
|
|
||||||
<Link href="/resetPassword" variant="body2">
|
|
||||||
{L("account.forgot_password")}
|
|
||||||
</Link>
|
|
||||||
</Grid>
|
|
||||||
{ props.info.registrationAllowed ?
|
|
||||||
<Grid item>
|
|
||||||
<Link href="/register" variant="body2">
|
|
||||||
{L("account.register_text")}
|
|
||||||
</Link>
|
|
||||||
</Grid> : <></>
|
|
||||||
}
|
|
||||||
</Grid>
|
|
||||||
</>
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!loaded) {
|
|
||||||
return <b>{L("general.loading")}… <Icon icon={"spinner"}/></b>
|
|
||||||
}
|
|
||||||
|
|
||||||
let successMessage = getParameter("success");
|
|
||||||
return <Container maxWidth={"xs"} className={classes.container}>
|
|
||||||
<div className={classes.paper}>
|
|
||||||
<div className={classes.headline}>
|
|
||||||
<Typography component="h1" variant="h4">
|
|
||||||
<img src={"/img/icons/logo.png"} alt={"Logo"} height={48} className={classes.logo}/>
|
|
||||||
{props.info.siteName}
|
|
||||||
</Typography>
|
|
||||||
</div>
|
|
||||||
<form className={classes.form} onSubmit={(e) => e.preventDefault()}>
|
|
||||||
{ createForm() }
|
|
||||||
<LanguageSelection api={api} />
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</Container>
|
|
||||||
}
|
|
@ -1,16 +1,12 @@
|
|||||||
import React, {useCallback, useContext, useState} from 'react';
|
import React, {useCallback, useContext, useState} from 'react';
|
||||||
import {Box, Button} from "@mui/material";
|
import {Box, styled} from "@mui/material";
|
||||||
import {LocaleContext} from "shared/locale";
|
import {LocaleContext} from "shared/locale";
|
||||||
|
|
||||||
/*
|
const LanguageFlag = styled(Box)((props) => ({
|
||||||
const useStyles = makeStyles((theme) => ({
|
display: "inline-block",
|
||||||
languageFlag: {
|
marginRight: props.theme.spacing(0.5),
|
||||||
margin: theme.spacing(0.2),
|
cursor: "pointer"
|
||||||
cursor: "pointer",
|
|
||||||
border: 0,
|
|
||||||
}
|
|
||||||
}));
|
}));
|
||||||
*/
|
|
||||||
|
|
||||||
export default function LanguageSelection(props) {
|
export default function LanguageSelection(props) {
|
||||||
|
|
||||||
@ -39,10 +35,10 @@ export default function LanguageSelection(props) {
|
|||||||
} else {
|
} else {
|
||||||
for (const language of Object.values(languages)) {
|
for (const language of Object.values(languages)) {
|
||||||
let key = `lang-${language.code}`;
|
let key = `lang-${language.code}`;
|
||||||
flags.push(<Button type={"button"} title={language.name} onClick={() => onSetLanguage(language.code)}
|
flags.push(<LanguageFlag key={key}>
|
||||||
key={key} >
|
<img alt={key} src={`/img/icons/lang/${language.code}.gif`} onClick={() => onSetLanguage(language.code)} />
|
||||||
<img alt={key} src={`/img/icons/lang/${language.code}.gif`} />
|
</LanguageFlag>
|
||||||
</Button>);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,76 +1,43 @@
|
|||||||
import {Box,
|
import {
|
||||||
|
Box,
|
||||||
Button,
|
Button,
|
||||||
Checkbox, CircularProgress, Container,
|
Checkbox, CircularProgress, Container,
|
||||||
FormControlLabel,
|
FormControlLabel,
|
||||||
Grid,
|
Grid,
|
||||||
Link,
|
Link, styled,
|
||||||
TextField,
|
TextField,
|
||||||
Typography
|
Typography
|
||||||
} from "@mui/material";
|
} from "@mui/material";
|
||||||
|
|
||||||
import {Alert} from '@mui/lab';
|
import {Alert} from '@mui/lab';
|
||||||
import React, {useCallback, useContext, useEffect, useState} from "react";
|
import React, {useCallback, useContext, useEffect, useRef, useState} from "react";
|
||||||
import ReplayIcon from '@mui/icons-material/Replay';
|
import ReplayIcon from '@mui/icons-material/Replay';
|
||||||
import LanguageSelection from "../elements/language-selection";
|
import LanguageSelection from "../elements/language-selection";
|
||||||
import {decodeText, encodeText, getParameter, removeParameter} from "shared/util";
|
import {decodeText, encodeText, getParameter, removeParameter} from "shared/util";
|
||||||
import {LocaleContext} from "shared/locale";
|
import {LocaleContext} from "shared/locale";
|
||||||
|
|
||||||
/*
|
|
||||||
const useStyles = makeStyles((theme) => ({
|
const LoginContainer = styled(Container)((props) => ({
|
||||||
paper: {
|
marginTop: props.theme.spacing(5),
|
||||||
marginTop: theme.spacing(8),
|
paddingBottom: props.theme.spacing(1),
|
||||||
display: 'flex',
|
borderColor: props.theme.palette.primary.main,
|
||||||
flexDirection: 'column',
|
borderStyle: "solid",
|
||||||
alignItems: 'center',
|
borderWidth: 1,
|
||||||
},
|
borderRadius: 5,
|
||||||
avatar: {
|
"& h1 > img": {
|
||||||
margin: theme.spacing(2),
|
marginRight: props.theme.spacing(2),
|
||||||
width: "60px",
|
width: "60px",
|
||||||
height: "60px"
|
height: "60px"
|
||||||
},
|
|
||||||
form: {
|
|
||||||
width: '100%', // Fix IE 11 issue.
|
|
||||||
marginTop: theme.spacing(1),
|
|
||||||
},
|
|
||||||
submit: {
|
|
||||||
margin: theme.spacing(3, 0, 2),
|
|
||||||
},
|
|
||||||
logo: {
|
|
||||||
marginRight: theme.spacing(3)
|
|
||||||
},
|
|
||||||
headline: {
|
|
||||||
width: "100%",
|
|
||||||
},
|
|
||||||
container: {
|
|
||||||
marginTop: theme.spacing(5),
|
|
||||||
paddingBottom: theme.spacing(1),
|
|
||||||
borderColor: theme.palette.primary.main,
|
|
||||||
borderStyle: "solid",
|
|
||||||
borderWidth: 1,
|
|
||||||
borderRadius: 5
|
|
||||||
},
|
|
||||||
buttons2FA: {
|
|
||||||
marginTop: theme.spacing(1),
|
|
||||||
marginBottom: theme.spacing(1),
|
|
||||||
},
|
|
||||||
error2FA: {
|
|
||||||
marginTop: theme.spacing(2),
|
|
||||||
marginBottom: theme.spacing(2),
|
|
||||||
"& > div": {
|
|
||||||
fontSize: 16
|
|
||||||
},
|
|
||||||
"& > button": {
|
|
||||||
marginTop: theme.spacing(1)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
*/
|
|
||||||
|
const ResponseAlert = styled(Alert)((props) => ({
|
||||||
|
marginBottom: props.theme.spacing(2),
|
||||||
|
}));
|
||||||
|
|
||||||
export default function LoginForm(props) {
|
export default function LoginForm(props) {
|
||||||
|
|
||||||
const api = props.api;
|
const api = props.api;
|
||||||
// const classes = useStyles();
|
|
||||||
const classes = { };
|
|
||||||
|
|
||||||
// inputs
|
// inputs
|
||||||
let [username, setUsername] = useState("");
|
let [username, setUsername] = useState("");
|
||||||
@ -91,6 +58,9 @@ export default function LoginForm(props) {
|
|||||||
let [isLoggingIn, setLoggingIn] = useState(false);
|
let [isLoggingIn, setLoggingIn] = useState(false);
|
||||||
let [loaded, setLoaded] = useState(false);
|
let [loaded, setLoaded] = useState(false);
|
||||||
|
|
||||||
|
// ui
|
||||||
|
let passwordRef = useRef();
|
||||||
|
|
||||||
const {translate: L, currentLocale, requestModules} = useContext(LocaleContext);
|
const {translate: L, currentLocale, requestModules} = useContext(LocaleContext);
|
||||||
|
|
||||||
const onUpdateLocale = useCallback(() => {
|
const onUpdateLocale = useCallback(() => {
|
||||||
@ -203,9 +173,9 @@ export default function LoginForm(props) {
|
|||||||
value={tfaCode} onChange={(e) => set2FACode(e.target.value)}
|
value={tfaCode} onChange={(e) => set2FACode(e.target.value)}
|
||||||
/>
|
/>
|
||||||
{
|
{
|
||||||
tfaToken.error ? <Alert severity="error">{tfaToken.error}</Alert> : <></>
|
tfaToken.error ? <ResponseAlert severity="error">{tfaToken.error}</ResponseAlert> : <></>
|
||||||
}
|
}
|
||||||
<Grid container spacing={2} className={classes.buttons2FA}>
|
<Grid container spacing={2}>
|
||||||
<Grid item xs={6}>
|
<Grid item xs={6}>
|
||||||
<Button
|
<Button
|
||||||
fullWidth variant={"contained"}
|
fullWidth variant={"contained"}
|
||||||
@ -237,16 +207,16 @@ export default function LoginForm(props) {
|
|||||||
<Box mt={2} textAlign={"center"}>
|
<Box mt={2} textAlign={"center"}>
|
||||||
{tfaToken.step !== 2
|
{tfaToken.step !== 2
|
||||||
? <CircularProgress/>
|
? <CircularProgress/>
|
||||||
: <div className={classes.error2FA}>
|
: <Box>
|
||||||
<div><b>{L("general.something_went_wrong")}:</b><br />{tfaToken.error}</div>
|
<div><b>{L("general.something_went_wrong")}:</b><br />{tfaToken.error}</div>
|
||||||
<Button onClick={() => set2FAToken({ ...tfaToken, step: 0, error: "" })}
|
<Button onClick={() => set2FAToken({ ...tfaToken, step: 0, error: "" })}
|
||||||
variant={"outlined"} color={"secondary"} size={"small"}>
|
variant={"outlined"} color={"secondary"} size={"small"}>
|
||||||
<ReplayIcon /> {L("general.retry")}
|
<ReplayIcon /> {L("general.retry")}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</Box>
|
||||||
}
|
}
|
||||||
</Box>
|
</Box>
|
||||||
<Grid container spacing={2} className={classes.buttons2FA}>
|
<Grid container spacing={2}>
|
||||||
<Grid item xs={6}>
|
<Grid item xs={6}>
|
||||||
<Button
|
<Button
|
||||||
fullWidth variant={"contained"}
|
fullWidth variant={"contained"}
|
||||||
@ -275,18 +245,21 @@ export default function LoginForm(props) {
|
|||||||
|
|
||||||
return <>
|
return <>
|
||||||
<TextField
|
<TextField
|
||||||
variant="outlined" margin="normal"
|
variant={"outlined"} margin={"normal"}
|
||||||
id="username" label={L("account.username")} name="username"
|
label={L("account.username")} name={"username"}
|
||||||
autoComplete="username" disabled={isLoggingIn}
|
autoComplete={"username"} disabled={isLoggingIn}
|
||||||
required fullWidth autoFocus
|
required fullWidth autoFocus
|
||||||
value={username} onChange={(e) => setUsername(e.target.value)}
|
value={username} onChange={(e) => setUsername(e.target.value)}
|
||||||
|
onKeyDown={e => e.key === "Enter" && passwordRef.current && passwordRef.current.focus()}
|
||||||
/>
|
/>
|
||||||
<TextField
|
<TextField
|
||||||
variant="outlined" margin="normal"
|
variant={"outlined"} margin={"normal"}
|
||||||
name="password" label={L("account.password")} type="password" id="password"
|
name={"password"} label={L("account.password")} type={"password"}
|
||||||
autoComplete="current-password"
|
autoComplete={"current-password"}
|
||||||
required fullWidth disabled={isLoggingIn}
|
required fullWidth disabled={isLoggingIn}
|
||||||
value={password} onChange={(e) => setPassword(e.target.value)}
|
value={password} onChange={(e) => setPassword(e.target.value)}
|
||||||
|
onKeyDown={e => e.key === "Enter" && onLogin()}
|
||||||
|
inputRef={passwordRef}
|
||||||
/>
|
/>
|
||||||
<FormControlLabel
|
<FormControlLabel
|
||||||
control={<Checkbox value="remember" color="primary"/>}
|
control={<Checkbox value="remember" color="primary"/>}
|
||||||
@ -295,20 +268,20 @@ export default function LoginForm(props) {
|
|||||||
/>
|
/>
|
||||||
{
|
{
|
||||||
error
|
error
|
||||||
? <Alert severity="error">
|
? <ResponseAlert severity={"error"}>
|
||||||
{error}
|
{error}
|
||||||
{emailConfirmed === false
|
{emailConfirmed === false
|
||||||
? <> <Link href={"/resendConfirmEmail"}>Click here</Link> to resend the confirmation email.</>
|
? <> <Link href={"/resendConfirmEmail"}>Click here</Link> to resend the confirmation email.</>
|
||||||
: <></>
|
: <></>
|
||||||
}
|
}
|
||||||
</Alert>
|
</ResponseAlert>
|
||||||
: (successMessage
|
: (successMessage
|
||||||
? <Alert severity="success">{successMessage}</Alert>
|
? <ResponseAlert severity={"success"}>{successMessage}</ResponseAlert>
|
||||||
: <></>)
|
: <></>)
|
||||||
}
|
}
|
||||||
<Button
|
<Button
|
||||||
type={"submit"} fullWidth variant={"contained"}
|
type={"submit"} fullWidth variant={"contained"}
|
||||||
color={"primary"} className={classes.submit}
|
color={"primary"}
|
||||||
size={"large"}
|
size={"large"}
|
||||||
disabled={isLoggingIn}
|
disabled={isLoggingIn}
|
||||||
onClick={onLogin}>
|
onClick={onLogin}>
|
||||||
@ -342,18 +315,14 @@ export default function LoginForm(props) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let successMessage = getParameter("success");
|
let successMessage = getParameter("success");
|
||||||
return <Container maxWidth={"xs"} className={classes.container}>
|
return <LoginContainer maxWidth={"xs"}>
|
||||||
<div className={classes.paper}>
|
<Box mt={2}>
|
||||||
<div className={classes.headline}>
|
<Typography component="h1" variant="h4">
|
||||||
<Typography component="h1" variant="h4">
|
<img src={"/img/icons/logo.png"} alt={"Logo"} height={48} />
|
||||||
<img src={"/img/icons/logo.png"} alt={"Logo"} height={48} className={classes.logo}/>
|
{props.info.siteName}
|
||||||
{props.info.siteName}
|
</Typography>
|
||||||
</Typography>
|
{ createForm() }
|
||||||
</div>
|
<LanguageSelection api={api} />
|
||||||
<form className={classes.form} onSubmit={(e) => e.preventDefault()}>
|
</Box>
|
||||||
{ createForm() }
|
</LoginContainer>
|
||||||
<LanguageSelection api={api} />
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</Container>
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user