diff options
author | 2019-03-28 16:23:17 +0100 | |
---|---|---|
committer | 2019-03-28 16:23:17 +0100 | |
commit | 7941831bf773b49944001c095a1949a1bdec2cf2 (patch) | |
tree | 5dbcbf097e340c381617410e032c2db6b811096e | |
parent | improve styling of workspace switch indicator (diff) | |
download | ferdium-app-7941831bf773b49944001c095a1949a1bdec2cf2.tar.gz ferdium-app-7941831bf773b49944001c095a1949a1bdec2cf2.tar.zst ferdium-app-7941831bf773b49944001c095a1949a1bdec2cf2.zip |
add workspace premium notice to dashboard
19 files changed, 230 insertions, 83 deletions
diff --git a/src/actions/lib/actions.js b/src/actions/lib/actions.js index 6571e9441..2bc7d2711 100644 --- a/src/actions/lib/actions.js +++ b/src/actions/lib/actions.js | |||
@@ -9,6 +9,10 @@ export const createActionsFromDefinitions = (actionDefinitions, validate) => { | |||
9 | actions[actionName] = action; | 9 | actions[actionName] = action; |
10 | action.listeners = []; | 10 | action.listeners = []; |
11 | action.listen = listener => action.listeners.push(listener); | 11 | action.listen = listener => action.listeners.push(listener); |
12 | action.off = (listener) => { | ||
13 | const { listeners } = action; | ||
14 | listeners.splice(listeners.indexOf(listener), 1); | ||
15 | }; | ||
12 | action.notify = params => action.listeners.forEach(listener => listener(params)); | 16 | action.notify = params => action.listeners.forEach(listener => listener(params)); |
13 | }); | 17 | }); |
14 | return actions; | 18 | return actions; |
diff --git a/src/components/layout/Sidebar.js b/src/components/layout/Sidebar.js index 4fa5e79de..327f76392 100644 --- a/src/components/layout/Sidebar.js +++ b/src/components/layout/Sidebar.js | |||
@@ -90,7 +90,7 @@ export default @observer class Sidebar extends Component { | |||
90 | enableToolTip={() => this.enableToolTip()} | 90 | enableToolTip={() => this.enableToolTip()} |
91 | disableToolTip={() => this.disableToolTip()} | 91 | disableToolTip={() => this.disableToolTip()} |
92 | /> | 92 | /> |
93 | {workspaceStore.isFeatureActive ? ( | 93 | {workspaceStore.isFeatureEnabled ? ( |
94 | <button | 94 | <button |
95 | type="button" | 95 | type="button" |
96 | onClick={() => { | 96 | onClick={() => { |
diff --git a/src/components/settings/navigation/SettingsNavigation.js b/src/components/settings/navigation/SettingsNavigation.js index a0eb7d796..dc3c1d6f1 100644 --- a/src/components/settings/navigation/SettingsNavigation.js +++ b/src/components/settings/navigation/SettingsNavigation.js | |||
@@ -69,7 +69,7 @@ export default @inject('stores') @observer class SettingsNavigation extends Comp | |||
69 | {' '} | 69 | {' '} |
70 | <span className="badge">{serviceCount}</span> | 70 | <span className="badge">{serviceCount}</span> |
71 | </Link> | 71 | </Link> |
72 | {workspaceStore.isFeatureActive ? ( | 72 | {workspaceStore.isFeatureEnabled ? ( |
73 | <Link | 73 | <Link |
74 | to="/settings/workspaces" | 74 | to="/settings/workspaces" |
75 | className="settings-navigation__link" | 75 | className="settings-navigation__link" |
diff --git a/src/components/settings/services/EditServiceForm.js b/src/components/settings/services/EditServiceForm.js index 21616b5de..4ba2eb844 100644 --- a/src/components/settings/services/EditServiceForm.js +++ b/src/components/settings/services/EditServiceForm.js | |||
@@ -341,14 +341,20 @@ export default @observer class EditServiceForm extends Component { | |||
341 | </div> | 341 | </div> |
342 | </div> | 342 | </div> |
343 | 343 | ||
344 | <PremiumFeatureContainer condition={isSpellcheckerPremiumFeature}> | 344 | <PremiumFeatureContainer |
345 | condition={isSpellcheckerPremiumFeature} | ||
346 | gaEventInfo={{ category: 'User', event: 'upgrade', label: 'spellchecker' }} | ||
347 | > | ||
345 | <div className="settings__settings-group"> | 348 | <div className="settings__settings-group"> |
346 | <Select field={form.$('spellcheckerLanguage')} /> | 349 | <Select field={form.$('spellcheckerLanguage')} /> |
347 | </div> | 350 | </div> |
348 | </PremiumFeatureContainer> | 351 | </PremiumFeatureContainer> |
349 | 352 | ||
350 | {isProxyFeatureEnabled && ( | 353 | {isProxyFeatureEnabled && ( |
351 | <PremiumFeatureContainer condition={isProxyPremiumFeature}> | 354 | <PremiumFeatureContainer |
355 | condition={isProxyPremiumFeature} | ||
356 | gaEventInfo={{ category: 'User', event: 'upgrade', label: 'proxy' }} | ||
357 | > | ||
352 | <div className="settings__settings-group"> | 358 | <div className="settings__settings-group"> |
353 | <h3> | 359 | <h3> |
354 | {intl.formatMessage(messages.headlineProxy)} | 360 | {intl.formatMessage(messages.headlineProxy)} |
diff --git a/src/components/settings/settings/EditSettingsForm.js b/src/components/settings/settings/EditSettingsForm.js index a92e559f3..8429d0ecb 100644 --- a/src/components/settings/settings/EditSettingsForm.js +++ b/src/components/settings/settings/EditSettingsForm.js | |||
@@ -170,6 +170,7 @@ export default @observer class EditSettingsForm extends Component { | |||
170 | <Select field={form.$('locale')} showLabel={false} /> | 170 | <Select field={form.$('locale')} showLabel={false} /> |
171 | <PremiumFeatureContainer | 171 | <PremiumFeatureContainer |
172 | condition={isSpellcheckerPremiumFeature} | 172 | condition={isSpellcheckerPremiumFeature} |
173 | gaEventInfo={{ category: 'User', event: 'upgrade', label: 'spellchecker' }} | ||
173 | > | 174 | > |
174 | <Fragment> | 175 | <Fragment> |
175 | <Toggle | 176 | <Toggle |
diff --git a/src/components/ui/PremiumFeatureContainer/index.js b/src/components/ui/PremiumFeatureContainer/index.js index 67cd6af0b..3c1e0fac3 100644 --- a/src/components/ui/PremiumFeatureContainer/index.js +++ b/src/components/ui/PremiumFeatureContainer/index.js | |||
@@ -9,6 +9,7 @@ import { oneOrManyChildElements } from '../../../prop-types'; | |||
9 | import UserStore from '../../../stores/UserStore'; | 9 | import UserStore from '../../../stores/UserStore'; |
10 | 10 | ||
11 | import styles from './styles'; | 11 | import styles from './styles'; |
12 | import { gaEvent } from '../../../lib/analytics'; | ||
12 | 13 | ||
13 | const messages = defineMessages({ | 14 | const messages = defineMessages({ |
14 | action: { | 15 | action: { |
@@ -17,14 +18,21 @@ const messages = defineMessages({ | |||
17 | }, | 18 | }, |
18 | }); | 19 | }); |
19 | 20 | ||
20 | export default @inject('stores', 'actions') @injectSheet(styles) @observer class PremiumFeatureContainer extends Component { | 21 | @inject('stores', 'actions') @injectSheet(styles) @observer |
22 | class PremiumFeatureContainer extends Component { | ||
21 | static propTypes = { | 23 | static propTypes = { |
22 | classes: PropTypes.object.isRequired, | 24 | classes: PropTypes.object.isRequired, |
23 | condition: PropTypes.bool, | 25 | condition: PropTypes.bool, |
26 | gaEventInfo: PropTypes.shape({ | ||
27 | category: PropTypes.string.isRequired, | ||
28 | event: PropTypes.string.isRequired, | ||
29 | label: PropTypes.string, | ||
30 | }), | ||
24 | }; | 31 | }; |
25 | 32 | ||
26 | static defaultProps = { | 33 | static defaultProps = { |
27 | condition: true, | 34 | condition: true, |
35 | gaEventInfo: null, | ||
28 | }; | 36 | }; |
29 | 37 | ||
30 | static contextTypes = { | 38 | static contextTypes = { |
@@ -38,6 +46,7 @@ export default @inject('stores', 'actions') @injectSheet(styles) @observer class | |||
38 | actions, | 46 | actions, |
39 | condition, | 47 | condition, |
40 | stores, | 48 | stores, |
49 | gaEventInfo, | ||
41 | } = this.props; | 50 | } = this.props; |
42 | 51 | ||
43 | const { intl } = this.context; | 52 | const { intl } = this.context; |
@@ -49,7 +58,13 @@ export default @inject('stores', 'actions') @injectSheet(styles) @observer class | |||
49 | <button | 58 | <button |
50 | className={classes.actionButton} | 59 | className={classes.actionButton} |
51 | type="button" | 60 | type="button" |
52 | onClick={() => actions.ui.openSettings({ path: 'user' })} | 61 | onClick={() => { |
62 | actions.ui.openSettings({ path: 'user' }); | ||
63 | if (gaEventInfo) { | ||
64 | const { category, event, label } = gaEventInfo; | ||
65 | gaEvent(category, event, label); | ||
66 | } | ||
67 | }} | ||
53 | > | 68 | > |
54 | {intl.formatMessage(messages.action)} | 69 | {intl.formatMessage(messages.action)} |
55 | </button> | 70 | </button> |
@@ -73,3 +88,5 @@ PremiumFeatureContainer.wrappedComponent.propTypes = { | |||
73 | }).isRequired, | 88 | }).isRequired, |
74 | }).isRequired, | 89 | }).isRequired, |
75 | }; | 90 | }; |
91 | |||
92 | export default PremiumFeatureContainer; | ||
diff --git a/src/components/ui/PremiumFeatureContainer/styles.js b/src/components/ui/PremiumFeatureContainer/styles.js index 81d6666c6..615ed0a79 100644 --- a/src/components/ui/PremiumFeatureContainer/styles.js +++ b/src/components/ui/PremiumFeatureContainer/styles.js | |||
@@ -6,6 +6,7 @@ export default theme => ({ | |||
6 | padding: 20, | 6 | padding: 20, |
7 | 'border-radius': theme.borderRadius, | 7 | 'border-radius': theme.borderRadius, |
8 | pointerEvents: 'none', | 8 | pointerEvents: 'none', |
9 | height: 'auto', | ||
9 | }, | 10 | }, |
10 | titleContainer: { | 11 | titleContainer: { |
11 | display: 'flex', | 12 | display: 'flex', |
@@ -26,7 +27,7 @@ export default theme => ({ | |||
26 | content: { | 27 | content: { |
27 | opacity: 0.5, | 28 | opacity: 0.5, |
28 | 'margin-top': 20, | 29 | 'margin-top': 20, |
29 | '& :last-child': { | 30 | '& > :last-child': { |
30 | 'margin-bottom': 0, | 31 | 'margin-bottom': 0, |
31 | }, | 32 | }, |
32 | }, | 33 | }, |
diff --git a/src/features/delayApp/index.js b/src/features/delayApp/index.js index abc8274cf..67f0fc5e6 100644 --- a/src/features/delayApp/index.js +++ b/src/features/delayApp/index.js | |||
@@ -55,7 +55,7 @@ export default function init(stores) { | |||
55 | 55 | ||
56 | setVisibility(true); | 56 | setVisibility(true); |
57 | gaPage('/delayApp'); | 57 | gaPage('/delayApp'); |
58 | gaEvent('delayApp', 'show', 'Delay App Feature'); | 58 | gaEvent('DelayApp', 'show', 'Delay App Feature'); |
59 | 59 | ||
60 | timeLastDelay = moment(); | 60 | timeLastDelay = moment(); |
61 | shownAfterLaunch = true; | 61 | shownAfterLaunch = true; |
diff --git a/src/features/utils/FeatureStore.js b/src/features/utils/FeatureStore.js new file mode 100644 index 000000000..66b66a104 --- /dev/null +++ b/src/features/utils/FeatureStore.js | |||
@@ -0,0 +1,21 @@ | |||
1 | import Reaction from '../../stores/lib/Reaction'; | ||
2 | |||
3 | export class FeatureStore { | ||
4 | _actions = null; | ||
5 | |||
6 | _reactions = null; | ||
7 | |||
8 | _listenToActions(actions) { | ||
9 | if (this._actions) this._actions.forEach(a => a[0].off(a[1])); | ||
10 | this._actions = []; | ||
11 | actions.forEach(a => this._actions.push(a)); | ||
12 | this._actions.forEach(a => a[0].listen(a[1])); | ||
13 | } | ||
14 | |||
15 | _startReactions(reactions) { | ||
16 | if (this._reactions) this._reactions.forEach(r => r.stop()); | ||
17 | this._reactions = []; | ||
18 | reactions.forEach(r => this._reactions.push(new Reaction(r))); | ||
19 | this._reactions.forEach(r => r.start()); | ||
20 | } | ||
21 | } | ||
diff --git a/src/features/workspaces/components/CreateWorkspaceForm.js b/src/features/workspaces/components/CreateWorkspaceForm.js index a8f07d0d5..0be2d528f 100644 --- a/src/features/workspaces/components/CreateWorkspaceForm.js +++ b/src/features/workspaces/components/CreateWorkspaceForm.js | |||
@@ -30,7 +30,6 @@ const styles = () => ({ | |||
30 | }, | 30 | }, |
31 | submitButton: { | 31 | submitButton: { |
32 | height: 'inherit', | 32 | height: 'inherit', |
33 | marginTop: '3px', | ||
34 | }, | 33 | }, |
35 | }); | 34 | }); |
36 | 35 | ||
diff --git a/src/features/workspaces/components/WorkspacesDashboard.js b/src/features/workspaces/components/WorkspacesDashboard.js index 52c3afdcf..1fad1f71d 100644 --- a/src/features/workspaces/components/WorkspacesDashboard.js +++ b/src/features/workspaces/components/WorkspacesDashboard.js | |||
@@ -10,6 +10,8 @@ import WorkspaceItem from './WorkspaceItem'; | |||
10 | import CreateWorkspaceForm from './CreateWorkspaceForm'; | 10 | import CreateWorkspaceForm from './CreateWorkspaceForm'; |
11 | import Request from '../../../stores/lib/Request'; | 11 | import Request from '../../../stores/lib/Request'; |
12 | import Appear from '../../../components/ui/effects/Appear'; | 12 | import Appear from '../../../components/ui/effects/Appear'; |
13 | import { workspaceStore } from '../index'; | ||
14 | import PremiumFeatureContainer from '../../../components/ui/PremiumFeatureContainer'; | ||
13 | 15 | ||
14 | const messages = defineMessages({ | 16 | const messages = defineMessages({ |
15 | headline: { | 17 | headline: { |
@@ -36,6 +38,14 @@ const messages = defineMessages({ | |||
36 | id: 'settings.workspaces.deletedInfo', | 38 | id: 'settings.workspaces.deletedInfo', |
37 | defaultMessage: '!!!Workspace has been deleted', | 39 | defaultMessage: '!!!Workspace has been deleted', |
38 | }, | 40 | }, |
41 | workspaceFeatureInfo: { | ||
42 | id: 'settings.workspaces.workspaceFeatureInfo', | ||
43 | defaultMessage: '!!!Info about workspace feature', | ||
44 | }, | ||
45 | workspaceFeatureHeadline: { | ||
46 | id: 'settings.workspaces.workspaceFeatureHeadline', | ||
47 | defaultMessage: '!!!Less is More: Introducing Franz Workspaces', | ||
48 | }, | ||
39 | }); | 49 | }); |
40 | 50 | ||
41 | const styles = () => ({ | 51 | const styles = () => ({ |
@@ -46,6 +56,12 @@ const styles = () => ({ | |||
46 | appear: { | 56 | appear: { |
47 | height: 'auto', | 57 | height: 'auto', |
48 | }, | 58 | }, |
59 | premiumAnnouncement: { | ||
60 | padding: '20px', | ||
61 | backgroundColor: '#3498db', | ||
62 | marginLeft: '-20px', | ||
63 | height: 'auto', | ||
64 | }, | ||
49 | }); | 65 | }); |
50 | 66 | ||
51 | @injectSheet(styles) @observer | 67 | @injectSheet(styles) @observer |
@@ -112,14 +128,24 @@ class WorkspacesDashboard extends Component { | |||
112 | </Appear> | 128 | </Appear> |
113 | )} | 129 | )} |
114 | 130 | ||
115 | {/* ===== Create workspace form ===== */} | 131 | <PremiumFeatureContainer |
116 | <div className={classes.createForm}> | 132 | condition={workspaceStore.isPremiumFeature} |
117 | <CreateWorkspaceForm | 133 | gaEventInfo={{ category: 'User', event: 'upgrade', label: 'workspaces' }} |
118 | isSubmitting={createWorkspaceRequest.isExecuting} | 134 | > |
119 | onSubmit={onCreateWorkspaceSubmit} | 135 | {/* ===== Create workspace form ===== */} |
120 | /> | 136 | <div className={classes.createForm}> |
121 | </div> | 137 | <CreateWorkspaceForm |
122 | 138 | isSubmitting={createWorkspaceRequest.isExecuting} | |
139 | onSubmit={onCreateWorkspaceSubmit} | ||
140 | /> | ||
141 | </div> | ||
142 | </PremiumFeatureContainer> | ||
143 | {workspaceStore.isUpgradeToPremiumRequired && ( | ||
144 | <div className={classes.premiumAnnouncement}> | ||
145 | <h2>{intl.formatMessage(messages.workspaceFeatureHeadline)}</h2> | ||
146 | <p>{intl.formatMessage(messages.workspaceFeatureInfo)}</p> | ||
147 | </div> | ||
148 | )} | ||
123 | {getUserWorkspacesRequest.isExecuting ? ( | 149 | {getUserWorkspacesRequest.isExecuting ? ( |
124 | <Loader /> | 150 | <Loader /> |
125 | ) : ( | 151 | ) : ( |
diff --git a/src/features/workspaces/index.js b/src/features/workspaces/index.js index 89999ab0f..524a83e3c 100644 --- a/src/features/workspaces/index.js +++ b/src/features/workspaces/index.js | |||
@@ -4,11 +4,12 @@ import { resetApiRequests } from './api'; | |||
4 | 4 | ||
5 | const debug = require('debug')('Franz:feature:workspaces'); | 5 | const debug = require('debug')('Franz:feature:workspaces'); |
6 | 6 | ||
7 | export const GA_CATEGORY_WORKSPACES = 'workspaces'; | 7 | export const GA_CATEGORY_WORKSPACES = 'Workspaces'; |
8 | 8 | ||
9 | export const workspaceStore = new WorkspacesStore(); | 9 | export const workspaceStore = new WorkspacesStore(); |
10 | 10 | ||
11 | export default function initWorkspaces(stores, actions) { | 11 | export default function initWorkspaces(stores, actions) { |
12 | stores.workspaces = workspaceStore; | ||
12 | const { features, user } = stores; | 13 | const { features, user } = stores; |
13 | 14 | ||
14 | // Toggle workspace feature | 15 | // Toggle workspace feature |
diff --git a/src/features/workspaces/store.js b/src/features/workspaces/store.js index f7df7b29c..62bf3efb4 100644 --- a/src/features/workspaces/store.js +++ b/src/features/workspaces/store.js | |||
@@ -3,9 +3,9 @@ import { | |||
3 | observable, | 3 | observable, |
4 | action, | 4 | action, |
5 | } from 'mobx'; | 5 | } from 'mobx'; |
6 | import Reaction from '../../stores/lib/Reaction'; | ||
7 | import { matchRoute } from '../../helpers/routing-helpers'; | 6 | import { matchRoute } from '../../helpers/routing-helpers'; |
8 | import { workspaceActions } from './actions'; | 7 | import { workspaceActions } from './actions'; |
8 | import { FeatureStore } from '../utils/FeatureStore'; | ||
9 | import { | 9 | import { |
10 | createWorkspaceRequest, | 10 | createWorkspaceRequest, |
11 | deleteWorkspaceRequest, | 11 | deleteWorkspaceRequest, |
@@ -15,7 +15,11 @@ import { | |||
15 | 15 | ||
16 | const debug = require('debug')('Franz:feature:workspaces:store'); | 16 | const debug = require('debug')('Franz:feature:workspaces:store'); |
17 | 17 | ||
18 | export default class WorkspacesStore { | 18 | export default class WorkspacesStore extends FeatureStore { |
19 | @observable isFeatureEnabled = false; | ||
20 | |||
21 | @observable isPremiumFeature = true; | ||
22 | |||
19 | @observable isFeatureActive = false; | 23 | @observable isFeatureActive = false; |
20 | 24 | ||
21 | @observable activeWorkspace = null; | 25 | @observable activeWorkspace = null; |
@@ -33,36 +37,39 @@ export default class WorkspacesStore { | |||
33 | return getUserWorkspacesRequest.result || []; | 37 | return getUserWorkspacesRequest.result || []; |
34 | } | 38 | } |
35 | 39 | ||
36 | constructor() { | 40 | @computed get isUpgradeToPremiumRequired() { |
37 | // Wire-up action handlers | 41 | return this.isFeatureEnabled && !this.isFeatureActive; |
38 | workspaceActions.edit.listen(this._edit); | ||
39 | workspaceActions.create.listen(this._create); | ||
40 | workspaceActions.delete.listen(this._delete); | ||
41 | workspaceActions.update.listen(this._update); | ||
42 | workspaceActions.activate.listen(this._setActiveWorkspace); | ||
43 | workspaceActions.deactivate.listen(this._deactivateActiveWorkspace); | ||
44 | workspaceActions.toggleWorkspaceDrawer.listen(this._toggleWorkspaceDrawer); | ||
45 | workspaceActions.openWorkspaceSettings.listen(this._openWorkspaceSettings); | ||
46 | |||
47 | // Register and start reactions | ||
48 | this._registerReactions([ | ||
49 | this._updateWorkspaceBeingEdited, | ||
50 | this._updateActiveServiceOnWorkspaceSwitch, | ||
51 | ]); | ||
52 | } | 42 | } |
53 | 43 | ||
54 | start(stores, actions) { | 44 | start(stores, actions) { |
55 | debug('WorkspacesStore::start'); | 45 | debug('WorkspacesStore::start'); |
56 | this.stores = stores; | 46 | this.stores = stores; |
57 | this.actions = actions; | 47 | this.actions = actions; |
58 | this._reactions.forEach(r => r.start()); | 48 | |
59 | this.isFeatureActive = true; | 49 | this._listenToActions([ |
50 | [workspaceActions.edit, this._edit], | ||
51 | [workspaceActions.create, this._create], | ||
52 | [workspaceActions.delete, this._delete], | ||
53 | [workspaceActions.update, this._update], | ||
54 | [workspaceActions.activate, this._setActiveWorkspace], | ||
55 | [workspaceActions.deactivate, this._deactivateActiveWorkspace], | ||
56 | [workspaceActions.toggleWorkspaceDrawer, this._toggleWorkspaceDrawer], | ||
57 | [workspaceActions.openWorkspaceSettings, this._openWorkspaceSettings], | ||
58 | ]); | ||
59 | |||
60 | this._startReactions([ | ||
61 | this._setWorkspaceBeingEditedReaction, | ||
62 | this._setActiveServiceOnWorkspaceSwitchReaction, | ||
63 | this._setFeatureEnabledReaction, | ||
64 | this._setIsPremiumFeatureReaction, | ||
65 | ]); | ||
66 | |||
60 | getUserWorkspacesRequest.execute(); | 67 | getUserWorkspacesRequest.execute(); |
68 | this.isFeatureActive = true; | ||
61 | } | 69 | } |
62 | 70 | ||
63 | stop() { | 71 | stop() { |
64 | debug('WorkspacesStore::stop'); | 72 | debug('WorkspacesStore::stop'); |
65 | this._reactions.forEach(r => r.stop()); | ||
66 | this.isFeatureActive = false; | 73 | this.isFeatureActive = false; |
67 | this.activeWorkspace = null; | 74 | this.activeWorkspace = null; |
68 | this.nextWorkspace = null; | 75 | this.nextWorkspace = null; |
@@ -85,12 +92,6 @@ export default class WorkspacesStore { | |||
85 | 92 | ||
86 | // ========== PRIVATE ========= // | 93 | // ========== PRIVATE ========= // |
87 | 94 | ||
88 | _reactions = []; | ||
89 | |||
90 | _registerReactions(reactions) { | ||
91 | reactions.forEach(r => this._reactions.push(new Reaction(r))); | ||
92 | } | ||
93 | |||
94 | _getWorkspaceById = id => this.workspaces.find(w => w.id === id); | 95 | _getWorkspaceById = id => this.workspaces.find(w => w.id === id); |
95 | 96 | ||
96 | // Actions | 97 | // Actions |
@@ -164,7 +165,17 @@ export default class WorkspacesStore { | |||
164 | 165 | ||
165 | // Reactions | 166 | // Reactions |
166 | 167 | ||
167 | _updateWorkspaceBeingEdited = () => { | 168 | _setFeatureEnabledReaction = () => { |
169 | const { isWorkspaceEnabled } = this.stores.features.features; | ||
170 | this.isFeatureEnabled = isWorkspaceEnabled; | ||
171 | }; | ||
172 | |||
173 | _setIsPremiumFeatureReaction = () => { | ||
174 | const { isWorkspacePremiumFeature } = this.stores.features.features; | ||
175 | this.isPremiumFeature = isWorkspacePremiumFeature; | ||
176 | }; | ||
177 | |||
178 | _setWorkspaceBeingEditedReaction = () => { | ||
168 | const { pathname } = this.stores.router.location; | 179 | const { pathname } = this.stores.router.location; |
169 | const match = matchRoute('/settings/workspaces/edit/:id', pathname); | 180 | const match = matchRoute('/settings/workspaces/edit/:id', pathname); |
170 | if (match) { | 181 | if (match) { |
@@ -172,7 +183,7 @@ export default class WorkspacesStore { | |||
172 | } | 183 | } |
173 | }; | 184 | }; |
174 | 185 | ||
175 | _updateActiveServiceOnWorkspaceSwitch = () => { | 186 | _setActiveServiceOnWorkspaceSwitchReaction = () => { |
176 | if (!this.isFeatureActive) return; | 187 | if (!this.isFeatureActive) return; |
177 | if (this.activeWorkspace) { | 188 | if (this.activeWorkspace) { |
178 | const services = this.stores.services.allDisplayed; | 189 | const services = this.stores.services.allDisplayed; |
diff --git a/src/i18n/locales/defaultMessages.json b/src/i18n/locales/defaultMessages.json index 659b1b361..1747e1976 100644 --- a/src/i18n/locales/defaultMessages.json +++ b/src/i18n/locales/defaultMessages.json | |||
@@ -2535,13 +2535,13 @@ | |||
2535 | "defaultMessage": "!!!Upgrade account", | 2535 | "defaultMessage": "!!!Upgrade account", |
2536 | "end": { | 2536 | "end": { |
2537 | "column": 3, | 2537 | "column": 3, |
2538 | "line": 17 | 2538 | "line": 18 |
2539 | }, | 2539 | }, |
2540 | "file": "src/components/ui/PremiumFeatureContainer/index.js", | 2540 | "file": "src/components/ui/PremiumFeatureContainer/index.js", |
2541 | "id": "premiumFeature.button.upgradeAccount", | 2541 | "id": "premiumFeature.button.upgradeAccount", |
2542 | "start": { | 2542 | "start": { |
2543 | "column": 10, | 2543 | "column": 10, |
2544 | "line": 14 | 2544 | "line": 15 |
2545 | } | 2545 | } |
2546 | } | 2546 | } |
2547 | ], | 2547 | ], |
@@ -3388,78 +3388,104 @@ | |||
3388 | "defaultMessage": "!!!Your workspaces", | 3388 | "defaultMessage": "!!!Your workspaces", |
3389 | "end": { | 3389 | "end": { |
3390 | "column": 3, | 3390 | "column": 3, |
3391 | "line": 18 | 3391 | "line": 20 |
3392 | }, | 3392 | }, |
3393 | "file": "src/features/workspaces/components/WorkspacesDashboard.js", | 3393 | "file": "src/features/workspaces/components/WorkspacesDashboard.js", |
3394 | "id": "settings.workspaces.headline", | 3394 | "id": "settings.workspaces.headline", |
3395 | "start": { | 3395 | "start": { |
3396 | "column": 12, | 3396 | "column": 12, |
3397 | "line": 15 | 3397 | "line": 17 |
3398 | } | 3398 | } |
3399 | }, | 3399 | }, |
3400 | { | 3400 | { |
3401 | "defaultMessage": "!!!You haven't added any workspaces yet.", | 3401 | "defaultMessage": "!!!You haven't added any workspaces yet.", |
3402 | "end": { | 3402 | "end": { |
3403 | "column": 3, | 3403 | "column": 3, |
3404 | "line": 22 | 3404 | "line": 24 |
3405 | }, | 3405 | }, |
3406 | "file": "src/features/workspaces/components/WorkspacesDashboard.js", | 3406 | "file": "src/features/workspaces/components/WorkspacesDashboard.js", |
3407 | "id": "settings.workspaces.noWorkspacesAdded", | 3407 | "id": "settings.workspaces.noWorkspacesAdded", |
3408 | "start": { | 3408 | "start": { |
3409 | "column": 19, | 3409 | "column": 19, |
3410 | "line": 19 | 3410 | "line": 21 |
3411 | } | 3411 | } |
3412 | }, | 3412 | }, |
3413 | { | 3413 | { |
3414 | "defaultMessage": "!!!Could not load your workspaces", | 3414 | "defaultMessage": "!!!Could not load your workspaces", |
3415 | "end": { | 3415 | "end": { |
3416 | "column": 3, | 3416 | "column": 3, |
3417 | "line": 26 | 3417 | "line": 28 |
3418 | }, | 3418 | }, |
3419 | "file": "src/features/workspaces/components/WorkspacesDashboard.js", | 3419 | "file": "src/features/workspaces/components/WorkspacesDashboard.js", |
3420 | "id": "settings.workspaces.workspacesRequestFailed", | 3420 | "id": "settings.workspaces.workspacesRequestFailed", |
3421 | "start": { | 3421 | "start": { |
3422 | "column": 27, | 3422 | "column": 27, |
3423 | "line": 23 | 3423 | "line": 25 |
3424 | } | 3424 | } |
3425 | }, | 3425 | }, |
3426 | { | 3426 | { |
3427 | "defaultMessage": "!!!Try again", | 3427 | "defaultMessage": "!!!Try again", |
3428 | "end": { | 3428 | "end": { |
3429 | "column": 3, | 3429 | "column": 3, |
3430 | "line": 30 | 3430 | "line": 32 |
3431 | }, | 3431 | }, |
3432 | "file": "src/features/workspaces/components/WorkspacesDashboard.js", | 3432 | "file": "src/features/workspaces/components/WorkspacesDashboard.js", |
3433 | "id": "settings.workspaces.tryReloadWorkspaces", | 3433 | "id": "settings.workspaces.tryReloadWorkspaces", |
3434 | "start": { | 3434 | "start": { |
3435 | "column": 23, | 3435 | "column": 23, |
3436 | "line": 27 | 3436 | "line": 29 |
3437 | } | 3437 | } |
3438 | }, | 3438 | }, |
3439 | { | 3439 | { |
3440 | "defaultMessage": "!!!Your changes have been saved", | 3440 | "defaultMessage": "!!!Your changes have been saved", |
3441 | "end": { | 3441 | "end": { |
3442 | "column": 3, | 3442 | "column": 3, |
3443 | "line": 34 | 3443 | "line": 36 |
3444 | }, | 3444 | }, |
3445 | "file": "src/features/workspaces/components/WorkspacesDashboard.js", | 3445 | "file": "src/features/workspaces/components/WorkspacesDashboard.js", |
3446 | "id": "settings.workspaces.updatedInfo", | 3446 | "id": "settings.workspaces.updatedInfo", |
3447 | "start": { | 3447 | "start": { |
3448 | "column": 15, | 3448 | "column": 15, |
3449 | "line": 31 | 3449 | "line": 33 |
3450 | } | 3450 | } |
3451 | }, | 3451 | }, |
3452 | { | 3452 | { |
3453 | "defaultMessage": "!!!Workspace has been deleted", | 3453 | "defaultMessage": "!!!Workspace has been deleted", |
3454 | "end": { | 3454 | "end": { |
3455 | "column": 3, | 3455 | "column": 3, |
3456 | "line": 38 | 3456 | "line": 40 |
3457 | }, | 3457 | }, |
3458 | "file": "src/features/workspaces/components/WorkspacesDashboard.js", | 3458 | "file": "src/features/workspaces/components/WorkspacesDashboard.js", |
3459 | "id": "settings.workspaces.deletedInfo", | 3459 | "id": "settings.workspaces.deletedInfo", |
3460 | "start": { | 3460 | "start": { |
3461 | "column": 15, | 3461 | "column": 15, |
3462 | "line": 35 | 3462 | "line": 37 |
3463 | } | ||
3464 | }, | ||
3465 | { | ||
3466 | "defaultMessage": "!!!Info about workspace feature", | ||
3467 | "end": { | ||
3468 | "column": 3, | ||
3469 | "line": 44 | ||
3470 | }, | ||
3471 | "file": "src/features/workspaces/components/WorkspacesDashboard.js", | ||
3472 | "id": "settings.workspaces.workspaceFeatureInfo", | ||
3473 | "start": { | ||
3474 | "column": 24, | ||
3475 | "line": 41 | ||
3476 | } | ||
3477 | }, | ||
3478 | { | ||
3479 | "defaultMessage": "!!!Less is More: Introducing Franz Workspaces", | ||
3480 | "end": { | ||
3481 | "column": 3, | ||
3482 | "line": 48 | ||
3483 | }, | ||
3484 | "file": "src/features/workspaces/components/WorkspacesDashboard.js", | ||
3485 | "id": "settings.workspaces.workspaceFeatureHeadline", | ||
3486 | "start": { | ||
3487 | "column": 28, | ||
3488 | "line": 45 | ||
3463 | } | 3489 | } |
3464 | } | 3490 | } |
3465 | ], | 3491 | ], |
diff --git a/src/i18n/locales/en-US.json b/src/i18n/locales/en-US.json index 5f7254317..987262c35 100644 --- a/src/i18n/locales/en-US.json +++ b/src/i18n/locales/en-US.json | |||
@@ -254,6 +254,8 @@ | |||
254 | "settings.workspaces.noWorkspacesAdded": "You haven't added any workspaces yet.", | 254 | "settings.workspaces.noWorkspacesAdded": "You haven't added any workspaces yet.", |
255 | "settings.workspaces.tryReloadWorkspaces": "Try again", | 255 | "settings.workspaces.tryReloadWorkspaces": "Try again", |
256 | "settings.workspaces.updatedInfo": "Your changes have been saved", | 256 | "settings.workspaces.updatedInfo": "Your changes have been saved", |
257 | "settings.workspaces.workspaceFeatureHeadline": "Less is More: Introducing Franz Workspaces", | ||
258 | "settings.workspaces.workspaceFeatureInfo": "Franz Workspaces let you focus on what’s important right now. Set up different sets of services and easily switch between them at any time. You decide which services you need when and where, so we can help you stay on top of your game - or easily switch off from work whenever you want.", | ||
257 | "settings.workspaces.workspacesRequestFailed": "Could not load your workspaces", | 259 | "settings.workspaces.workspacesRequestFailed": "Could not load your workspaces", |
258 | "sidebar.addNewService": "Add new service", | 260 | "sidebar.addNewService": "Add new service", |
259 | "sidebar.closeWorkspaceDrawer": "Close workspace drawer", | 261 | "sidebar.closeWorkspaceDrawer": "Close workspace drawer", |
diff --git a/src/i18n/messages/src/components/ui/PremiumFeatureContainer/index.json b/src/i18n/messages/src/components/ui/PremiumFeatureContainer/index.json index 582d546fa..320d3ca3e 100644 --- a/src/i18n/messages/src/components/ui/PremiumFeatureContainer/index.json +++ b/src/i18n/messages/src/components/ui/PremiumFeatureContainer/index.json | |||
@@ -4,11 +4,11 @@ | |||
4 | "defaultMessage": "!!!Upgrade account", | 4 | "defaultMessage": "!!!Upgrade account", |
5 | "file": "src/components/ui/PremiumFeatureContainer/index.js", | 5 | "file": "src/components/ui/PremiumFeatureContainer/index.js", |
6 | "start": { | 6 | "start": { |
7 | "line": 14, | 7 | "line": 15, |
8 | "column": 10 | 8 | "column": 10 |
9 | }, | 9 | }, |
10 | "end": { | 10 | "end": { |
11 | "line": 17, | 11 | "line": 18, |
12 | "column": 3 | 12 | "column": 3 |
13 | } | 13 | } |
14 | } | 14 | } |
diff --git a/src/i18n/messages/src/features/workspaces/components/WorkspacesDashboard.json b/src/i18n/messages/src/features/workspaces/components/WorkspacesDashboard.json index a957358c8..ef8f1bebc 100644 --- a/src/i18n/messages/src/features/workspaces/components/WorkspacesDashboard.json +++ b/src/i18n/messages/src/features/workspaces/components/WorkspacesDashboard.json | |||
@@ -4,11 +4,11 @@ | |||
4 | "defaultMessage": "!!!Your workspaces", | 4 | "defaultMessage": "!!!Your workspaces", |
5 | "file": "src/features/workspaces/components/WorkspacesDashboard.js", | 5 | "file": "src/features/workspaces/components/WorkspacesDashboard.js", |
6 | "start": { | 6 | "start": { |
7 | "line": 15, | 7 | "line": 17, |
8 | "column": 12 | 8 | "column": 12 |
9 | }, | 9 | }, |
10 | "end": { | 10 | "end": { |
11 | "line": 18, | 11 | "line": 20, |
12 | "column": 3 | 12 | "column": 3 |
13 | } | 13 | } |
14 | }, | 14 | }, |
@@ -17,11 +17,11 @@ | |||
17 | "defaultMessage": "!!!You haven't added any workspaces yet.", | 17 | "defaultMessage": "!!!You haven't added any workspaces yet.", |
18 | "file": "src/features/workspaces/components/WorkspacesDashboard.js", | 18 | "file": "src/features/workspaces/components/WorkspacesDashboard.js", |
19 | "start": { | 19 | "start": { |
20 | "line": 19, | 20 | "line": 21, |
21 | "column": 19 | 21 | "column": 19 |
22 | }, | 22 | }, |
23 | "end": { | 23 | "end": { |
24 | "line": 22, | 24 | "line": 24, |
25 | "column": 3 | 25 | "column": 3 |
26 | } | 26 | } |
27 | }, | 27 | }, |
@@ -30,11 +30,11 @@ | |||
30 | "defaultMessage": "!!!Could not load your workspaces", | 30 | "defaultMessage": "!!!Could not load your workspaces", |
31 | "file": "src/features/workspaces/components/WorkspacesDashboard.js", | 31 | "file": "src/features/workspaces/components/WorkspacesDashboard.js", |
32 | "start": { | 32 | "start": { |
33 | "line": 23, | 33 | "line": 25, |
34 | "column": 27 | 34 | "column": 27 |
35 | }, | 35 | }, |
36 | "end": { | 36 | "end": { |
37 | "line": 26, | 37 | "line": 28, |
38 | "column": 3 | 38 | "column": 3 |
39 | } | 39 | } |
40 | }, | 40 | }, |
@@ -43,11 +43,11 @@ | |||
43 | "defaultMessage": "!!!Try again", | 43 | "defaultMessage": "!!!Try again", |
44 | "file": "src/features/workspaces/components/WorkspacesDashboard.js", | 44 | "file": "src/features/workspaces/components/WorkspacesDashboard.js", |
45 | "start": { | 45 | "start": { |
46 | "line": 27, | 46 | "line": 29, |
47 | "column": 23 | 47 | "column": 23 |
48 | }, | 48 | }, |
49 | "end": { | 49 | "end": { |
50 | "line": 30, | 50 | "line": 32, |
51 | "column": 3 | 51 | "column": 3 |
52 | } | 52 | } |
53 | }, | 53 | }, |
@@ -56,11 +56,11 @@ | |||
56 | "defaultMessage": "!!!Your changes have been saved", | 56 | "defaultMessage": "!!!Your changes have been saved", |
57 | "file": "src/features/workspaces/components/WorkspacesDashboard.js", | 57 | "file": "src/features/workspaces/components/WorkspacesDashboard.js", |
58 | "start": { | 58 | "start": { |
59 | "line": 31, | 59 | "line": 33, |
60 | "column": 15 | 60 | "column": 15 |
61 | }, | 61 | }, |
62 | "end": { | 62 | "end": { |
63 | "line": 34, | 63 | "line": 36, |
64 | "column": 3 | 64 | "column": 3 |
65 | } | 65 | } |
66 | }, | 66 | }, |
@@ -69,11 +69,37 @@ | |||
69 | "defaultMessage": "!!!Workspace has been deleted", | 69 | "defaultMessage": "!!!Workspace has been deleted", |
70 | "file": "src/features/workspaces/components/WorkspacesDashboard.js", | 70 | "file": "src/features/workspaces/components/WorkspacesDashboard.js", |
71 | "start": { | 71 | "start": { |
72 | "line": 35, | 72 | "line": 37, |
73 | "column": 15 | 73 | "column": 15 |
74 | }, | 74 | }, |
75 | "end": { | 75 | "end": { |
76 | "line": 38, | 76 | "line": 40, |
77 | "column": 3 | ||
78 | } | ||
79 | }, | ||
80 | { | ||
81 | "id": "settings.workspaces.workspaceFeatureInfo", | ||
82 | "defaultMessage": "!!!Info about workspace feature", | ||
83 | "file": "src/features/workspaces/components/WorkspacesDashboard.js", | ||
84 | "start": { | ||
85 | "line": 41, | ||
86 | "column": 24 | ||
87 | }, | ||
88 | "end": { | ||
89 | "line": 44, | ||
90 | "column": 3 | ||
91 | } | ||
92 | }, | ||
93 | { | ||
94 | "id": "settings.workspaces.workspaceFeatureHeadline", | ||
95 | "defaultMessage": "!!!Less is More: Introducing Franz Workspaces", | ||
96 | "file": "src/features/workspaces/components/WorkspacesDashboard.js", | ||
97 | "start": { | ||
98 | "line": 45, | ||
99 | "column": 28 | ||
100 | }, | ||
101 | "end": { | ||
102 | "line": 48, | ||
77 | "column": 3 | 103 | "column": 3 |
78 | } | 104 | } |
79 | } | 105 | } |
diff --git a/src/lib/Menu.js b/src/lib/Menu.js index d19aa9d6e..a4e41c17c 100644 --- a/src/lib/Menu.js +++ b/src/lib/Menu.js | |||
@@ -323,7 +323,7 @@ const _templateFactory = intl => [ | |||
323 | { | 323 | { |
324 | label: intl.formatMessage(menuItems.workspaces), | 324 | label: intl.formatMessage(menuItems.workspaces), |
325 | submenu: [], | 325 | submenu: [], |
326 | visible: workspaceStore.isFeatureActive, | 326 | visible: workspaceStore.isFeatureEnabled, |
327 | }, | 327 | }, |
328 | { | 328 | { |
329 | label: intl.formatMessage(menuItems.window), | 329 | label: intl.formatMessage(menuItems.window), |
@@ -732,7 +732,7 @@ export default class FranzMenu { | |||
732 | tpl[3].submenu = serviceTpl; | 732 | tpl[3].submenu = serviceTpl; |
733 | } | 733 | } |
734 | 734 | ||
735 | if (workspaceStore.isFeatureActive) { | 735 | if (workspaceStore.isFeatureEnabled) { |
736 | tpl[4].submenu = this.workspacesMenu(); | 736 | tpl[4].submenu = this.workspacesMenu(); |
737 | } | 737 | } |
738 | 738 | ||
diff --git a/src/stores/FeaturesStore.js b/src/stores/FeaturesStore.js index 2bda82e17..52e38ad96 100644 --- a/src/stores/FeaturesStore.js +++ b/src/stores/FeaturesStore.js | |||
@@ -1,4 +1,4 @@ | |||
1 | import { computed, observable, reaction } from 'mobx'; | 1 | import { computed, observable, reaction, runInAction } from 'mobx'; |
2 | 2 | ||
3 | import Store from './lib/Store'; | 3 | import Store from './lib/Store'; |
4 | import CachedRequest from './lib/CachedRequest'; | 4 | import CachedRequest from './lib/CachedRequest'; |
@@ -17,8 +17,11 @@ export default class FeaturesStore extends Store { | |||
17 | 17 | ||
18 | @observable featuresRequest = new CachedRequest(this.api.features, 'features'); | 18 | @observable featuresRequest = new CachedRequest(this.api.features, 'features'); |
19 | 19 | ||
20 | @observable features = Object.assign({}, DEFAULT_FEATURES_CONFIG); | ||
21 | |||
20 | async setup() { | 22 | async setup() { |
21 | this.registerReactions([ | 23 | this.registerReactions([ |
24 | this._updateFeatures, | ||
22 | this._monitorLoginStatus.bind(this), | 25 | this._monitorLoginStatus.bind(this), |
23 | ]); | 26 | ]); |
24 | 27 | ||
@@ -37,13 +40,16 @@ export default class FeaturesStore extends Store { | |||
37 | return this.defaultFeaturesRequest.execute().result || DEFAULT_FEATURES_CONFIG; | 40 | return this.defaultFeaturesRequest.execute().result || DEFAULT_FEATURES_CONFIG; |
38 | } | 41 | } |
39 | 42 | ||
40 | @computed get features() { | 43 | _updateFeatures = () => { |
44 | const features = Object.assign({}, DEFAULT_FEATURES_CONFIG); | ||
41 | if (this.stores.user.isLoggedIn) { | 45 | if (this.stores.user.isLoggedIn) { |
42 | return Object.assign({}, DEFAULT_FEATURES_CONFIG, this.featuresRequest.execute().result); | 46 | const requestResult = this.featuresRequest.execute().result; |
47 | Object.assign(features, requestResult); | ||
43 | } | 48 | } |
44 | 49 | runInAction('FeaturesStore::_updateFeatures', () => { | |
45 | return DEFAULT_FEATURES_CONFIG; | 50 | this.features = features; |
46 | } | 51 | }); |
52 | }; | ||
47 | 53 | ||
48 | _monitorLoginStatus() { | 54 | _monitorLoginStatus() { |
49 | if (this.stores.user.isLoggedIn) { | 55 | if (this.stores.user.isLoggedIn) { |