sharded-gotify/ui/src/layout/Layout.tsx

170 lines
6.7 KiB
TypeScript

import {createMuiTheme, MuiThemeProvider, Theme, WithStyles, withStyles} from '@material-ui/core';
import CssBaseline from '@material-ui/core/CssBaseline';
import * as React from 'react';
import {HashRouter, Redirect, Route, Switch} from 'react-router-dom';
import Header from './Header';
import LoadingSpinner from '../common/LoadingSpinner';
import Navigation from './Navigation';
import ScrollUpButton from '../common/ScrollUpButton';
import SettingsDialog from '../common/SettingsDialog';
import SnackBarHandler from '../snack/SnackBarHandler';
import * as config from '../config';
import Applications from '../application/Applications';
import Clients from '../client/Clients';
import Plugins from '../plugin/Plugins';
import PluginDetailView from '../plugin/PluginDetailView';
import Login from '../user/Login';
import Messages from '../message/Messages';
import Users from '../user/Users';
import {observer} from 'mobx-react';
import {observable} from 'mobx';
import {inject, Stores} from '../inject';
import {ConnectionErrorBanner} from '../common/ConnectionErrorBanner';
const styles = (theme: Theme) => ({
content: {
margin: '0 auto',
marginTop: 64,
padding: theme.spacing(4),
width: '100%',
[theme.breakpoints.down('xs')]: {
marginTop: 0,
},
},
});
const localStorageThemeKey = 'gotify-theme';
type ThemeKey = 'dark' | 'light';
const themeMap: Record<ThemeKey, Theme> = {
light: createMuiTheme({
palette: {
type: 'light',
},
}),
dark: createMuiTheme({
palette: {
type: 'dark',
},
}),
};
const isThemeKey = (value: string | null): value is ThemeKey =>
value === 'light' || value === 'dark';
@observer
class Layout extends React.Component<
WithStyles<'content'> & Stores<'currentUser' | 'snackManager'>
> {
@observable
private currentTheme: ThemeKey = 'dark';
@observable
private showSettings = false;
@observable
private navOpen = false;
private setNavOpen(open: boolean) {
this.navOpen = open;
}
public componentDidMount() {
const localStorageTheme = window.localStorage.getItem(localStorageThemeKey);
if (isThemeKey(localStorageTheme)) {
this.currentTheme = localStorageTheme;
} else {
window.localStorage.setItem(localStorageThemeKey, this.currentTheme);
}
}
public render() {
const {showSettings, currentTheme} = this;
const {
classes,
currentUser: {
loggedIn,
authenticating,
user: {name, admin},
logout,
tryReconnect,
connectionErrorMessage,
},
} = this.props;
const theme = themeMap[currentTheme];
const loginRoute = () => (loggedIn ? <Redirect to="/" /> : <Login />);
const {version} = config.get('version');
return (
<MuiThemeProvider theme={theme}>
<HashRouter>
<div>
{!connectionErrorMessage ? null : (
<ConnectionErrorBanner
height={64}
retry={() => tryReconnect()}
message={connectionErrorMessage}
/>
)}
<div style={{display: 'flex', flexDirection: 'column'}}>
<CssBaseline />
<Header
style={{top: !connectionErrorMessage ? 0 : 64}}
admin={admin}
name={name}
version={version}
loggedIn={loggedIn}
toggleTheme={this.toggleTheme.bind(this)}
showSettings={() => (this.showSettings = true)}
logout={logout}
setNavOpen={this.setNavOpen.bind(this)}
/>
<div style={{display: 'flex'}}>
<Navigation
loggedIn={loggedIn}
navOpen={this.navOpen}
setNavOpen={this.setNavOpen.bind(this)}
/>
<main className={classes.content}>
<Switch>
{authenticating ? (
<Route path="/">
<LoadingSpinner />
</Route>
) : null}
<Route exact path="/login" render={loginRoute} />
{loggedIn ? null : <Redirect to="/login" />}
<Route exact path="/" component={Messages} />
<Route exact path="/messages/:id" component={Messages} />
<Route
exact
path="/applications"
component={Applications}
/>
<Route exact path="/clients" component={Clients} />
<Route exact path="/users" component={Users} />
<Route exact path="/plugins" component={Plugins} />
<Route
exact
path="/plugins/:id"
component={PluginDetailView}
/>
</Switch>
</main>
</div>
{showSettings && (
<SettingsDialog fClose={() => (this.showSettings = false)} />
)}
<ScrollUpButton />
<SnackBarHandler />
</div>
</div>
</HashRouter>
</MuiThemeProvider>
);
}
private toggleTheme() {
this.currentTheme = this.currentTheme === 'dark' ? 'light' : 'dark';
localStorage.setItem(localStorageThemeKey, this.currentTheme);
}
}
export default withStyles(styles, {withTheme: true})(inject('currentUser', 'snackManager')(Layout));