@@ -20,6 +20,7 @@ import Users from '../user/Users';
2020import { observer } from 'mobx-react' ;
2121import { observable } from 'mobx' ;
2222import { inject , Stores } from '../inject' ;
23+ import { NetworkLostBanner } from '../common/NetworkLostBanner' ;
2324
2425const styles = ( theme : Theme ) => ( {
2526 content : {
@@ -50,7 +51,9 @@ const isThemeKey = (value: string | null): value is ThemeKey => {
5051} ;
5152
5253@observer
53- class Layout extends React . Component < WithStyles < 'content' > & Stores < 'currentUser' > > {
54+ class Layout extends React . Component <
55+ WithStyles < 'content' > & Stores < 'currentUser' | 'snackManager' >
56+ > {
5457 private static defaultVersion = '0.0.0' ;
5558
5659 @observable
@@ -59,6 +62,8 @@ class Layout extends React.Component<WithStyles<'content'> & Stores<'currentUser
5962 private showSettings = false ;
6063 @observable
6164 private version = Layout . defaultVersion ;
65+ @observable
66+ private reconnecting = false ;
6267
6368 public componentDidMount ( ) {
6469 if ( this . version === Layout . defaultVersion ) {
@@ -75,6 +80,19 @@ class Layout extends React.Component<WithStyles<'content'> & Stores<'currentUser
7580 }
7681 }
7782
83+ private doReconnect = ( ) => {
84+ this . reconnecting = true ;
85+ this . props . currentUser
86+ . tryAuthenticate ( )
87+ . then ( ( ) => {
88+ this . reconnecting = false ;
89+ } )
90+ . catch ( ( ) => {
91+ this . reconnecting = false ;
92+ this . props . snackManager . snack ( 'Reconnect failed' ) ;
93+ } ) ;
94+ } ;
95+
7896 public render ( ) {
7997 const { version, showSettings, currentTheme} = this ;
8098 const {
@@ -84,49 +102,56 @@ class Layout extends React.Component<WithStyles<'content'> & Stores<'currentUser
84102 authenticating,
85103 user : { name, admin} ,
86104 logout,
105+ hasNetwork,
87106 } ,
88107 } = this . props ;
89108 const theme = themeMap [ currentTheme ] ;
90109 const loginRoute = ( ) => ( loggedIn ? < Redirect to = "/" /> : < Login /> ) ;
91110 return (
92111 < MuiThemeProvider theme = { theme } >
93112 < HashRouter >
94- < div style = { { display : 'flex' } } >
95- < CssBaseline />
96- < Header
97- admin = { admin }
98- name = { name }
99- version = { version }
100- loggedIn = { loggedIn }
101- toggleTheme = { this . toggleTheme . bind ( this ) }
102- showSettings = { ( ) => ( this . showSettings = true ) }
103- logout = { logout }
104- />
105- < Navigation loggedIn = { loggedIn } />
106-
107- < main className = { classes . content } >
108- < Switch >
109- { authenticating ? (
110- < Route path = "/" >
111- < LoadingSpinner />
112- </ Route >
113- ) : null }
114- < Route exact path = "/login" render = { loginRoute } />
115- { loggedIn ? null : < Redirect to = "/login" /> }
116- < Route exact path = "/" component = { Messages } />
117- < Route exact path = "/messages/:id" component = { Messages } />
118- < Route exact path = "/applications" component = { Applications } />
119- < Route exact path = "/clients" component = { Clients } />
120- < Route exact path = "/users" component = { Users } />
121- < Route exact path = "/plugins" component = { Plugins } />
122- < Route exact path = "/plugins/:id" component = { PluginDetailView } />
123- </ Switch >
124- </ main >
125- { showSettings && (
126- < SettingsDialog fClose = { ( ) => ( this . showSettings = false ) } />
113+ < div >
114+ { hasNetwork ? null : (
115+ < NetworkLostBanner height = { 64 } retry = { this . doReconnect } />
127116 ) }
128- < ScrollUpButton />
129- < SnackBarHandler />
117+ < div style = { { display : 'flex' } } >
118+ < CssBaseline />
119+ < Header
120+ style = { { top : hasNetwork ? 0 : 64 } }
121+ admin = { admin }
122+ name = { name }
123+ version = { version }
124+ loggedIn = { loggedIn }
125+ toggleTheme = { this . toggleTheme . bind ( this ) }
126+ showSettings = { ( ) => ( this . showSettings = true ) }
127+ logout = { logout }
128+ />
129+ < Navigation loggedIn = { loggedIn } />
130+
131+ < main className = { classes . content } >
132+ < Switch >
133+ { authenticating || this . reconnecting ? (
134+ < Route path = "/" >
135+ < LoadingSpinner />
136+ </ Route >
137+ ) : null }
138+ < Route exact path = "/login" render = { loginRoute } />
139+ { loggedIn ? null : < Redirect to = "/login" /> }
140+ < Route exact path = "/" component = { Messages } />
141+ < Route exact path = "/messages/:id" component = { Messages } />
142+ < Route exact path = "/applications" component = { Applications } />
143+ < Route exact path = "/clients" component = { Clients } />
144+ < Route exact path = "/users" component = { Users } />
145+ < Route exact path = "/plugins" component = { Plugins } />
146+ < Route exact path = "/plugins/:id" component = { PluginDetailView } />
147+ </ Switch >
148+ </ main >
149+ { showSettings && (
150+ < SettingsDialog fClose = { ( ) => ( this . showSettings = false ) } />
151+ ) }
152+ < ScrollUpButton />
153+ < SnackBarHandler />
154+ </ div >
130155 </ div >
131156 </ HashRouter >
132157 </ MuiThemeProvider >
@@ -139,4 +164,6 @@ class Layout extends React.Component<WithStyles<'content'> & Stores<'currentUser
139164 }
140165}
141166
142- export default withStyles ( styles , { withTheme : true } ) < { } > ( inject ( 'currentUser' ) ( Layout ) ) ;
167+ export default withStyles ( styles , { withTheme : true } ) < { } > (
168+ inject ( 'currentUser' , 'snackManager' ) ( Layout )
169+ ) ;
0 commit comments