diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/components/layout/AppLayout.js | 134 | ||||
-rw-r--r-- | src/components/services/content/ServiceWebview.js | 1 | ||||
-rw-r--r-- | src/components/settings/SettingsLayout.js | 21 | ||||
-rw-r--r-- | src/components/util/ErrorBoundary/index.js | 54 | ||||
-rw-r--r-- | src/components/util/ErrorBoundary/styles.js | 13 | ||||
-rw-r--r-- | src/containers/settings/AccountScreen.js | 35 | ||||
-rw-r--r-- | src/containers/settings/EditServiceScreen.js | 32 | ||||
-rw-r--r-- | src/containers/settings/EditSettingsScreen.js | 31 | ||||
-rw-r--r-- | src/containers/settings/EditUserScreen.js | 20 | ||||
-rw-r--r-- | src/containers/settings/InviteScreen.js | 16 | ||||
-rw-r--r-- | src/containers/settings/RecipesScreen.js | 29 | ||||
-rw-r--r-- | src/containers/settings/ServicesScreen.js | 31 | ||||
-rw-r--r-- | src/containers/settings/SettingsWindow.js | 15 | ||||
-rw-r--r-- | src/i18n/locales/en-US.json | 4 | ||||
-rw-r--r-- | src/theme/dark/index.js | 2 | ||||
-rw-r--r-- | src/theme/default/index.js | 2 |
16 files changed, 274 insertions, 166 deletions
diff --git a/src/components/layout/AppLayout.js b/src/components/layout/AppLayout.js index 3ababe54a..e526f6b1f 100644 --- a/src/components/layout/AppLayout.js +++ b/src/components/layout/AppLayout.js | |||
@@ -6,6 +6,8 @@ import { TitleBar } from 'electron-react-titlebar'; | |||
6 | 6 | ||
7 | import InfoBar from '../ui/InfoBar'; | 7 | import InfoBar from '../ui/InfoBar'; |
8 | import { Component as DelayApp } from '../../features/delayApp'; | 8 | import { Component as DelayApp } from '../../features/delayApp'; |
9 | import ErrorBoundary from '../util/ErrorBoundary'; | ||
10 | |||
9 | import globalMessages from '../../i18n/globalMessages'; | 11 | import globalMessages from '../../i18n/globalMessages'; |
10 | 12 | ||
11 | import { isWindows } from '../../environment'; | 13 | import { isWindows } from '../../environment'; |
@@ -94,74 +96,76 @@ export default @observer class AppLayout extends Component { | |||
94 | const { intl } = this.context; | 96 | const { intl } = this.context; |
95 | 97 | ||
96 | return ( | 98 | return ( |
97 | <div className={(darkMode ? 'theme__dark' : '')}> | 99 | <ErrorBoundary> |
98 | <div className="app"> | 100 | <div className={(darkMode ? 'theme__dark' : '')}> |
99 | {isWindows && !isFullScreen && <TitleBar menu={window.franz.menu.template} icon={'assets/images/logo.svg'} />} | 101 | <div className="app"> |
100 | <div className="app__content"> | 102 | {isWindows && !isFullScreen && <TitleBar menu={window.franz.menu.template} icon={'assets/images/logo.svg'} />} |
101 | {sidebar} | 103 | <div className="app__content"> |
102 | <div className="app__service"> | 104 | {sidebar} |
103 | {news.length > 0 && news.map(item => ( | 105 | <div className="app__service"> |
104 | <InfoBar | 106 | {news.length > 0 && news.map(item => ( |
105 | key={item.id} | 107 | <InfoBar |
106 | position="top" | 108 | key={item.id} |
107 | type={item.type} | 109 | position="top" |
108 | sticky={item.sticky} | 110 | type={item.type} |
109 | onHide={() => removeNewsItem({ newsId: item.id })} | 111 | sticky={item.sticky} |
110 | > | 112 | onHide={() => removeNewsItem({ newsId: item.id })} |
111 | <span dangerouslySetInnerHTML={createMarkup(item.message)} /> | 113 | > |
112 | </InfoBar> | 114 | <span dangerouslySetInnerHTML={createMarkup(item.message)} /> |
113 | ))} | 115 | </InfoBar> |
114 | {!isOnline && ( | 116 | ))} |
115 | <InfoBar | 117 | {!isOnline && ( |
116 | type="danger" | 118 | <InfoBar |
117 | > | 119 | type="danger" |
118 | <span className="mdi mdi-flash" /> | 120 | > |
119 | {intl.formatMessage(globalMessages.notConnectedToTheInternet)} | 121 | <span className="mdi mdi-flash" /> |
120 | </InfoBar> | 122 | {intl.formatMessage(globalMessages.notConnectedToTheInternet)} |
121 | )} | 123 | </InfoBar> |
122 | {!areRequiredRequestsSuccessful && showRequiredRequestsError && ( | 124 | )} |
123 | <InfoBar | 125 | {!areRequiredRequestsSuccessful && showRequiredRequestsError && ( |
124 | type="danger" | 126 | <InfoBar |
125 | ctaLabel="Try again" | 127 | type="danger" |
126 | ctaLoading={areRequiredRequestsLoading} | 128 | ctaLabel="Try again" |
127 | sticky | 129 | ctaLoading={areRequiredRequestsLoading} |
128 | onClick={retryRequiredRequests} | 130 | sticky |
129 | > | 131 | onClick={retryRequiredRequests} |
130 | <span className="mdi mdi-flash" /> | 132 | > |
131 | {intl.formatMessage(messages.requiredRequestsFailed)} | 133 | <span className="mdi mdi-flash" /> |
132 | </InfoBar> | 134 | {intl.formatMessage(messages.requiredRequestsFailed)} |
133 | )} | 135 | </InfoBar> |
134 | {showServicesUpdatedInfoBar && ( | 136 | )} |
135 | <InfoBar | 137 | {showServicesUpdatedInfoBar && ( |
136 | type="primary" | 138 | <InfoBar |
137 | ctaLabel={intl.formatMessage(messages.buttonReloadServices)} | 139 | type="primary" |
138 | onClick={reloadServicesAfterUpdate} | 140 | ctaLabel={intl.formatMessage(messages.buttonReloadServices)} |
139 | sticky | 141 | onClick={reloadServicesAfterUpdate} |
140 | > | 142 | sticky |
141 | <span className="mdi mdi-power-plug" /> | 143 | > |
142 | {intl.formatMessage(messages.servicesUpdated)} | 144 | <span className="mdi mdi-power-plug" /> |
143 | </InfoBar> | 145 | {intl.formatMessage(messages.servicesUpdated)} |
144 | )} | 146 | </InfoBar> |
145 | {appUpdateIsDownloaded && ( | 147 | )} |
146 | <InfoBar | 148 | {appUpdateIsDownloaded && ( |
147 | type="primary" | 149 | <InfoBar |
148 | ctaLabel={intl.formatMessage(messages.buttonInstallUpdate)} | 150 | type="primary" |
149 | onClick={installAppUpdate} | 151 | ctaLabel={intl.formatMessage(messages.buttonInstallUpdate)} |
150 | sticky | 152 | onClick={installAppUpdate} |
151 | > | 153 | sticky |
152 | <span className="mdi mdi-information" /> | 154 | > |
153 | {intl.formatMessage(messages.updateAvailable)} <a href="https://meetfranz.com/changelog" target="_blank"> | 155 | <span className="mdi mdi-information" /> |
154 | <u>{intl.formatMessage(messages.changelog)}</u> | 156 | {intl.formatMessage(messages.updateAvailable)} <a href="https://meetfranz.com/changelog" target="_blank"> |
155 | </a> | 157 | <u>{intl.formatMessage(messages.changelog)}</u> |
156 | </InfoBar> | 158 | </a> |
157 | )} | 159 | </InfoBar> |
158 | {isDelayAppScreenVisible && (<DelayApp />)} | 160 | )} |
159 | {services} | 161 | {isDelayAppScreenVisible && (<DelayApp />)} |
162 | {services} | ||
163 | </div> | ||
160 | </div> | 164 | </div> |
161 | </div> | 165 | </div> |
166 | {children} | ||
162 | </div> | 167 | </div> |
163 | {children} | 168 | </ErrorBoundary> |
164 | </div> | ||
165 | ); | 169 | ); |
166 | } | 170 | } |
167 | } | 171 | } |
diff --git a/src/components/services/content/ServiceWebview.js b/src/components/services/content/ServiceWebview.js index f59205c0e..98daf9b9f 100644 --- a/src/components/services/content/ServiceWebview.js +++ b/src/components/services/content/ServiceWebview.js | |||
@@ -59,6 +59,7 @@ export default @observer class ServiceWebview extends Component { | |||
59 | } | 59 | } |
60 | 60 | ||
61 | autorunDisposer = null; | 61 | autorunDisposer = null; |
62 | |||
62 | webview = null; | 63 | webview = null; |
63 | 64 | ||
64 | render() { | 65 | render() { |
diff --git a/src/components/settings/SettingsLayout.js b/src/components/settings/SettingsLayout.js index 3cb08feb1..d5d8f0bb0 100644 --- a/src/components/settings/SettingsLayout.js +++ b/src/components/settings/SettingsLayout.js | |||
@@ -2,6 +2,7 @@ import React, { Component } from 'react'; | |||
2 | import PropTypes from 'prop-types'; | 2 | import PropTypes from 'prop-types'; |
3 | import { observer } from 'mobx-react'; | 3 | import { observer } from 'mobx-react'; |
4 | 4 | ||
5 | import ErrorBoundary from '../util/ErrorBoundary'; | ||
5 | import { oneOrManyChildElements } from '../../prop-types'; | 6 | import { oneOrManyChildElements } from '../../prop-types'; |
6 | import Appear from '../ui/effects/Appear'; | 7 | import Appear from '../ui/effects/Appear'; |
7 | 8 | ||
@@ -36,18 +37,20 @@ export default @observer class SettingsLayout extends Component { | |||
36 | return ( | 37 | return ( |
37 | <Appear transitionName="fadeIn-fast"> | 38 | <Appear transitionName="fadeIn-fast"> |
38 | <div className="settings-wrapper"> | 39 | <div className="settings-wrapper"> |
39 | <button | 40 | <ErrorBoundary> |
40 | className="settings-wrapper__action" | ||
41 | onClick={closeSettings} | ||
42 | /> | ||
43 | <div className="settings franz-form"> | ||
44 | {navigation} | ||
45 | {children} | ||
46 | <button | 41 | <button |
47 | className="settings__close mdi mdi-close" | 42 | className="settings-wrapper__action" |
48 | onClick={closeSettings} | 43 | onClick={closeSettings} |
49 | /> | 44 | /> |
50 | </div> | 45 | <div className="settings franz-form"> |
46 | {navigation} | ||
47 | {children} | ||
48 | <button | ||
49 | className="settings__close mdi mdi-close" | ||
50 | onClick={closeSettings} | ||
51 | /> | ||
52 | </div> | ||
53 | </ErrorBoundary> | ||
51 | </div> | 54 | </div> |
52 | </Appear> | 55 | </Appear> |
53 | ); | 56 | ); |
diff --git a/src/components/util/ErrorBoundary/index.js b/src/components/util/ErrorBoundary/index.js new file mode 100644 index 000000000..def01c74f --- /dev/null +++ b/src/components/util/ErrorBoundary/index.js | |||
@@ -0,0 +1,54 @@ | |||
1 | import React, { Component } from 'react'; | ||
2 | import injectSheet from 'react-jss'; | ||
3 | import { defineMessages, intlShape } from 'react-intl'; | ||
4 | |||
5 | import Button from '../../ui/Button'; | ||
6 | |||
7 | import styles from './styles'; | ||
8 | |||
9 | const messages = defineMessages({ | ||
10 | headline: { | ||
11 | id: 'app.errorHandler.headline', | ||
12 | defaultMessage: '!!!Something went wrong.', | ||
13 | }, | ||
14 | action: { | ||
15 | id: 'app.errorHandler.action', | ||
16 | defaultMessage: '!!!Reload', | ||
17 | }, | ||
18 | }); | ||
19 | |||
20 | export default @injectSheet(styles) class ErrorBoundary extends Component { | ||
21 | state = { | ||
22 | hasError: false, | ||
23 | } | ||
24 | |||
25 | static contextTypes = { | ||
26 | intl: intlShape, | ||
27 | }; | ||
28 | |||
29 | componentDidCatch(error, info) { | ||
30 | this.setState({ hasError: true }); | ||
31 | } | ||
32 | |||
33 | render() { | ||
34 | const { classes } = this.props; | ||
35 | const { intl } = this.context; | ||
36 | |||
37 | if (this.state.hasError) { | ||
38 | return ( | ||
39 | <div className={classes.component}> | ||
40 | <h1 className={classes.title}> | ||
41 | {intl.formatMessage(messages.headline)} | ||
42 | </h1> | ||
43 | <Button | ||
44 | label={intl.formatMessage(messages.action)} | ||
45 | buttonType="inverted" | ||
46 | onClick={() => location.reload()} | ||
47 | /> | ||
48 | </div> | ||
49 | ); | ||
50 | } | ||
51 | |||
52 | return this.props.children; | ||
53 | } | ||
54 | } \ No newline at end of file | ||
diff --git a/src/components/util/ErrorBoundary/styles.js b/src/components/util/ErrorBoundary/styles.js new file mode 100644 index 000000000..8d62767f6 --- /dev/null +++ b/src/components/util/ErrorBoundary/styles.js | |||
@@ -0,0 +1,13 @@ | |||
1 | export default (theme) => ({ | ||
2 | component: { | ||
3 | display: 'flex', | ||
4 | width: '100%', | ||
5 | alignItems: 'center', | ||
6 | justifyContent: 'center', | ||
7 | flexDirection: 'column', | ||
8 | }, | ||
9 | title: { | ||
10 | fontSize: 20, | ||
11 | color: theme.colorText, | ||
12 | } | ||
13 | }); | ||
diff --git a/src/containers/settings/AccountScreen.js b/src/containers/settings/AccountScreen.js index 5818af0b1..019b3d7d6 100644 --- a/src/containers/settings/AccountScreen.js +++ b/src/containers/settings/AccountScreen.js | |||
@@ -9,6 +9,7 @@ import AppStore from '../../stores/AppStore'; | |||
9 | import { gaPage } from '../../lib/analytics'; | 9 | import { gaPage } from '../../lib/analytics'; |
10 | 10 | ||
11 | import AccountDashboard from '../../components/settings/account/AccountDashboard'; | 11 | import AccountDashboard from '../../components/settings/account/AccountDashboard'; |
12 | import ErrorBoundary from '../../components/util/ErrorBoundary'; | ||
12 | 13 | ||
13 | const { BrowserWindow } = remote; | 14 | const { BrowserWindow } = remote; |
14 | 15 | ||
@@ -67,22 +68,24 @@ export default @inject('stores', 'actions') @observer class AccountScreen extend | |||
67 | const isLoadingPlans = payment.plansRequest.isExecuting; | 68 | const isLoadingPlans = payment.plansRequest.isExecuting; |
68 | 69 | ||
69 | return ( | 70 | return ( |
70 | <AccountDashboard | 71 | <ErrorBoundary> |
71 | user={user.data} | 72 | <AccountDashboard |
72 | orders={payment.orders} | 73 | user={user.data} |
73 | isLoading={isLoadingUserInfo} | 74 | orders={payment.orders} |
74 | isLoadingOrdersInfo={isLoadingOrdersInfo} | 75 | isLoading={isLoadingUserInfo} |
75 | isLoadingPlans={isLoadingPlans} | 76 | isLoadingOrdersInfo={isLoadingOrdersInfo} |
76 | userInfoRequestFailed={user.getUserInfoRequest.wasExecuted && user.getUserInfoRequest.isError} | 77 | isLoadingPlans={isLoadingPlans} |
77 | retryUserInfoRequest={() => this.reloadData()} | 78 | userInfoRequestFailed={user.getUserInfoRequest.wasExecuted && user.getUserInfoRequest.isError} |
78 | isCreatingPaymentDashboardUrl={payment.createDashboardUrlRequest.isExecuting} | 79 | retryUserInfoRequest={() => this.reloadData()} |
79 | openDashboard={price => this.handlePaymentDashboard(price)} | 80 | isCreatingPaymentDashboardUrl={payment.createDashboardUrlRequest.isExecuting} |
80 | openExternalUrl={url => openExternalUrl({ url })} | 81 | openDashboard={price => this.handlePaymentDashboard(price)} |
81 | onCloseSubscriptionWindow={() => this.onCloseWindow()} | 82 | openExternalUrl={url => openExternalUrl({ url })} |
82 | deleteAccount={userActions.delete} | 83 | onCloseSubscriptionWindow={() => this.onCloseWindow()} |
83 | isLoadingDeleteAccount={user.deleteAccountRequest.isExecuting} | 84 | deleteAccount={userActions.delete} |
84 | isDeleteAccountSuccessful={user.deleteAccountRequest.wasExecuted && !user.deleteAccountRequest.isError} | 85 | isLoadingDeleteAccount={user.deleteAccountRequest.isExecuting} |
85 | /> | 86 | isDeleteAccountSuccessful={user.deleteAccountRequest.wasExecuted && !user.deleteAccountRequest.isError} |
87 | /> | ||
88 | </ErrorBoundary> | ||
86 | ); | 89 | ); |
87 | } | 90 | } |
88 | } | 91 | } |
diff --git a/src/containers/settings/EditServiceScreen.js b/src/containers/settings/EditServiceScreen.js index f4915f68b..f0b7268d6 100644 --- a/src/containers/settings/EditServiceScreen.js +++ b/src/containers/settings/EditServiceScreen.js | |||
@@ -13,6 +13,8 @@ import { gaPage } from '../../lib/analytics'; | |||
13 | 13 | ||
14 | import ServiceError from '../../components/settings/services/ServiceError'; | 14 | import ServiceError from '../../components/settings/services/ServiceError'; |
15 | import EditServiceForm from '../../components/settings/services/EditServiceForm'; | 15 | import EditServiceForm from '../../components/settings/services/EditServiceForm'; |
16 | import ErrorBoundary from '../../components/util/ErrorBoundary'; | ||
17 | |||
16 | import { required, url, oneRequired } from '../../helpers/validation-helpers'; | 18 | import { required, url, oneRequired } from '../../helpers/validation-helpers'; |
17 | import { getSelectOptions } from '../../helpers/i18n-helpers'; | 19 | import { getSelectOptions } from '../../helpers/i18n-helpers'; |
18 | 20 | ||
@@ -302,20 +304,22 @@ export default @inject('stores', 'actions') @observer class EditServiceScreen ex | |||
302 | const form = this.prepareForm(recipe, service, proxyFeature); | 304 | const form = this.prepareForm(recipe, service, proxyFeature); |
303 | 305 | ||
304 | return ( | 306 | return ( |
305 | <EditServiceForm | 307 | <ErrorBoundary> |
306 | action={action} | 308 | <EditServiceForm |
307 | recipe={recipe} | 309 | action={action} |
308 | service={service} | 310 | recipe={recipe} |
309 | user={user.data} | 311 | service={service} |
310 | form={form} | 312 | user={user.data} |
311 | status={services.actionStatus} | 313 | form={form} |
312 | isSaving={services.updateServiceRequest.isExecuting || services.createServiceRequest.isExecuting} | 314 | status={services.actionStatus} |
313 | isDeleting={services.deleteServiceRequest.isExecuting} | 315 | isSaving={services.updateServiceRequest.isExecuting || services.createServiceRequest.isExecuting} |
314 | onSubmit={d => this.onSubmit(d)} | 316 | isDeleting={services.deleteServiceRequest.isExecuting} |
315 | onDelete={() => this.deleteService()} | 317 | onSubmit={d => this.onSubmit(d)} |
316 | isProxyFeatureEnabled={proxyFeature.isEnabled} | 318 | onDelete={() => this.deleteService()} |
317 | isProxyFeaturePremiumFeature={proxyFeature.isPremium} | 319 | isProxyFeatureEnabled={proxyFeature.isEnabled} |
318 | /> | 320 | isProxyFeaturePremiumFeature={proxyFeature.isPremium} |
321 | /> | ||
322 | </ErrorBoundary> | ||
319 | ); | 323 | ); |
320 | } | 324 | } |
321 | } | 325 | } |
diff --git a/src/containers/settings/EditSettingsScreen.js b/src/containers/settings/EditSettingsScreen.js index 350bd9f8a..f1706a721 100644 --- a/src/containers/settings/EditSettingsScreen.js +++ b/src/containers/settings/EditSettingsScreen.js | |||
@@ -16,6 +16,7 @@ import { getSelectOptions } from '../../helpers/i18n-helpers'; | |||
16 | 16 | ||
17 | 17 | ||
18 | import EditSettingsForm from '../../components/settings/settings/EditSettingsForm'; | 18 | import EditSettingsForm from '../../components/settings/settings/EditSettingsForm'; |
19 | import ErrorBoundary from '../../components/util/ErrorBoundary'; | ||
19 | 20 | ||
20 | const messages = defineMessages({ | 21 | const messages = defineMessages({ |
21 | autoLaunchOnStart: { | 22 | autoLaunchOnStart: { |
@@ -216,20 +217,22 @@ export default @inject('stores', 'actions') @observer class EditSettingsScreen e | |||
216 | const form = this.prepareForm(); | 217 | const form = this.prepareForm(); |
217 | 218 | ||
218 | return ( | 219 | return ( |
219 | <EditSettingsForm | 220 | <ErrorBoundary> |
220 | form={form} | 221 | <EditSettingsForm |
221 | checkForUpdates={checkForUpdates} | 222 | form={form} |
222 | installUpdate={installUpdate} | 223 | checkForUpdates={checkForUpdates} |
223 | isCheckingForUpdates={updateStatus === updateStatusTypes.CHECKING} | 224 | installUpdate={installUpdate} |
224 | isUpdateAvailable={updateStatus === updateStatusTypes.AVAILABLE} | 225 | isCheckingForUpdates={updateStatus === updateStatusTypes.CHECKING} |
225 | noUpdateAvailable={updateStatus === updateStatusTypes.NOT_AVAILABLE} | 226 | isUpdateAvailable={updateStatus === updateStatusTypes.AVAILABLE} |
226 | updateIsReadyToInstall={updateStatus === updateStatusTypes.DOWNLOADED} | 227 | noUpdateAvailable={updateStatus === updateStatusTypes.NOT_AVAILABLE} |
227 | onSubmit={d => this.onSubmit(d)} | 228 | updateIsReadyToInstall={updateStatus === updateStatusTypes.DOWNLOADED} |
228 | cacheSize={cacheSize} | 229 | onSubmit={d => this.onSubmit(d)} |
229 | isClearingAllCache={isClearingAllCache} | 230 | cacheSize={cacheSize} |
230 | onClearAllCache={clearAllCache} | 231 | isClearingAllCache={isClearingAllCache} |
231 | isSpellcheckerPremiumFeature={spellcheckerConfig.isPremiumFeature} | 232 | onClearAllCache={clearAllCache} |
232 | /> | 233 | isSpellcheckerPremiumFeature={spellcheckerConfig.isPremiumFeature} |
234 | /> | ||
235 | </ErrorBoundary> | ||
233 | ); | 236 | ); |
234 | } | 237 | } |
235 | } | 238 | } |
diff --git a/src/containers/settings/EditUserScreen.js b/src/containers/settings/EditUserScreen.js index 3da3e8d2c..adad8a9bd 100644 --- a/src/containers/settings/EditUserScreen.js +++ b/src/containers/settings/EditUserScreen.js | |||
@@ -6,6 +6,8 @@ import { defineMessages, intlShape } from 'react-intl'; | |||
6 | import UserStore from '../../stores/UserStore'; | 6 | import UserStore from '../../stores/UserStore'; |
7 | import Form from '../../lib/Form'; | 7 | import Form from '../../lib/Form'; |
8 | import EditUserForm from '../../components/settings/user/EditUserForm'; | 8 | import EditUserForm from '../../components/settings/user/EditUserForm'; |
9 | import ErrorBoundary from '../../components/util/ErrorBoundary'; | ||
10 | |||
9 | import { required, email, minLength } from '../../helpers/validation-helpers'; | 11 | import { required, email, minLength } from '../../helpers/validation-helpers'; |
10 | import { gaPage } from '../../lib/analytics'; | 12 | import { gaPage } from '../../lib/analytics'; |
11 | 13 | ||
@@ -140,14 +142,16 @@ export default @inject('stores', 'actions') @observer class EditUserScreen exten | |||
140 | const form = this.prepareForm(user.data); | 142 | const form = this.prepareForm(user.data); |
141 | 143 | ||
142 | return ( | 144 | return ( |
143 | <EditUserForm | 145 | <ErrorBoundary> |
144 | // user={user.data} | 146 | <EditUserForm |
145 | status={user.actionStatus} | 147 | // user={user.data} |
146 | form={form} | 148 | status={user.actionStatus} |
147 | isEnterprise={user.data.isEnterprise} | 149 | form={form} |
148 | isSaving={user.updateUserInfoRequest.isExecuting} | 150 | isEnterprise={user.data.isEnterprise} |
149 | onSubmit={d => this.onSubmit(d)} | 151 | isSaving={user.updateUserInfoRequest.isExecuting} |
150 | /> | 152 | onSubmit={d => this.onSubmit(d)} |
153 | /> | ||
154 | </ErrorBoundary> | ||
151 | ); | 155 | ); |
152 | } | 156 | } |
153 | } | 157 | } |
diff --git a/src/containers/settings/InviteScreen.js b/src/containers/settings/InviteScreen.js index 38ca6ec74..cd36610e4 100644 --- a/src/containers/settings/InviteScreen.js +++ b/src/containers/settings/InviteScreen.js | |||
@@ -3,6 +3,8 @@ import PropTypes from 'prop-types'; | |||
3 | import { inject, observer } from 'mobx-react'; | 3 | import { inject, observer } from 'mobx-react'; |
4 | 4 | ||
5 | import Invite from '../../components/auth/Invite'; | 5 | import Invite from '../../components/auth/Invite'; |
6 | import ErrorBoundary from '../../components/util/ErrorBoundary'; | ||
7 | |||
6 | import { gaPage } from '../../lib/analytics'; | 8 | import { gaPage } from '../../lib/analytics'; |
7 | 9 | ||
8 | export default @inject('stores', 'actions') @observer class InviteScreen extends Component { | 10 | export default @inject('stores', 'actions') @observer class InviteScreen extends Component { |
@@ -19,12 +21,14 @@ export default @inject('stores', 'actions') @observer class InviteScreen extends | |||
19 | const { user } = this.props.stores; | 21 | const { user } = this.props.stores; |
20 | 22 | ||
21 | return ( | 23 | return ( |
22 | <Invite | 24 | <ErrorBoundary> |
23 | onSubmit={actions.user.invite} | 25 | <Invite |
24 | isLoadingInvite={user.inviteRequest.isExecuting} | 26 | onSubmit={actions.user.invite} |
25 | isInviteSuccessful={user.inviteRequest.wasExecuted && !user.inviteRequest.isError} | 27 | isLoadingInvite={user.inviteRequest.isExecuting} |
26 | embed | 28 | isInviteSuccessful={user.inviteRequest.wasExecuted && !user.inviteRequest.isError} |
27 | /> | 29 | embed |
30 | /> | ||
31 | </ErrorBoundary> | ||
28 | ); | 32 | ); |
29 | } | 33 | } |
30 | } | 34 | } |
diff --git a/src/containers/settings/RecipesScreen.js b/src/containers/settings/RecipesScreen.js index b125e6a05..1f05b6510 100644 --- a/src/containers/settings/RecipesScreen.js +++ b/src/containers/settings/RecipesScreen.js | |||
@@ -10,6 +10,7 @@ import UserStore from '../../stores/UserStore'; | |||
10 | import { gaPage } from '../../lib/analytics'; | 10 | import { gaPage } from '../../lib/analytics'; |
11 | 11 | ||
12 | import RecipesDashboard from '../../components/settings/recipes/RecipesDashboard'; | 12 | import RecipesDashboard from '../../components/settings/recipes/RecipesDashboard'; |
13 | import ErrorBoundary from '../../components/util/ErrorBoundary'; | ||
13 | 14 | ||
14 | export default @inject('stores', 'actions') @observer class RecipesScreen extends Component { | 15 | export default @inject('stores', 'actions') @observer class RecipesScreen extends Component { |
15 | static propTypes = { | 16 | static propTypes = { |
@@ -93,19 +94,21 @@ export default @inject('stores', 'actions') @observer class RecipesScreen extend | |||
93 | || recipePreviews.searchRecipePreviewsRequest.isExecuting; | 94 | || recipePreviews.searchRecipePreviewsRequest.isExecuting; |
94 | 95 | ||
95 | return ( | 96 | return ( |
96 | <RecipesDashboard | 97 | <ErrorBoundary> |
97 | recipes={allRecipes} | 98 | <RecipesDashboard |
98 | isLoading={isLoading} | 99 | recipes={allRecipes} |
99 | addedServiceCount={services.all.length} | 100 | isLoading={isLoading} |
100 | isPremium={user.data.isPremium} | 101 | addedServiceCount={services.all.length} |
101 | hasLoadedRecipes={recipePreviews.featuredRecipePreviewsRequest.wasExecuted} | 102 | isPremium={user.data.isPremium} |
102 | showAddServiceInterface={showAddServiceInterface} | 103 | hasLoadedRecipes={recipePreviews.featuredRecipePreviewsRequest.wasExecuted} |
103 | searchRecipes={e => this.searchRecipes(e)} | 104 | showAddServiceInterface={showAddServiceInterface} |
104 | resetSearch={() => this.resetSearch()} | 105 | searchRecipes={e => this.searchRecipes(e)} |
105 | searchNeedle={this.state.needle} | 106 | resetSearch={() => this.resetSearch()} |
106 | serviceStatus={services.actionStatus} | 107 | searchNeedle={this.state.needle} |
107 | devRecipesCount={recipePreviews.dev.length} | 108 | serviceStatus={services.actionStatus} |
108 | /> | 109 | devRecipesCount={recipePreviews.dev.length} |
110 | /> | ||
111 | </ErrorBoundary> | ||
109 | ); | 112 | ); |
110 | } | 113 | } |
111 | } | 114 | } |
diff --git a/src/containers/settings/ServicesScreen.js b/src/containers/settings/ServicesScreen.js index c1a133ef7..b70a5506e 100644 --- a/src/containers/settings/ServicesScreen.js +++ b/src/containers/settings/ServicesScreen.js | |||
@@ -9,6 +9,7 @@ import ServiceStore from '../../stores/ServicesStore'; | |||
9 | import { gaPage } from '../../lib/analytics'; | 9 | import { gaPage } from '../../lib/analytics'; |
10 | 10 | ||
11 | import ServicesDashboard from '../../components/settings/services/ServicesDashboard'; | 11 | import ServicesDashboard from '../../components/settings/services/ServicesDashboard'; |
12 | import ErrorBoundary from '../../components/util/ErrorBoundary'; | ||
12 | 13 | ||
13 | export default @inject('stores', 'actions') @observer class ServicesScreen extends Component { | 14 | export default @inject('stores', 'actions') @observer class ServicesScreen extends Component { |
14 | componentDidMount() { | 15 | componentDidMount() { |
@@ -40,20 +41,22 @@ export default @inject('stores', 'actions') @observer class ServicesScreen exten | |||
40 | } | 41 | } |
41 | 42 | ||
42 | return ( | 43 | return ( |
43 | <ServicesDashboard | 44 | <ErrorBoundary> |
44 | user={user.data} | 45 | <ServicesDashboard |
45 | services={allServices} | 46 | user={user.data} |
46 | status={services.actionStatus} | 47 | services={allServices} |
47 | deleteService={() => this.deleteService()} | 48 | status={services.actionStatus} |
48 | toggleService={toggleService} | 49 | deleteService={() => this.deleteService()} |
49 | isLoading={isLoading} | 50 | toggleService={toggleService} |
50 | filterServices={filter} | 51 | isLoading={isLoading} |
51 | resetFilter={resetFilter} | 52 | filterServices={filter} |
52 | goTo={router.push} | 53 | resetFilter={resetFilter} |
53 | servicesRequestFailed={services.allServicesRequest.wasExecuted && services.allServicesRequest.isError} | 54 | goTo={router.push} |
54 | retryServicesRequest={() => services.allServicesRequest.reload()} | 55 | servicesRequestFailed={services.allServicesRequest.wasExecuted && services.allServicesRequest.isError} |
55 | searchNeedle={services.filterNeedle} | 56 | retryServicesRequest={() => services.allServicesRequest.reload()} |
56 | /> | 57 | searchNeedle={services.filterNeedle} |
58 | /> | ||
59 | </ErrorBoundary> | ||
57 | ); | 60 | ); |
58 | } | 61 | } |
59 | } | 62 | } |
diff --git a/src/containers/settings/SettingsWindow.js b/src/containers/settings/SettingsWindow.js index 55589d0be..6d9e0ee77 100644 --- a/src/containers/settings/SettingsWindow.js +++ b/src/containers/settings/SettingsWindow.js | |||
@@ -6,6 +6,7 @@ import ServicesStore from '../../stores/ServicesStore'; | |||
6 | 6 | ||
7 | import Layout from '../../components/settings/SettingsLayout'; | 7 | import Layout from '../../components/settings/SettingsLayout'; |
8 | import Navigation from '../../components/settings/navigation/SettingsNavigation'; | 8 | import Navigation from '../../components/settings/navigation/SettingsNavigation'; |
9 | import ErrorBoundary from '../../components/util/ErrorBoundary'; | ||
9 | 10 | ||
10 | export default @inject('stores', 'actions') @observer class SettingsContainer extends Component { | 11 | export default @inject('stores', 'actions') @observer class SettingsContainer extends Component { |
11 | render() { | 12 | render() { |
@@ -19,12 +20,14 @@ export default @inject('stores', 'actions') @observer class SettingsContainer ex | |||
19 | ); | 20 | ); |
20 | 21 | ||
21 | return ( | 22 | return ( |
22 | <Layout | 23 | <ErrorBoundary> |
23 | navigation={navigation} | 24 | <Layout |
24 | closeSettings={closeSettings} | 25 | navigation={navigation} |
25 | > | 26 | closeSettings={closeSettings} |
26 | {children} | 27 | > |
27 | </Layout> | 28 | {children} |
29 | </Layout> | ||
30 | </ErrorBoundary> | ||
28 | ); | 31 | ); |
29 | } | 32 | } |
30 | } | 33 | } |
diff --git a/src/i18n/locales/en-US.json b/src/i18n/locales/en-US.json index 83eff2fc8..356eaae66 100644 --- a/src/i18n/locales/en-US.json +++ b/src/i18n/locales/en-US.json | |||
@@ -269,5 +269,7 @@ | |||
269 | "feature.delayApp.headline": "Please purchase a Franz Supporter License to skip waiting", | 269 | "feature.delayApp.headline": "Please purchase a Franz Supporter License to skip waiting", |
270 | "feature.delayApp.action": "Get a Franz Supporter License", | 270 | "feature.delayApp.action": "Get a Franz Supporter License", |
271 | "feature.delayApp.text": "Franz will continue in {seconds} seconds.", | 271 | "feature.delayApp.text": "Franz will continue in {seconds} seconds.", |
272 | "premiumFeature.button.upgradeAccount": "Upgrade account" | 272 | "premiumFeature.button.upgradeAccount": "Upgrade account", |
273 | "app.errorHandler.headline": "Something went wrong", | ||
274 | "app.errorHandler.action": "Reload" | ||
273 | } | 275 | } |
diff --git a/src/theme/dark/index.js b/src/theme/dark/index.js index 496a51119..5aa64a902 100644 --- a/src/theme/dark/index.js +++ b/src/theme/dark/index.js | |||
@@ -4,3 +4,5 @@ export const colorBackground = legacyStyles.darkThemeGrayDarkest; | |||
4 | export const colorBackgroundSubscriptionContainer = legacyStyles.themeBrandInfo; | 4 | export const colorBackgroundSubscriptionContainer = legacyStyles.themeBrandInfo; |
5 | 5 | ||
6 | export const colorHeadline = legacyStyles.darkThemeTextColor; | 6 | export const colorHeadline = legacyStyles.darkThemeTextColor; |
7 | export const colorText = legacyStyles.darkThemeTextColor; | ||
8 | |||
diff --git a/src/theme/default/index.js b/src/theme/default/index.js index 8766fb609..e67f2ba58 100644 --- a/src/theme/default/index.js +++ b/src/theme/default/index.js | |||
@@ -12,6 +12,8 @@ export const borderRadiusSmall = legacyStyles.themeBorderRadiusSmall; | |||
12 | export const colorBackground = legacyStyles.themeGrayLighter; | 12 | export const colorBackground = legacyStyles.themeGrayLighter; |
13 | export const colorHeadline = legacyStyles.themeGrayDark; | 13 | export const colorHeadline = legacyStyles.themeGrayDark; |
14 | 14 | ||
15 | export const colorText = legacyStyles.themeTextColor; | ||
16 | |||
15 | // Subscription Container Component | 17 | // Subscription Container Component |
16 | export const colorSubscriptionContainerBackground = 'none'; | 18 | export const colorSubscriptionContainerBackground = 'none'; |
17 | export const colorSubscriptionContainerBorder = [1, 'solid', brandPrimary]; | 19 | export const colorSubscriptionContainerBorder = [1, 'solid', brandPrimary]; |