diff options
Diffstat (limited to 'src/components/layout/AppLayout.jsx')
-rw-r--r-- | src/components/layout/AppLayout.jsx | 226 |
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 @@ | |||
1 | import { Component } from 'react'; | ||
2 | import PropTypes from 'prop-types'; | ||
3 | import { observer } from 'mobx-react'; | ||
4 | import { defineMessages, injectIntl } from 'react-intl'; | ||
5 | import { TitleBar } from 'electron-react-titlebar/renderer'; | ||
6 | import injectSheet from 'react-jss'; | ||
7 | import { ipcRenderer } from 'electron'; | ||
8 | |||
9 | import { mdiFlash, mdiPowerPlug } from '@mdi/js'; | ||
10 | import { Outlet } from 'react-router-dom'; | ||
11 | import InfoBar from '../ui/InfoBar'; | ||
12 | import { Component as BasicAuth } from '../../features/basicAuth'; | ||
13 | import { Component as QuickSwitch } from '../../features/quickSwitch'; | ||
14 | import { Component as PublishDebugInfo } from '../../features/publishDebugInfo'; | ||
15 | import ErrorBoundary from '../util/ErrorBoundary'; | ||
16 | import { updateVersionParse } from '../../helpers/update-helpers'; | ||
17 | |||
18 | // import globalMessages from '../../i18n/globalMessages'; | ||
19 | |||
20 | import { isWindows, isMac } from '../../environment'; | ||
21 | import WorkspaceSwitchingIndicator from '../../features/workspaces/components/WorkspaceSwitchingIndicator'; | ||
22 | import { workspaceStore } from '../../features/workspaces'; | ||
23 | import AppUpdateInfoBar from '../AppUpdateInfoBar'; | ||
24 | import Todos from '../../features/todos/containers/TodosScreen'; | ||
25 | import Icon from '../ui/icon'; | ||
26 | |||
27 | import LockedScreen from '../../containers/auth/LockedScreen'; | ||
28 | |||
29 | const 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 | |||
49 | let transition = 'none'; | ||
50 | |||
51 | if (window && window.matchMedia('(prefers-reduced-motion: no-preference)')) { | ||
52 | transition = 'transform 0.5s ease'; | ||
53 | } | ||
54 | |||
55 | const 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 | |||
76 | const toggleFullScreen = () => { | ||
77 | ipcRenderer.send('window.toolbar-double-clicked'); | ||
78 | }; | ||
79 | |||
80 | class 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 | |||
224 | export default injectIntl( | ||
225 | injectSheet(styles, { injectTheme: true })(observer(AppLayout)), | ||
226 | ); | ||