1- import React , { Dispatch , useContext , useEffect } from 'react' ;
2- import Router from './routes/Router' ;
3- import Layout from './components/Layout/Layout' ;
4- import { connect } from 'react-redux' ;
5- import * as actions from './auth/authActions' ;
6- import { PrivateRouteProps } from './routes/PrivateRoute' ;
7- import { Dialog , DialogActions , DialogContent , DialogTitle , Snackbar , ThemeProvider } from '@material-ui/core' ;
8- import { theme } from './Theme'
9- import { AlertContext } from './contexts/AlertContext' ;
10- import Alert from '@material-ui/lab/Alert' ;
11- import { AxiosError } from './interfaces/axios/AxiosError'
12- import { ThemeContext } from './contexts/ThemeContext' ;
13- import { useLocation } from "react-router-dom" ;
14- import { DialogContext } from './contexts/DialogContext' ;
1+ import React , { useContext , useEffect , useMemo , useState } from "react" ;
2+ import {
3+ BrowserRouter as Router ,
4+ Switch ,
5+ Route ,
6+ useLocation ,
7+ Redirect ,
8+ useHistory ,
9+ } from "react-router-dom" ;
10+ import axios from 'axios' ;
11+ import { ThemeProvider , CssBaseline , Snackbar , Dialog , DialogTitle , DialogContent , DialogActions } from "@material-ui/core" ;
1512
13+ import { useAppSelector } from './redux/hooks' ;
14+ import { Login } from './components/Login/Login' ;
15+ import { appArray } from "./routes/Routes" ;
16+ import PrivateRoute from "./routes/PrivateRoute" ;
17+ import Layout from "./components/Layout/Layout" ;
18+ import Footer from "./components/Layout/Footer" ;
19+ import { theme } from "./Theme" ;
20+ import { DialogContext } from "./contexts/DialogContext" ;
21+ import { Alert } from "@material-ui/lab" ;
22+ import { AlertContext } from "./contexts/AlertContext" ;
23+ import PasswordUpdate from "./components/Login/PasswordUpdate" ;
24+ import PasswordReset from "./components/Login/PasswordReset" ;
1625
17- type Error = {
18- message : string
19- response : {
20- data : Record < string , string [ ] >
21- }
22- }
23- export interface AuthProps {
24- logout : Function
25- setAuthenticatedIfRequired : Function
26- onAuth : Function
27- token : string
28- error : Error
29- }
30-
31- export interface AppProps extends AuthProps , PrivateRouteProps { }
32-
33- function App ( props : AppProps ) {
34-
35- const { alertType, openAlert, alertMessage, handleAlertClose } = useContext ( AlertContext ) ;
26+ export function App ( ) {
27+ const location = useLocation ( ) ;
28+ const { authenticated } = useAppSelector ( state => state . auth )
29+ const { darkMode } = useAppSelector ( state => state . darkMode )
30+ const history = useHistory ( )
3631 const { showDialog, dialogTitle, dialogBody, dialogActions, handleDialogClose } = useContext ( DialogContext ) ;
37- const { darkMode } = useContext ( ThemeContext ) ;
38- const palletType = darkMode ? "dark" : "light"
39- const location = useLocation ( ) . pathname
32+ const { alertType, openAlert, alertMessage, handleAlertClose } = useContext ( AlertContext ) ;
4033
4134 useEffect ( ( ) => {
42- props . setAuthenticatedIfRequired ( ) ;
43- } , [ props ] ) ;
35+ if ( authenticated ) {
36+ axios . get ( '/api/auth/loggedin/' )
37+ }
38+ } , [ ] )
4439
45- useEffect ( ( ) => {
46- handleAlertClose ( )
47- } , [ location ] )
40+ const publicRoutes = [
41+ { path : "login" , component : Login , exact : true } ,
42+ { path : "password_reset" , component : PasswordReset , exact : true }
43+ ]
4844
49- return (
50- < div className = "App" >
51- < ThemeProvider theme = { theme ( palletType ) } >
52- < Layout { ...props } >
53- < Router { ...props } />
54- </ Layout >
55- < Snackbar id = "appAlertSnackbar" open = { openAlert } autoHideDuration = { 6000 } onClose = { handleAlertClose } >
56- < Alert variant = "filled" onClose = { handleAlertClose } severity = { alertType } >
57- { alertMessage }
58- </ Alert >
59- </ Snackbar >
60- < Dialog maxWidth = "md" fullWidth open = { showDialog } onClose = { handleDialogClose } aria-labelledby = "alert-dialog-title" >
61- < DialogTitle id = "alert-dialog-title" > { dialogTitle } </ DialogTitle >
62- < DialogContent >
63- { dialogBody }
64- </ DialogContent >
65- < DialogActions >
66- { dialogActions }
67- </ DialogActions >
68- </ Dialog >
69- </ ThemeProvider >
70- </ div >
71- ) ;
72- }
45+ const atPublicRoute = publicRoutes . findIndex ( route => location . pathname . includes ( route . path ) ) !== - 1
7346
74- interface MapStateToPropsInterface {
75- auth : {
76- token : string ,
77- error : AxiosError
78- }
79- }
47+ useEffect ( ( ) => {
48+ // when un-authenticated, redirect to login (only for non-public routes)
49+ if ( ! authenticated && ! atPublicRoute ) {
50+ history . push ( { pathname : "/login" , state : { from : location } } )
51+ }
52+ } , [ authenticated , location . pathname ] )
8053
81- //This means that one or more of the redux states in the store are available as props
82- const mapStateToProps = ( state : MapStateToPropsInterface ) => {
83- return {
84- isAuthenticated : state . auth . token !== null && typeof state . auth . token !== 'undefined' ,
85- token : state . auth . token ,
86- error : state . auth . error
54+ const generateAppRoutes = ( ) => {
55+ return appArray
56+ . map ( ( app , index1 ) => {
57+ let result = app . routes ?. map ( ( route , index2 ) => {
58+ const key = `${ index1 } _${ index2 } `
59+ return < PrivateRoute key = { key } exact = { route . exact } path = { route . path } component = { route . component } /> ;
60+ } )
61+ return result
62+ } )
8763 }
88- }
8964
90- //This means that one or more of the redux actions in the form of dispatch(action) combinations are available as props
91- const mapDispatchToProps = ( dispatch : Dispatch < any > ) => {
92- return {
93- setAuthenticatedIfRequired : ( ) => dispatch ( actions . authCheckState ( ) ) ,
94- logout : ( ) => dispatch ( actions . authLogout ( ) )
95- }
65+ const privateRoutes = useMemo ( ( ) => generateAppRoutes ( ) , [ ] ) ;
66+
67+ return (
68+ < ThemeProvider theme = { theme ( darkMode ? "dark" : "light" ) } >
69+ < CssBaseline />
70+ < Snackbar id = "appAlertSnackbar" open = { openAlert } autoHideDuration = { 6000 } onClose = { handleAlertClose } >
71+ < Alert variant = "filled" onClose = { handleAlertClose } severity = { alertType } >
72+ { alertMessage }
73+ </ Alert >
74+ </ Snackbar >
75+ < Dialog maxWidth = "md" fullWidth open = { showDialog } onClose = { handleDialogClose } aria-labelledby = "alert-dialog-title" >
76+ < DialogTitle id = "alert-dialog-title" > { dialogTitle } </ DialogTitle >
77+ < DialogContent >
78+ { dialogBody }
79+ </ DialogContent >
80+ < DialogActions >
81+ { dialogActions }
82+ </ DialogActions >
83+ </ Dialog >
84+ < Layout >
85+ < div className = { atPublicRoute ? "" : "content-wrap" } >
86+ < div className = { atPublicRoute ? "" : "container-fluid body main_container" } >
87+ < Switch >
88+ { publicRoutes . map ( ( route , index ) =>
89+ < Route key = { index } component = { route . component } path = { "/" + route . path } exact = { route . exact } />
90+ ) }
91+ { privateRoutes }
92+ < PrivateRoute component = { PasswordUpdate } path = { "/change_password" } />
93+ < Redirect from = "/" to = { "/home" } />
94+ </ Switch >
95+ </ div >
96+ </ div >
97+ </ Layout >
98+ < Footer />
99+ </ ThemeProvider >
100+ )
96101}
97102
98- export default connect ( mapStateToProps , mapDispatchToProps ) ( App ) ;
103+ export function MainPage ( ) {
104+ return (
105+ < Router >
106+ < App />
107+ </ Router >
108+ )
109+ }
0 commit comments