Added logout button functionality

This commit is contained in:
kunkliricsi 2020-11-04 12:34:37 +01:00
parent 8e6759f917
commit 05a8d7f090
7 changed files with 75 additions and 33 deletions

View File

@ -12,7 +12,7 @@
"jquery": "^3.5.1", "jquery": "^3.5.1",
"merge": "1.2.1", "merge": "1.2.1",
"popper.js": "^1.16.0", "popper.js": "^1.16.0",
"react": "16.11.0", "react": "^16.11.0",
"react-dom": "16.11.0", "react-dom": "16.11.0",
"react-redux": "7.1.1", "react-redux": "7.1.1",
"react-router": "5.1.2", "react-router": "5.1.2",

View File

@ -1,4 +1,4 @@
import { Box, Container, IconButton, Menu, MenuItem } from '@material-ui/core'; import { Box, Container, IconButton, Menu, MenuItem, MenuList, Paper, Grow, Popper } from '@material-ui/core';
import AccountCircle from '@material-ui/icons/AccountCircle'; import AccountCircle from '@material-ui/icons/AccountCircle';
import AppBar from '@material-ui/core/AppBar'; import AppBar from '@material-ui/core/AppBar';
import blue from '@material-ui/core/colors/blue'; import blue from '@material-ui/core/colors/blue';
@ -7,11 +7,12 @@ import { createMuiTheme, createStyles, makeStyles, Theme } from '@material-ui/co
import Toolbar from '@material-ui/core/Toolbar'; import Toolbar from '@material-ui/core/Toolbar';
import Typography from '@material-ui/core/Typography'; import Typography from '@material-ui/core/Typography';
import { ThemeProvider } from '@material-ui/styles'; import { ThemeProvider } from '@material-ui/styles';
import React, { useState } from 'react'; import React, { useState, } from 'react';
import { BrowserRouter, NavLink, Redirect, Route, Switch } from 'react-router-dom'; import { BrowserRouter, NavLink, Redirect, Route, Switch, Link } from 'react-router-dom';
import BirdmapTitle from './common/components/BirdmapTitle'; import BirdmapTitle from './common/components/BirdmapTitle';
import Auth from './components/auth/Auth'; import Auth from './components/auth/Auth';
import AuthService from './components/auth/AuthService'; import AuthService from './components/auth/AuthService';
import { ClickAwayListener } from '@material-ui/core';
const theme = createMuiTheme({ const theme = createMuiTheme({
@ -87,17 +88,47 @@ const PrivateRoute = ({ component: Component, authenticated: Authenticated, ...r
const DefaultLayout = ({ component: Component, authenticated: Authenticated, ...rest }: { [x: string]: any, component: any, authenticated: any }) => { const DefaultLayout = ({ component: Component, authenticated: Authenticated, ...rest }: { [x: string]: any, component: any, authenticated: any }) => {
const classes = useDefaultLayoutStyles(); const classes = useDefaultLayoutStyles();
const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null); const [open, setOpen] = React.useState(false);
const open = Boolean(anchorEl); const anchorRef = React.useRef<HTMLButtonElement>(null);
const handleMenu = (event: React.MouseEvent<HTMLElement>) => { const handleToggle = () => {
setAnchorEl(event.currentTarget); setOpen((prevOpen) => !prevOpen);
}; };
const handleClose = () => { const handleClose = (event: React.MouseEvent<EventTarget>) => {
setAnchorEl(null); if (anchorRef.current && anchorRef.current.contains(event.target as HTMLElement)) {
return;
}
setOpen(false);
}; };
const handleLogout = (event: React.MouseEvent<EventTarget>) => {
if (anchorRef.current && anchorRef.current.contains(event.target as HTMLElement)) {
return;
}
AuthService.logout();
setOpen(false);
};
function handleListKeyDown(event: React.KeyboardEvent) {
if (event.key === 'Tab') {
event.preventDefault();
setOpen(false);
}
}
const prevOpen = React.useRef(open);
React.useEffect(() => {
if (prevOpen.current === true && open === false) {
anchorRef.current!.focus();
}
prevOpen.current = open;
}, [open]);
const renderNavLinks = () => { const renderNavLinks = () => {
return Authenticated return Authenticated
? <Container className={classes.nav_menu}> ? <Container className={classes.nav_menu}>
@ -105,28 +136,28 @@ const DefaultLayout = ({ component: Component, authenticated: Authenticated, ...
<NavLink exact to="/devices" className={classes.nav_menu_item} activeClassName={classes.nav_menu_item_active}>Devices</NavLink> <NavLink exact to="/devices" className={classes.nav_menu_item} activeClassName={classes.nav_menu_item_active}>Devices</NavLink>
<NavLink exact to="/heatmap" className={classes.nav_menu_item} activeClassName={classes.nav_menu_item_active}>Heatmap</NavLink> <NavLink exact to="/heatmap" className={classes.nav_menu_item} activeClassName={classes.nav_menu_item_active}>Heatmap</NavLink>
<IconButton className={classes.nav_menu_icon} <IconButton className={classes.nav_menu_icon}
ref={anchorRef}
aria-haspopup="true" aria-haspopup="true"
aria-controls="menu-appbar" aria-controls={open ? 'menu-list-grow' : undefined}
aria-label="account of current user" aria-label="account of current user"
onClick={handleMenu}> onClick={handleToggle}>
<AccountCircle/> <AccountCircle/>
</IconButton> </IconButton>
<Menu <Popper open={open} anchorEl={anchorRef.current} role={undefined} transition disablePortal>
id="menu-appbar" {({ TransitionProps, placement }) => (
anchorEl={anchorEl} <Grow
anchorOrigin={{ {...TransitionProps}
vertical: 'bottom', style={{ transformOrigin: placement === 'bottom' ? 'center top' : 'center bottom' }}>
horizontal: 'right', <Paper>
}} <ClickAwayListener onClickAway={handleClose}>
keepMounted <MenuList autoFocusItem={open} id="menu-list-grow" onKeyDown={handleListKeyDown}>
transformOrigin={{ <MenuItem onClick={handleLogout} component={Link} {...{ to: '/login' }}>Logout</MenuItem>
vertical: 'top', </MenuList>
horizontal: 'right', </ClickAwayListener>
}} </Paper>
open={open} </Grow>
onClose={handleClose}> )}
<MenuItem onClick={handleClose}>Logout</MenuItem> </Popper>
</Menu>
</Container> </Container>
: null; : null;
}; };

View File

@ -5,6 +5,7 @@ import { makeStyles, createStyles, Theme } from '@material-ui/core/styles';
import AuthService from './AuthService'; import AuthService from './AuthService';
export default function Auth(props: any) { export default function Auth(props: any) {
props.onAuthenticated();
const history = useHistory(); const history = useHistory();
const classes = useStyles(); const classes = useStyles();
@ -36,7 +37,6 @@ export default function Auth(props: any) {
}; };
const onLoginClicked = () => { const onLoginClicked = () => {
setIsLoggingIn(true);
if (!username) { if (!username) {
setShowError(true); setShowError(true);
@ -52,6 +52,7 @@ export default function Auth(props: any) {
return; return;
} }
setIsLoggingIn(true);
AuthService.login(username, password) AuthService.login(username, password)
.then(() => { .then(() => {
props.onAuthenticated(); props.onAuthenticated();
@ -86,7 +87,7 @@ export default function Auth(props: any) {
</Typography> </Typography>
</Grid> </Grid>
<Grid item xs={12} > <Grid item xs={12} >
<TextField label="Username" type="text" onChange={onUsernameChanged} /> <TextField autoFocus label="Username" type="text" onChange={onUsernameChanged} />
</Grid> </Grid>
<Grid item xs={12} > <Grid item xs={12} >
<TextField label="Password" type="password" onChange={onPasswordChanged} onKeyPress={onPasswordKeyPress} /> <TextField label="Password" type="password" onChange={onPasswordChanged} onKeyPress={onPasswordKeyPress} />

View File

@ -9,6 +9,10 @@ exports.default = {
isAdmin: function () { isAdmin: function () {
return sessionStorage.getItem('role') === 'Admin'; return sessionStorage.getItem('role') === 'Admin';
}, },
logout: function () {
sessionStorage.removeItem('user');
sessionStorage.removeItem('role');
},
login: function (username, password) { login: function (username, password) {
var body = { var body = {
username: username, username: username,

View File

@ -1 +1 @@
{"version":3,"file":"AuthService.js","sourceRoot":"","sources":["AuthService.ts"],"names":[],"mappings":";;AAAA,wDAAmD;AAEnD,IAAM,SAAS,GAAG,uBAAuB,CAAC;AAE1C,kBAAe;IACX,eAAe;QACX,OAAO,cAAc,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,IAAI,CAAC;IACnD,CAAC;IAED,OAAO;QACH,OAAO,cAAc,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,OAAO,CAAC;IACtD,CAAC;IAED,KAAK,EAAL,UAAM,QAAgB,EAAE,QAAgB;QACpC,IAAI,IAAI,GAAG;YACP,QAAQ,EAAE,QAAQ;YAClB,QAAQ,EAAE,QAAQ;SACrB,CAAC;QACF,IAAI,OAAO,GAAG;YACV,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACL,cAAc,EAAE,kBAAkB;aACrC;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;SAC7B,CAAC;QAEF,OAAO,qBAAW,CAAC,WAAW,CAAC,SAAS,EAAE,OAAO,CAAC;aAC7C,IAAI,CAAC,UAAA,QAAQ;YACV,cAAc,CAAC,OAAO,CAAC,MAAM,EAAK,QAAQ,CAAC,UAAU,SAAI,QAAQ,CAAC,YAAc,CAAC,CAAC;YAClF,cAAc,CAAC,OAAO,CAAC,MAAM,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAC;YAC9C,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;QAC7B,CAAC,CAAC,CAAC;IACX,CAAC;CACJ,CAAA"} {"version":3,"file":"AuthService.js","sourceRoot":"","sources":["AuthService.ts"],"names":[],"mappings":";;AAAA,wDAAmD;AAEnD,IAAM,SAAS,GAAG,uBAAuB,CAAC;AAE1C,kBAAe;IACX,eAAe;QACX,OAAO,cAAc,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,IAAI,CAAC;IACnD,CAAC;IAED,OAAO;QACH,OAAO,cAAc,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,OAAO,CAAC;IACtD,CAAC;IAED,MAAM;QACF,cAAc,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;QAClC,cAAc,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;IACtC,CAAC;IAED,KAAK,EAAL,UAAM,QAAgB,EAAE,QAAgB;QACpC,IAAI,IAAI,GAAG;YACP,QAAQ,EAAE,QAAQ;YAClB,QAAQ,EAAE,QAAQ;SACrB,CAAC;QACF,IAAI,OAAO,GAAG;YACV,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACL,cAAc,EAAE,kBAAkB;aACrC;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;SAC7B,CAAC;QAEF,OAAO,qBAAW,CAAC,WAAW,CAAC,SAAS,EAAE,OAAO,CAAC;aAC7C,IAAI,CAAC,UAAA,QAAQ;YACV,cAAc,CAAC,OAAO,CAAC,MAAM,EAAK,QAAQ,CAAC,UAAU,SAAI,QAAQ,CAAC,YAAc,CAAC,CAAC;YAClF,cAAc,CAAC,OAAO,CAAC,MAAM,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAC;YAC9C,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;QAC7B,CAAC,CAAC,CAAC;IACX,CAAC;CACJ,CAAA"}

View File

@ -11,6 +11,11 @@ export default {
return sessionStorage.getItem('role') === 'Admin'; return sessionStorage.getItem('role') === 'Admin';
}, },
logout() {
sessionStorage.removeItem('user');
sessionStorage.removeItem('role');
},
login(username: string, password: string) { login(username: string, password: string) {
let body = { let body = {
username: username, username: username,

View File

@ -8,7 +8,8 @@
}, },
"AllowedHosts": "*", "AllowedHosts": "*",
"Secret": "7vj.3KW.hYE!}4u6", "Secret": "7vj.3KW.hYE!}4u6",
"LocalDbConnectionString": "Data Source=DESKTOP-A6JQ6B5\\SQLEXPRESS;Initial Catalog=Birdmap;Integrated Security=True;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False", // "LocalDbConnectionString": "Data Source=DESKTOP-3600\\SQLEXPRESS;Initial Catalog=birdmap;Integrated Security=True;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False",
"LocalDbConnectionString": "Data Source=DESKTOP-3600;Initial Catalog=birdmap;Integrated Security=True;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False",
"Defaults": { "Defaults": {
"Services": { "Services": {
"Local Database": "https://localhost:44331/health", "Local Database": "https://localhost:44331/health",