Refactor authentication with Context

This commit is contained in:
rui hildt 2020-08-21 11:51:52 +02:00
parent ec65c3b9dd
commit 51ec69a3cb
11 changed files with 137 additions and 109 deletions

View File

@ -1,10 +1,12 @@
import React from 'react';
import React, { useState } from 'react';
import 'rsuite/lib/styles/index.less';
import { BrowserRouter as Router, Switch, Route } from 'react-router-dom';
import PrivateRoute from './components/routes/PrivateRoute';
import PublicRoute from './components/routes/PublicRoute';
import { AuthContext } from './helpers/authContext';
import PrivateRoute from './components/Routes/PrivateRoute';
import Home from './screens/Home';
import Dashboard from './screens/Dashboard';
import Schedule from './screens/Schedule/Schedule';
import Availability from './screens/Availability/Availability';
@ -12,21 +14,35 @@ import Invite from './screens/Invite/Invite';
import Login from './screens/Login';
import Register from './screens/Register';
const existingToken = localStorage.getItem('token');
// const existingUser = JSON.parse(localStorage.getItem('user'));
export default function App() {
const [authToken, setAuthToken] = useState(existingToken);
const setToken = (data) => {
localStorage.setItem('token', JSON.stringify(data));
setAuthToken(data);
};
return (
<Router>
<Switch>
<Route path='/' exact component={Login} />
<AuthContext.Provider value={{ authToken, setAuthToken: setToken }}>
<Router>
<Switch>
<Route path='/' exact component={Home} />
<Route path='/login' component={Login} />
<Route path='/register' component={Register} />
<PublicRoute path='/login' component={Login} />
<PublicRoute path='/register' component={Register} />
<PrivateRoute path='/dashboard' component={Dashboard} />
<PrivateRoute path='/schedule' component={Schedule} />
<PrivateRoute path='/invite' component={Invite} />
<PrivateRoute path='/availability' component={Availability} />
<PrivateRoute path='/schedule' component={Schedule} />
</Switch>
</Router>
<PrivateRoute path='/dashboard' component={Dashboard} />
<PrivateRoute path='/schedule' component={Schedule} />
<PrivateRoute path='/invite' component={Invite} />
<PrivateRoute
path='/availability'
component={Availability}
/>
<PrivateRoute path='/schedule' component={Schedule} />
</Switch>
</Router>
</AuthContext.Provider>
);
}

View File

