Implement public/private routing

This commit is contained in:
rui hildt 2020-08-19 20:04:52 +02:00
parent 125a03f529
commit ec65c3b9dd
13 changed files with 110 additions and 82 deletions

32
src/App.js Normal file
View File

@ -0,0 +1,32 @@
import React 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 Dashboard from './screens/Dashboard';
import Schedule from './screens/Schedule/Schedule';
import Availability from './screens/Availability/Availability';
import Invite from './screens/Invite/Invite';
import Login from './screens/Login';
import Register from './screens/Register';
export default function App() {
return (
<Router>
<Switch>
<Route path='/' exact component={Login} />
<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>
);
}

View File

@ -2,10 +2,9 @@ import React from 'react';
import { Helmet } from 'react-helmet'; import { Helmet } from 'react-helmet';
export default function TitleComponent({ title }) { export default function TitleComponent({ title }) {
var defaultTitle = 'Meeting Planner';
return ( return (
<Helmet> <Helmet>
<title>{title ? `${title} | Meeting Planner` : defaultTitle}</title> <title>{title ? `${title} | Meeting Planner` : 'Meeting Planner'}</title>
</Helmet> </Helmet>
); );
} }

View File

@ -16,13 +16,11 @@ export default function NavBar({ title }) {
alignItems: 'center', alignItems: 'center',
}} }}
> >
{/* This hidden nav is a hack to have the title perfectly centered. */}
<Nav style={{ visibility: 'hidden' }}> <Nav style={{ visibility: 'hidden' }}>
{/* This hidden nav is a hack to have the title perfectly centered. */}
<MenuDropdown /> <MenuDropdown />
</Nav> </Nav>
<div>
<h3>{title}</h3> <h3>{title}</h3>
</div>
<MenuDropdown /> <MenuDropdown />
</Navbar.Body> </Navbar.Body>
</Navbar> </Navbar>

View File

@ -0,0 +1,29 @@
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

@ -0,0 +1,22 @@
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

@ -1,6 +1,6 @@
import React from 'react'; import React from 'react';
import { render } from 'react-dom'; import { render } from 'react-dom';
import App from './screens/App'; import App from './App';
import 'rsuite/lib/styles/index.less'; import 'rsuite/lib/styles/index.less';

View File

@ -1,51 +0,0 @@
import React from 'react';
import 'rsuite/lib/styles/index.less';
import { BrowserRouter as Router, Switch, Route } from 'react-router-dom';
import Dashboard from './Dashboard';
import Schedule from './Schedule/Schedule';
import Availability from './Availability/Availability';
import Invite from './Invite/Invite';
import Login from './Login';
import Register from './Register';
const titles = {
schedule: 'Schedule a meeting',
invite: 'Invite participants',
availability: 'Add your availability',
confirm: 'Confirm meeting date',
dashboard: 'Dashboard',
login: 'Login',
register: 'Register',
settings: 'Settings',
};
export default function App() {
return (
<Router>
<Switch>
<Route path='/' exact>
<Login title={titles.login} />
</Route>
<Route path='/schedule'>
<Schedule title={titles.schedule} />
</Route>
<Route path='/invite'>
<Invite title={titles.invite} />
</Route>
<Route path='/availability'>
<Availability title={titles.availability} />
</Route>
<Route path='/dashboard'>
<Dashboard title={titles.dashboard} />
</Route>
<Route path='/login'>
<Login title={titles.login} />
</Route>
<Route path='/register'>
<Register title={titles.register} />
</Route>
</Switch>
</Router>
);
}

View File

@ -17,7 +17,7 @@ import IntervalSelector from '../../components/Interval/IntervalSelector';
import './Availability.less'; import './Availability.less';
export default function Availability({ title }) { export default function Availability() {
const [availability, setAvailability] = useState([...availabilityList]); const [availability, setAvailability] = useState([...availabilityList]);
const handleClear = () => { const handleClear = () => {
@ -36,7 +36,7 @@ export default function Availability({ title }) {
return ( return (
<> <>
<NavBar title={title} /> <NavBar title='Add your availability' />
<Panel style={containerStyle}> <Panel style={containerStyle}>
<Form className={'av-container'}> <Form className={'av-container'}>
<div className={'av-details'}> <div className={'av-details'}>

View File

@ -6,7 +6,7 @@ import { Panel, Form, Button, ButtonGroup, Message, TagPicker } from 'rsuite';
import NavBar from '../../components/Navbar/NavBar'; import NavBar from '../../components/Navbar/NavBar';
import './Invite.less'; import './Invite.less';
export default function Invite({ title }) { export default function Invite() {
const [participants, setParticipants] = useState([]); const [participants, setParticipants] = useState([]);
const [contactDropdown, setContactDropdown] = useState([]); const [contactDropdown, setContactDropdown] = useState([]);
@ -63,7 +63,7 @@ export default function Invite({ title }) {
return ( return (
<> <>
<NavBar title={title} /> <NavBar title='Invite participants' />
<Panel style={containerStyle}> <Panel style={containerStyle}>
<Form className={'av-container'}> <Form className={'av-container'}>
<div className={'interval-selector'}> <div className={'interval-selector'}>

View File

@ -14,7 +14,7 @@ import {
import { setUserSession } from '../utils/common'; import { setUserSession } from '../utils/common';
import NavBar from './../components/Navbar/NavBar'; import NavBar from './../components/Navbar/NavBar';
export default function Login({ title }) { export default function Login() {
const history = useHistory(); const history = useHistory();
const [error, setError] = useState(false); const [error, setError] = useState(false);
@ -46,7 +46,7 @@ export default function Login({ title }) {
return ( return (
<> <>
<NavBar title={title} /> <NavBar title='Login' />
<Panel bordered style={boxStyle}> <Panel bordered style={boxStyle}>
{error && <Message type='error' description={error} />} {error && <Message type='error' description={error} />}
<Form> <Form>

View File

@ -16,10 +16,10 @@ const boxStyle = {
padding: '1rem', padding: '1rem',
}; };
export default function Register({ title }) { export default function Register() {
return ( return (
<> <>
<NavBar title={title} /> <NavBar title='Register' />
<Panel bordered style={boxStyle}> <Panel bordered style={boxStyle}>
<Form> <Form>
<FormGroup> <FormGroup>

View File

@ -21,7 +21,7 @@ import SelectedDates from '../../components/Schedule/SelectedDates';
import './Schedule.less'; import './Schedule.less';
export default function Schedule({ title }) { export default function Schedule() {
const [eventsList, setEventsList] = useState([]); const [eventsList, setEventsList] = useState([]);
const [datesList, setDatesList] = useState(eventsToDates(eventsList)); const [datesList, setDatesList] = useState(eventsToDates(eventsList));
@ -117,7 +117,7 @@ export default function Schedule({ title }) {
return ( return (
<> <>
<NavBar title={title} /> <NavBar title='Schedule a meeting' />
<Panel style={containerStyle}> <Panel style={containerStyle}>
<Form className={'meeting-container'}> <Form className={'meeting-container'}>
<div className={'meeting-info'}> <div className={'meeting-info'}>

View File

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