feat(ui): client side private routes

This commit is contained in:
wpetit 2020-08-09 10:51:02 +02:00
parent ae4e54453b
commit a30d6b76d3
12 changed files with 119 additions and 41 deletions

View File

@ -1,18 +1,29 @@
import React from 'react'; import React, { FunctionComponent, useState, useEffect } from 'react';
import { BrowserRouter, Route, Redirect, Switch } from "react-router-dom"; import { BrowserRouter, Route, Redirect, Switch } from "react-router-dom";
import { HomePage } from './HomePage/HomePage'; import { HomePage } from './HomePage/HomePage';
import { ProfilePage } from './ProfilePage/ProfilePage'; import { ProfilePage } from './ProfilePage/ProfilePage';
import { DashboardPage } from './DashboardPage/DashboardPage';
import { PrivateRoute } from './PrivateRoute';
import { useLoggedIn, LoggedInContext } from '../hooks/useLoggedIn';
import { useUserProfile } from '../gql/queries/user';
export class App extends React.Component { export interface AppProps {
render() {
return ( }
export const App: FunctionComponent<AppProps> = () => {
const { user } = useUserProfile();
return (
<LoggedInContext.Provider value={user.id !== ''}>
<BrowserRouter> <BrowserRouter>
<Switch> <Switch>
<Route path="/" exact component={HomePage} /> <Route path="/" exact component={HomePage} />
<Route path="/profile" exact component={ProfilePage} /> <PrivateRoute path="/profile" exact component={ProfilePage} />
<PrivateRoute path="/dashboard" exact component={DashboardPage} />
<Route component={() => <Redirect to="/" />} /> <Route component={() => <Redirect to="/" />} />
</Switch> </Switch>
</BrowserRouter> </BrowserRouter>
); </LoggedInContext.Provider>
} );
} }

View File

@ -0,0 +1,19 @@
import React from 'react';
import { EstimationPanel } from './EstimationPanel';
export function Dashboard() {
return (
<div className="container is-fluid">
<div className="columns">
<div className="column is-4">
<EstimationPanel />
</div>
<div className="column is-4">
</div>
<div className="column is-4">
</div>
</div>
</div>
);
}

View File

@ -0,0 +1,13 @@
import React from 'react';
import { Page } from '../Page';
import { Dashboard } from './Dashboard';
export function DashboardPage() {
return (
<Page title="Tableau de bord">
<section className="mt-5">
<Dashboard />
</section>
</Page>
);
}

View File

@ -0,0 +1,20 @@
import React, { FunctionComponent } from "react";
import { ItemPanel } from "./ItemPanel";
export interface EstimationPanelProps {
}
export const EstimationPanel: FunctionComponent<EstimationPanelProps> = () => {
return (
<ItemPanel
title="Mes estimations"
className="is-primary"
newItemUrl="/estimations/new"
items={[]}
itemKey={(item) => { return item.id }}
itemLabel={(item) => { return item.id }}
itemUrl={(item) => { return `/estimations/${item.id}` }}
/>
);
};

View File

@ -1,15 +0,0 @@
import React from 'react';
export function Dashboard() {
return (
<div className="columns">
<div className="column is-6">
</div>
<div className="column is-3">
</div>
<div className="column is-3">
</div>
</div>
);
}

View File

