aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorLibravatar Stefan Malzner <stefan@adlk.io>2019-09-04 15:37:56 +0200
committerLibravatar Stefan Malzner <stefan@adlk.io>2019-09-04 15:37:56 +0200
commitc6dda35baf7eb9a7d89bf224c38973a1b6171c14 (patch)
tree98f562911fcccc356a0594427f6891ce0e12f22a /src
parentFix icons & button color (diff)
downloadferdium-app-c6dda35baf7eb9a7d89bf224c38973a1b6171c14.tar.gz
ferdium-app-c6dda35baf7eb9a7d89bf224c38973a1b6171c14.tar.zst
ferdium-app-c6dda35baf7eb9a7d89bf224c38973a1b6171c14.zip
bugfixing & polishing
Diffstat (limited to 'src')
-rw-r--r--src/assets/images/workspaces/teaser_dark.pngbin0 -> 179047 bytes
-rw-r--r--src/assets/images/workspaces/teaser_light.pngbin0 -> 182321 bytes
-rw-r--r--src/components/settings/account/AccountDashboard.js19
-rw-r--r--src/components/settings/recipes/RecipesDashboard.js4
-rw-r--r--src/components/subscription/TrialForm.js3
-rw-r--r--src/components/ui/ActivateTrialButton/index.js115
-rw-r--r--src/components/ui/FeatureItem.js2
-rw-r--r--src/components/ui/PremiumFeatureContainer/index.js22
-rw-r--r--src/config.js4
-rw-r--r--src/containers/settings/AccountScreen.js1
-rw-r--r--src/features/todos/components/TodosWebview.js14
-rw-r--r--src/features/todos/containers/TodosScreen.js6
-rw-r--r--src/features/todos/store.js3
-rw-r--r--src/features/workspaces/components/WorkspacesDashboard.js50
-rw-r--r--src/features/workspaces/store.js5
-rw-r--r--src/helpers/plan-helpers.js10
-rw-r--r--src/i18n/locales/defaultMessages.json133
-rw-r--r--src/i18n/locales/en-US.json2
-rw-r--r--src/i18n/messages/src/components/ui/ActivateTrialButton/index.json54
-rw-r--r--src/i18n/messages/src/components/ui/PremiumFeatureContainer/index.json4
-rw-r--r--src/i18n/messages/src/features/todos/components/TodosWebview.json12
-rw-r--r--src/i18n/messages/src/features/workspaces/components/WorkspacesDashboard.json32
-rw-r--r--src/stores/UserStore.js22
23 files changed, 411 insertions, 106 deletions
diff --git a/src/assets/images/workspaces/teaser_dark.png b/src/assets/images/workspaces/teaser_dark.png
new file mode 100644
index 000000000..5b6d7334b
--- /dev/null
+++ b/src/assets/images/workspaces/teaser_dark.png
Binary files differ
diff --git a/src/assets/images/workspaces/teaser_light.png b/src/assets/images/workspaces/teaser_light.png
new file mode 100644
index 000000000..635af43fa
--- /dev/null
+++ b/src/assets/images/workspaces/teaser_light.png
Binary files differ
diff --git a/src/components/settings/account/AccountDashboard.js b/src/components/settings/account/AccountDashboard.js
index 900a83a78..4fd1e8163 100644
--- a/src/components/settings/account/AccountDashboard.js
+++ b/src/components/settings/account/AccountDashboard.js
@@ -93,9 +93,11 @@ const messages = defineMessages({
93 }, 93 },
94}); 94});
95 95
96export default @observer class AccountDashboard extends Component { 96@observer
97class AccountDashboard extends Component {
97 static propTypes = { 98 static propTypes = {
98 user: MobxPropTypes.observableObject.isRequired, 99 user: MobxPropTypes.observableObject.isRequired,
100 isProUser: PropTypes.bool.isRequired,
99 isLoading: PropTypes.bool.isRequired, 101 isLoading: PropTypes.bool.isRequired,
100 userInfoRequestFailed: PropTypes.bool.isRequired, 102 userInfoRequestFailed: PropTypes.bool.isRequired,
101 retryUserInfoRequest: PropTypes.func.isRequired, 103 retryUserInfoRequest: PropTypes.func.isRequired,
@@ -115,6 +117,7 @@ export default @observer class AccountDashboard extends Component {
115 render() { 117 render() {
116 const { 118 const {
117 user, 119 user,
120 isProUser,
118 isLoading, 121 isLoading,
119 userInfoRequestFailed, 122 userInfoRequestFailed,
120 retryUserInfoRequest, 123 retryUserInfoRequest,
@@ -234,11 +237,13 @@ export default @observer class AccountDashboard extends Component {
234 </> 237 </>
235 )} 238 )}
236 <div className="manage-user-links"> 239 <div className="manage-user-links">
237 <Button 240 {!isProUser && (
238 label={intl.formatMessage(messages.upgradeAccountToPro)} 241 <Button
239 className="franz-form__button--primary" 242 label={intl.formatMessage(messages.upgradeAccountToPro)}
240 onClick={upgradeToPro} 243 className="franz-form__button--primary"
241 /> 244 onClick={upgradeToPro}
245 />
246 )}
242 <Button 247 <Button
243 label={intl.formatMessage(messages.manageSubscriptionButtonLabel)} 248 label={intl.formatMessage(messages.manageSubscriptionButtonLabel)}
244 className="franz-form__button--inverted" 249 className="franz-form__button--inverted"
@@ -290,3 +295,5 @@ export default @observer class AccountDashboard extends Component {
290 ); 295 );
291 } 296 }
292} 297}
298
299export default AccountDashboard;
diff --git a/src/components/settings/recipes/RecipesDashboard.js b/src/components/settings/recipes/RecipesDashboard.js
index 75e60b7ec..08988024a 100644
--- a/src/components/settings/recipes/RecipesDashboard.js
+++ b/src/components/settings/recipes/RecipesDashboard.js
@@ -218,7 +218,7 @@ export default @injectSheet(styles) @observer class RecipesDashboard extends Com
218 <> 218 <>
219 <H2> 219 <H2>
220 {intl.formatMessage(messages.headlineCustomRecipes)} 220 {intl.formatMessage(messages.headlineCustomRecipes)}
221 {isCommunityRecipesIncludedInCurrentPlan && ( 221 {!isCommunityRecipesIncludedInCurrentPlan && (
222 <ProBadge className={classes.proBadge} /> 222 <ProBadge className={classes.proBadge} />
223 )} 223 )}
224 </H2> 224 </H2>
@@ -247,7 +247,7 @@ export default @injectSheet(styles) @observer class RecipesDashboard extends Com
247 </> 247 </>
248 )} 248 )}
249 <PremiumFeatureContainer 249 <PremiumFeatureContainer
250 condition={(recipeFilter === 'dev' && communityRecipes.length > 0) && isCommunityRecipesIncludedInCurrentPlan} 250 condition={(recipeFilter === 'dev' && communityRecipes.length > 0) && !isCommunityRecipesIncludedInCurrentPlan}
251 > 251 >
252 {recipeFilter === 'dev' && communityRecipes.length > 0 && ( 252 {recipeFilter === 'dev' && communityRecipes.length > 0 && (
253 <H3>{intl.formatMessage(messages.headlineCommunityRecipes)}</H3> 253 <H3>{intl.formatMessage(messages.headlineCommunityRecipes)}</H3>
diff --git a/src/components/subscription/TrialForm.js b/src/components/subscription/TrialForm.js
index 9fe1c93b7..9ed548f16 100644
--- a/src/components/subscription/TrialForm.js
+++ b/src/components/subscription/TrialForm.js
@@ -41,7 +41,7 @@ const messages = defineMessages({
41 }, 41 },
42}); 42});
43 43
44const styles = () => ({ 44const styles = theme => ({
45 activateTrialButton: { 45 activateTrialButton: {
46 margin: [40, 0, 10], 46 margin: [40, 0, 10],
47 }, 47 },
@@ -49,6 +49,7 @@ const styles = () => ({
49 margin: [0, 0, 40], 49 margin: [0, 0, 40],
50 background: 'none', 50 background: 'none',
51 border: 'none', 51 border: 'none',
52 color: theme.colorText,
52 }, 53 },
53 keyTerms: { 54 keyTerms: {
54 marginTop: 20, 55 marginTop: 20,
diff --git a/src/components/ui/ActivateTrialButton/index.js b/src/components/ui/ActivateTrialButton/index.js
new file mode 100644
index 000000000..c3e5f4a6f
--- /dev/null
+++ b/src/components/ui/ActivateTrialButton/index.js
@@ -0,0 +1,115 @@
1import React, { Component } from 'react';
2import PropTypes from 'prop-types';
3import { inject, observer } from 'mobx-react';
4import { defineMessages, intlShape } from 'react-intl';
5import classnames from 'classnames';
6
7import { Button } from '@meetfranz/forms';
8import { gaEvent } from '../../../lib/analytics';
9
10import UserStore from '../../../stores/UserStore';
11
12const messages = defineMessages({
13 action: {
14 id: 'feature.delayApp.upgrade.action',
15 defaultMessage: '!!!Get a Franz Supporter License',
16 },
17 actionTrial: {
18 id: 'feature.delayApp.trial.action',
19 defaultMessage: '!!!Yes, I want the free 14 day trial of Franz Professional',
20 },
21 shortAction: {
22 id: 'feature.delayApp.upgrade.actionShort',
23 defaultMessage: '!!!Upgrade account',
24 },
25 shortActionTrial: {
26 id: 'feature.delayApp.trial.actionShort',
27 defaultMessage: '!!!Activate the free Franz Professional trial',
28 },
29});
30
31@inject('stores', 'actions') @observer
32class ActivateTrialButton extends Component {
33 static propTypes = {
34 // eslint-disable-next-line
35 classes: PropTypes.object.isRequired,
36 className: PropTypes.string,
37 short: PropTypes.bool,
38 gaEventInfo: PropTypes.shape({
39 category: PropTypes.string.isRequired,
40 event: PropTypes.string.isRequired,
41 label: PropTypes.string,
42 }),
43 };
44
45 static defaultProps = {
46 className: '',
47 short: false,
48 gaEventInfo: null,
49 }
50
51 static contextTypes = {
52 intl: intlShape,
53 };
54
55 handleCTAClick() {
56 const { actions, stores, gaEventInfo } = this.props;
57 const { hadSubscription } = stores.user.data;
58 const { defaultTrialPlan } = stores.features.features;
59
60 let label = '';
61 if (!hadSubscription) {
62 actions.user.activateTrial({ planId: defaultTrialPlan });
63
64 label = 'Start Trial';
65 } else {
66 actions.ui.openSettings({ path: 'user' });
67
68 label = 'Upgrade Account';
69 }
70
71 if (gaEventInfo) {
72 const { category, event } = gaEventInfo;
73 gaEvent(category, event, label);
74 }
75 }
76
77 render() {
78 const { stores, className, short } = this.props;
79 const { intl } = this.context;
80
81 const { hadSubscription } = stores.user.data;
82
83 let label;
84 if (hadSubscription) {
85 label = short ? messages.shortAction : messages.action;
86 } else {
87 label = short ? messages.shortActionTrial : messages.actionTrial;
88 }
89
90 return (
91 <Button
92 label={intl.formatMessage(label)}
93 className={classnames({
94 [className]: className,
95 })}
96 buttonType="inverted"
97 onClick={this.handleCTAClick.bind(this)}
98 busy={stores.user.activateTrialRequest.isExecuting}
99 />
100 );
101 }
102}
103
104export default ActivateTrialButton;
105
106ActivateTrialButton.wrappedComponent.propTypes = {
107 stores: PropTypes.shape({
108 user: PropTypes.instanceOf(UserStore).isRequired,
109 }).isRequired,
110 actions: PropTypes.shape({
111 ui: PropTypes.shape({
112 openSettings: PropTypes.func.isRequired,
113 }).isRequired,
114 }).isRequired,
115};
diff --git a/src/components/ui/FeatureItem.js b/src/components/ui/FeatureItem.js
index 53616f2eb..7c482c4d4 100644
--- a/src/components/ui/FeatureItem.js
+++ b/src/components/ui/FeatureItem.js
@@ -6,7 +6,7 @@ import { mdiCheckCircle } from '@mdi/js';
6 6
7const styles = theme => ({ 7const styles = theme => ({
8 featureItem: { 8 featureItem: {
9 borderBottom: [1, 'solid', theme.legacyStyles.themeGrayDark], 9 borderBottom: [1, 'solid', theme.defaultContentBorder],
10 padding: [8, 0], 10 padding: [8, 0],
11 display: 'flex', 11 display: 'flex',
12 alignItems: 'center', 12 alignItems: 'center',
diff --git a/src/components/ui/PremiumFeatureContainer/index.js b/src/components/ui/PremiumFeatureContainer/index.js
index 3c1e0fac3..8d2746e22 100644
--- a/src/components/ui/PremiumFeatureContainer/index.js
+++ b/src/components/ui/PremiumFeatureContainer/index.js
@@ -10,6 +10,7 @@ import UserStore from '../../../stores/UserStore';
10 10
11import styles from './styles'; 11import styles from './styles';
12import { gaEvent } from '../../../lib/analytics'; 12import { gaEvent } from '../../../lib/analytics';
13import { FeatureStore } from '../../../features/utils/FeatureStore';
13 14
14const messages = defineMessages({ 15const messages = defineMessages({
15 action: { 16 action: {
@@ -22,7 +23,10 @@ const messages = defineMessages({
22class PremiumFeatureContainer extends Component { 23class PremiumFeatureContainer extends Component {
23 static propTypes = { 24 static propTypes = {
24 classes: PropTypes.object.isRequired, 25 classes: PropTypes.object.isRequired,
25 condition: PropTypes.bool, 26 condition: PropTypes.oneOfType([
27 PropTypes.bool,
28 PropTypes.func,
29 ]),
26 gaEventInfo: PropTypes.shape({ 30 gaEventInfo: PropTypes.shape({
27 category: PropTypes.string.isRequired, 31 category: PropTypes.string.isRequired,
28 event: PropTypes.string.isRequired, 32 event: PropTypes.string.isRequired,
@@ -31,7 +35,7 @@ class PremiumFeatureContainer extends Component {
31 }; 35 };
32 36
33 static defaultProps = { 37 static defaultProps = {
34 condition: true, 38 condition: null,
35 gaEventInfo: null, 39 gaEventInfo: null,
36 }; 40 };
37 41
@@ -51,7 +55,18 @@ class PremiumFeatureContainer extends Component {
51 55
52 const { intl } = this.context; 56 const { intl } = this.context;
53 57
54 return !stores.user.data.isPremium && !!condition ? ( 58 let showWrapper = !!condition;
59
60 if (condition === null) {
61 showWrapper = !stores.user.data.isPremium;
62 } else if (typeof condition === 'function') {
63 showWrapper = condition({
64 isPremium: stores.user.data.isPremium,
65 features: stores.features.features,
66 });
67 }
68
69 return showWrapper ? (
55 <div className={classes.container}> 70 <div className={classes.container}>
56 <div className={classes.titleContainer}> 71 <div className={classes.titleContainer}>
57 <p className={classes.title}>Premium Feature</p> 72 <p className={classes.title}>Premium Feature</p>
@@ -81,6 +96,7 @@ PremiumFeatureContainer.wrappedComponent.propTypes = {
81 children: oneOrManyChildElements.isRequired, 96 children: oneOrManyChildElements.isRequired,
82 stores: PropTypes.shape({ 97 stores: PropTypes.shape({
83 user: PropTypes.instanceOf(UserStore).isRequired, 98 user: PropTypes.instanceOf(UserStore).isRequired,
99 features: PropTypes.instanceOf(FeatureStore).isRequired,
84 }).isRequired, 100 }).isRequired,
85 actions: PropTypes.shape({ 101 actions: PropTypes.shape({
86 ui: PropTypes.shape({ 102 ui: PropTypes.shape({
diff --git a/src/config.js b/src/config.js
index 405cc5253..fba739ddd 100644
--- a/src/config.js
+++ b/src/config.js
@@ -91,8 +91,8 @@ export const ALLOWED_PROTOCOLS = [
91]; 91];
92 92
93export const PLANS = { 93export const PLANS = {
94 PERSONAL: 'PERSONAL_MONTHLY', 94 PERSONAL: 'PERSONAL',
95 PRO: 'PRO_MONTHLY', 95 PRO: 'PRO',
96 LEGACY: 'LEGACY', 96 LEGACY: 'LEGACY',
97 FREE: 'FREE', 97 FREE: 'FREE',
98}; 98};
diff --git a/src/containers/settings/AccountScreen.js b/src/containers/settings/AccountScreen.js
index f9eae4957..2b5eba91c 100644
--- a/src/containers/settings/AccountScreen.js
+++ b/src/containers/settings/AccountScreen.js
@@ -42,6 +42,7 @@ export default @inject('stores', 'actions') @observer class AccountScreen extend
42 <ErrorBoundary> 42 <ErrorBoundary>
43 <AccountDashboard 43 <AccountDashboard
44 user={user.data} 44 user={user.data}
45 isProUser={user.isPro}
45 isLoading={isLoadingUserInfo} 46 isLoading={isLoadingUserInfo}
46 isLoadingPlans={isLoadingPlans} 47 isLoadingPlans={isLoadingPlans}
47 userInfoRequestFailed={user.getUserInfoRequest.wasExecuted && user.getUserInfoRequest.isError} 48 userInfoRequestFailed={user.getUserInfoRequest.wasExecuted && user.getUserInfoRequest.isError}
diff --git a/src/features/todos/components/TodosWebview.js b/src/features/todos/components/TodosWebview.js
index d8d96ba85..9cf925444 100644
--- a/src/features/todos/components/TodosWebview.js
+++ b/src/features/todos/components/TodosWebview.js
@@ -10,6 +10,7 @@ import { mdiChevronRight, mdiCheckAll } from '@mdi/js';
10import { Button } from '@meetfranz/forms'; 10import { Button } from '@meetfranz/forms';
11import * as environment from '../../../environment'; 11import * as environment from '../../../environment';
12import Appear from '../../../components/ui/effects/Appear'; 12import Appear from '../../../components/ui/effects/Appear';
13import ActivateTrialButton from '../../../components/ui/activateTrialButton';
13 14
14const OPEN_TODOS_BUTTON_SIZE = 45; 15const OPEN_TODOS_BUTTON_SIZE = 45;
15const CLOSE_TODOS_BUTTON_SIZE = 35; 16const CLOSE_TODOS_BUTTON_SIZE = 35;
@@ -70,7 +71,7 @@ const styles = theme => ({
70 height: OPEN_TODOS_BUTTON_SIZE, 71 height: OPEN_TODOS_BUTTON_SIZE,
71 background: theme.todos.toggleButton.background, 72 background: theme.todos.toggleButton.background,
72 position: 'absolute', 73 position: 'absolute',
73 bottom: 80, 74 bottom: 120,
74 right: props => (props.width + (props.isVisible ? -OPEN_TODOS_BUTTON_SIZE / 2 : 0)), 75 right: props => (props.width + (props.isVisible ? -OPEN_TODOS_BUTTON_SIZE / 2 : 0)),
75 borderRadius: OPEN_TODOS_BUTTON_SIZE / 2, 76 borderRadius: OPEN_TODOS_BUTTON_SIZE / 2,
76 opacity: props => (props.isVisible ? 0 : 1), 77 opacity: props => (props.isVisible ? 0 : 1),
@@ -94,7 +95,7 @@ const styles = theme => ({
94 height: CLOSE_TODOS_BUTTON_SIZE, 95 height: CLOSE_TODOS_BUTTON_SIZE,
95 background: theme.todos.toggleButton.background, 96 background: theme.todos.toggleButton.background,
96 position: 'absolute', 97 position: 'absolute',
97 bottom: 80, 98 bottom: 120,
98 right: ({ width }) => (width + -CLOSE_TODOS_BUTTON_SIZE / 2), 99 right: ({ width }) => (width + -CLOSE_TODOS_BUTTON_SIZE / 2),
99 borderRadius: CLOSE_TODOS_BUTTON_SIZE / 2, 100 borderRadius: CLOSE_TODOS_BUTTON_SIZE / 2,
100 opacity: ({ isTodosIncludedInCurrentPlan }) => (!isTodosIncludedInCurrentPlan ? 1 : 0), 101 opacity: ({ isTodosIncludedInCurrentPlan }) => (!isTodosIncludedInCurrentPlan ? 1 : 0),
@@ -143,7 +144,6 @@ class TodosWebview extends Component {
143 width: PropTypes.number.isRequired, 144 width: PropTypes.number.isRequired,
144 minWidth: PropTypes.number.isRequired, 145 minWidth: PropTypes.number.isRequired,
145 isTodosIncludedInCurrentPlan: PropTypes.bool.isRequired, 146 isTodosIncludedInCurrentPlan: PropTypes.bool.isRequired,
146 upgradeAccount: PropTypes.func.isRequired,
147 }; 147 };
148 148
149 state = { 149 state = {
@@ -235,7 +235,6 @@ class TodosWebview extends Component {
235 isVisible, 235 isVisible,
236 togglePanel, 236 togglePanel,
237 isTodosIncludedInCurrentPlan, 237 isTodosIncludedInCurrentPlan,
238 upgradeAccount,
239 } = this.props; 238 } = this.props;
240 239
241 const { 240 const {
@@ -291,11 +290,10 @@ class TodosWebview extends Component {
291 <Icon icon={mdiCheckAll} className={classes.premiumIcon} size={5} /> 290 <Icon icon={mdiCheckAll} className={classes.premiumIcon} size={5} />
292 <p>{intl.formatMessage(messages.premiumInfo)}</p> 291 <p>{intl.formatMessage(messages.premiumInfo)}</p>
293 <p>{intl.formatMessage(messages.rolloutInfo)}</p> 292 <p>{intl.formatMessage(messages.rolloutInfo)}</p>
294 <Button 293 <ActivateTrialButton
295 label={intl.formatMessage(messages.upgradeCTA)}
296 className={classes.premiumCTA} 294 className={classes.premiumCTA}
297 onClick={upgradeAccount} 295 gaEventInfo={{ category: 'Todos', event: 'upgrade' }}
298 buttonType="inverted" 296 short
299 /> 297 />
300 </div> 298 </div>
301 </Appear> 299 </Appear>
diff --git a/src/features/todos/containers/TodosScreen.js b/src/features/todos/containers/TodosScreen.js
index 7f3688828..65afc985b 100644
--- a/src/features/todos/containers/TodosScreen.js
+++ b/src/features/todos/containers/TodosScreen.js
@@ -26,7 +26,6 @@ class TodosScreen extends Component {
26 minWidth={TODOS_MIN_WIDTH} 26 minWidth={TODOS_MIN_WIDTH}
27 resize={width => todoActions.resize({ width })} 27 resize={width => todoActions.resize({ width })}
28 isTodosIncludedInCurrentPlan={this.props.stores.features.features.isTodosIncludedInCurrentPlan || false} 28 isTodosIncludedInCurrentPlan={this.props.stores.features.features.isTodosIncludedInCurrentPlan || false}
29 upgradeAccount={() => this.props.actions.ui.openSettings({ path: 'user' })}
30 /> 29 />
31 </ErrorBoundary> 30 </ErrorBoundary>
32 ); 31 );
@@ -39,9 +38,4 @@ TodosScreen.wrappedComponent.propTypes = {
39 stores: PropTypes.shape({ 38 stores: PropTypes.shape({
40 features: PropTypes.instanceOf(FeaturesStore).isRequired, 39 features: PropTypes.instanceOf(FeaturesStore).isRequired,
41 }).isRequired, 40 }).isRequired,
42 actions: PropTypes.shape({
43 ui: PropTypes.shape({
44 openSettings: PropTypes.func.isRequired,
45 }).isRequired,
46 }).isRequired,
47}; 41};
diff --git a/src/features/todos/store.js b/src/features/todos/store.js
index 7da3b7f49..56e117c6c 100644
--- a/src/features/todos/store.js
+++ b/src/features/todos/store.js
@@ -12,6 +12,7 @@ import { createReactions } from '../../stores/lib/Reaction';
12import { createActionBindings } from '../utils/ActionBinding'; 12import { createActionBindings } from '../utils/ActionBinding';
13import { DEFAULT_TODOS_WIDTH, TODOS_MIN_WIDTH, DEFAULT_TODOS_VISIBLE } from '.'; 13import { DEFAULT_TODOS_WIDTH, TODOS_MIN_WIDTH, DEFAULT_TODOS_VISIBLE } from '.';
14import { IPC } from './constants'; 14import { IPC } from './constants';
15import { state as delayAppState } from '../delayApp';
15 16
16const debug = require('debug')('Franz:feature:todos:store'); 17const debug = require('debug')('Franz:feature:todos:store');
17 18
@@ -29,7 +30,7 @@ export default class TodoStore extends FeatureStore {
29 } 30 }
30 31
31 @computed get isTodosPanelVisible() { 32 @computed get isTodosPanelVisible() {
32 if (this.stores.services.all.length === 0) return false; 33 if (this.stores.services.all.length === 0 || delayAppState.isDelayAppScreenVisible) return false;
33 if (this.settings.isTodosPanelVisible === undefined) return DEFAULT_TODOS_VISIBLE; 34 if (this.settings.isTodosPanelVisible === undefined) return DEFAULT_TODOS_VISIBLE;
34 35
35 return this.settings.isTodosPanelVisible; 36 return this.settings.isTodosPanelVisible;
diff --git a/src/features/workspaces/components/WorkspacesDashboard.js b/src/features/workspaces/components/WorkspacesDashboard.js
index 09c98ab8c..9e06a78e3 100644
--- a/src/features/workspaces/components/WorkspacesDashboard.js
+++ b/src/features/workspaces/components/WorkspacesDashboard.js
@@ -1,6 +1,6 @@
1import React, { Component, Fragment } from 'react'; 1import React, { Component, Fragment } from 'react';
2import PropTypes from 'prop-types'; 2import PropTypes from 'prop-types';
3import { observer, PropTypes as MobxPropTypes } from 'mobx-react'; 3import { observer, PropTypes as MobxPropTypes, inject } from 'mobx-react';
4import { defineMessages, intlShape } from 'react-intl'; 4import { defineMessages, intlShape } from 'react-intl';
5import injectSheet from 'react-jss'; 5import injectSheet from 'react-jss';
6import { Infobox } from '@meetfranz/ui'; 6import { Infobox } from '@meetfranz/ui';
@@ -12,6 +12,8 @@ import Request from '../../../stores/lib/Request';
12import Appear from '../../../components/ui/effects/Appear'; 12import Appear from '../../../components/ui/effects/Appear';
13import { workspaceStore } from '../index'; 13import { workspaceStore } from '../index';
14import PremiumFeatureContainer from '../../../components/ui/PremiumFeatureContainer'; 14import PremiumFeatureContainer from '../../../components/ui/PremiumFeatureContainer';
15import UIStore from '../../../stores/UIStore';
16import ActivateTrialButton from '../../../components/ui/activateTrialButton';
15 17
16const messages = defineMessages({ 18const messages = defineMessages({
17 headline: { 19 headline: {
@@ -62,17 +64,27 @@ const styles = theme => ({
62 height: 'auto', 64 height: 'auto',
63 }, 65 },
64 premiumAnnouncement: { 66 premiumAnnouncement: {
65 padding: '20px', 67 padding: 20,
66 backgroundColor: '#3498db', 68 // backgroundColor: '#3498db',
67 marginLeft: '-20px', 69 marginLeft: -20,
68 marginBottom: '20px', 70 marginBottom: 40,
71 paddingBottom: 40,
69 height: 'auto', 72 height: 'auto',
70 color: 'white', 73 display: 'flex',
71 borderRadius: theme.borderRadius, 74 borderBottom: [1, 'solid', theme.inputBackground],
75 },
76 teaserImage: {
77 width: 200,
78 height: '100%',
79 float: 'left',
80 margin: [-8, 0, 0, -20],
81 },
82 upgradeCTA: {
83 marginTop: 20,
72 }, 84 },
73}); 85});
74 86
75@injectSheet(styles) @observer 87@inject('stores') @injectSheet(styles) @observer
76class WorkspacesDashboard extends Component { 88class WorkspacesDashboard extends Component {
77 static propTypes = { 89 static propTypes = {
78 classes: PropTypes.object.isRequired, 90 classes: PropTypes.object.isRequired,
@@ -100,7 +112,9 @@ class WorkspacesDashboard extends Component {
100 onWorkspaceClick, 112 onWorkspaceClick,
101 workspaces, 113 workspaces,
102 } = this.props; 114 } = this.props;
115
103 const { intl } = this.context; 116 const { intl } = this.context;
117
104 return ( 118 return (
105 <div className="settings__main"> 119 <div className="settings__main">
106 <div className="settings__header"> 120 <div className="settings__header">
@@ -138,13 +152,21 @@ class WorkspacesDashboard extends Component {
138 152
139 {workspaceStore.isPremiumUpgradeRequired && ( 153 {workspaceStore.isPremiumUpgradeRequired && (
140 <div className={classes.premiumAnnouncement}> 154 <div className={classes.premiumAnnouncement}>
141 <h2>{intl.formatMessage(messages.workspaceFeatureHeadline)}</h2> 155 <img src={`./assets/images/workspaces/teaser_${this.props.stores.ui.isDarkThemeActive ? 'dark' : 'light'}.png`} className={classes.teaserImage} alt="" />
142 <p>{intl.formatMessage(messages.workspaceFeatureInfo)}</p> 156 <div>
157 <h2>{intl.formatMessage(messages.workspaceFeatureHeadline)}</h2>
158 <p>{intl.formatMessage(messages.workspaceFeatureInfo)}</p>
159 <ActivateTrialButton
160 className={classes.upgradeCTA}
161 gaEventInfo={{ category: 'Workspaces', event: 'upgrade' }}
162 short
163 />
164 </div>
143 </div> 165 </div>
144 )} 166 )}
145 167
146 <PremiumFeatureContainer 168 <PremiumFeatureContainer
147 condition={workspaceStore.isPremiumFeature} 169 condition={() => workspaceStore.isPremiumUpgradeRequired}
148 gaEventInfo={{ category: 'User', event: 'upgrade', label: 'workspaces' }} 170 gaEventInfo={{ category: 'User', event: 'upgrade', label: 'workspaces' }}
149 > 171 >
150 {/* ===== Create workspace form ===== */} 172 {/* ===== Create workspace form ===== */}
@@ -207,3 +229,9 @@ class WorkspacesDashboard extends Component {
207} 229}
208 230
209export default WorkspacesDashboard; 231export default WorkspacesDashboard;
232
233WorkspacesDashboard.wrappedComponent.propTypes = {
234 stores: PropTypes.shape({
235 ui: PropTypes.instanceOf(UIStore).isRequired,
236 }).isRequired,
237};
diff --git a/src/features/workspaces/store.js b/src/features/workspaces/store.js
index e44569be9..4a1f80b4e 100644
--- a/src/features/workspaces/store.js
+++ b/src/features/workspaces/store.js
@@ -253,11 +253,10 @@ export default class WorkspacesStore extends FeatureStore {
253 }; 253 };
254 254
255 _setIsPremiumFeatureReaction = () => { 255 _setIsPremiumFeatureReaction = () => {
256 const { features, user } = this.stores; 256 const { features } = this.stores;
257 const { isPremium } = user.data;
258 const { isWorkspaceIncludedInCurrentPlan } = features.features; 257 const { isWorkspaceIncludedInCurrentPlan } = features.features;
259 this.isPremiumFeature = !isWorkspaceIncludedInCurrentPlan; 258 this.isPremiumFeature = !isWorkspaceIncludedInCurrentPlan;
260 this.isPremiumUpgradeRequired = !isWorkspaceIncludedInCurrentPlan && !isPremium; 259 this.isPremiumUpgradeRequired = !isWorkspaceIncludedInCurrentPlan;
261 }; 260 };
262 261
263 _setWorkspaceBeingEditedReaction = () => { 262 _setWorkspaceBeingEditedReaction = () => {
diff --git a/src/helpers/plan-helpers.js b/src/helpers/plan-helpers.js
index 19392585e..e0f1fd89a 100644
--- a/src/helpers/plan-helpers.js
+++ b/src/helpers/plan-helpers.js
@@ -33,3 +33,13 @@ export function i18nPlanName(planId, intl) {
33 33
34 return intl.formatMessage(messages[plan]); 34 return intl.formatMessage(messages[plan]);
35} 35}
36
37export function getPlan(planId) {
38 if (!planId) {
39 throw new Error('planId is required');
40 }
41
42 const plan = PLANS_MAPPING[planId];
43
44 return plan;
45}
diff --git a/src/i18n/locales/defaultMessages.json b/src/i18n/locales/defaultMessages.json
index dabe2f11f..367184c01 100644
--- a/src/i18n/locales/defaultMessages.json
+++ b/src/i18n/locales/defaultMessages.json
@@ -2895,6 +2895,63 @@
2895 { 2895 {
2896 "descriptors": [ 2896 "descriptors": [
2897 { 2897 {
2898 "defaultMessage": "!!!Get a Franz Supporter License",
2899 "end": {
2900 "column": 3,
2901 "line": 16
2902 },
2903 "file": "src/components/ui/ActivateTrialButton/index.js",
2904 "id": "feature.delayApp.upgrade.action",
2905 "start": {
2906 "column": 10,
2907 "line": 13
2908 }
2909 },
2910 {
2911 "defaultMessage": "!!!Yes, I want the free 14 day trial of Franz Professional",
2912 "end": {
2913 "column": 3,
2914 "line": 20
2915 },
2916 "file": "src/components/ui/ActivateTrialButton/index.js",
2917 "id": "feature.delayApp.trial.action",
2918 "start": {
2919 "column": 15,
2920 "line": 17
2921 }
2922 },
2923 {
2924 "defaultMessage": "!!!Upgrade account",
2925 "end": {
2926 "column": 3,
2927 "line": 24
2928 },
2929 "file": "src/components/ui/ActivateTrialButton/index.js",
2930 "id": "feature.delayApp.upgrade.actionShort",
2931 "start": {
2932 "column": 15,
2933 "line": 21
2934 }
2935 },
2936 {
2937 "defaultMessage": "!!!Activate the free Franz Professional trial",
2938 "end": {
2939 "column": 3,
2940 "line": 28
2941 },
2942 "file": "src/components/ui/ActivateTrialButton/index.js",
2943 "id": "feature.delayApp.trial.actionShort",
2944 "start": {
2945 "column": 20,
2946 "line": 25
2947 }
2948 }
2949 ],
2950 "path": "src/components/ui/ActivateTrialButton/index.json"
2951 },
2952 {
2953 "descriptors": [
2954 {
2898 "defaultMessage": "!!!Add unlimited services", 2955 "defaultMessage": "!!!Add unlimited services",
2899 "end": { 2956 "end": {
2900 "column": 3, 2957 "column": 3,
@@ -3033,13 +3090,13 @@
3033 "defaultMessage": "!!!Upgrade account", 3090 "defaultMessage": "!!!Upgrade account",
3034 "end": { 3091 "end": {
3035 "column": 3, 3092 "column": 3,
3036 "line": 18 3093 "line": 19
3037 }, 3094 },
3038 "file": "src/components/ui/PremiumFeatureContainer/index.js", 3095 "file": "src/components/ui/PremiumFeatureContainer/index.js",
3039 "id": "premiumFeature.button.upgradeAccount", 3096 "id": "premiumFeature.button.upgradeAccount",
3040 "start": { 3097 "start": {
3041 "column": 10, 3098 "column": 10,
3042 "line": 15 3099 "line": 16
3043 } 3100 }
3044 } 3101 }
3045 ], 3102 ],
@@ -3720,91 +3777,91 @@
3720 "defaultMessage": "!!!Franz is better together!", 3777 "defaultMessage": "!!!Franz is better together!",
3721 "end": { 3778 "end": {
3722 "column": 3, 3779 "column": 3,
3723 "line": 19 3780 "line": 21
3724 }, 3781 },
3725 "file": "src/features/shareFranz/Component.js", 3782 "file": "src/features/shareFranz/Component.js",
3726 "id": "feature.shareFranz.headline", 3783 "id": "feature.shareFranz.headline",
3727 "start": { 3784 "start": {
3728 "column": 12, 3785 "column": 12,
3729 "line": 16 3786 "line": 18
3730 } 3787 }
3731 }, 3788 },
3732 { 3789 {
3733 "defaultMessage": "!!!Tell your friends and colleagues how awesome Franz is and help us to spread the word.", 3790 "defaultMessage": "!!!Tell your friends and colleagues how awesome Franz is and help us to spread the word.",
3734 "end": { 3791 "end": {
3735 "column": 3, 3792 "column": 3,
3736 "line": 23 3793 "line": 25
3737 }, 3794 },
3738 "file": "src/features/shareFranz/Component.js", 3795 "file": "src/features/shareFranz/Component.js",
3739 "id": "feature.shareFranz.text", 3796 "id": "feature.shareFranz.text",
3740 "start": { 3797 "start": {
3741 "column": 8, 3798 "column": 8,
3742 "line": 20 3799 "line": 22
3743 } 3800 }
3744 }, 3801 },
3745 { 3802 {
3746 "defaultMessage": "!!!Share as email", 3803 "defaultMessage": "!!!Share as email",
3747 "end": { 3804 "end": {
3748 "column": 3, 3805 "column": 3,
3749 "line": 27 3806 "line": 29
3750 }, 3807 },
3751 "file": "src/features/shareFranz/Component.js", 3808 "file": "src/features/shareFranz/Component.js",
3752 "id": "feature.shareFranz.action.email", 3809 "id": "feature.shareFranz.action.email",
3753 "start": { 3810 "start": {
3754 "column": 16, 3811 "column": 16,
3755 "line": 24 3812 "line": 26
3756 } 3813 }
3757 }, 3814 },
3758 { 3815 {
3759 "defaultMessage": "!!!Share on Facebook", 3816 "defaultMessage": "!!!Share on Facebook",
3760 "end": { 3817 "end": {
3761 "column": 3, 3818 "column": 3,
3762 "line": 31 3819 "line": 33
3763 }, 3820 },
3764 "file": "src/features/shareFranz/Component.js", 3821 "file": "src/features/shareFranz/Component.js",
3765 "id": "feature.shareFranz.action.facebook", 3822 "id": "feature.shareFranz.action.facebook",
3766 "start": { 3823 "start": {
3767 "column": 19, 3824 "column": 19,
3768 "line": 28 3825 "line": 30
3769 } 3826 }
3770 }, 3827 },
3771 { 3828 {
3772 "defaultMessage": "!!!Share on Twitter", 3829 "defaultMessage": "!!!Share on Twitter",
3773 "end": { 3830 "end": {
3774 "column": 3, 3831 "column": 3,
3775 "line": 35 3832 "line": 37
3776 }, 3833 },
3777 "file": "src/features/shareFranz/Component.js", 3834 "file": "src/features/shareFranz/Component.js",
3778 "id": "feature.shareFranz.action.twitter", 3835 "id": "feature.shareFranz.action.twitter",
3779 "start": { 3836 "start": {
3780 "column": 18, 3837 "column": 18,
3781 "line": 32 3838 "line": 34
3782 } 3839 }
3783 }, 3840 },
3784 { 3841 {
3785 "defaultMessage": "!!! I've added {count} services to Franz! Get the free app for WhatsApp, Messenger, Slack, Skype and co at www.meetfranz.com", 3842 "defaultMessage": "!!! I've added {count} services to Franz! Get the free app for WhatsApp, Messenger, Slack, Skype and co at www.meetfranz.com",
3786 "end": { 3843 "end": {
3787 "column": 3, 3844 "column": 3,
3788 "line": 39 3845 "line": 41
3789 }, 3846 },
3790 "file": "src/features/shareFranz/Component.js", 3847 "file": "src/features/shareFranz/Component.js",
3791 "id": "feature.shareFranz.shareText.email", 3848 "id": "feature.shareFranz.shareText.email",
3792 "start": { 3849 "start": {
3793 "column": 18, 3850 "column": 18,
3794 "line": 36 3851 "line": 38
3795 } 3852 }
3796 }, 3853 },
3797 { 3854 {
3798 "defaultMessage": "!!! I've added {count} services to Franz! Get the free app for WhatsApp, Messenger, Slack, Skype and co at www.meetfranz.com /cc @FranzMessenger", 3855 "defaultMessage": "!!! I've added {count} services to Franz! Get the free app for WhatsApp, Messenger, Slack, Skype and co at www.meetfranz.com /cc @FranzMessenger",
3799 "end": { 3856 "end": {
3800 "column": 3, 3857 "column": 3,
3801 "line": 43 3858 "line": 45
3802 }, 3859 },
3803 "file": "src/features/shareFranz/Component.js", 3860 "file": "src/features/shareFranz/Component.js",
3804 "id": "feature.shareFranz.shareText.twitter", 3861 "id": "feature.shareFranz.shareText.twitter",
3805 "start": { 3862 "start": {
3806 "column": 20, 3863 "column": 20,
3807 "line": 40 3864 "line": 42
3808 } 3865 }
3809 } 3866 }
3810 ], 3867 ],
@@ -3816,39 +3873,39 @@
3816 "defaultMessage": "!!!The Franz Todos Preview is currently only available for Franz Premium accounts.", 3873 "defaultMessage": "!!!The Franz Todos Preview is currently only available for Franz Premium accounts.",
3817 "end": { 3874 "end": {
3818 "column": 3, 3875 "column": 3,
3819 "line": 21 3876 "line": 22
3820 }, 3877 },
3821 "file": "src/features/todos/components/TodosWebview.js", 3878 "file": "src/features/todos/components/TodosWebview.js",
3822 "id": "feature.todos.premium.info", 3879 "id": "feature.todos.premium.info",
3823 "start": { 3880 "start": {
3824 "column": 15, 3881 "column": 15,
3825 "line": 18 3882 "line": 19
3826 } 3883 }
3827 }, 3884 },
3828 { 3885 {
3829 "defaultMessage": "!!!Upgrade Account", 3886 "defaultMessage": "!!!Upgrade Account",
3830 "end": { 3887 "end": {
3831 "column": 3, 3888 "column": 3,
3832 "line": 25 3889 "line": 26
3833 }, 3890 },
3834 "file": "src/features/todos/components/TodosWebview.js", 3891 "file": "src/features/todos/components/TodosWebview.js",
3835 "id": "feature.todos.premium.upgrade", 3892 "id": "feature.todos.premium.upgrade",
3836 "start": { 3893 "start": {
3837 "column": 14, 3894 "column": 14,
3838 "line": 22 3895 "line": 23
3839 } 3896 }
3840 }, 3897 },
3841 { 3898 {
3842 "defaultMessage": "!!!Franz Todos will be available to everyone soon.", 3899 "defaultMessage": "!!!Franz Todos will be available to everyone soon.",
3843 "end": { 3900 "end": {
3844 "column": 3, 3901 "column": 3,
3845 "line": 29 3902 "line": 30
3846 }, 3903 },
3847 "file": "src/features/todos/components/TodosWebview.js", 3904 "file": "src/features/todos/components/TodosWebview.js",
3848 "id": "feature.todos.premium.rollout", 3905 "id": "feature.todos.premium.rollout",
3849 "start": { 3906 "start": {
3850 "column": 15, 3907 "column": 15,
3851 "line": 26 3908 "line": 27
3852 } 3909 }
3853 } 3910 }
3854 ], 3911 ],
@@ -4127,104 +4184,104 @@
4127 "defaultMessage": "!!!Your workspaces", 4184 "defaultMessage": "!!!Your workspaces",
4128 "end": { 4185 "end": {
4129 "column": 3, 4186 "column": 3,
4130 "line": 20 4187 "line": 22
4131 }, 4188 },
4132 "file": "src/features/workspaces/components/WorkspacesDashboard.js", 4189 "file": "src/features/workspaces/components/WorkspacesDashboard.js",
4133 "id": "settings.workspaces.headline", 4190 "id": "settings.workspaces.headline",
4134 "start": { 4191 "start": {
4135 "column": 12, 4192 "column": 12,
4136 "line": 17 4193 "line": 19
4137 } 4194 }
4138 }, 4195 },
4139 { 4196 {
4140 "defaultMessage": "!!!You haven't added any workspaces yet.", 4197 "defaultMessage": "!!!You haven't added any workspaces yet.",
4141 "end": { 4198 "end": {
4142 "column": 3, 4199 "column": 3,
4143 "line": 24 4200 "line": 26
4144 }, 4201 },
4145 "file": "src/features/workspaces/components/WorkspacesDashboard.js", 4202 "file": "src/features/workspaces/components/WorkspacesDashboard.js",
4146 "id": "settings.workspaces.noWorkspacesAdded", 4203 "id": "settings.workspaces.noWorkspacesAdded",
4147 "start": { 4204 "start": {
4148 "column": 19, 4205 "column": 19,
4149 "line": 21 4206 "line": 23
4150 } 4207 }
4151 }, 4208 },
4152 { 4209 {
4153 "defaultMessage": "!!!Could not load your workspaces", 4210 "defaultMessage": "!!!Could not load your workspaces",
4154 "end": { 4211 "end": {
4155 "column": 3, 4212 "column": 3,
4156 "line": 28 4213 "line": 30
4157 }, 4214 },
4158 "file": "src/features/workspaces/components/WorkspacesDashboard.js", 4215 "file": "src/features/workspaces/components/WorkspacesDashboard.js",
4159 "id": "settings.workspaces.workspacesRequestFailed", 4216 "id": "settings.workspaces.workspacesRequestFailed",
4160 "start": { 4217 "start": {
4161 "column": 27, 4218 "column": 27,
4162 "line": 25 4219 "line": 27
4163 } 4220 }
4164 }, 4221 },
4165 { 4222 {
4166 "defaultMessage": "!!!Try again", 4223 "defaultMessage": "!!!Try again",
4167 "end": { 4224 "end": {
4168 "column": 3, 4225 "column": 3,
4169 "line": 32 4226 "line": 34
4170 }, 4227 },
4171 "file": "src/features/workspaces/components/WorkspacesDashboard.js", 4228 "file": "src/features/workspaces/components/WorkspacesDashboard.js",
4172 "id": "settings.workspaces.tryReloadWorkspaces", 4229 "id": "settings.workspaces.tryReloadWorkspaces",
4173 "start": { 4230 "start": {
4174 "column": 23, 4231 "column": 23,
4175 "line": 29 4232 "line": 31
4176 } 4233 }
4177 }, 4234 },
4178 { 4235 {
4179 "defaultMessage": "!!!Your changes have been saved", 4236 "defaultMessage": "!!!Your changes have been saved",
4180 "end": { 4237 "end": {
4181 "column": 3, 4238 "column": 3,
4182 "line": 36 4239 "line": 38
4183 }, 4240 },
4184 "file": "src/features/workspaces/components/WorkspacesDashboard.js", 4241 "file": "src/features/workspaces/components/WorkspacesDashboard.js",
4185 "id": "settings.workspaces.updatedInfo", 4242 "id": "settings.workspaces.updatedInfo",
4186 "start": { 4243 "start": {
4187 "column": 15, 4244 "column": 15,
4188 "line": 33 4245 "line": 35
4189 } 4246 }
4190 }, 4247 },
4191 { 4248 {
4192 "defaultMessage": "!!!Workspace has been deleted", 4249 "defaultMessage": "!!!Workspace has been deleted",
4193 "end": { 4250 "end": {
4194 "column": 3, 4251 "column": 3,
4195 "line": 40 4252 "line": 42
4196 }, 4253 },
4197 "file": "src/features/workspaces/components/WorkspacesDashboard.js", 4254 "file": "src/features/workspaces/components/WorkspacesDashboard.js",
4198 "id": "settings.workspaces.deletedInfo", 4255 "id": "settings.workspaces.deletedInfo",
4199 "start": { 4256 "start": {
4200 "column": 15, 4257 "column": 15,
4201 "line": 37 4258 "line": 39
4202 } 4259 }
4203 }, 4260 },
4204 { 4261 {
4205 "defaultMessage": "!!!Info about workspace feature", 4262 "defaultMessage": "!!!Info about workspace feature",
4206 "end": { 4263 "end": {
4207 "column": 3, 4264 "column": 3,
4208 "line": 44 4265 "line": 46
4209 }, 4266 },
4210 "file": "src/features/workspaces/components/WorkspacesDashboard.js", 4267 "file": "src/features/workspaces/components/WorkspacesDashboard.js",
4211 "id": "settings.workspaces.workspaceFeatureInfo", 4268 "id": "settings.workspaces.workspaceFeatureInfo",
4212 "start": { 4269 "start": {
4213 "column": 24, 4270 "column": 24,
4214 "line": 41 4271 "line": 43
4215 } 4272 }
4216 }, 4273 },
4217 { 4274 {
4218 "defaultMessage": "!!!Less is More: Introducing Franz Workspaces", 4275 "defaultMessage": "!!!Less is More: Introducing Franz Workspaces",
4219 "end": { 4276 "end": {
4220 "column": 3, 4277 "column": 3,
4221 "line": 48 4278 "line": 50
4222 }, 4279 },
4223 "file": "src/features/workspaces/components/WorkspacesDashboard.js", 4280 "file": "src/features/workspaces/components/WorkspacesDashboard.js",
4224 "id": "settings.workspaces.workspaceFeatureHeadline", 4281 "id": "settings.workspaces.workspaceFeatureHeadline",
4225 "start": { 4282 "start": {
4226 "column": 28, 4283 "column": 28,
4227 "line": 45 4284 "line": 47
4228 } 4285 }
4229 } 4286 }
4230 ], 4287 ],
diff --git a/src/i18n/locales/en-US.json b/src/i18n/locales/en-US.json
index 32e9c743a..f11d5ca91 100644
--- a/src/i18n/locales/en-US.json
+++ b/src/i18n/locales/en-US.json
@@ -5,8 +5,10 @@
5 "feature.delayApp.headline": "Please purchase a Franz Supporter License to skip waiting", 5 "feature.delayApp.headline": "Please purchase a Franz Supporter License to skip waiting",
6 "feature.delayApp.text": "Franz will continue in {seconds} seconds.", 6 "feature.delayApp.text": "Franz will continue in {seconds} seconds.",
7 "feature.delayApp.trial.action": "Yes, I want the free 14 day trial of Franz Professional", 7 "feature.delayApp.trial.action": "Yes, I want the free 14 day trial of Franz Professional",
8 "feature.delayApp.trial.actionShort": "Activate the free Franz Professional trial",
8 "feature.delayApp.trial.headline": "Get the free Franz Professional 14 day trial and skip the line", 9 "feature.delayApp.trial.headline": "Get the free Franz Professional 14 day trial and skip the line",
9 "feature.delayApp.upgrade.action": "Get a Franz Supporter License", 10 "feature.delayApp.upgrade.action": "Get a Franz Supporter License",
11 "feature.delayApp.upgrade.actionShort": "Upgrade account",
10 "feature.serviceLimit.limitReached": "You have added {amount} out of {limit} services that are included in your plan. Please upgrade your account to add more services.", 12 "feature.serviceLimit.limitReached": "You have added {amount} out of {limit} services that are included in your plan. Please upgrade your account to add more services.",
11 "feature.shareFranz.action.email": "Send as email", 13 "feature.shareFranz.action.email": "Send as email",
12 "feature.shareFranz.action.facebook": "Share on Facebook", 14 "feature.shareFranz.action.facebook": "Share on Facebook",
diff --git a/src/i18n/messages/src/components/ui/ActivateTrialButton/index.json b/src/i18n/messages/src/components/ui/ActivateTrialButton/index.json
new file mode 100644
index 000000000..08c1a9293
--- /dev/null
+++ b/src/i18n/messages/src/components/ui/ActivateTrialButton/index.json
@@ -0,0 +1,54 @@
1[
2 {
3 "id": "feature.delayApp.upgrade.action",
4 "defaultMessage": "!!!Get a Franz Supporter License",
5 "file": "src/components/ui/ActivateTrialButton/index.js",
6 "start": {
7 "line": 13,
8 "column": 10
9 },
10 "end": {
11 "line": 16,
12 "column": 3
13 }
14 },
15 {
16 "id": "feature.delayApp.trial.action",
17 "defaultMessage": "!!!Yes, I want the free 14 day trial of Franz Professional",
18 "file": "src/components/ui/ActivateTrialButton/index.js",
19 "start": {
20 "line": 17,
21 "column": 15
22 },
23 "end": {
24 "line": 20,
25 "column": 3
26 }
27 },
28 {
29 "id": "feature.delayApp.upgrade.actionShort",
30 "defaultMessage": "!!!Upgrade account",
31 "file": "src/components/ui/ActivateTrialButton/index.js",
32 "start": {
33 "line": 21,
34 "column": 15
35 },
36 "end": {
37 "line": 24,
38 "column": 3
39 }
40 },
41 {
42 "id": "feature.delayApp.trial.actionShort",
43 "defaultMessage": "!!!Activate the free Franz Professional trial",
44 "file": "src/components/ui/ActivateTrialButton/index.js",
45 "start": {
46 "line": 25,
47 "column": 20
48 },
49 "end": {
50 "line": 28,
51 "column": 3
52 }
53 }
54] \ No newline at end of file
diff --git a/src/i18n/messages/src/components/ui/PremiumFeatureContainer/index.json b/src/i18n/messages/src/components/ui/PremiumFeatureContainer/index.json
index 320d3ca3e..0cde4cee5 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": 15, 7 "line": 16,
8 "column": 10 8 "column": 10
9 }, 9 },
10 "end": { 10 "end": {
11 "line": 18, 11 "line": 19,
12 "column": 3 12 "column": 3
13 } 13 }
14 } 14 }
diff --git a/src/i18n/messages/src/features/todos/components/TodosWebview.json b/src/i18n/messages/src/features/todos/components/TodosWebview.json
index 2387112b4..7d26342b7 100644
--- a/src/i18n/messages/src/features/todos/components/TodosWebview.json
+++ b/src/i18n/messages/src/features/todos/components/TodosWebview.json
@@ -4,11 +4,11 @@
4 "defaultMessage": "!!!The Franz Todos Preview is currently only available for Franz Premium accounts.", 4 "defaultMessage": "!!!The Franz Todos Preview is currently only available for Franz Premium accounts.",
5 "file": "src/features/todos/components/TodosWebview.js", 5 "file": "src/features/todos/components/TodosWebview.js",
6 "start": { 6 "start": {
7 "line": 18, 7 "line": 19,
8 "column": 15 8 "column": 15
9 }, 9 },
10 "end": { 10 "end": {
11 "line": 21, 11 "line": 22,
12 "column": 3 12 "column": 3
13 } 13 }
14 }, 14 },
@@ -17,11 +17,11 @@
17 "defaultMessage": "!!!Upgrade Account", 17 "defaultMessage": "!!!Upgrade Account",
18 "file": "src/features/todos/components/TodosWebview.js", 18 "file": "src/features/todos/components/TodosWebview.js",
19 "start": { 19 "start": {
20 "line": 22, 20 "line": 23,
21 "column": 14 21 "column": 14
22 }, 22 },
23 "end": { 23 "end": {
24 "line": 25, 24 "line": 26,
25 "column": 3 25 "column": 3
26 } 26 }
27 }, 27 },
@@ -30,11 +30,11 @@
30 "defaultMessage": "!!!Franz Todos will be available to everyone soon.", 30 "defaultMessage": "!!!Franz Todos will be available to everyone soon.",
31 "file": "src/features/todos/components/TodosWebview.js", 31 "file": "src/features/todos/components/TodosWebview.js",
32 "start": { 32 "start": {
33 "line": 26, 33 "line": 27,
34 "column": 15 34 "column": 15
35 }, 35 },
36 "end": { 36 "end": {
37 "line": 29, 37 "line": 30,
38 "column": 3 38 "column": 3
39 } 39 }
40 } 40 }
diff --git a/src/i18n/messages/src/features/workspaces/components/WorkspacesDashboard.json b/src/i18n/messages/src/features/workspaces/components/WorkspacesDashboard.json
index ef8f1bebc..7eb4fab50 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": 17, 7 "line": 19,
8 "column": 12 8 "column": 12
9 }, 9 },
10 "end": { 10 "end": {
11 "line": 20, 11 "line": 22,
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": 21, 20 "line": 23,
21 "column": 19 21 "column": 19
22 }, 22 },
23 "end": { 23 "end": {
24 "line": 24, 24 "line": 26,
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": 25, 33 "line": 27,
34 "column": 27 34 "column": 27
35 }, 35 },
36 "end": { 36 "end": {
37 "line": 28, 37 "line": 30,
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": 29, 46 "line": 31,
47 "column": 23 47 "column": 23
48 }, 48 },
49 "end": { 49 "end": {
50 "line": 32, 50 "line": 34,
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": 33, 59 "line": 35,
60 "column": 15 60 "column": 15
61 }, 61 },
62 "end": { 62 "end": {
63 "line": 36, 63 "line": 38,
64 "column": 3 64 "column": 3
65 } 65 }
66 }, 66 },
@@ -69,11 +69,11 @@
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": 37, 72 "line": 39,
73 "column": 15 73 "column": 15
74 }, 74 },
75 "end": { 75 "end": {
76 "line": 40, 76 "line": 42,
77 "column": 3 77 "column": 3
78 } 78 }
79 }, 79 },
@@ -82,11 +82,11 @@
82 "defaultMessage": "!!!Info about workspace feature", 82 "defaultMessage": "!!!Info about workspace feature",
83 "file": "src/features/workspaces/components/WorkspacesDashboard.js", 83 "file": "src/features/workspaces/components/WorkspacesDashboard.js",
84 "start": { 84 "start": {
85 "line": 41, 85 "line": 43,
86 "column": 24 86 "column": 24
87 }, 87 },
88 "end": { 88 "end": {
89 "line": 44, 89 "line": 46,
90 "column": 3 90 "column": 3
91 } 91 }
92 }, 92 },
@@ -95,11 +95,11 @@
95 "defaultMessage": "!!!Less is More: Introducing Franz Workspaces", 95 "defaultMessage": "!!!Less is More: Introducing Franz Workspaces",
96 "file": "src/features/workspaces/components/WorkspacesDashboard.js", 96 "file": "src/features/workspaces/components/WorkspacesDashboard.js",
97 "start": { 97 "start": {
98 "line": 45, 98 "line": 47,
99 "column": 28 99 "column": 28
100 }, 100 },
101 "end": { 101 "end": {
102 "line": 48, 102 "line": 50,
103 "column": 3 103 "column": 3
104 } 104 }
105 } 105 }
diff --git a/src/stores/UserStore.js b/src/stores/UserStore.js
index f3dfbdbf0..7ac7d2375 100644
--- a/src/stores/UserStore.js
+++ b/src/stores/UserStore.js
@@ -10,6 +10,8 @@ import Request from './lib/Request';
10import CachedRequest from './lib/CachedRequest'; 10import CachedRequest from './lib/CachedRequest';
11import { gaEvent } from '../lib/analytics'; 11import { gaEvent } from '../lib/analytics';
12import { sleep } from '../helpers/async-helpers'; 12import { sleep } from '../helpers/async-helpers';
13import { getPlan } from '../helpers/plan-helpers';
14import { PLANS } from '../config';
13 15
14const debug = require('debug')('Franz:UserStore'); 16const debug = require('debug')('Franz:UserStore');
15 17
@@ -150,10 +152,30 @@ export default class UserStore extends Store {
150 return this.getUserInfoRequest.execute().result || {}; 152 return this.getUserInfoRequest.execute().result || {};
151 } 153 }
152 154
155 @computed get team() {
156 return this.data.team || null;
157 }
158
153 @computed get isPremium() { 159 @computed get isPremium() {
154 return !!this.data.isPremium; 160 return !!this.data.isPremium;
155 } 161 }
156 162
163 @computed get isPersonal() {
164 if (!this.team.plan) return false;
165 const plan = getPlan(this.team.plan);
166
167 return plan === PLANS.PERSONAL;
168 }
169
170 @computed get isPro() {
171 if (!this.team.plan && this.isPremium) return true;
172
173 if (!this.team.plan) return false;
174 const plan = getPlan(this.team.plan);
175
176 return plan === PLANS.PRO;
177 }
178
157 @computed get legacyServices() { 179 @computed get legacyServices() {
158 return this.getLegacyServicesRequest.execute() || {}; 180 return this.getLegacyServicesRequest.execute() || {};
159 } 181 }