diff options
Diffstat (limited to 'src/components/settings')
6 files changed, 515 insertions, 93 deletions
diff --git a/src/components/settings/account/AccountDashboard.js b/src/components/settings/account/AccountDashboard.js index b4ff072ab..83dc34a52 100644 --- a/src/components/settings/account/AccountDashboard.js +++ b/src/components/settings/account/AccountDashboard.js | |||
@@ -69,7 +69,7 @@ const messages = defineMessages({ | |||
69 | }, | 69 | }, |
70 | deleteInfo: { | 70 | deleteInfo: { |
71 | id: 'settings.account.deleteInfo', | 71 | id: 'settings.account.deleteInfo', |
72 | defaultMessage: '!!!If you don\'t need your Franz account any longer, you can delete your account and all related data here.', | 72 | defaultMessage: '!!!If you don\'t need your Ferdi account any longer, you can delete your account and all related data here.', |
73 | }, | 73 | }, |
74 | deleteEmailSent: { | 74 | deleteEmailSent: { |
75 | id: 'settings.account.deleteEmailSent', | 75 | id: 'settings.account.deleteEmailSent', |
diff --git a/src/components/settings/navigation/SettingsNavigation.js b/src/components/settings/navigation/SettingsNavigation.js index 4696b82eb..192cfde7a 100644 --- a/src/components/settings/navigation/SettingsNavigation.js +++ b/src/components/settings/navigation/SettingsNavigation.js | |||
@@ -3,10 +3,13 @@ import PropTypes from 'prop-types'; | |||
3 | import { defineMessages, intlShape } from 'react-intl'; | 3 | import { defineMessages, intlShape } from 'react-intl'; |
4 | import { inject, observer } from 'mobx-react'; | 4 | import { inject, observer } from 'mobx-react'; |
5 | import { ProBadge } from '@meetfranz/ui'; | 5 | import { ProBadge } from '@meetfranz/ui'; |
6 | import { RouterStore } from 'mobx-react-router'; | ||
6 | 7 | ||
8 | import { LOCAL_SERVER, LIVE_API } from '../../../config'; | ||
7 | import Link from '../../ui/Link'; | 9 | import Link from '../../ui/Link'; |
8 | import { workspaceStore } from '../../../features/workspaces'; | 10 | import { workspaceStore } from '../../../features/workspaces'; |
9 | import UIStore from '../../../stores/UIStore'; | 11 | import UIStore from '../../../stores/UIStore'; |
12 | import SettingsStore from '../../../stores/SettingsStore'; | ||
10 | import UserStore from '../../../stores/UserStore'; | 13 | import UserStore from '../../../stores/UserStore'; |
11 | import { serviceLimitStore } from '../../../features/serviceLimit'; | 14 | import { serviceLimitStore } from '../../../features/serviceLimit'; |
12 | 15 | ||
@@ -35,9 +38,9 @@ const messages = defineMessages({ | |||
35 | id: 'settings.navigation.settings', | 38 | id: 'settings.navigation.settings', |
36 | defaultMessage: '!!!Settings', | 39 | defaultMessage: '!!!Settings', |
37 | }, | 40 | }, |
38 | inviteFriends: { | 41 | supportFerdi: { |
39 | id: 'settings.navigation.inviteFriends', | 42 | id: 'settings.navigation.supportFerdi', |
40 | defaultMessage: '!!!Invite Friends', | 43 | defaultMessage: '!!!Support Ferdi', |
41 | }, | 44 | }, |
42 | logout: { | 45 | logout: { |
43 | id: 'settings.navigation.logout', | 46 | id: 'settings.navigation.logout', |
@@ -45,11 +48,18 @@ const messages = defineMessages({ | |||
45 | }, | 48 | }, |
46 | }); | 49 | }); |
47 | 50 | ||
48 | export default @inject('stores') @observer class SettingsNavigation extends Component { | 51 | export default @inject('stores', 'actions') @observer class SettingsNavigation extends Component { |
49 | static propTypes = { | 52 | static propTypes = { |
50 | stores: PropTypes.shape({ | 53 | stores: PropTypes.shape({ |
51 | ui: PropTypes.instanceOf(UIStore).isRequired, | 54 | ui: PropTypes.instanceOf(UIStore).isRequired, |
52 | user: PropTypes.instanceOf(UserStore).isRequired, | 55 | user: PropTypes.instanceOf(UserStore).isRequired, |
56 | settings: PropTypes.instanceOf(SettingsStore).isRequired, | ||
57 | router: PropTypes.instanceOf(RouterStore).isRequired, | ||
58 | }).isRequired, | ||
59 | actions: PropTypes.shape({ | ||
60 | settings: PropTypes.shape({ | ||
61 | update: PropTypes.func.isRequired, | ||
62 | }).isRequired, | ||
53 | }).isRequired, | 63 | }).isRequired, |
54 | serviceCount: PropTypes.number.isRequired, | 64 | serviceCount: PropTypes.number.isRequired, |
55 | workspaceCount: PropTypes.number.isRequired, | 65 | workspaceCount: PropTypes.number.isRequired, |
@@ -59,11 +69,42 @@ export default @inject('stores') @observer class SettingsNavigation extends Comp | |||
59 | intl: intlShape, | 69 | intl: intlShape, |
60 | }; | 70 | }; |
61 | 71 | ||
72 | handleLoginLogout() { | ||
73 | const isLoggedIn = Boolean(localStorage.getItem('authToken')); | ||
74 | const isUsingWithoutAccount = this.props.stores.settings.app.server === LOCAL_SERVER; | ||
75 | |||
76 | if (isLoggedIn) { | ||
77 | // Remove current auth token | ||
78 | localStorage.removeItem('authToken'); | ||
79 | |||
80 | if (isUsingWithoutAccount) { | ||
81 | // Reset server back to Ferdi API | ||
82 | this.props.actions.settings.update({ | ||
83 | type: 'app', | ||
84 | data: { | ||
85 | server: LIVE_API, | ||
86 | }, | ||
87 | }); | ||
88 | } | ||
89 | this.props.stores.user.isLoggingOut = true; | ||
90 | } | ||
91 | |||
92 | this.props.stores.router.push(isLoggedIn ? '/auth/logout' : '/auth/welcome'); | ||
93 | |||
94 | if (isLoggedIn) { | ||
95 | // Reload Ferdi, otherwise many settings won't sync correctly with the server | ||
96 | // after logging into another account | ||
97 | window.location.reload(); | ||
98 | } | ||
99 | } | ||
100 | |||
62 | render() { | 101 | render() { |
63 | const { serviceCount, workspaceCount, stores } = this.props; | 102 | const { serviceCount, workspaceCount, stores } = this.props; |
64 | const { isDarkThemeActive } = stores.ui; | 103 | const { isDarkThemeActive } = stores.ui; |
65 | const { router, user } = stores; | 104 | const { router, user } = stores; |
66 | const { intl } = this.context; | 105 | const { intl } = this.context; |
106 | const isLoggedIn = Boolean(localStorage.getItem('authToken')); | ||
107 | const isUsingWithoutAccount = stores.settings.app.server === LOCAL_SERVER; | ||
67 | 108 | ||
68 | return ( | 109 | return ( |
69 | <div className="settings-navigation"> | 110 | <div className="settings-navigation"> |
@@ -128,19 +169,21 @@ export default @inject('stores') @observer class SettingsNavigation extends Comp | |||
128 | {intl.formatMessage(messages.settings)} | 169 | {intl.formatMessage(messages.settings)} |
129 | </Link> | 170 | </Link> |
130 | <Link | 171 | <Link |
131 | to="/settings/invite" | 172 | to="/settings/support" |
132 | className="settings-navigation__link" | 173 | className="settings-navigation__link" |
133 | activeClassName="is-active" | 174 | activeClassName="is-active" |
134 | > | 175 | > |
135 | {intl.formatMessage(messages.inviteFriends)} | 176 | {intl.formatMessage(messages.supportFerdi)} |
136 | </Link> | 177 | </Link> |
137 | <span className="settings-navigation__expander" /> | 178 | <span className="settings-navigation__expander" /> |
138 | <Link | 179 | <button |
139 | to="/auth/logout" | 180 | type="button" |
181 | to={isLoggedIn ? '/auth/logout' : '/auth/welcome'} | ||
140 | className="settings-navigation__link" | 182 | className="settings-navigation__link" |
183 | onClick={this.handleLoginLogout.bind(this)} | ||
141 | > | 184 | > |
142 | {intl.formatMessage(messages.logout)} | 185 | { isLoggedIn && !isUsingWithoutAccount ? intl.formatMessage(messages.logout) : 'Login'} |
143 | </Link> | 186 | </button> |
144 | </div> | 187 | </div> |
145 | ); | 188 | ); |
146 | } | 189 | } |
diff --git a/src/components/settings/services/EditServiceForm.js b/src/components/settings/services/EditServiceForm.js index 5cde0db8e..fa34ac60b 100644 --- a/src/components/settings/services/EditServiceForm.js +++ b/src/components/settings/services/EditServiceForm.js | |||
@@ -29,6 +29,10 @@ const messages = defineMessages({ | |||
29 | id: 'settings.service.form.deleteButton', | 29 | id: 'settings.service.form.deleteButton', |
30 | defaultMessage: '!!!Delete Service', | 30 | defaultMessage: '!!!Delete Service', |
31 | }, | 31 | }, |
32 | openDarkmodeCss: { | ||
33 | id: 'settings.service.form.openDarkmodeCss', | ||
34 | defaultMessage: '!!!Open darkmode.css', | ||
35 | }, | ||
32 | availableServices: { | 36 | availableServices: { |
33 | id: 'settings.service.form.availableServices', | 37 | id: 'settings.service.form.availableServices', |
34 | defaultMessage: '!!!Available services', | 38 | defaultMessage: '!!!Available services', |
@@ -63,7 +67,7 @@ const messages = defineMessages({ | |||
63 | }, | 67 | }, |
64 | customUrlPremiumInfo: { | 68 | customUrlPremiumInfo: { |
65 | id: 'settings.service.form.customUrlPremiumInfo', | 69 | id: 'settings.service.form.customUrlPremiumInfo', |
66 | defaultMessage: '!!!To add self hosted services, you need a Franz Premium Supporter Account.', | 70 | defaultMessage: '!!!To add self hosted services, you need a Ferdi Premium Supporter Account.', |
67 | }, | 71 | }, |
68 | customUrlUpgradeAccount: { | 72 | customUrlUpgradeAccount: { |
69 | id: 'settings.service.form.customUrlUpgradeAccount', | 73 | id: 'settings.service.form.customUrlUpgradeAccount', |
@@ -103,11 +107,11 @@ const messages = defineMessages({ | |||
103 | }, | 107 | }, |
104 | proxyRestartInfo: { | 108 | proxyRestartInfo: { |
105 | id: 'settings.service.form.proxy.restartInfo', | 109 | id: 'settings.service.form.proxy.restartInfo', |
106 | defaultMessage: '!!!Please restart Franz after changing proxy Settings.', | 110 | defaultMessage: '!!!Please restart Ferdi after changing proxy Settings.', |
107 | }, | 111 | }, |
108 | proxyInfo: { | 112 | proxyInfo: { |
109 | id: 'settings.service.form.proxy.info', | 113 | id: 'settings.service.form.proxy.info', |
110 | defaultMessage: '!!!Proxy settings will not be synchronized with the Franz servers.', | 114 | defaultMessage: '!!!Proxy settings will not be synchronized with the Ferdi servers.', |
111 | }, | 115 | }, |
112 | }); | 116 | }); |
113 | 117 | ||
@@ -127,6 +131,8 @@ export default @observer class EditServiceForm extends Component { | |||
127 | form: PropTypes.instanceOf(Form).isRequired, | 131 | form: PropTypes.instanceOf(Form).isRequired, |
128 | onSubmit: PropTypes.func.isRequired, | 132 | onSubmit: PropTypes.func.isRequired, |
129 | onDelete: PropTypes.func.isRequired, | 133 | onDelete: PropTypes.func.isRequired, |
134 | openDarkmodeCss: PropTypes.func.isRequired, | ||
135 | isOpeningDarkModeCss: PropTypes.bool.isRequired, | ||
130 | isSaving: PropTypes.bool.isRequired, | 136 | isSaving: PropTypes.bool.isRequired, |
131 | isDeleting: PropTypes.bool.isRequired, | 137 | isDeleting: PropTypes.bool.isRequired, |
132 | isProxyFeatureEnabled: PropTypes.bool.isRequired, | 138 | isProxyFeatureEnabled: PropTypes.bool.isRequired, |
@@ -155,7 +161,7 @@ export default @observer class EditServiceForm extends Component { | |||
155 | const values = form.values(); | 161 | const values = form.values(); |
156 | let isValid = true; | 162 | let isValid = true; |
157 | 163 | ||
158 | const files = form.$('customIcon').files; | 164 | const { files } = form.$('customIcon'); |
159 | if (files) { | 165 | if (files) { |
160 | values.iconFile = files[0]; | 166 | values.iconFile = files[0]; |
161 | } | 167 | } |
@@ -193,6 +199,8 @@ export default @observer class EditServiceForm extends Component { | |||
193 | isSaving, | 199 | isSaving, |
194 | isDeleting, | 200 | isDeleting, |
195 | onDelete, | 201 | onDelete, |
202 | openDarkmodeCss, | ||
203 | isOpeningDarkModeCss, | ||
196 | isProxyFeatureEnabled, | 204 | isProxyFeatureEnabled, |
197 | isServiceProxyIncludedInCurrentPlan, | 205 | isServiceProxyIncludedInCurrentPlan, |
198 | isSpellcheckerIncludedInCurrentPlan, | 206 | isSpellcheckerIncludedInCurrentPlan, |
@@ -218,6 +226,23 @@ export default @observer class EditServiceForm extends Component { | |||
218 | /> | 226 | /> |
219 | ); | 227 | ); |
220 | 228 | ||
229 | const openDarkmodeCssButton = isOpeningDarkModeCss ? ( | ||
230 | <Button | ||
231 | label={intl.formatMessage(messages.openDarkmodeCss)} | ||
232 | loaded={false} | ||
233 | buttonType="secondary" | ||
234 | className="settings__open-dark-mode-button" | ||
235 | disabled | ||
236 | /> | ||
237 | ) : ( | ||
238 | <Button | ||
239 | buttonType="secondary" | ||
240 | label={intl.formatMessage(messages.openDarkmodeCss)} | ||
241 | className="settings__open-dark-mode-button" | ||
242 | onClick={openDarkmodeCss} | ||
243 | /> | ||
244 | ); | ||
245 | |||
221 | let activeTabIndex = 0; | 246 | let activeTabIndex = 0; |
222 | if (recipe.hasHostedOption && service.team) { | 247 | if (recipe.hasHostedOption && service.team) { |
223 | activeTabIndex = 1; | 248 | activeTabIndex = 1; |
@@ -303,6 +328,18 @@ export default @observer class EditServiceForm extends Component { | |||
303 | )} | 328 | )} |
304 | </Tabs> | 329 | </Tabs> |
305 | )} | 330 | )} |
331 | |||
332 | {recipe.message && ( | ||
333 | <p | ||
334 | className="settings__message" | ||
335 | style={{ | ||
336 | marginTop: 0, | ||
337 | }} | ||
338 | > | ||
339 | <span className="mdi mdi-information" /> | ||
340 | {recipe.message} | ||
341 | </p> | ||
342 | )} | ||
306 | <div className="service-flex-grid"> | 343 | <div className="service-flex-grid"> |
307 | <div className="settings__options"> | 344 | <div className="settings__options"> |
308 | <div className="settings__settings-group"> | 345 | <div className="settings__settings-group"> |
@@ -329,9 +366,7 @@ export default @observer class EditServiceForm extends Component { | |||
329 | 366 | ||
330 | <div className="settings__settings-group"> | 367 | <div className="settings__settings-group"> |
331 | <h3>{intl.formatMessage(messages.headlineGeneral)}</h3> | 368 | <h3>{intl.formatMessage(messages.headlineGeneral)}</h3> |
332 | {recipe.hasDarkMode && ( | 369 | <Toggle field={form.$('isDarkModeEnabled')} /> |
333 | <Toggle field={form.$('isDarkModeEnabled')} /> | ||
334 | )} | ||
335 | <Toggle field={form.$('isEnabled')} /> | 370 | <Toggle field={form.$('isEnabled')} /> |
336 | </div> | 371 | </div> |
337 | </div> | 372 | </div> |
@@ -394,18 +429,12 @@ export default @observer class EditServiceForm extends Component { | |||
394 | </div> | 429 | </div> |
395 | </PremiumFeatureContainer> | 430 | </PremiumFeatureContainer> |
396 | )} | 431 | )} |
397 | |||
398 | {recipe.message && ( | ||
399 | <p className="settings__message"> | ||
400 | <span className="mdi mdi-information" /> | ||
401 | {recipe.message} | ||
402 | </p> | ||
403 | )} | ||
404 | </form> | 432 | </form> |
405 | </div> | 433 | </div> |
406 | <div className="settings__controls"> | 434 | <div className="settings__controls"> |
407 | {/* Delete Button */} | 435 | {/* Delete Button */} |
408 | {action === 'edit' && deleteButton} | 436 | {action === 'edit' && deleteButton} |
437 | {action === 'edit' && openDarkmodeCssButton} | ||
409 | 438 | ||
410 | {/* Save Button */} | 439 | {/* Save Button */} |
411 | {isSaving || isValidatingCustomUrl ? ( | 440 | {isSaving || isValidatingCustomUrl ? ( |
diff --git a/src/components/settings/settings/EditSettingsForm.js b/src/components/settings/settings/EditSettingsForm.js index 0b69f7514..2be5c4ed7 100644 --- a/src/components/settings/settings/EditSettingsForm.js +++ b/src/components/settings/settings/EditSettingsForm.js | |||
@@ -9,9 +9,19 @@ import Button from '../../ui/Button'; | |||
9 | import Toggle from '../../ui/Toggle'; | 9 | import Toggle from '../../ui/Toggle'; |
10 | import Select from '../../ui/Select'; | 10 | import Select from '../../ui/Select'; |
11 | import PremiumFeatureContainer from '../../ui/PremiumFeatureContainer'; | 11 | import PremiumFeatureContainer from '../../ui/PremiumFeatureContainer'; |
12 | import Input from '../../ui/Input'; | ||
12 | 13 | ||
13 | import { FRANZ_TRANSLATION } from '../../../config'; | 14 | import { FRANZ_TRANSLATION } from '../../../config'; |
14 | 15 | ||
16 | function escapeHtml(unsafe) { | ||
17 | return unsafe | ||
18 | .replace(/&/g, '&') | ||
19 | .replace(/</g, '<') | ||
20 | .replace(/>/g, '>') | ||
21 | .replace(/"/g, '"') | ||
22 | .replace(/'/g, '''); | ||
23 | } | ||
24 | |||
15 | const messages = defineMessages({ | 25 | const messages = defineMessages({ |
16 | headline: { | 26 | headline: { |
17 | id: 'settings.app.headline', | 27 | id: 'settings.app.headline', |
@@ -21,6 +31,42 @@ const messages = defineMessages({ | |||
21 | id: 'settings.app.headlineGeneral', | 31 | id: 'settings.app.headlineGeneral', |
22 | defaultMessage: '!!!General', | 32 | defaultMessage: '!!!General', |
23 | }, | 33 | }, |
34 | hibernateInfo: { | ||
35 | id: 'settings.app.hibernateInfo', | ||
36 | defaultMessage: '!!!By default, Ferdi will keep all your services open and loaded in the background so they are ready when you want to use them. Service Hibernation will unload your services after a specified amount. This is useful to save RAM or keeping services from slowing down your computer.', | ||
37 | }, | ||
38 | serverInfo: { | ||
39 | id: 'settings.app.serverInfo', | ||
40 | defaultMessage: '!!!We advice you to logout after changing your server as your settings might not be saved otherwise.', | ||
41 | }, | ||
42 | serverMoneyInfo: { | ||
43 | id: 'settings.app.serverMoneyInfo', | ||
44 | defaultMessage: '!!!You are using the official Franz Server for Ferdi.\nWe know that Ferdi allows you to use all its features for free but you are still using Franz\'s server resources - which Franz\'s creator has to pay for.\nPlease still consider [Link 1]paying for a Franz account[/Link] or [Link 2]using a self-hosted ferdi-server[/Link] (if you have the knowledge and resources to do so). \nBy using Ferdi, you still profit greatly from Franz\'s recipe store, server resources and its development.', | ||
45 | }, | ||
46 | todoServerInfo: { | ||
47 | id: 'settings.app.todoServerInfo', | ||
48 | defaultMessage: '!!!This server will be used for the "Franz Todo" feature. (default: https://app.franztodos.com)', | ||
49 | }, | ||
50 | lockedPassword: { | ||
51 | id: 'settings.app.lockedPassword', | ||
52 | defaultMessage: '!!!Ferdi Lock Password', | ||
53 | }, | ||
54 | lockedPasswordInfo: { | ||
55 | id: 'settings.app.lockedPasswordInfo', | ||
56 | defaultMessage: '!!!Please make sure to set a password you\'ll remember.\nIf you loose this password, you will have to reinstall Ferdi.', | ||
57 | }, | ||
58 | lockInfo: { | ||
59 | id: 'settings.app.lockInfo', | ||
60 | defaultMessage: '!!!Ferdi password lock allows you to keep your messages protected.\nUsing Ferdi password lock, you will be prompted to enter your password everytime you start Ferdi or lock Ferdi yourself using the lock symbol in the bottom left corner or the shortcut CMD/CTRL+Shift+L.', | ||
61 | }, | ||
62 | scheduledDNDTimeInfo: { | ||
63 | id: 'settings.app.scheduledDNDTimeInfo', | ||
64 | defaultMessage: '!!!Times in 24-Hour-Format. End time can be before start time (e.g. start 17:00, end 09:00) to enable Do-not-Disturb overnight.', | ||
65 | }, | ||
66 | scheduledDNDInfo: { | ||
67 | id: 'settings.app.scheduledDNDInfo', | ||
68 | defaultMessage: '!!!Scheduled Do-not-Disturb allows you to define a period of time in which you do not want to get Notifications from Ferdi.', | ||
69 | }, | ||
24 | headlineLanguage: { | 70 | headlineLanguage: { |
25 | id: 'settings.app.headlineLanguage', | 71 | id: 'settings.app.headlineLanguage', |
26 | defaultMessage: '!!!Language', | 72 | defaultMessage: '!!!Language', |
@@ -33,13 +79,21 @@ const messages = defineMessages({ | |||
33 | id: 'settings.app.headlineAppearance', | 79 | id: 'settings.app.headlineAppearance', |
34 | defaultMessage: '!!!Appearance', | 80 | defaultMessage: '!!!Appearance', |
35 | }, | 81 | }, |
82 | universalDarkModeInfo: { | ||
83 | id: 'settings.app.universalDarkModeInfo', | ||
84 | defaultMessage: '!!!Universal Dark Mode tries to dynamically generate dark mode styles for services that are otherwise not currently supported.', | ||
85 | }, | ||
86 | accentColorInfo: { | ||
87 | id: 'settings.app.accentColorInfo', | ||
88 | defaultMessage: '!!!Write your accent color in a CSS-compatible format. (Default: #7367f0)', | ||
89 | }, | ||
36 | headlineAdvanced: { | 90 | headlineAdvanced: { |
37 | id: 'settings.app.headlineAdvanced', | 91 | id: 'settings.app.headlineAdvanced', |
38 | defaultMessage: '!!!Advanced', | 92 | defaultMessage: '!!!Advanced', |
39 | }, | 93 | }, |
40 | translationHelp: { | 94 | translationHelp: { |
41 | id: 'settings.app.translationHelp', | 95 | id: 'settings.app.translationHelp', |
42 | defaultMessage: '!!!Help us to translate Franz into your language.', | 96 | defaultMessage: '!!!Help us to translate Ferdi into your language.', |
43 | }, | 97 | }, |
44 | subheadlineCache: { | 98 | subheadlineCache: { |
45 | id: 'settings.app.subheadlineCache', | 99 | id: 'settings.app.subheadlineCache', |
@@ -47,7 +101,7 @@ const messages = defineMessages({ | |||
47 | }, | 101 | }, |
48 | cacheInfo: { | 102 | cacheInfo: { |
49 | id: 'settings.app.cacheInfo', | 103 | id: 'settings.app.cacheInfo', |
50 | defaultMessage: '!!!Franz cache is currently using {size} of disk space.', | 104 | defaultMessage: '!!!Ferdi cache is currently using {size} of disk space.', |
51 | }, | 105 | }, |
52 | buttonClearAllCache: { | 106 | buttonClearAllCache: { |
53 | id: 'settings.app.buttonClearAllCache', | 107 | id: 'settings.app.buttonClearAllCache', |
@@ -71,7 +125,7 @@ const messages = defineMessages({ | |||
71 | }, | 125 | }, |
72 | updateStatusUpToDate: { | 126 | updateStatusUpToDate: { |
73 | id: 'settings.app.updateStatusUpToDate', | 127 | id: 'settings.app.updateStatusUpToDate', |
74 | defaultMessage: '!!!You are using the latest version of Franz', | 128 | defaultMessage: '!!!You are using the latest version of Ferdi', |
75 | }, | 129 | }, |
76 | currentVersion: { | 130 | currentVersion: { |
77 | id: 'settings.app.currentVersion', | 131 | id: 'settings.app.currentVersion', |
@@ -103,6 +157,11 @@ export default @observer class EditSettingsForm extends Component { | |||
103 | isSpellcheckerIncludedInCurrentPlan: PropTypes.bool.isRequired, | 157 | isSpellcheckerIncludedInCurrentPlan: PropTypes.bool.isRequired, |
104 | isTodosEnabled: PropTypes.bool.isRequired, | 158 | isTodosEnabled: PropTypes.bool.isRequired, |
105 | isWorkspaceEnabled: PropTypes.bool.isRequired, | 159 | isWorkspaceEnabled: PropTypes.bool.isRequired, |
160 | server: PropTypes.string.isRequired, | ||
161 | noUpdates: PropTypes.bool.isRequired, | ||
162 | hibernationEnabled: PropTypes.bool.isRequired, | ||
163 | isDarkmodeEnabled: PropTypes.bool.isRequired, | ||
164 | openProcessManager: PropTypes.func.isRequired, | ||
106 | }; | 165 | }; |
107 | 166 | ||
108 | static contextTypes = { | 167 | static contextTypes = { |
@@ -135,6 +194,11 @@ export default @observer class EditSettingsForm extends Component { | |||
135 | isSpellcheckerIncludedInCurrentPlan, | 194 | isSpellcheckerIncludedInCurrentPlan, |
136 | isTodosEnabled, | 195 | isTodosEnabled, |
137 | isWorkspaceEnabled, | 196 | isWorkspaceEnabled, |
197 | server, | ||
198 | noUpdates, | ||
199 | hibernationEnabled, | ||
200 | isDarkmodeEnabled, | ||
201 | openProcessManager, | ||
138 | } = this.props; | 202 | } = this.props; |
139 | const { intl } = this.context; | 203 | const { intl } = this.context; |
140 | 204 | ||
@@ -147,6 +211,13 @@ export default @observer class EditSettingsForm extends Component { | |||
147 | updateButtonLabelMessage = messages.buttonSearchForUpdate; | 211 | updateButtonLabelMessage = messages.buttonSearchForUpdate; |
148 | } | 212 | } |
149 | 213 | ||
214 | const isLoggedIn = Boolean(localStorage.getItem('authToken')); | ||
215 | |||
216 | const { | ||
217 | lockingFeatureEnabled, | ||
218 | scheduledDNDEnabled, | ||
219 | } = window.ferdi.stores.settings.all.app; | ||
220 | |||
150 | return ( | 221 | return ( |
151 | <div className="settings__main"> | 222 | <div className="settings__main"> |
152 | <div className="settings__header"> | 223 | <div className="settings__header"> |
@@ -163,21 +234,177 @@ export default @observer class EditSettingsForm extends Component { | |||
163 | <Toggle field={form.$('autoLaunchOnStart')} /> | 234 | <Toggle field={form.$('autoLaunchOnStart')} /> |
164 | <Toggle field={form.$('runInBackground')} /> | 235 | <Toggle field={form.$('runInBackground')} /> |
165 | <Toggle field={form.$('enableSystemTray')} /> | 236 | <Toggle field={form.$('enableSystemTray')} /> |
237 | <Toggle field={form.$('privateNotifications')} /> | ||
238 | <Toggle field={form.$('showServiceNavigationBar')} /> | ||
239 | <Toggle field={form.$('hibernate')} /> | ||
240 | {hibernationEnabled && ( | ||
241 | <Select field={form.$('hibernationStrategy')} /> | ||
242 | )} | ||
243 | <p | ||
244 | className="settings__message" | ||
245 | style={{ | ||
246 | borderTop: 0, marginTop: 0, paddingTop: 0, marginBottom: '2rem', | ||
247 | }} | ||
248 | > | ||
249 | <span> | ||
250 | { intl.formatMessage(messages.hibernateInfo) } | ||
251 | </span> | ||
252 | </p> | ||
166 | {process.platform === 'win32' && ( | 253 | {process.platform === 'win32' && ( |
167 | <Toggle field={form.$('minimizeToSystemTray')} /> | 254 | <Toggle field={form.$('minimizeToSystemTray')} /> |
168 | )} | 255 | )} |
256 | <Input | ||
257 | placeholder="Server" | ||
258 | onChange={e => this.submit(e)} | ||
259 | field={form.$('server')} | ||
260 | autoFocus | ||
261 | /> | ||
262 | {isLoggedIn && ( | ||
263 | <p>{ intl.formatMessage(messages.serverInfo) }</p> | ||
264 | )} | ||
265 | {server === 'https://api.franzinfra.com' && ( | ||
266 | <p | ||
267 | className="settings__message" | ||
268 | style={{ | ||
269 | borderTop: 0, marginTop: 0, paddingTop: 0, marginBottom: '2rem', | ||
270 | }} | ||
271 | > | ||
272 | <span | ||
273 | dangerouslySetInnerHTML={{ | ||
274 | __html: | ||
275 | // Needed to make links work | ||
276 | escapeHtml( | ||
277 | intl.formatMessage(messages.serverMoneyInfo), | ||
278 | ).replace('[Link 1]', '<a href="https://www.meetfranz.com/pricing" target="_blank">') | ||
279 | .replace('[Link 2]', '<a href="https://github.com/getferdi/server" target="_blank">') | ||
280 | .replace(/\[\/Link]/g, '</a>'), | ||
281 | }} | ||
282 | style={{ | ||
283 | whiteSpace: 'pre-wrap', | ||
284 | }} | ||
285 | /> | ||
286 | </p> | ||
287 | )} | ||
169 | {isWorkspaceEnabled && ( | 288 | {isWorkspaceEnabled && ( |
170 | <Toggle field={form.$('keepAllWorkspacesLoaded')} /> | 289 | <Toggle field={form.$('keepAllWorkspacesLoaded')} /> |
171 | )} | 290 | )} |
172 | {isTodosEnabled && ( | 291 | {isTodosEnabled && ( |
173 | <Toggle field={form.$('enableTodos')} /> | 292 | <> |
293 | <Toggle field={form.$('enableTodos')} /> | ||
294 | <Input | ||
295 | placeholder="Todo Server" | ||
296 | onChange={e => this.submit(e)} | ||
297 | field={form.$('todoServer')} | ||
298 | /> | ||
299 | <p>{ intl.formatMessage(messages.todoServerInfo) }</p> | ||
300 | </> | ||
174 | )} | 301 | )} |
175 | 302 | ||
303 | <Toggle field={form.$('lockingFeatureEnabled')} /> | ||
304 | {lockingFeatureEnabled && ( | ||
305 | <> | ||
306 | <Input | ||
307 | placeholder={intl.formatMessage(messages.lockedPassword)} | ||
308 | onChange={e => this.submit(e)} | ||
309 | field={form.$('lockedPassword')} | ||
310 | type="password" | ||
311 | scorePassword | ||
312 | showPasswordToggle | ||
313 | /> | ||
314 | <p> | ||
315 | { intl.formatMessage(messages.lockedPasswordInfo) } | ||
316 | </p> | ||
317 | </> | ||
318 | )} | ||
319 | <p | ||
320 | className="settings__message" | ||
321 | style={{ | ||
322 | borderTop: 0, marginTop: 0, paddingTop: 0, marginBottom: '2rem', | ||
323 | }} | ||
324 | > | ||
325 | <span> | ||
326 | { intl.formatMessage(messages.lockInfo) } | ||
327 | </span> | ||
328 | </p> | ||
329 | |||
330 | |||
331 | <Toggle field={form.$('scheduledDNDEnabled')} /> | ||
332 | {scheduledDNDEnabled && ( | ||
333 | <> | ||
334 | <div style={{ | ||
335 | display: 'flex', | ||
336 | justifyContent: 'center', | ||
337 | }} | ||
338 | > | ||
339 | <div style={{ | ||
340 | padding: '0 1rem', | ||
341 | width: '100%', | ||
342 | }} | ||
343 | > | ||
344 | <Input | ||
345 | placeholder="17:00" | ||
346 | onChange={e => this.submit(e)} | ||
347 | field={form.$('scheduledDNDStart')} | ||
348 | type="time" | ||
349 | /> | ||
350 | </div> | ||
351 | <div style={{ | ||
352 | padding: '0 1rem', | ||
353 | width: '100%', | ||
354 | }} | ||
355 | > | ||
356 | <Input | ||
357 | placeholder="09:00" | ||
358 | onChange={e => this.submit(e)} | ||
359 | field={form.$('scheduledDNDEnd')} | ||
360 | type="time" | ||
361 | /> | ||
362 | </div> | ||
363 | </div> | ||
364 | <p> | ||
365 | { intl.formatMessage(messages.scheduledDNDTimeInfo) } | ||
366 | </p> | ||
367 | </> | ||
368 | )} | ||
369 | <p | ||
370 | className="settings__message" | ||
371 | style={{ | ||
372 | borderTop: 0, marginTop: 0, paddingTop: 0, marginBottom: '2rem', | ||
373 | }} | ||
374 | > | ||
375 | <span> | ||
376 | { intl.formatMessage(messages.scheduledDNDInfo) } | ||
377 | </span> | ||
378 | </p> | ||
379 | |||
380 | |||
176 | {/* Appearance */} | 381 | {/* Appearance */} |
177 | <h2 id="apperance">{intl.formatMessage(messages.headlineAppearance)}</h2> | 382 | <h2 id="apperance">{intl.formatMessage(messages.headlineAppearance)}</h2> |
178 | <Toggle field={form.$('showDisabledServices')} /> | 383 | <Toggle field={form.$('showDisabledServices')} /> |
179 | <Toggle field={form.$('showMessageBadgeWhenMuted')} /> | 384 | <Toggle field={form.$('showMessageBadgeWhenMuted')} /> |
180 | <Toggle field={form.$('darkMode')} /> | 385 | <Toggle field={form.$('darkMode')} /> |
386 | {isDarkmodeEnabled && ( | ||
387 | <> | ||
388 | <Toggle field={form.$('universalDarkMode')} /> | ||
389 | <p | ||
390 | className="settings__message" | ||
391 | style={{ | ||
392 | borderTop: 0, marginTop: 0, paddingTop: 0, marginBottom: '2rem', | ||
393 | }} | ||
394 | > | ||
395 | <span> | ||
396 | { intl.formatMessage(messages.universalDarkModeInfo) } | ||
397 | </span> | ||
398 | </p> | ||
399 | </> | ||
400 | )} | ||
401 | |||
402 | <Input | ||
403 | placeholder="Accent Color" | ||
404 | onChange={e => this.submit(e)} | ||
405 | field={form.$('accentColor')} | ||
406 | /> | ||
407 | <p>{intl.formatMessage(messages.accentColorInfo)}</p> | ||
181 | 408 | ||
182 | {/* Language */} | 409 | {/* Language */} |
183 | <h2 id="language">{intl.formatMessage(messages.headlineLanguage)}</h2> | 410 | <h2 id="language">{intl.formatMessage(messages.headlineLanguage)}</h2> |
@@ -227,6 +454,16 @@ export default @observer class EditSettingsForm extends Component { | |||
227 | loaded={!isClearingAllCache} | 454 | loaded={!isClearingAllCache} |
228 | /> | 455 | /> |
229 | </p> | 456 | </p> |
457 | <div style={{ | ||
458 | marginTop: 20, | ||
459 | }} | ||
460 | > | ||
461 | <Button | ||
462 | buttonType="secondary" | ||
463 | label="Open Process Manager" | ||
464 | onClick={openProcessManager} | ||
465 | /> | ||
466 | </div> | ||
230 | </div> | 467 | </div> |
231 | 468 | ||
232 | {/* Updates */} | 469 | {/* Updates */} |
@@ -241,7 +478,7 @@ export default @observer class EditSettingsForm extends Component { | |||
241 | buttonType="secondary" | 478 | buttonType="secondary" |
242 | label={intl.formatMessage(updateButtonLabelMessage)} | 479 | label={intl.formatMessage(updateButtonLabelMessage)} |
243 | onClick={checkForUpdates} | 480 | onClick={checkForUpdates} |
244 | disabled={isCheckingForUpdates || isUpdateAvailable} | 481 | disabled={noUpdates || isCheckingForUpdates || isUpdateAvailable} |
245 | loaded={!isCheckingForUpdates || !isUpdateAvailable} | 482 | loaded={!isCheckingForUpdates || !isUpdateAvailable} |
246 | /> | 483 | /> |
247 | )} | 484 | )} |
@@ -250,6 +487,7 @@ export default @observer class EditSettingsForm extends Component { | |||
250 | )} | 487 | )} |
251 | <br /> | 488 | <br /> |
252 | <Toggle field={form.$('beta')} /> | 489 | <Toggle field={form.$('beta')} /> |
490 | <Toggle field={form.$('noUpdates')} /> | ||
253 | {intl.formatMessage(messages.currentVersion)} | 491 | {intl.formatMessage(messages.currentVersion)} |
254 | {' '} | 492 | {' '} |
255 | {remote.app.getVersion()} | 493 | {remote.app.getVersion()} |
@@ -257,6 +495,18 @@ export default @observer class EditSettingsForm extends Component { | |||
257 | <span className="mdi mdi-information" /> | 495 | <span className="mdi mdi-information" /> |
258 | {intl.formatMessage(messages.languageDisclaimer)} | 496 | {intl.formatMessage(messages.languageDisclaimer)} |
259 | </p> | 497 | </p> |
498 | <p className="settings__message"> | ||
499 | <span className="mdi mdi-github-face" /> | ||
500 | <span> | ||
501 | Ferdi is based on | ||
502 | {' '} | ||
503 | <a href="https://github.com/meetfranz/franz" target="_blank">Franz</a> | ||
504 | , a project published | ||
505 | under the | ||
506 | {' '} | ||
507 | <a href="https://github.com/meetfranz/franz/blob/master/LICENSE" target="_blank">Apache-2.0 License</a> | ||
508 | </span> | ||
509 | </p> | ||
260 | </form> | 510 | </form> |
261 | </div> | 511 | </div> |
262 | </div> | 512 | </div> |
diff --git a/src/components/settings/supportFerdi/SupportFerdiDashboard.js b/src/components/settings/supportFerdi/SupportFerdiDashboard.js new file mode 100644 index 000000000..57920a4a2 --- /dev/null +++ b/src/components/settings/supportFerdi/SupportFerdiDashboard.js | |||
@@ -0,0 +1,73 @@ | |||
1 | import React, { Component } from 'react'; | ||
2 | import PropTypes from 'prop-types'; | ||
3 | import { defineMessages, intlShape } from 'react-intl'; | ||
4 | |||
5 | import Button from '../../ui/Button'; | ||
6 | |||
7 | const messages = defineMessages({ | ||
8 | headline: { | ||
9 | id: 'settings.supportFerdi.headline', | ||
10 | defaultMessage: '!!!Support Ferdi', | ||
11 | }, | ||
12 | title: { | ||
13 | id: 'settings.supportFerdi.title', | ||
14 | defaultMessage: '!!!Do you like Ferdi? Spread the love!', | ||
15 | }, | ||
16 | github: { | ||
17 | id: 'settings.supportFerdi.github', | ||
18 | defaultMessage: '!!!Star on GitHub', | ||
19 | }, | ||
20 | share: { | ||
21 | id: 'settings.supportFerdi.share', | ||
22 | defaultMessage: '!!!Tell your Friends', | ||
23 | }, | ||
24 | openCollective: { | ||
25 | id: 'settings.supportFerdi.openCollective', | ||
26 | defaultMessage: '!!!Support our Open Collective', | ||
27 | }, | ||
28 | }); | ||
29 | |||
30 | class SupportFerdiDashboard extends Component { | ||
31 | static contextTypes = { | ||
32 | intl: intlShape, | ||
33 | }; | ||
34 | |||
35 | static propTypes = { | ||
36 | openLink: PropTypes.func.isRequired, | ||
37 | }; | ||
38 | |||
39 | render() { | ||
40 | const { openLink } = this.props; | ||
41 | const { intl } = this.context; | ||
42 | |||
43 | return ( | ||
44 | <div className="settings__main"> | ||
45 | <div className="settings__header"> | ||
46 | <span className="settings__header-item"> | ||
47 | {intl.formatMessage(messages.headline)} | ||
48 | </span> | ||
49 | </div> | ||
50 | <div className="settings__body"> | ||
51 | <h1>{intl.formatMessage(messages.title)}</h1> | ||
52 | <Button | ||
53 | label={intl.formatMessage(messages.github)} | ||
54 | className="franz-form__button--inverted franz-form__button--large" | ||
55 | onClick={() => openLink('https://github.com/getferdi/ferdi')} | ||
56 | /> | ||
57 | <Button | ||
58 | label={intl.formatMessage(messages.share)} | ||
59 | className="franz-form__button--inverted franz-form__button--large" | ||
60 | onClick={() => openLink('https://twitter.com/intent/tweet?text=Ferdi%3A%20A%20messaging%20browser%20that%20allows%20you%20to%20combine%20your%20favourite%20messaging%20services%20into%20one%20application.%0A%0ACheck%20out%20Ferdi%20at%20https%3A//getferdi.com')} | ||
61 | /> | ||
62 | <Button | ||
63 | label={intl.formatMessage(messages.openCollective)} | ||
64 | className="franz-form__button--inverted franz-form__button--large" | ||
65 | onClick={() => openLink('https://opencollective.com/getferdi')} | ||
66 | /> | ||
67 | </div> | ||
68 | </div> | ||
69 | ); | ||
70 | } | ||
71 | } | ||
72 | |||
73 | export default SupportFerdiDashboard; | ||
diff --git a/src/components/settings/team/TeamDashboard.js b/src/components/settings/team/TeamDashboard.js index 366b0113a..7e6d93997 100644 --- a/src/components/settings/team/TeamDashboard.js +++ b/src/components/settings/team/TeamDashboard.js | |||
@@ -20,7 +20,7 @@ const messages = defineMessages({ | |||
20 | }, | 20 | }, |
21 | contentHeadline: { | 21 | contentHeadline: { |
22 | id: 'settings.team.contentHeadline', | 22 | id: 'settings.team.contentHeadline', |
23 | defaultMessage: '!!!Franz for Teams', | 23 | defaultMessage: '!!!Ferdi for Teams', |
24 | }, | 24 | }, |
25 | intro: { | 25 | intro: { |
26 | id: 'settings.team.intro', | 26 | id: 'settings.team.intro', |
@@ -28,7 +28,7 @@ const messages = defineMessages({ | |||
28 | }, | 28 | }, |
29 | copy: { | 29 | copy: { |
30 | id: 'settings.team.copy', | 30 | id: 'settings.team.copy', |
31 | defaultMessage: '!!!Franz for Teams gives you the option to invite co-workers to your team by sending them email invitations and manage their subscriptions in your account’s preferences. Don’t waste time setting up subscriptions for every team member individually, forget about multiple invoices and different billing cycles - one team to rule them all!', | 31 | defaultMessage: '!!!Ferdi for Teams gives you the option to invite co-workers to your team by sending them email invitations and manage their subscriptions in your account’s preferences. Don’t waste time setting up subscriptions for every team member individually, forget about multiple invoices and different billing cycles - one team to rule them all!', |
32 | }, | 32 | }, |
33 | manageButton: { | 33 | manageButton: { |
34 | id: 'settings.team.manageAction', | 34 | id: 'settings.team.manageAction', |
@@ -38,6 +38,14 @@ const messages = defineMessages({ | |||
38 | id: 'settings.team.upgradeAction', | 38 | id: 'settings.team.upgradeAction', |
39 | defaultMessage: '!!!Upgrade your Account', | 39 | defaultMessage: '!!!Upgrade your Account', |
40 | }, | 40 | }, |
41 | teamsUnavailable: { | ||
42 | id: 'settings.team.teamsUnavailable', | ||
43 | defaultMessage: '!!!Teams are unavailable', | ||
44 | }, | ||
45 | teamsUnavailableInfo: { | ||
46 | id: 'settings.team.teamsUnavailableInfo', | ||
47 | defaultMessage: '!!!Teams are currently only available when using the Franz Server and after paying for Franz Professional. Please change your server to https://api.franzinfra.com to use teams.', | ||
48 | }, | ||
41 | }); | 49 | }); |
42 | 50 | ||
43 | const styles = { | 51 | const styles = { |
@@ -98,6 +106,7 @@ export default @injectSheet(styles) @observer class TeamDashboard extends Compon | |||
98 | openTeamManagement: PropTypes.func.isRequired, | 106 | openTeamManagement: PropTypes.func.isRequired, |
99 | classes: PropTypes.object.isRequired, | 107 | classes: PropTypes.object.isRequired, |
100 | isProUser: PropTypes.bool.isRequired, | 108 | isProUser: PropTypes.bool.isRequired, |
109 | server: PropTypes.string.isRequired, | ||
101 | }; | 110 | }; |
102 | 111 | ||
103 | static contextTypes = { | 112 | static contextTypes = { |
@@ -112,9 +121,84 @@ export default @injectSheet(styles) @observer class TeamDashboard extends Compon | |||
112 | openTeamManagement, | 121 | openTeamManagement, |
113 | isProUser, | 122 | isProUser, |
114 | classes, | 123 | classes, |
124 | server, | ||
115 | } = this.props; | 125 | } = this.props; |
116 | const { intl } = this.context; | 126 | const { intl } = this.context; |
117 | 127 | ||
128 | if (server === 'https://api.franzinfra.com') { | ||
129 | return ( | ||
130 | <div className="settings__main"> | ||
131 | <div className="settings__header"> | ||
132 | <span className="settings__header-item"> | ||
133 | {intl.formatMessage(messages.headline)} | ||
134 | </span> | ||
135 | </div> | ||
136 | <div className="settings__body"> | ||
137 | {isLoading && ( | ||
138 | <Loader /> | ||
139 | )} | ||
140 | |||
141 | {!isLoading && userInfoRequestFailed && ( | ||
142 | <Infobox | ||
143 | icon="alert" | ||
144 | type="danger" | ||
145 | ctaLabel={intl.formatMessage(messages.tryReloadUserInfoRequest)} | ||
146 | ctaLoading={isLoading} | ||
147 | ctaOnClick={retryUserInfoRequest} | ||
148 | > | ||
149 | {intl.formatMessage(messages.userInfoRequestFailed)} | ||
150 | </Infobox> | ||
151 | )} | ||
152 | |||
153 | {!userInfoRequestFailed && ( | ||
154 | <> | ||
155 | {!isLoading && ( | ||
156 | <> | ||
157 | <> | ||
158 | <h1 className={classnames({ | ||
159 | [classes.headline]: true, | ||
160 | [classes.headlineWithSpacing]: isProUser, | ||
161 | })} | ||
162 | > | ||
163 | {intl.formatMessage(messages.contentHeadline)} | ||
164 | |||
165 | </h1> | ||
166 | {!isProUser && ( | ||
167 | <Badge className={classes.proRequired}>{intl.formatMessage(globalMessages.proRequired)}</Badge> | ||
168 | )} | ||
169 | <div className={classes.container}> | ||
170 | <div className={classes.content}> | ||
171 | <p>{intl.formatMessage(messages.intro)}</p> | ||
172 | <p>{intl.formatMessage(messages.copy)}</p> | ||
173 | </div> | ||
174 | <img className={classes.image} src="https://cdn.franzinfra.com/announcements/assets/teams.png" alt="Franz for Teams" /> | ||
175 | </div> | ||
176 | <div className={classes.buttonContainer}> | ||
177 | {!isProUser ? ( | ||
178 | <UpgradeButton | ||
179 | className={classes.cta} | ||
180 | gaEventInfo={{ category: 'Todos', event: 'upgrade' }} | ||
181 | requiresPro | ||
182 | short | ||
183 | /> | ||
184 | ) : ( | ||
185 | <Button | ||
186 | label={intl.formatMessage(messages.manageButton)} | ||
187 | onClick={openTeamManagement} | ||
188 | className={classes.cta} | ||
189 | /> | ||
190 | )} | ||
191 | </div> | ||
192 | </> | ||
193 | </> | ||
194 | )} | ||
195 | </> | ||
196 | )} | ||
197 | </div> | ||
198 | <ReactTooltip place="right" type="dark" effect="solid" /> | ||
199 | </div> | ||
200 | ); | ||
201 | } | ||
118 | return ( | 202 | return ( |
119 | <div className="settings__main"> | 203 | <div className="settings__main"> |
120 | <div className="settings__header"> | 204 | <div className="settings__header"> |
@@ -123,68 +207,11 @@ export default @injectSheet(styles) @observer class TeamDashboard extends Compon | |||
123 | </span> | 207 | </span> |
124 | </div> | 208 | </div> |
125 | <div className="settings__body"> | 209 | <div className="settings__body"> |
126 | {isLoading && ( | 210 | <h1 className={classes.headline}> |
127 | <Loader /> | 211 | {intl.formatMessage(messages.teamsUnavailable)} |
128 | )} | 212 | </h1> |
129 | 213 | {intl.formatMessage(messages.teamsUnavailableInfo)} | |
130 | {!isLoading && userInfoRequestFailed && ( | ||
131 | <Infobox | ||
132 | icon="alert" | ||
133 | type="danger" | ||
134 | ctaLabel={intl.formatMessage(messages.tryReloadUserInfoRequest)} | ||
135 | ctaLoading={isLoading} | ||
136 | ctaOnClick={retryUserInfoRequest} | ||
137 | > | ||
138 | {intl.formatMessage(messages.userInfoRequestFailed)} | ||
139 | </Infobox> | ||
140 | )} | ||
141 | |||
142 | {!userInfoRequestFailed && ( | ||
143 | <> | ||
144 | {!isLoading && ( | ||
145 | <> | ||
146 | <> | ||
147 | <h1 className={classnames({ | ||
148 | [classes.headline]: true, | ||
149 | [classes.headlineWithSpacing]: isProUser, | ||
150 | })} | ||
151 | > | ||
152 | {intl.formatMessage(messages.contentHeadline)} | ||
153 | |||
154 | </h1> | ||
155 | {!isProUser && ( | ||
156 | <Badge className={classes.proRequired}>{intl.formatMessage(globalMessages.proRequired)}</Badge> | ||
157 | )} | ||
158 | <div className={classes.container}> | ||
159 | <div className={classes.content}> | ||
160 | <p>{intl.formatMessage(messages.intro)}</p> | ||
161 | <p>{intl.formatMessage(messages.copy)}</p> | ||
162 | </div> | ||
163 | <img className={classes.image} src="https://cdn.franzinfra.com/announcements/assets/teams.png" alt="Franz for Teams" /> | ||
164 | </div> | ||
165 | <div className={classes.buttonContainer}> | ||
166 | {!isProUser ? ( | ||
167 | <UpgradeButton | ||
168 | className={classes.cta} | ||
169 | gaEventInfo={{ category: 'Todos', event: 'upgrade' }} | ||
170 | requiresPro | ||
171 | short | ||
172 | /> | ||
173 | ) : ( | ||
174 | <Button | ||
175 | label={intl.formatMessage(messages.manageButton)} | ||
176 | onClick={openTeamManagement} | ||
177 | className={classes.cta} | ||
178 | /> | ||
179 | )} | ||
180 | </div> | ||
181 | </> | ||
182 | </> | ||
183 | )} | ||
184 | </> | ||
185 | )} | ||
186 | </div> | 214 | </div> |
187 | <ReactTooltip place="right" type="dark" effect="solid" /> | ||
188 | </div> | 215 | </div> |
189 | ); | 216 | ); |
190 | } | 217 | } |