aboutsummaryrefslogtreecommitdiffstats
path: root/src/components/layout/AppLayout.jsx
diff options
context:
space:
mode:
Diffstat (limited to 'src/components/layout/AppLayout.jsx')
-rw-r--r--src/components/layout/AppLayout.jsx226
1 files changed, 226 insertions, 0 deletions
diff --git a/src/components/layout/AppLayout.jsx b/src/components/layout/AppLayout.jsx
new file mode 100644
index 000000000..685839c0a
--- /dev/null
+++ b/src/components/layout/AppLayout.jsx
@@ -0,0 +1,226 @@
1import { Component } from 'react';
2import PropTypes from 'prop-types';
3import { observer } from 'mobx-react';
4import { defineMessages, injectIntl } from 'react-intl';
5import { TitleBar } from 'electron-react-titlebar/renderer';
6import injectSheet from 'react-jss';
7import { ipcRenderer } from 'electron';
8
9import { mdiFlash, mdiPowerPlug } from '@mdi/js';
10import { Outlet } from 'react-router-dom';
11import InfoBar from '../ui/InfoBar';
12import { Component as BasicAuth } from '../../features/basicAuth';
13import { Component as QuickSwitch } from '../../features/quickSwitch';
14import { Component as PublishDebugInfo } from '../../features/publishDebugInfo';
15import ErrorBoundary from '../util/ErrorBoundary';
16import { updateVersionParse } from '../../helpers/update-helpers';
17
18// import globalMessages from '../../i18n/globalMessages';
19
20import { isWindows, isMac } from '../../environment';
21import WorkspaceSwitchingIndicator from '../../features/workspaces/components/WorkspaceSwitchingIndicator';
22import { workspaceStore } from '../../features/workspaces';
23import AppUpdateInfoBar from '../AppUpdateInfoBar';
24import Todos from '../../features/todos/containers/TodosScreen';
25import Icon from '../ui/icon';
26
27import LockedScreen from '../../containers/auth/LockedScreen';
28
29const messages = defineMessages({
30 servicesUpdated: {
31 id: 'infobar.servicesUpdated',
32 defaultMessage: 'Your services have been updated.',
33 },
34 buttonReloadServices: {
35 id: 'infobar.buttonReloadServices',
36 defaultMessage: 'Reload services',
37 },
38 requiredRequestsFailed: {
39 id: 'infobar.requiredRequestsFailed',
40 defaultMessage: 'Could not load services and user information',
41 },
42 authRequestFailed: {
43 id: 'infobar.authRequestFailed',
44 defaultMessage:
45 'There were errors while trying to perform an authenticated request. Please try logging out and back in if this error persists.',
46 },
47});
48
49let transition = 'none';
50
51if (window && window.matchMedia('(prefers-reduced-motion: no-preference)')) {
52 transition = 'transform 0.5s ease';
53}
54
55const styles = theme => ({
56 appContent: {
57 // width: `calc(100% + ${theme.workspaces.drawer.width}px)`,
58 width: '100%',
59 transition,
60 transform() {
61 return workspaceStore.isWorkspaceDrawerOpen
62 ? 'translateX(0)'
63 : `translateX(-${theme.workspaces.drawer.width}px)`;
64 },
65 },
66 titleBar: {
67 display: 'block',
68 zIndex: 1,
69 width: '100%',
70 height: '10px',
71 position: 'absolute',
72 top: 0,
73 },
74});
75
76const toggleFullScreen = () => {
77 ipcRenderer.send('window.toolbar-double-clicked');
78};
79
80class AppLayout extends Component {
81 static propTypes = {
82 classes: PropTypes.object.isRequired,
83 settings: PropTypes.object.isRequired,
84 isFullScreen: PropTypes.bool.isRequired,
85 sidebar: PropTypes.element.isRequired,
86 workspacesDrawer: PropTypes.element.isRequired,
87 services: PropTypes.element.isRequired,
88 showServicesUpdatedInfoBar: PropTypes.bool.isRequired,
89 appUpdateIsDownloaded: PropTypes.bool.isRequired,
90 authRequestFailed: PropTypes.bool.isRequired,
91 installAppUpdate: PropTypes.func.isRequired,
92 showRequiredRequestsError: PropTypes.bool.isRequired,
93 areRequiredRequestsSuccessful: PropTypes.bool.isRequired,
94 retryRequiredRequests: PropTypes.func.isRequired,
95 areRequiredRequestsLoading: PropTypes.bool.isRequired,
96 };
97
98 constructor(props) {
99 super(props);
100
101 this.state = {
102 shouldShowAppUpdateInfoBar: true,
103 shouldShowServicesUpdatedInfoBar: true,
104 };
105 }
106
107 render() {
108 const {
109 classes,
110 isFullScreen,
111 workspacesDrawer,
112 sidebar,
113 services,
114 showServicesUpdatedInfoBar,
115 appUpdateIsDownloaded,
116 authRequestFailed,
117 installAppUpdate,
118 settings,
119 showRequiredRequestsError,
120 areRequiredRequestsSuccessful,
121 retryRequiredRequests,
122 areRequiredRequestsLoading,
123 updateVersion,
124 } = this.props;
125
126 const { intl } = this.props;
127
128 const { locked, automaticUpdates } = settings.app;
129 if (locked) {
130 return <LockedScreen />;
131 }
132
133 return (
134 <>
135 {isMac && !isFullScreen && <div className="window-draggable" />}
136 <ErrorBoundary>
137 <div className="app">
138 {isWindows && !isFullScreen && (
139 <TitleBar
140 menu={window['ferdium'].menu.template}
141 icon="assets/images/logo.svg"
142 />
143 )}
144 {isMac && !isFullScreen && (
145 <span
146 onDoubleClick={toggleFullScreen}
147 className={classes.titleBar}
148 />
149 )}
150 <div className={`app__content ${classes.appContent}`}>
151 {workspacesDrawer}
152 {sidebar}
153 <div className="app__service">
154 <WorkspaceSwitchingIndicator />
155 {!areRequiredRequestsSuccessful && showRequiredRequestsError && (
156 <InfoBar
157 type="danger"
158 ctaLabel="Try again"
159 ctaLoading={areRequiredRequestsLoading}
160 sticky
161 onClick={retryRequiredRequests}
162 >
163 <Icon icon={mdiFlash} />
164 {intl.formatMessage(messages.requiredRequestsFailed)}
165 </InfoBar>
166 )}
167 {authRequestFailed && (
168 <InfoBar
169 type="danger"
170 ctaLabel="Try again"
171 ctaLoading={areRequiredRequestsLoading}
172 sticky
173 onClick={retryRequiredRequests}
174 >
175 <Icon icon={mdiFlash} />
176 {intl.formatMessage(messages.authRequestFailed)}
177 </InfoBar>
178 )}
179 {automaticUpdates &&
180 showServicesUpdatedInfoBar &&
181 this.state.shouldShowServicesUpdatedInfoBar && (
182 <InfoBar
183 type="primary"
184 ctaLabel={intl.formatMessage(
185 messages.buttonReloadServices,
186 )}
187 onClick={() => window.location.reload()}
188 onHide={() => {
189 this.setState({
190 shouldShowServicesUpdatedInfoBar: false,
191 });
192 }}
193 >
194 <Icon icon={mdiPowerPlug} />
195 {intl.formatMessage(messages.servicesUpdated)}
196 </InfoBar>
197 )}
198 {automaticUpdates &&
199 appUpdateIsDownloaded &&
200 this.state.shouldShowAppUpdateInfoBar && (
201 <AppUpdateInfoBar
202 onInstallUpdate={installAppUpdate}
203 updateVersionParsed={updateVersionParse(updateVersion)}
204 onHide={() => {
205 this.setState({ shouldShowAppUpdateInfoBar: false });
206 }}
207 />
208 )}
209 <BasicAuth />
210 <QuickSwitch />
211 <PublishDebugInfo />
212 {services}
213 <Outlet />
214 </div>
215 <Todos />
216 </div>
217 </div>
218 </ErrorBoundary>
219 </>
220 );
221 }
222}
223
224export default injectIntl(
225 injectSheet(styles, { injectTheme: true })(observer(AppLayout)),
226);