aboutsummaryrefslogtreecommitdiffstats
path: root/src/components
diff options
context:
space:
mode:
authorLibravatar Stefan Malzner <stefan@adlk.io>2018-11-28 20:51:17 +0100
committerLibravatar Stefan Malzner <stefan@adlk.io>2018-11-28 20:51:17 +0100
commit8b648553a115ed753f78bb81af2752eadaf47754 (patch)
treeb56cfd517a836dffa6b738896df125940f9936b8 /src/components
parentfix(App): App menu was not initialized on app launch. Resolving copy & paste ... (diff)
parentFix linting issues (diff)
downloadferdium-app-8b648553a115ed753f78bb81af2752eadaf47754.tar.gz
ferdium-app-8b648553a115ed753f78bb81af2752eadaf47754.tar.zst
ferdium-app-8b648553a115ed753f78bb81af2752eadaf47754.zip
Merge branch 'update/monetization' into develop
Diffstat (limited to 'src/components')
-rw-r--r--src/components/layout/AppLayout.js2
-rw-r--r--src/components/settings/account/AccountDashboard.js8
-rw-r--r--src/components/settings/navigation/SettingsNavigation.js25
-rw-r--r--src/components/settings/services/EditServiceForm.js45
-rw-r--r--src/components/settings/settings/EditSettingsForm.js12
-rw-r--r--src/components/subscription/SubscriptionForm.js32
-rw-r--r--src/components/ui/PremiumFeatureContainer/index.js76
-rw-r--r--src/components/ui/PremiumFeatureContainer/styles.js31
-rw-r--r--src/components/ui/Toggle.js6
9 files changed, 187 insertions, 50 deletions
diff --git a/src/components/layout/AppLayout.js b/src/components/layout/AppLayout.js
index 4b20fc480..3ababe54a 100644
--- a/src/components/layout/AppLayout.js
+++ b/src/components/layout/AppLayout.js
@@ -5,7 +5,7 @@ import { defineMessages, intlShape } from 'react-intl';
5import { TitleBar } from 'electron-react-titlebar'; 5import { TitleBar } from 'electron-react-titlebar';
6 6
7import InfoBar from '../ui/InfoBar'; 7import InfoBar from '../ui/InfoBar';
8import { component as DelayApp } from '../../features/delayApp'; 8import { Component as DelayApp } from '../../features/delayApp';
9import globalMessages from '../../i18n/globalMessages'; 9import globalMessages from '../../i18n/globalMessages';
10 10
11import { isWindows } from '../../environment'; 11import { isWindows } from '../../environment';
diff --git a/src/components/settings/account/AccountDashboard.js b/src/components/settings/account/AccountDashboard.js
index ede519fd6..06c7074dd 100644
--- a/src/components/settings/account/AccountDashboard.js
+++ b/src/components/settings/account/AccountDashboard.js
@@ -180,11 +180,9 @@ export default @observer class AccountDashboard extends Component {
180 <span className="badge badge--success">{intl.formatMessage(messages.accountTypeEnterprise)}</span> 180 <span className="badge badge--success">{intl.formatMessage(messages.accountTypeEnterprise)}</span>
181 )} 181 )}
182 </div> 182 </div>
183 {!user.isSSO && ( 183 <Link to="/settings/user/edit" className="button">
184 <Link to="/settings/user/edit" className="button"> 184 {intl.formatMessage(messages.accountEditButton)}
185 {intl.formatMessage(messages.accountEditButton)} 185 </Link>
186 </Link>
187 )}
188 {user.emailValidated} 186 {user.emailValidated}
189 </div> 187 </div>
190 </div> 188 </div>
diff --git a/src/components/settings/navigation/SettingsNavigation.js b/src/components/settings/navigation/SettingsNavigation.js
index d8b410aaf..b86d94ac7 100644
--- a/src/components/settings/navigation/SettingsNavigation.js
+++ b/src/components/settings/navigation/SettingsNavigation.js
@@ -43,20 +43,17 @@ export default @inject('stores') @observer class SettingsNavigation extends Comp
43 43
44 render() { 44 render() {
45 const { serviceCount } = this.props; 45 const { serviceCount } = this.props;
46 const { features } = this.props.stores.features;
47 const { intl } = this.context; 46 const { intl } = this.context;
48 47
49 return ( 48 return (
50 <div className="settings-navigation"> 49 <div className="settings-navigation">
51 {features.userCanManageServices && ( 50 <Link
52 <Link 51 to="/settings/recipes"
53 to="/settings/recipes" 52 className="settings-navigation__link"
54 className="settings-navigation__link" 53 activeClassName="is-active"
55 activeClassName="is-active" 54 >
56 > 55 {intl.formatMessage(messages.availableServices)}
57 {intl.formatMessage(messages.availableServices)} 56 </Link>
58 </Link>
59 )}
60 <Link 57 <Link
61 to="/settings/services" 58 to="/settings/services"
62 className="settings-navigation__link" 59 className="settings-navigation__link"
@@ -97,11 +94,3 @@ export default @inject('stores') @observer class SettingsNavigation extends Comp
97 } 94 }
98} 95}
99 96
100SettingsNavigation.wrappedComponent.propTypes = {
101 stores: PropTypes.shape({
102 features: PropTypes.shape({
103 features: PropTypes.object.isRequired,
104 }).isRequired,
105 }).isRequired,
106};
107
diff --git a/src/components/settings/services/EditServiceForm.js b/src/components/settings/services/EditServiceForm.js
index 777a95fcf..47772efae 100644
--- a/src/components/settings/services/EditServiceForm.js
+++ b/src/components/settings/services/EditServiceForm.js
@@ -15,6 +15,8 @@ import Toggle from '../../ui/Toggle';
15import Button from '../../ui/Button'; 15import Button from '../../ui/Button';
16import ImageUpload from '../../ui/ImageUpload'; 16import ImageUpload from '../../ui/ImageUpload';
17 17
18import PremiumFeatureContainer from '../../ui/PremiumFeatureContainer';
19
18const messages = defineMessages({ 20const messages = defineMessages({
19 saveService: { 21 saveService: {
20 id: 'settings.service.form.saveButton', 22 id: 'settings.service.form.saveButton',
@@ -92,6 +94,14 @@ const messages = defineMessages({
92 id: 'settings.service.form.iconUpload', 94 id: 'settings.service.form.iconUpload',
93 defaultMessage: '!!!Drop your image, or click here', 95 defaultMessage: '!!!Drop your image, or click here',
94 }, 96 },
97 headlineProxy: {
98 id: 'settings.service.form.proxy.headline',
99 defaultMessage: '!!!Proxy Settings',
100 },
101 proxyInfo: {
102 id: 'settings.service.form.proxy.info',
103 defaultMessage: '!!!Proxy settings will not be synchronized with the Franz servers.',
104 },
95}); 105});
96 106
97export default @observer class EditServiceForm extends Component { 107export default @observer class EditServiceForm extends Component {
@@ -106,13 +116,14 @@ export default @observer class EditServiceForm extends Component {
106 return null; 116 return null;
107 }, 117 },
108 user: PropTypes.instanceOf(User).isRequired, 118 user: PropTypes.instanceOf(User).isRequired,
109 userCanManageServices: PropTypes.bool.isRequired,
110 action: PropTypes.string.isRequired, 119 action: PropTypes.string.isRequired,
111 form: PropTypes.instanceOf(Form).isRequired, 120 form: PropTypes.instanceOf(Form).isRequired,
112 onSubmit: PropTypes.func.isRequired, 121 onSubmit: PropTypes.func.isRequired,
113 onDelete: PropTypes.func.isRequired, 122 onDelete: PropTypes.func.isRequired,
114 isSaving: PropTypes.bool.isRequired, 123 isSaving: PropTypes.bool.isRequired,
115 isDeleting: PropTypes.bool.isRequired, 124 isDeleting: PropTypes.bool.isRequired,
125 isProxyFeatureEnabled: PropTypes.bool.isRequired,
126 isProxyFeaturePremiumFeature: PropTypes.bool.isRequired,
116 }; 127 };
117 128
118 static defaultProps = { 129 static defaultProps = {
@@ -169,11 +180,12 @@ export default @observer class EditServiceForm extends Component {
169 service, 180 service,
170 action, 181 action,
171 user, 182 user,
172 userCanManageServices,
173 form, 183 form,
174 isSaving, 184 isSaving,
175 isDeleting, 185 isDeleting,
176 onDelete, 186 onDelete,
187 isProxyFeatureEnabled,
188 isProxyFeaturePremiumFeature,
177 } = this.props; 189 } = this.props;
178 const { intl } = this.context; 190 const { intl } = this.context;
179 191
@@ -318,6 +330,33 @@ export default @observer class EditServiceForm extends Component {
318 /> 330 />
319 </div> 331 </div>
320 </div> 332 </div>
333
334 {isProxyFeatureEnabled && (
335 <PremiumFeatureContainer condition={isProxyFeaturePremiumFeature}>
336 <div className="settings__settings-group">
337 <h3>
338 {intl.formatMessage(messages.headlineProxy)}
339 <span className="badge badge--success">beta</span>
340 </h3>
341 <Toggle field={form.$('proxy.isEnabled')} />
342 {form.$('proxy.isEnabled').value && (
343 <div>
344 <Input field={form.$('proxy.host')} />
345 <Input field={form.$('proxy.user')} />
346 <Input
347 field={form.$('proxy.password')}
348 showPasswordToggle
349 />
350 <p>
351 <span className="mdi mdi-information" />
352 {intl.formatMessage(messages.proxyInfo)}
353 </p>
354 </div>
355 )}
356 </div>
357 </PremiumFeatureContainer>
358 )}
359
321 {recipe.message && ( 360 {recipe.message && (
322 <p className="settings__message"> 361 <p className="settings__message">
323 <span className="mdi mdi-information" /> 362 <span className="mdi mdi-information" />
@@ -328,7 +367,7 @@ export default @observer class EditServiceForm extends Component {
328 </div> 367 </div>
329 <div className="settings__controls"> 368 <div className="settings__controls">
330 {/* Delete Button */} 369 {/* Delete Button */}
331 {action === 'edit' && userCanManageServices && deleteButton} 370 {action === 'edit' && deleteButton}
332 371
333 {/* Save Button */} 372 {/* Save Button */}
334 {isSaving || isValidatingCustomUrl ? ( 373 {isSaving || isValidatingCustomUrl ? (
diff --git a/src/components/settings/settings/EditSettingsForm.js b/src/components/settings/settings/EditSettingsForm.js
index b5c048ebd..280449ead 100644
--- a/src/components/settings/settings/EditSettingsForm.js
+++ b/src/components/settings/settings/EditSettingsForm.js
@@ -8,6 +8,7 @@ import Form from '../../../lib/Form';
8import Button from '../../ui/Button'; 8import Button from '../../ui/Button';
9import Toggle from '../../ui/Toggle'; 9import Toggle from '../../ui/Toggle';
10import Select from '../../ui/Select'; 10import Select from '../../ui/Select';
11import PremiumFeatureContainer from '../../ui/PremiumFeatureContainer';
11 12
12import { FRANZ_TRANSLATION } from '../../../config'; 13import { FRANZ_TRANSLATION } from '../../../config';
13 14
@@ -95,6 +96,7 @@ export default @observer class EditSettingsForm extends Component {
95 isClearingAllCache: PropTypes.bool.isRequired, 96 isClearingAllCache: PropTypes.bool.isRequired,
96 onClearAllCache: PropTypes.func.isRequired, 97 onClearAllCache: PropTypes.func.isRequired,
97 cacheSize: PropTypes.string.isRequired, 98 cacheSize: PropTypes.string.isRequired,
99 isSpellcheckerPremiumFeature: PropTypes.bool.isRequired,
98 }; 100 };
99 101
100 static contextTypes = { 102 static contextTypes = {
@@ -124,6 +126,7 @@ export default @observer class EditSettingsForm extends Component {
124 isClearingAllCache, 126 isClearingAllCache,
125 onClearAllCache, 127 onClearAllCache,
126 cacheSize, 128 cacheSize,
129 isSpellcheckerPremiumFeature,
127 } = this.props; 130 } = this.props;
128 const { intl } = this.context; 131 const { intl } = this.context;
129 132
@@ -175,7 +178,14 @@ export default @observer class EditSettingsForm extends Component {
175 178
176 {/* Advanced */} 179 {/* Advanced */}
177 <h2 id="advanced">{intl.formatMessage(messages.headlineAdvanced)}</h2> 180 <h2 id="advanced">{intl.formatMessage(messages.headlineAdvanced)}</h2>
178 <Toggle field={form.$('enableSpellchecking')} /> 181 <PremiumFeatureContainer
182 condition={isSpellcheckerPremiumFeature}
183 >
184 <Toggle
185 field={form.$('enableSpellchecking')}
186 disabled
187 />
188 </PremiumFeatureContainer>
179 <Toggle field={form.$('enableGPUAcceleration')} /> 189 <Toggle field={form.$('enableGPUAcceleration')} />
180 <p className="settings__help">{intl.formatMessage(messages.enableGPUAccelerationInfo)}</p> 190 <p className="settings__help">{intl.formatMessage(messages.enableGPUAccelerationInfo)}</p>
181 {/* <Select field={form.$('spellcheckingLanguage')} /> */} 191 {/* <Select field={form.$('spellcheckingLanguage')} /> */}
diff --git a/src/components/subscription/SubscriptionForm.js b/src/components/subscription/SubscriptionForm.js
index 5992e4204..12965e307 100644
--- a/src/components/subscription/SubscriptionForm.js
+++ b/src/components/subscription/SubscriptionForm.js
@@ -36,26 +36,22 @@ const messages = defineMessages({
36 defaultMessage: '!!!The Franz Premium Supporter Account includes', 36 defaultMessage: '!!!The Franz Premium Supporter Account includes',
37 }, 37 },
38 features: { 38 features: {
39 unlimitedServices: {
40 id: 'subscription.features.unlimitedServices',
41 defaultMessage: '!!!Add unlimited services',
42 },
43 onpremise: { 39 onpremise: {
44 id: 'subscription.features.onpremise', 40 id: 'subscription.features.onpremise.mattermost',
45 defaultMessage: '!!!Add on-premise/hosted services like HipChat', 41 defaultMessage: '!!!Add on-premise/hosted services like Mattermost',
46 },
47 customServices: {
48 id: 'subscription.features.customServices',
49 defaultMessage: '!!!Add your custom services',
50 }, 42 },
51 encryptedSync: { 43 noInterruptions: {
52 id: 'subscription.features.encryptedSync', 44 id: 'subscription.features.noInterruptions',
53 defaultMessage: '!!!Encrypted session synchronization', 45 defaultMessage: '!!!No app delays & nagging to upgrade license',
54 }, 46 },
55 vpn: { 47 vpn: {
56 id: 'subscription.features.vpn', 48 id: 'subscription.features.vpn',
57 defaultMessage: '!!!Proxy & VPN support', 49 defaultMessage: '!!!Proxy & VPN support',
58 }, 50 },
51 spellchecker: {
52 id: 'subscription.features.spellchecker',
53 defaultMessage: '!!!Support for Spellchecker',
54 },
59 ads: { 55 ads: {
60 id: 'subscription.features.ads', 56 id: 'subscription.features.ads',
61 defaultMessage: '!!!No ads, ever!', 57 defaultMessage: '!!!No ads, ever!',
@@ -170,16 +166,10 @@ export default @observer class SubscriptionForm extends Component {
170 <ul className="subscription__premium-features"> 166 <ul className="subscription__premium-features">
171 <li>{intl.formatMessage(messages.features.onpremise)}</li> 167 <li>{intl.formatMessage(messages.features.onpremise)}</li>
172 <li> 168 <li>
173 {intl.formatMessage(messages.features.encryptedSync)} 169 {intl.formatMessage(messages.features.noInterruptions)}
174 <span className="badge">{intl.formatMessage(messages.features.comingSoon)}</span>
175 </li>
176 <li>
177 {intl.formatMessage(messages.features.customServices)}
178 <span className="badge">{intl.formatMessage(messages.features.comingSoon)}</span>
179 </li> 170 </li>
180 <li> 171 <li>
181 {intl.formatMessage(messages.features.vpn)} 172 {intl.formatMessage(messages.features.spellchecker)}
182 <span className="badge">{intl.formatMessage(messages.features.comingSoon)}</span>
183 </li> 173 </li>
184 <li> 174 <li>
185 {intl.formatMessage(messages.features.ads)} 175 {intl.formatMessage(messages.features.ads)}
diff --git a/src/components/ui/PremiumFeatureContainer/index.js b/src/components/ui/PremiumFeatureContainer/index.js
new file mode 100644
index 000000000..73984be94
--- /dev/null
+++ b/src/components/ui/PremiumFeatureContainer/index.js
@@ -0,0 +1,76 @@
1import React, { Component } from 'react';
2import { inject, observer } from 'mobx-react';
3import PropTypes from 'prop-types';
4import { defineMessages, intlShape } from 'react-intl';
5import injectSheet from 'react-jss';
6
7import { oneOrManyChildElements } from '../../../prop-types';
8
9import UserStore from '../../../stores/UserStore';
10
11import styles from './styles';
12
13const messages = defineMessages({
14 action: {
15 id: 'premiumFeature.button.upgradeAccount',
16 defaultMessage: '!!!Upgrade account',
17 },
18});
19
20export default @inject('stores', 'actions') @injectSheet(styles) @observer class PremiumFeatureContainer extends Component {
21 static propTypes = {
22 classes: PropTypes.object.isRequired,
23 condition: PropTypes.bool,
24 };
25
26 static defaultProps = {
27 condition: true,
28 };
29
30 static contextTypes = {
31 intl: intlShape,
32 };
33
34 render() {
35 const {
36 classes,
37 children,
38 actions,
39 condition,
40 stores,
41 } = this.props;
42
43 const { intl } = this.context;
44
45 return !stores.user.data.isPremium && !!condition ? (
46 <div className={classes.container}>
47 <div className={classes.titleContainer}>
48 <p className={classes.title}>Premium Feature</p>
49 <button
50 className={classes.actionButton}
51 type="button"
52 onClick={() => actions.ui.openSettings({ path: 'user' })}
53 >
54 {intl.formatMessage(messages.action)}
55 </button>
56 </div>
57 <div className={classes.content}>
58 {children}
59 </div>
60 </div>
61 ) : children;
62 }
63}
64
65PremiumFeatureContainer.wrappedComponent.propTypes = {
66 children: oneOrManyChildElements.isRequired,
67 stores: PropTypes.shape({
68 user: PropTypes.instanceOf(UserStore).isRequired,
69 }).isRequired,
70 actions: PropTypes.shape({
71 ui: PropTypes.shape({
72 openSettings: PropTypes.func.isRequired,
73 }).isRequired,
74 }).isRequired,
75};
76
diff --git a/src/components/ui/PremiumFeatureContainer/styles.js b/src/components/ui/PremiumFeatureContainer/styles.js
new file mode 100644
index 000000000..16c40d0ec
--- /dev/null
+++ b/src/components/ui/PremiumFeatureContainer/styles.js
@@ -0,0 +1,31 @@
1export default theme => ({
2 container: {
3 background: theme.colorSubscriptionContainerBackground,
4 border: theme.colorSubscriptionContainerBorder,
5 margin: [0, 0, 20, -20],
6 padding: 20,
7 'border-radius': theme.borderRadius,
8 },
9 titleContainer: {
10 display: 'flex',
11 },
12 title: {
13 'font-weight': 'bold',
14 color: theme.colorSubscriptionContainerTitle,
15 },
16 actionButton: {
17 background: theme.colorSubscriptionContainerActionButtonBackground,
18 color: theme.colorSubscriptionContainerActionButtonColor,
19 'margin-left': 'auto',
20 'border-radius': theme.borderRadiusSmall,
21 padding: [2, 4],
22 'font-size': 12,
23 },
24 content: {
25 opacity: 0.5,
26 'margin-top': 20,
27 '& :last-child': {
28 'margin-bottom': 0,
29 },
30 },
31});
diff --git a/src/components/ui/Toggle.js b/src/components/ui/Toggle.js
index f7c2ec955..78fb77cbe 100644
--- a/src/components/ui/Toggle.js
+++ b/src/components/ui/Toggle.js
@@ -9,11 +9,13 @@ export default @observer class Toggle extends Component {
9 field: PropTypes.instanceOf(Field).isRequired, 9 field: PropTypes.instanceOf(Field).isRequired,
10 className: PropTypes.string, 10 className: PropTypes.string,
11 showLabel: PropTypes.bool, 11 showLabel: PropTypes.bool,
12 disabled: PropTypes.bool,
12 }; 13 };
13 14
14 static defaultProps = { 15 static defaultProps = {
15 className: '', 16 className: '',
16 showLabel: true, 17 showLabel: true,
18 disabled: false,
17 }; 19 };
18 20
19 onChange(e) { 21 onChange(e) {
@@ -27,6 +29,7 @@ export default @observer class Toggle extends Component {
27 field, 29 field,
28 className, 30 className,
29 showLabel, 31 showLabel,
32 disabled,
30 } = this.props; 33 } = this.props;
31 34
32 if (field.value === '' && field.default !== '') { 35 if (field.value === '' && field.default !== '') {
@@ -38,6 +41,7 @@ export default @observer class Toggle extends Component {
38 className={classnames([ 41 className={classnames([
39 'franz-form__field', 42 'franz-form__field',
40 'franz-form__toggle-wrapper', 43 'franz-form__toggle-wrapper',
44 'franz-form__toggle-disabled',
41 className, 45 className,
42 ])} 46 ])}
43 > 47 >
@@ -55,7 +59,7 @@ export default @observer class Toggle extends Component {
55 name={field.name} 59 name={field.name}
56 value={field.name} 60 value={field.name}
57 checked={field.value} 61 checked={field.value}
58 onChange={e => this.onChange(e)} 62 onChange={e => (!disabled ? this.onChange(e) : null)}
59 /> 63 />
60 </label> 64 </label>
61 {field.error && <div className={field.error}>{field.error}</div>} 65 {field.error && <div className={field.error}>{field.error}</div>}