diff options
author | Dominik Guzei <dominik.guzei@gmail.com> | 2019-03-28 16:23:17 +0100 |
---|---|---|
committer | Dominik Guzei <dominik.guzei@gmail.com> | 2019-03-28 16:23:17 +0100 |
commit | 7941831bf773b49944001c095a1949a1bdec2cf2 (patch) | |
tree | 5dbcbf097e340c381617410e032c2db6b811096e /src/features | |
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
Diffstat (limited to 'src/features')
-rw-r--r-- | src/features/delayApp/index.js | 2 | ||||
-rw-r--r-- | src/features/utils/FeatureStore.js | 21 | ||||
-rw-r--r-- | src/features/workspaces/components/CreateWorkspaceForm.js | 1 | ||||
-rw-r--r-- | src/features/workspaces/components/WorkspacesDashboard.js | 42 | ||||
-rw-r--r-- | src/features/workspaces/index.js | 3 | ||||
-rw-r--r-- | src/features/workspaces/store.js | 69 |
6 files changed, 98 insertions, 40 deletions
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; |