Merged PR 19: login step update

login step update
master
Tudor Stanciu 2020-12-24 14:48:43 +00:00
commit 4286b55d57
9 changed files with 159 additions and 22 deletions

View File

@ -21,6 +21,8 @@
"Username": "Username", "Username": "Username",
"Password": "Password", "Password": "Password",
"Label": "Login", "Label": "Login",
"ChangeUser": "Change user",
"Logout": "Logout",
"IncorrectCredentials": "Incorrect credentials." "IncorrectCredentials": "Incorrect credentials."
} }
} }

View File

@ -12,6 +12,8 @@
"Username": "Utilizator", "Username": "Utilizator",
"Password": "Parolă", "Password": "Parolă",
"Label": "Autentificare", "Label": "Autentificare",
"ChangeUser": "Schimbă utilizatorul",
"Logout": "Deconectare",
"IncorrectCredentials": "Credențiale incorecte." "IncorrectCredentials": "Credențiale incorecte."
} }
} }

View File

@ -7,7 +7,6 @@ import LoginContainer from "../../features/login/components/LoginContainer";
const useStyles = makeStyles(() => ({ const useStyles = makeStyles(() => ({
app: { app: {
textAlign: "center",
backgroundColor: "#282c34", backgroundColor: "#282c34",
minHeight: "100vh", minHeight: "100vh",
display: "flex", display: "flex",
@ -23,7 +22,6 @@ const useStyles = makeStyles(() => ({
color: "white" color: "white"
}, },
appLoginOnly: { appLoginOnly: {
textAlign: "center",
backgroundColor: "#282c34", backgroundColor: "#282c34",
minHeight: "100vh", minHeight: "100vh",
display: "flex", display: "flex",
@ -34,12 +32,12 @@ const useStyles = makeStyles(() => ({
const Main = () => { const Main = () => {
const classes = useStyles(); const classes = useStyles();
const { tokenIsValid } = useAuthorizationToken(); const { validateToken } = useAuthorizationToken();
const _tokenIsValid = tokenIsValid(); const tokenIsValid = validateToken();
return ( return (
<div className={_tokenIsValid ? classes.app : classes.appLoginOnly}> <div className={tokenIsValid ? classes.app : classes.appLoginOnly}>
{_tokenIsValid ? ( {tokenIsValid ? (
<> <>
<ApplicationStepper /> <ApplicationStepper />
<div className={classes.content}> <div className={classes.content}>

View File

@ -0,0 +1,80 @@
import React from "react";
import { makeStyles } from "@material-ui/core/styles";
import Card from "@material-ui/core/Card";
import CardHeader from "@material-ui/core/CardHeader";
import CardContent from "@material-ui/core/CardContent";
import CardActions from "@material-ui/core/CardActions";
import { Avatar, Collapse, Tooltip, Divider } from "@material-ui/core";
import IconButton from "@material-ui/core/IconButton";
import { AccountBox, RotateLeft, ExitToApp } from "@material-ui/icons";
import LoginComponent from "./LoginComponent";
import { useTranslation } from "react-i18next";
const useStyles = makeStyles(theme => ({
root: {
minWidth: 350
},
onRight: {
marginLeft: "auto"
},
avatar: {
backgroundColor: theme.palette.primary.main
}
}));
const LoggedInComponent = ({ credentials, onChange, onLogin, onLogout }) => {
const classes = useStyles();
const { t } = useTranslation();
const [expanded, setExpanded] = React.useState(false);
const handleExpandLogin = () => {
setExpanded(!expanded);
};
return (
<Card className={classes.root}>
<CardHeader
avatar={
<Avatar aria-label="recipe" className={classes.avatar}>
<AccountBox />
</Avatar>
}
title={<strong>{t("Server.ActiveSession")}</strong>}
subheader="September 14, 2016"
/>
<CardActions disableSpacing>
<Tooltip title={t("Login.ChangeUser")}>
<IconButton
size="small"
className={classes.onRight}
onClick={handleExpandLogin}
aria-expanded={expanded}
aria-label="show login component"
>
<RotateLeft />
</IconButton>
</Tooltip>
<Tooltip title={t("Login.Logout")}>
<IconButton size="small" onClick={onLogout}>
<ExitToApp />
</IconButton>
</Tooltip>
</CardActions>
<Divider />
<Collapse in={expanded} timeout="auto" unmountOnExit>
<CardContent>
<LoginComponent
credentials={credentials}
onChange={onChange}
onLogin={onLogin}
/>
</CardContent>
</Collapse>
</Card>
);
};
LoggedInComponent.propTypes = {};
export default LoggedInComponent;

View File

@ -0,0 +1,25 @@
import React from "react";
import PropTypes from "prop-types";
import { Card } from "@material-ui/core";
import LoginComponent from "./LoginComponent";
const LoginCard = ({ credentials, onChange, onLogin }) => {
return (
<Card variant="outlined">
<LoginComponent
credentials={credentials}
onChange={onChange}
onLogin={onLogin}
/>
</Card>
);
};
LoginCard.propTypes = {
credentials: PropTypes.object.isRequired,
onChange: PropTypes.func.isRequired,
onLogin: PropTypes.func.isRequired
};
export default LoginCard;

View File

@ -5,7 +5,6 @@ import {
TextField, TextField,
InputAdornment, InputAdornment,
Button, Button,
Card,
CardActions, CardActions,
CardContent CardContent
} from "@material-ui/core"; } from "@material-ui/core";
@ -17,6 +16,9 @@ const useStyles = makeStyles(theme => ({
field: { field: {
margin: theme.spacing(1), margin: theme.spacing(1),
width: "300px" width: "300px"
},
onRight: {
marginLeft: "auto"
} }
})); }));
@ -25,7 +27,7 @@ const LoginComponent = ({ credentials, onChange, onLogin }) => {
const { t } = useTranslation(); const { t } = useTranslation();
return ( return (
<Card variant="outlined"> <>
<CardContent> <CardContent>
<TextField <TextField
className={classes.field} className={classes.field}
@ -51,11 +53,16 @@ const LoginComponent = ({ credentials, onChange, onLogin }) => {
/> />
</CardContent> </CardContent>
<CardActions> <CardActions>
<Button variant="contained" color="primary" onClick={onLogin}> <Button
className={classes.onRight}
variant="contained"
color="primary"
onClick={onLogin}
>
{t("Login.Label")} {t("Login.Label")}
</Button> </Button>
</CardActions> </CardActions>
</Card> </>
); );
}; };

View File

@ -1,18 +1,20 @@
import React, { useContext } from "react"; import React, { useContext } from "react";
import LoginComponent from "./LoginComponent"; import LoginCard from "./LoginCard";
import { authenticate } from "../../../utils/identity"; import { authenticate, invalidate } from "../../../utils/identity";
import { import {
ApplicationStateContext, ApplicationStateContext,
ApplicationDispatchContext ApplicationDispatchContext
} from "../../../state/ApplicationContexts"; } from "../../../state/ApplicationContexts";
import { useToast } from "../../../hooks"; import { useToast, useAuthorizationToken } from "../../../hooks";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import LoggedInComponent from "./LoggedInComponent";
const LoginContainer = () => { const LoginContainer = () => {
const state = useContext(ApplicationStateContext); const state = useContext(ApplicationStateContext);
const dispatchActions = useContext(ApplicationDispatchContext); const dispatchActions = useContext(ApplicationDispatchContext);
const { error } = useToast(); const { error } = useToast();
const { t } = useTranslation(); const { t } = useTranslation();
const { tokenIsValid } = useAuthorizationToken();
const handleChange = prop => event => { const handleChange = prop => event => {
dispatchActions.onCredentialsChange(prop, event.target.value); dispatchActions.onCredentialsChange(prop, event.target.value);
@ -33,13 +35,26 @@ const LoginContainer = () => {
} }
}; };
const handleLogout = () => {
invalidate();
};
return ( return (
<> <>
<LoginComponent {tokenIsValid ? (
<LoggedInComponent
credentials={state.credentials}
onChange={handleChange}
onLogin={handleLogin}
onLogout={handleLogout}
/>
) : (
<LoginCard
credentials={state.credentials} credentials={state.credentials}
onChange={handleChange} onChange={handleChange}
onLogin={handleLogin} onLogin={handleLogin}
/> />
)}
</> </>
); );
}; };

View File

@ -5,7 +5,7 @@ export const useAuthorizationToken = () => {
const state = useContext(ApplicationStateContext); const state = useContext(ApplicationStateContext);
const getToken = () => state.security.authorization.token; const getToken = () => state.security.authorization.token;
const tokenIsValid = () => { const validateToken = () => {
const token = getToken(); const token = getToken();
if (!token) { if (!token) {
return false; return false;
@ -15,5 +15,6 @@ export const useAuthorizationToken = () => {
return valid; return valid;
}; };
return { getToken, tokenIsValid }; const tokenIsValid = validateToken();
return { getToken, validateToken, tokenIsValid };
}; };

View File

@ -1,5 +1,5 @@
import { request } from "./axios"; import { request } from "./axios";
import { setItem } from "./localStorage"; import { setItem, getItem, removeItem } from "./localStorage";
const storageKeys = { const storageKeys = {
TOKEN: "AUTHORIZATION_TOKEN" TOKEN: "AUTHORIZATION_TOKEN"
@ -22,4 +22,11 @@ const authenticate = async (username, password) => {
return response; return response;
}; };
export { storageKeys, authenticate }; const invalidate = () => {
const token = getItem(storageKeys.TOKEN);
if (token) {
removeItem(storageKeys.TOKEN);
}
};
export { storageKeys, authenticate, invalidate };