add PublicRoute, AdminRouter (wrappers for react-router-dom's Route), Link, NotFoundPage

This commit is contained in:
Dawid Wysokiński 2021-03-07 18:35:21 +01:00
parent 81d8eccb08
commit 8c8296fb74
14 changed files with 186 additions and 25 deletions

50
src/common/Link/Link.tsx Normal file
View File

@ -0,0 +1,50 @@
import React, { forwardRef, RefObject } from 'react';
import {
Link as RRDLink,
LinkProps as RRDLinkProps,
generatePath,
} from 'react-router-dom';
import { Link as MUILink, LinkProps as MUILinkProps } from '@material-ui/core';
export type Props = MUILinkProps &
RRDLinkProps & {
params?: { [paramName: string]: string | number | boolean | undefined };
};
const CustomizedRRDLink = forwardRef(
(
{ children, params, to, ...props }: Props,
ref:
| ((instance: HTMLAnchorElement | null) => void)
| RefObject<HTMLAnchorElement>
| null
| undefined
) => (
<RRDLink
{...props}
to={params && typeof to === 'string' ? generatePath(to, params) : to}
ref={ref}
>
{children}
</RRDLink>
)
);
const Link = forwardRef(
(
{ children, ...props }: Props,
ref:
| ((instance: HTMLAnchorElement | null) => void)
| RefObject<HTMLAnchorElement>
| null
| undefined
) => {
return (
<MUILink {...props} ref={ref} component={CustomizedRRDLink}>
{children}
</MUILink>
);
}
);
export default Link;

4
src/config/app.ts Normal file
View File

@ -0,0 +1,4 @@
export enum Role {
Admin = 'admin',
User = 'user',
}

9
src/config/routing.ts Normal file
View File

@ -0,0 +1,9 @@
export const ROUTE = {
SIGN_IN_PAGE: '/',
DASHBOARD_PAGE: '/dashboard',
};
export const PUBLIC_ROUTES = [ROUTE.SIGN_IN_PAGE];
export const ADMIN_ROUTES = Object.values(ROUTE).filter(
route => !PUBLIC_ROUTES.includes(route)
);

View File

@ -0,0 +1,15 @@
import { Switch, Route } from 'react-router-dom';
import { ROUTE } from '../config/routing';
import DashboardPage from './DashboardPage/DashboardPage';
function AdminRoutes() {
return (
<Switch>
<Route exact path={ROUTE.DASHBOARD_PAGE}>
<DashboardPage />
</Route>
</Switch>
);
}
export default AdminRoutes;

View File

@ -1,22 +1,27 @@
import { Route, Switch } from 'react-router-dom';
import PublicRoute from '../libs/router/PublicRoute';
import AdminRoute from '../libs/router/AdminRoute';
import AppLoading from './AppLoading';
import SignInPage from './SignInPage/SignInPage';
import NotFoundPage from './NotFoundPage/NotFoundPage';
import AdminRoutes from './AdminRoutes';
import { ROUTE, ADMIN_ROUTES } from '../config/routing';
function App() {
return (
<div className="App">
<header className="App-header">
<p>
Edit <code>src/App.tsx</code> and save to reload.
</p>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a>
</header>
</div>
<AppLoading>
<Switch>
<PublicRoute exact path={ROUTE.SIGN_IN_PAGE}>
<SignInPage />
</PublicRoute>
<AdminRoute exact path={ADMIN_ROUTES}>
<AdminRoutes />
</AdminRoute>
<Route path="*">
<NotFoundPage />
</Route>
</Switch>
</AppLoading>
);
}

View File

@ -0,0 +1,5 @@
const DashboardPage = () => {
return <div>DashboardPage</div>;
};
export default DashboardPage;

View File

@ -0,0 +1,39 @@
import React from 'react';
import { ROUTE } from 'config/routing';
import { makeStyles } from '@material-ui/core/styles';
import { Container, Typography } from '@material-ui/core';
import Link from 'common/Link/Link';
const NotFoundPage = () => {
const classes = useStyles();
return (
<main>
<Container className={classes.container}>
<Typography gutterBottom variant="h1">
Nie znaleziono strony
</Typography>
<Typography gutterBottom variant="h4">
Wygląda na to, że kliknąłeś uszkodzony link lub wpisałeś adres URL,
który nie istnieje.
</Typography>
<Typography variant="h4">
<Link to={ROUTE.SIGN_IN_PAGE}>Wróć na stronę główną</Link>
</Typography>
</Container>
</main>
);
};
const useStyles = makeStyles(() => ({
container: {
display: 'flex',
flexDirection: 'column',
justifyContent: 'center',
textAlign: 'center',
minHeight: '100vh',
},
}));
export default NotFoundPage;

View File

@ -0,0 +1,5 @@
const SignInPage = () => {
return <div>SignInPage</div>;
};
export default SignInPage;

4
src/global.d.ts vendored
View File

@ -1,4 +0,0 @@
declare enum UserRole {
Admin = "admin",
User = "user",
}

View File

@ -3,7 +3,6 @@ import ReactDOM from 'react-dom';
import { BrowserRouter } from 'react-router-dom';
import { ApolloProvider } from '@apollo/client';
import App from './features/App';
import AppLoading from './features/AppLoading';
import { AuthProvider } from './libs/auth';
import ThemeProvider from './libs/material-ui/ThemeProvider';
import TokenStorage from './libs/tokenstorage/TokenStorage';
@ -18,9 +17,7 @@ ReactDOM.render(
<ApolloProvider client={createClient(API_URI, tokenStorage)}>
<ThemeProvider>
<AuthProvider tokenStorage={tokenStorage}>
<AppLoading>
<App />
</AppLoading>
<App />
</AuthProvider>
</ThemeProvider>
</ApolloProvider>

View File

@ -1,4 +1,4 @@
import { gql } from "@apollo/client";
import { gql } from '@apollo/client';
export const MUTATION_SIGN_IN = gql`
mutation signIn(

View File

@ -1,9 +1,10 @@
import TokenStorage from '../tokenstorage/TokenStorage';
import { Role } from 'config/app';
export type User = {
id: number;
displayName: string;
role: UserRole;
role: Role;
email: string;
};

View File

@ -0,0 +1,20 @@
import { Route, Redirect, RouteProps } from 'react-router-dom';
import { isNil } from 'lodash';
import { useAuth } from '../auth';
import { Role } from 'config/app';
import { ROUTE } from 'config/routing';
const AdminRoute = ({ children, ...rest }: RouteProps) => {
const { user } = useAuth();
return (
<Route {...rest}>
{!isNil(user) && user.role === Role.Admin ? (
children
) : (
<Redirect to={ROUTE.DASHBOARD_PAGE} />
)}
</Route>
);
};
export default AdminRoute;

View File

@ -0,0 +1,15 @@
import { Route, Redirect, RouteProps } from 'react-router-dom';
import { isNil } from 'lodash';
import { useAuth } from '../auth';
import { ROUTE } from '../../config/routing';
const PublicRoute = ({ children, ...rest }: RouteProps) => {
const { user } = useAuth();
return (
<Route {...rest}>
{isNil(user) ? children : <Redirect to={ROUTE.DASHBOARD_PAGE} />}
</Route>
);
};
export default PublicRoute;