@ -1,6 +1,5 @@
import React from 'react';
import { useHistory } from 'react-router-dom';
import { Nav, Icon, Dropdown, Popover, Whisper } from 'rsuite';
export default function MenuDropdown() {
@ -12,18 +11,34 @@ export default function MenuDropdown() {
triggerRef.current.hide();
}
function handleLogout() {
localStorage.removeItem('token');
localStorage.removeItem('user');
history.push('/');
}
const MenuPopover = ({ onSelect, ...rest }) => (
<Popover {...rest} full>
<Dropdown.Menu onSelect={onSelect}>
<Dropdown.Item eventKey={'/'}>Dashboard</Dropdown.Item>
<Dropdown.Item eventKey={'register'}>Register</Dropdown.Item>
<Dropdown.Item eventKey={'login'}>Login</Dropdown.Item>
<Dropdown.Item eventKey={'schedule'}>1 - Schedule a meeting</Dropdown.Item>
<Dropdown.Item eventKey={'invite'}>2 - Invite participants</Dropdown.Item>
<Dropdown.Item eventKey={'availability'}>3 - Add your availability</Dropdown.Item>
<Dropdown.Item eventKey={'confirm'}>4 - Confirm meeting date</Dropdown.Item>
<Dropdown.Item eventKey={'schedule'}>
1 - Schedule a meeting
</Dropdown.Item>
<Dropdown.Item eventKey={'invite'}>
2 - Invite participants
</Dropdown.Item>
<Dropdown.Item eventKey={'availability'}>
3 - Add your availability
</Dropdown.Item>
<Dropdown.Item eventKey={'confirm'}>
4 - Confirm meeting date
</Dropdown.Item>
<Dropdown.Item eventKey={'settings'}>Settings</Dropdown.Item>
<Dropdown.Item eventKey={5}>Log Out</Dropdown.Item>
<Dropdown.Item eventKey={5} onSelect={() => handleLogout()}>
Log Out
</Dropdown.Item>
</Dropdown.Menu>
</Popover>
);

View File

@ -0,0 +1,19 @@
import React from 'react';
import { Redirect, Route } from 'react-router-dom';
import { useAuth } from '../../helpers/authContext';
const PrivateRoute = ({ component: Component, ...rest }) => {
const { authToken } = useAuth();
return (
<Route
{...rest}
render={(props) =>
authToken ? <Component {...props} /> : <Redirect to='/login' />
}
/>
);
};
export default PrivateRoute;

View File

@ -0,0 +1,25 @@
import React from 'react';
import { Redirect, Route } from 'react-router-dom';
import { useAuth } from '../../helpers/authContext';
// TODO Make sure it's used, else delete it and remove message in App
const PublicRoute = ({ component: Component, ...rest }) => {
const isAuthenticated = useAuth();
return (
<Route
{...rest}
render={(props) =>
isAuthenticated ? (
<Redirect to='/dashboard' />
) : (
<Component {...props} />
)
}
/>
);
};
export default PublicRoute;

View File

@ -1,29 +0,0 @@
import React from 'react';
import { Route, Redirect } from 'react-router-dom';
import { getToken } from '../../utils/common';
const isLoggedIn = getToken();
const PrivateRoute = ({ component: Component, user, ...rest }) => {
return (
<Route
{...rest}
render={(props) =>
isLoggedIn ? (
<Component {...rest} {...props} />
) : (
<Redirect
to={{
pathname: '/login',
state: {
from: props.location,
},
}}
/>
)
}
/>
);
};
export default PrivateRoute;

View File

@ -1,22 +0,0 @@
import React from 'react';
import { Route, Redirect } from 'react-router-dom';
import { getToken } from '../../utils/common';
const isLoggedIn = getToken();
function PublicRoute({ component: Component, ...rest }) {
return (
<Route
{...rest}
render={(props) =>
!isLoggedIn ? (
<Component {...props} />
) : (
<Redirect to={{ pathname: '/dashboard' }} />
)
}
/>
);
}
export default PublicRoute;

View File

@ -0,0 +1,7 @@
import { createContext, useContext } from 'react';
export const AuthContext = createContext();
export function useAuth() {
return useContext(AuthContext);
}

19
src/screens/Home.js Normal file
View File

@ -0,0 +1,19 @@
import React from 'react';
import { Panel } from 'rsuite';
import NavBar from '../components/Navbar/NavBar';
const boxStyle = {
margin: '50px 10px',
};
export default function Home() {
return (
<>
<NavBar title='Meeting Planner' />
<Panel header={<h3>Home</h3>} bordered style={boxStyle}>
<p>This will be the home page</p>
</Panel>
</>
);
}

View File

@ -1,6 +1,5 @@
import React, { useState } from 'react';
import { useHistory } from 'react-router-dom';
import { backend } from '../utils/http-common';
import { Redirect } from 'react-router-dom';
import {
Panel,
Form,
@ -11,18 +10,19 @@ import {
Message,
} from 'rsuite';
import { setUserSession } from '../utils/common';
import NavBar from './../components/Navbar/NavBar';
import { backend } from '../helpers/http-common';
import { useAuth } from '../helpers/authContext';
export default function Login() {
const history = useHistory();
const [error, setError] = useState(false);
const [credentials, setCredentials] = useState({
email: '',
password: '',
});
const { setAuthToken, authToken } = useAuth();
const handleChange = (value, evt) => {
setCredentials({
...credentials,
@ -34,16 +34,20 @@ export default function Login() {
backend
.post('/auth/login', credentials)
.then((response) => {
setUserSession(response.data.token, response.data.user);
history.push('/dashboard');
setAuthToken(response.data.token);
})
.catch((error) => {
if (error.response.status === 401)
setError('Incorrect credentials. Please try again.');
else setError('Something went wrong. Please try again later.');
if (error.response.status === 401) {
setError('The credentials provided were incorrect.');
} else
setError('Something went wrong. Please try again later.');
});
};
if (authToken) {
return <Redirect to='/dashboard' />;
}
return (
<>
<NavBar title='Login' />

View File

@ -1,26 +0,0 @@
// Set/Remove user and token to local storage
export const setUserSession = (token, user) => {
localStorage.setItem('token', token);
localStorage.setItem('user', JSON.stringify(user));
};
export const getUser = () => {
const userJSON = localStorage.getItem('user');
if (userJSON) {
const user = JSON.parse(userJSON);
return user;
} else return null;
};
export const getToken = () => {
const token = localStorage.getItem('token');
if (token) return token;
else return null;
};
export const removeUserSession = () => {
localStorage.removeItem('token');
localStorage.removeItem('user');
};