// SPDX-FileCopyrightText: © 2017 EteSync Authors // SPDX-License-Identifier: AGPL-3.0-only import * as React from 'react'; import { List as ImmutableList } from 'immutable'; import { connect } from 'react-redux'; import { withRouter } from 'react-router'; import { BrowserRouter } from 'react-router-dom'; import { MuiThemeProvider as ThemeProvider, createMuiTheme } from '@material-ui/core/styles'; // v1.x import amber from '@material-ui/core/colors/amber'; import lightBlue from '@material-ui/core/colors/lightBlue'; import AppBar from '@material-ui/core/AppBar'; import Toolbar from '@material-ui/core/Toolbar'; import Drawer from '@material-ui/core/Drawer'; import IconButton from '@material-ui/core/IconButton'; import Badge from '@material-ui/core/Badge'; import NavigationMenu from '@material-ui/icons/Menu'; import NavigationBack from '@material-ui/icons/ArrowBack'; import NavigationRefresh from '@material-ui/icons/Refresh'; import ErrorsIcon from '@material-ui/icons/Error'; import 'react-virtualized/styles.css'; // only needs to be imported once import './App.css'; import ConfirmationDialog from './widgets/ConfirmationDialog'; import PrettyError from './widgets/PrettyError'; import { List, ListItem } from './widgets/List'; import withSpin from './widgets/withSpin'; import ErrorBoundary from './components/ErrorBoundary'; import SideMenu from './SideMenu'; import LoginGate from './LoginGate'; import { RouteResolver } from './routes'; import * as store from './store'; import * as actions from './store/actions'; import { credentialsSelector } from './login'; import { History } from 'history'; export const routeResolver = new RouteResolver({ home: '', pim: { contacts: { _id: { _base: ':itemUid', edit: 'edit', log: 'log', }, new: 'new', }, events: { _id: { _base: ':itemUid', edit: 'edit', duplicate: 'duplicate', log: 'log', }, new: 'new', }, tasks: { _id: { _base: ':itemUid', edit: 'edit', log: 'log', }, new: 'new', }, }, journals: { _id: { _base: ':journalUid', edit: 'edit', items: { _id: { _base: ':itemUid', }, }, entries: { _id: { _base: ':entryUid', }, }, members: { }, }, new: 'new', import: 'import', }, settings: { }, debug: { }, }); const AppBarWitHistory = withRouter( class extends React.PureComponent { public props: { title: string; toggleDrawerIcon: any; history?: History; staticContext?: any; iconElementRight: any; }; constructor(props: any) { super(props); this.goBack = this.goBack.bind(this); this.canGoBack = this.canGoBack.bind(this); } public render() { const { staticContext, toggleDrawerIcon, history, iconElementRight, ...props } = this.props; return (
{!this.canGoBack() ? toggleDrawerIcon : }
{iconElementRight}
); } private canGoBack() { return ( (this.props.history!.length > 1) && (this.props.history!.location.pathname !== routeResolver.getRoute('pim')) && (this.props.history!.location.pathname !== routeResolver.getRoute('home')) ); } private goBack() { this.props.history!.goBack(); } } ); const IconRefreshWithSpin = withSpin(NavigationRefresh); class App extends React.PureComponent { public state: { drawerOpen: boolean; errorsDialog: boolean; }; public props: { credentials: store.CredentialsData; entries: store.EntriesData; fetchCount: number; darkMode: boolean; errors: ImmutableList; }; constructor(props: any) { super(props); this.state = { drawerOpen: false, errorsDialog: false }; this.toggleDrawer = this.toggleDrawer.bind(this); this.closeDrawer = this.closeDrawer.bind(this); this.refresh = this.refresh.bind(this); this.autoRefresh = this.autoRefresh.bind(this); } public render() { const credentials = this.props.credentials ?? null; const { darkMode } = this.props; const errors = this.props.errors; const fetching = this.props.fetchCount > 0; const muiTheme = createMuiTheme({ palette: { type: darkMode ? 'dark' : undefined, primary: amber, secondary: { light: lightBlue.A200, main: lightBlue.A400, dark: lightBlue.A700, contrastText: '#fff', }, }, }); const styles = { main: { backgroundColor: muiTheme.palette.background.default, color: muiTheme.palette.text.primary, flexGrow: 1, }, }; return (
} iconElementRight={ <> {(errors.size > 0) && ( this.setState({ errorsDialog: true })} title="Parse Errors"> )} } /> this.setState({ errorsDialog: false })} onOk={() => this.setState({ errorsDialog: false })} >

This should not happen, please contact developers!

{errors.map((error, index) => ( (window as any).navigator.clipboard.writeText(`${error.message}\n\n${error.stack}`)} > ))}
); } private toggleDrawer() { this.setState({ drawerOpen: !this.state.drawerOpen }); } private closeDrawer() { this.setState({ drawerOpen: false }); } private refresh() { store.store.dispatch(actions.fetchAll(this.props.credentials, this.props.entries)); } private autoRefresh() { if (navigator.onLine && this.props.credentials && !(window.location.pathname.match(/.*\/(new|edit|duplicate)$/))) { this.refresh(); } } componentDidMount() { const interval = 60 * 1000; setInterval(this.autoRefresh, interval); } } const mapStateToProps = (state: store.StoreState) => { return { credentials: credentialsSelector(state), entries: state.cache.entries, fetchCount: state.fetchCount, darkMode: !!state.settings.darkMode, errors: state.errors, }; }; export default connect( mapStateToProps )(App);