@ -1,20 +1,22 @@
import React from 'react'; import React, { useEffect } from 'react';
import { Page } from '../Page'; import { Page } from '../Page';
import { Dashboard } from './Dashboard';
import { useUserProfile } from '../../gql/queries/user'; import { useUserProfile } from '../../gql/queries/user';
import { WelcomeContent } from './WelcomeContent'; import { WelcomeContent } from './WelcomeContent';
import { useHistory } from 'react-router';
import { useLoggedIn } from '../../hooks/useLoggedIn';
export function HomePage() { export function HomePage() {
const { user, loading } = useUserProfile(); const loggedIn = useLoggedIn();
const history = useHistory();
useEffect(() => {
if (loggedIn) history.push('/dashboard');
}, [loggedIn]);
return ( return (
<Page title={user.id ? 'Tableau de bord' : 'Accueil'}> <Page title="Accueil">
<section className="mt-5"> <section className="mt-5">
{ <WelcomeContent />
user.id ?
<Dashboard /> :
<WelcomeContent />
}
</section> </section>
</Page> </Page>
); );

View File

@ -61,7 +61,7 @@ export const WelcomeContent: FunctionComponent<WelcomeContentProps> = () => {
</div> </div>
<div className="card-content"> <div className="card-content">
<div className="content"> <div className="content">
<h4>Partager simplement vos estimations.</h4> <h4>Partagez simplement vos estimations.</h4>
<p>Une adresse courriel et votre estimation est partagée ! Le niveau d'accès (lecture seule, écriture, vue partielle...) peut être défini pour chaque partage.</p> <p>Une adresse courriel et votre estimation est partagée ! Le niveau d'accès (lecture seule, écriture, vue partielle...) peut être défini pour chaque partage.</p>
{/* <p><a href="#">En savoir plus</a></p> */} {/* <p><a href="#">En savoir plus</a></p> */}
</div> </div>

View File

@ -3,9 +3,10 @@ import { Config } from '../config';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
import { useUserProfile } from '../gql/queries/user'; import { useUserProfile } from '../gql/queries/user';
import { WithLoader } from './WithLoader'; import { WithLoader } from './WithLoader';
import { useLoggedIn } from '../hooks/useLoggedIn';
export function Navbar() { export function Navbar() {
const { user, loading } = useUserProfile(); const loggedIn = useLoggedIn();
const [ isActive, setActive ] = useState(false); const [ isActive, setActive ] = useState(false);
const toggleMenu = () => { const toggleMenu = () => {
@ -16,7 +17,7 @@ export function Navbar() {
<nav className="navbar is-fixed-top" role="navigation" aria-label="main navigation"> <nav className="navbar is-fixed-top" role="navigation" aria-label="main navigation">
<div className="container is-fluid"> <div className="container is-fluid">
<div className="navbar-brand"> <div className="navbar-brand">
<Link className="navbar-item" to="/"> <Link className="navbar-item" to={loggedIn ? '/dashboard' : '/'}>
<h1 className="is-size-4"> <h1 className="is-size-4">
<i className="fa fa-stopwatch mr-1"></i> <i className="fa fa-stopwatch mr-1"></i>
Guesstimate Guesstimate
@ -37,7 +38,7 @@ export function Navbar() {
<div className="navbar-item"> <div className="navbar-item">
<div className="buttons"> <div className="buttons">
{ {
user.id ? loggedIn ?
<Fragment> <Fragment>
<Link to="/profile" className="button"> <Link to="/profile" className="button">
<span className="icon"> <span className="icon">

View File

@ -0,0 +1,18 @@
import React, { FunctionComponent, Component, ReactType } from "react"
import { Route, Redirect, RouteProps } from "react-router"
import { useLoggedIn } from "../hooks/useLoggedIn";
export interface PrivateRouteProps extends RouteProps {
}
export const PrivateRoute: FunctionComponent<PrivateRouteProps> = ({component: Component, ...rest}) => {
const loggedIn = useLoggedIn();
return (
<Route
{...rest}
render={(props) => loggedIn === true
? <Component {...props} />
: <Redirect to={{pathname: '/', state: {from: props.location}}} />}
/>
)
}

View File

@ -23,12 +23,14 @@ export function ProfilePage() {
<section className="section"> <section className="section">
<div className="columns"> <div className="columns">
<div className="column is-6 is-offset-3"> <div className="column is-6 is-offset-3">
<h2 className="is-size-2 subtitle">Mon profil</h2> <div className="box">
<WithLoader loading={isLoading || !user}> <h2 className="is-size-2 subtitle">Mon profil</h2>
{ <WithLoader loading={isLoading || !user}>
<UserForm onChange={onUserChange} user={user} /> {
} <UserForm onChange={onUserChange} user={user} />
</WithLoader> }
</WithLoader>
</div>
</div> </div>
</div> </div>
</section> </section>

View File

@ -0,0 +1,7 @@
import React, { useState, useContext } from "react";
export const LoggedInContext = React.createContext(false);
export const useLoggedIn = () => {
return useContext(LoggedInContext);
};