aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/api/server/ServerApi.js2
-rw-r--r--src/components/TrialActivationInfoBar.js94
-rw-r--r--src/components/layout/AppLayout.js37
-rw-r--r--src/components/services/content/Services.js61
-rw-r--r--src/components/settings/account/AccountDashboard.js134
-rw-r--r--src/components/settings/settings/EditSettingsForm.js2
-rw-r--r--src/containers/layout/AppLayoutContainer.js2
-rw-r--r--src/features/delayApp/Component.js43
-rw-r--r--src/features/delayApp/index.js2
-rw-r--r--src/i18n/locales/defaultMessages.json284
-rw-r--r--src/i18n/locales/en-US.json29
-rw-r--r--src/i18n/messages/src/components/TrialActivationInfoBar.json15
-rw-r--r--src/i18n/messages/src/components/layout/AppLayout.json12
-rw-r--r--src/i18n/messages/src/features/delayApp/Component.json40
-rw-r--r--src/models/User.js14
-rw-r--r--src/stores/UserStore.js21
-rw-r--r--src/styles/recipes.scss1
17 files changed, 630 insertions, 163 deletions
diff --git a/src/api/server/ServerApi.js b/src/api/server/ServerApi.js
index f2568d597..f56c7b6e4 100644
--- a/src/api/server/ServerApi.js
+++ b/src/api/server/ServerApi.js
@@ -87,8 +87,6 @@ export default class ServerApi {
87 } 87 }
88 const trial = await request.json(); 88 const trial = await request.json();
89 89
90 console.log(trial);
91
92 debug('ServerApi::signup resolves', trial); 90 debug('ServerApi::signup resolves', trial);
93 return true; 91 return true;
94 } 92 }
diff --git a/src/components/TrialActivationInfoBar.js b/src/components/TrialActivationInfoBar.js
new file mode 100644
index 000000000..acdf51d08
--- /dev/null
+++ b/src/components/TrialActivationInfoBar.js
@@ -0,0 +1,94 @@
1import React, { Component } from 'react';
2import PropTypes from 'prop-types';
3import { defineMessages, intlShape } from 'react-intl';
4import ms from 'ms';
5import injectSheet from 'react-jss';
6import classnames from 'classnames';
7
8import InfoBar from './ui/InfoBar';
9
10const messages = defineMessages({
11 message: {
12 id: 'infobar.trialActivated',
13 defaultMessage: '!!!Your trial was successfully activated. Happy messaging!',
14 },
15});
16
17const styles = {
18 notification: {
19 height: 'auto',
20 position: 'absolute',
21 top: -50,
22 transition: 'top 0.3s',
23 zIndex: 300,
24 width: 'calc(100% - 300px)',
25 },
26 show: {
27 top: 0,
28 },
29};
30
31@injectSheet(styles)
32class TrialActivationInfoBar extends Component {
33 static propTypes = {
34 // eslint-disable-next-line
35 classes: PropTypes.object.isRequired,
36 };
37
38 static contextTypes = {
39 intl: intlShape,
40 };
41
42 state = {
43 showing: false,
44 removed: false,
45 }
46
47 componentDidMount() {
48 setTimeout(() => {
49 this.setState({
50 showing: true,
51 });
52 }, 0);
53
54 setTimeout(() => {
55 this.setState({
56 showing: false,
57 });
58 }, ms('6s'));
59
60 setTimeout(() => {
61 this.setState({
62 removed: true,
63 });
64 }, ms('7s'));
65 }
66
67 render() {
68 const { classes } = this.props;
69 const { showing, removed } = this.state;
70 const { intl } = this.context;
71
72 if (removed) return null;
73
74 return (
75 <div
76 className={classnames({
77 [classes.notification]: true,
78 [classes.show]: showing,
79 })}
80 >
81 <InfoBar
82 type="primary"
83 position="top"
84 sticky
85 >
86 <span className="mdi mdi-information" />
87 {intl.formatMessage(messages.message)}
88 </InfoBar>
89 </div>
90 );
91 }
92}
93
94export default TrialActivationInfoBar;
diff --git a/src/components/layout/AppLayout.js b/src/components/layout/AppLayout.js
index ebb9849ea..1976f5a50 100644
--- a/src/components/layout/AppLayout.js
+++ b/src/components/layout/AppLayout.js
@@ -17,6 +17,7 @@ import { isWindows } from '../../environment';
17import WorkspaceSwitchingIndicator from '../../features/workspaces/components/WorkspaceSwitchingIndicator'; 17import WorkspaceSwitchingIndicator from '../../features/workspaces/components/WorkspaceSwitchingIndicator';
18import { workspaceStore } from '../../features/workspaces'; 18import { workspaceStore } from '../../features/workspaces';
19import AppUpdateInfoBar from '../AppUpdateInfoBar'; 19import AppUpdateInfoBar from '../AppUpdateInfoBar';
20import TrialActivationInfoBar from '../TrialActivationInfoBar';
20 21
21function createMarkup(HTMLString) { 22function createMarkup(HTMLString) {
22 return { __html: HTMLString }; 23 return { __html: HTMLString };
@@ -57,7 +58,6 @@ class AppLayout extends Component {
57 services: PropTypes.element.isRequired, 58 services: PropTypes.element.isRequired,
58 children: PropTypes.element, 59 children: PropTypes.element,
59 news: MobxPropTypes.arrayOrObservableArray.isRequired, 60 news: MobxPropTypes.arrayOrObservableArray.isRequired,
60 // isOnline: PropTypes.bool.isRequired,
61 showServicesUpdatedInfoBar: PropTypes.bool.isRequired, 61 showServicesUpdatedInfoBar: PropTypes.bool.isRequired,
62 appUpdateIsDownloaded: PropTypes.bool.isRequired, 62 appUpdateIsDownloaded: PropTypes.bool.isRequired,
63 nextAppReleaseVersion: PropTypes.string, 63 nextAppReleaseVersion: PropTypes.string,
@@ -69,6 +69,7 @@ class AppLayout extends Component {
69 retryRequiredRequests: PropTypes.func.isRequired, 69 retryRequiredRequests: PropTypes.func.isRequired,
70 areRequiredRequestsLoading: PropTypes.bool.isRequired, 70 areRequiredRequestsLoading: PropTypes.bool.isRequired,
71 isDelayAppScreenVisible: PropTypes.bool.isRequired, 71 isDelayAppScreenVisible: PropTypes.bool.isRequired,
72 hasActivatedTrial: PropTypes.bool.isRequired,
72 }; 73 };
73 74
74 static defaultProps = { 75 static defaultProps = {
@@ -88,7 +89,6 @@ class AppLayout extends Component {
88 sidebar, 89 sidebar,
89 services, 90 services,
90 children, 91 children,
91 // isOnline,
92 news, 92 news,
93 showServicesUpdatedInfoBar, 93 showServicesUpdatedInfoBar,
94 appUpdateIsDownloaded, 94 appUpdateIsDownloaded,
@@ -101,6 +101,7 @@ class AppLayout extends Component {
101 retryRequiredRequests, 101 retryRequiredRequests,
102 areRequiredRequestsLoading, 102 areRequiredRequestsLoading,
103 isDelayAppScreenVisible, 103 isDelayAppScreenVisible,
104 hasActivatedTrial,
104 } = this.props; 105 } = this.props;
105 106
106 const { intl } = this.context; 107 const { intl } = this.context;
@@ -125,26 +126,20 @@ class AppLayout extends Component {
125 <span dangerouslySetInnerHTML={createMarkup(item.message)} /> 126 <span dangerouslySetInnerHTML={createMarkup(item.message)} />
126 </InfoBar> 127 </InfoBar>
127 ))} 128 ))}
128 {/* {!isOnline && ( 129 {hasActivatedTrial && (
129 <InfoBar 130 <TrialActivationInfoBar />
130 type="danger" 131 )}
131 sticky
132 >
133 <span className="mdi mdi-flash" />
134 {intl.formatMessage(globalMessages.notConnectedToTheInternet)}
135 </InfoBar>
136 )} */}
137 {!areRequiredRequestsSuccessful && showRequiredRequestsError && ( 132 {!areRequiredRequestsSuccessful && showRequiredRequestsError && (
138 <InfoBar 133 <InfoBar
139 type="danger" 134 type="danger"
140 ctaLabel="Try again" 135 ctaLabel="Try again"
141 ctaLoading={areRequiredRequestsLoading} 136 ctaLoading={areRequiredRequestsLoading}
142 sticky 137 sticky
143 onClick={retryRequiredRequests} 138 onClick={retryRequiredRequests}
144 > 139 >
145 <span className="mdi mdi-flash" /> 140 <span className="mdi mdi-flash" />
146 {intl.formatMessage(messages.requiredRequestsFailed)} 141 {intl.formatMessage(messages.requiredRequestsFailed)}
147 </InfoBar> 142 </InfoBar>
148 )} 143 )}
149 {showServicesUpdatedInfoBar && ( 144 {showServicesUpdatedInfoBar && (
150 <InfoBar 145 <InfoBar
diff --git a/src/components/services/content/Services.js b/src/components/services/content/Services.js
index 7f1624003..b71ddd8e6 100644
--- a/src/components/services/content/Services.js
+++ b/src/components/services/content/Services.js
@@ -26,7 +26,8 @@ const styles = {
26 confettiContainer: { 26 confettiContainer: {
27 position: 'absolute', 27 position: 'absolute',
28 width: '100%', 28 width: '100%',
29 zIndex: 0, 29 zIndex: 9999,
30 pointerEvents: 'none',
30 }, 31 },
31}; 32};
32 33
@@ -41,6 +42,7 @@ export default @observer @injectSheet(styles) class Services extends Component {
41 openSettings: PropTypes.func.isRequired, 42 openSettings: PropTypes.func.isRequired,
42 update: PropTypes.func.isRequired, 43 update: PropTypes.func.isRequired,
43 userHasCompletedSignup: PropTypes.bool.isRequired, 44 userHasCompletedSignup: PropTypes.bool.isRequired,
45 hasActivatedTrial: PropTypes.bool.isRequired,
44 classes: PropTypes.object.isRequired, 46 classes: PropTypes.object.isRequired,
45 }; 47 };
46 48
@@ -75,6 +77,7 @@ export default @observer @injectSheet(styles) class Services extends Component {
75 openSettings, 77 openSettings,
76 update, 78 update,
77 userHasCompletedSignup, 79 userHasCompletedSignup,
80 hasActivatedTrial,
78 classes, 81 classes,
79 } = this.props; 82 } = this.props;
80 83
@@ -84,37 +87,37 @@ export default @observer @injectSheet(styles) class Services extends Component {
84 87
85 const { intl } = this.context; 88 const { intl } = this.context;
86 89
90 console.log('hasActivatedTrial', hasActivatedTrial, (userHasCompletedSignup || hasActivatedTrial));
91
87 return ( 92 return (
88 <div className="services"> 93 <div className="services">
94 {(userHasCompletedSignup || hasActivatedTrial) && (
95 <div className={classes.confettiContainer}>
96 <Confetti
97 width={window.width}
98 height={window.height}
99 numberOfPieces={showConfetti ? 200 : 0}
100 />
101 </div>
102 )}
89 {services.length === 0 && ( 103 {services.length === 0 && (
90 <> 104 <Appear
91 {userHasCompletedSignup && ( 105 timeout={1500}
92 <div className={classes.confettiContainer}> 106 transitionName="slideUp"
93 <Confetti 107 >
94 width={window.width} 108 <div className="services__no-service">
95 height={window.height} 109 <img src="./assets/images/logo.svg" alt="" />
96 numberOfPieces={showConfetti ? 200 : 0} 110 <h1>{intl.formatMessage(messages.welcome)}</h1>
97 /> 111 <Appear
98 </div> 112 timeout={300}
99 )} 113 transitionName="slideUp"
100 <Appear 114 >
101 timeout={1500} 115 <Link to="/settings/recipes" className="button">
102 transitionName="slideUp" 116 {intl.formatMessage(messages.getStarted)}
103 > 117 </Link>
104 <div className="services__no-service"> 118 </Appear>
105 <img src="./assets/images/logo.svg" alt="" /> 119 </div>
106 <h1>{intl.formatMessage(messages.welcome)}</h1> 120 </Appear>
107 <Appear
108 timeout={300}
109 transitionName="slideUp"
110 >
111 <Link to="/settings/recipes" className="button">
112 {intl.formatMessage(messages.getStarted)}
113 </Link>
114 </Appear>
115 </div>
116 </Appear>
117 </>
118 )} 121 )}
119 {services.map(service => ( 122 {services.map(service => (
120 <ServiceView 123 <ServiceView
diff --git a/src/components/settings/account/AccountDashboard.js b/src/components/settings/account/AccountDashboard.js
index 3f6964b6b..0366dc1ee 100644
--- a/src/components/settings/account/AccountDashboard.js
+++ b/src/components/settings/account/AccountDashboard.js
@@ -135,62 +135,96 @@ export default @observer class AccountDashboard extends Component {
135 )} 135 )}
136 136
137 {!userInfoRequestFailed && ( 137 {!userInfoRequestFailed && (
138 <Fragment> 138 <>
139 {!isLoading && ( 139 {!isLoading && (
140 <div className="account"> 140 <>
141 <div className="account__box account__box--flex"> 141 <div className="account">
142 <div className="account__avatar"> 142 <div className="account__box account__box--flex">
143 <img 143 <div className="account__avatar">
144 src="./assets/images/logo.svg" 144 <img
145 alt="" 145 src="./assets/images/logo.svg"
146 /> 146 alt=""
147 </div> 147 />
148 <div className="account__info"> 148 </div>
149 <h2> 149 <div className="account__info">
150 <span className="username">{`${user.firstname} ${user.lastname}`}</span> 150 <h2>
151 {user.isPremium && ( 151 <span className="username">{`${user.firstname} ${user.lastname}`}</span>
152 <> 152 {user.isPremium && (
153 {' '}
154 <ProBadge />
155 <span className="badge badge--premium">{intl.formatMessage(messages.accountTypePremium)}</span>
156 </>
157 )}
158 </h2>
159 {user.organization && `${user.organization}, `}
160 {user.email}
161 {user.isPremium && (
162 <div className="manage-user-links">
163 <Button
164 label={intl.formatMessage(messages.accountEditButton)}
165 className="franz-form__button--inverted"
166 onClick={openEditAccount}
167 />
168 {user.isSubscriptionOwner && (
169 <> 153 <>
170 <Button 154 {' '}
171 label={intl.formatMessage(messages.manageSubscriptionButtonLabel)} 155 <ProBadge />
172 className="franz-form__button--inverted" 156 {/* <span className="badge badge--premium">{intl.formatMessage(messages.accountTypePremium)}</span> */}
173 onClick={openBilling}
174 />
175 <Button
176 label={intl.formatMessage(messages.invoicesButton)}
177 className="franz-form__button--inverted"
178 onClick={openInvoices}
179 />
180 </> 157 </>
181 )} 158 )}
182 </div> 159 </h2>
160 <p>
161 {user.organization && `${user.organization}, `}
162 {user.email}
163 </p>
164 {user.isPremium && (
165 <div className="manage-user-links">
166 <Button
167 label={intl.formatMessage(messages.accountEditButton)}
168 className="franz-form__button--inverted"
169 onClick={openEditAccount}
170 />
171 {/* {user.isSubscriptionOwner && (
172 <>
173 <Button
174 label={intl.formatMessage(messages.manageSubscriptionButtonLabel)}
175 className="franz-form__button--inverted"
176 onClick={openBilling}
177 />
178 <Button
179 label={intl.formatMessage(messages.invoicesButton)}
180 className="franz-form__button--inverted"
181 onClick={openInvoices}
182 />
183 </>
184 )} */}
185 </div>
186 )}
187 </div>
188 {!user.isPremium && (
189 <Button
190 label={intl.formatMessage(messages.accountEditButton)}
191 className="franz-form__button--inverted"
192 onClick={openEditAccount}
193 />
183 )} 194 )}
184 </div> 195 </div>
185 {!user.isPremium && (
186 <Button
187 label={intl.formatMessage(messages.accountEditButton)}
188 className="franz-form__button--inverted"
189 onClick={openEditAccount}
190 />
191 )}
192 </div> 196 </div>
193 </div> 197 {user.isSubscriptionOwner && (
198 <div className="account">
199 <div className="account__box">
200 <h2>
201 Your license: {user.team.plan}
202 </h2>
203 {user.team.isTrial && (
204 <>
205 <p>
206 Trial ends in 14 days
207 </p>
208 </>
209 )}
210 {user.isPremium && (
211 <div className="manage-user-links">
212 <Button
213 label={intl.formatMessage(messages.manageSubscriptionButtonLabel)}
214 className="franz-form__button--inverted"
215 onClick={openBilling}
216 />
217 <Button
218 label={intl.formatMessage(messages.invoicesButton)}
219 className="franz-form__button--inverted"
220 onClick={openInvoices}
221 />
222 </div>
223 )}
224 </div>
225 </div>
226 )}
227 </>
194 )} 228 )}
195 229
196 {!user.isPremium && ( 230 {!user.isPremium && (
@@ -227,7 +261,7 @@ export default @observer class AccountDashboard extends Component {
227 )} 261 )}
228 </div> 262 </div>
229 </div> 263 </div>
230 </Fragment> 264 </>
231 )} 265 )}
232 </div> 266 </div>
233 <ReactTooltip place="right" type="dark" effect="solid" /> 267 <ReactTooltip place="right" type="dark" effect="solid" />
diff --git a/src/components/settings/settings/EditSettingsForm.js b/src/components/settings/settings/EditSettingsForm.js
index 6d0811b1b..3f9e0a6bc 100644
--- a/src/components/settings/settings/EditSettingsForm.js
+++ b/src/components/settings/settings/EditSettingsForm.js
@@ -143,8 +143,6 @@ export default @observer class EditSettingsForm extends Component {
143 updateButtonLabelMessage = messages.buttonSearchForUpdate; 143 updateButtonLabelMessage = messages.buttonSearchForUpdate;
144 } 144 }
145 145
146 console.log('isSpellcheckerIncludedInCurrentPlan', isSpellcheckerIncludedInCurrentPlan);
147
148 return ( 146 return (
149 <div className="settings__main"> 147 <div className="settings__main">
150 <div className="settings__header"> 148 <div className="settings__header">
diff --git a/src/containers/layout/AppLayoutContainer.js b/src/containers/layout/AppLayoutContainer.js
index b4e32cffa..a14a98554 100644
--- a/src/containers/layout/AppLayoutContainer.js
+++ b/src/containers/layout/AppLayoutContainer.js
@@ -128,6 +128,7 @@ export default @inject('stores', 'actions') @observer class AppLayoutContainer e
128 openSettings={openSettings} 128 openSettings={openSettings}
129 update={updateService} 129 update={updateService}
130 userHasCompletedSignup={user.hasCompletedSignup} 130 userHasCompletedSignup={user.hasCompletedSignup}
131 hasActivatedTrial={user.hasActivatedTrial}
131 /> 132 />
132 ); 133 );
133 134
@@ -152,6 +153,7 @@ export default @inject('stores', 'actions') @observer class AppLayoutContainer e
152 retryRequiredRequests={retryRequiredRequests} 153 retryRequiredRequests={retryRequiredRequests}
153 areRequiredRequestsLoading={requests.areRequiredRequestsLoading} 154 areRequiredRequestsLoading={requests.areRequiredRequestsLoading}
154 isDelayAppScreenVisible={delayAppState.isDelayAppScreenVisible} 155 isDelayAppScreenVisible={delayAppState.isDelayAppScreenVisible}
156 hasActivatedTrial={user.hasActivatedTrial}
155 > 157 >
156 {React.Children.count(children) > 0 ? children : null} 158 {React.Children.count(children) > 0 ? children : null}
157 </AppLayout> 159 </AppLayout>
diff --git a/src/features/delayApp/Component.js b/src/features/delayApp/Component.js
index ff0f1f2f8..de5653f04 100644
--- a/src/features/delayApp/Component.js
+++ b/src/features/delayApp/Component.js
@@ -4,29 +4,39 @@ import { inject, observer } 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';
6 6
7import { Button } from '@meetfranz/forms';
7import { gaEvent } from '../../lib/analytics'; 8import { gaEvent } from '../../lib/analytics';
8 9
9import Button from '../../components/ui/Button'; 10// import Button from '../../components/ui/Button';
10 11
11import { config } from '.'; 12import { config } from '.';
12import styles from './styles'; 13import styles from './styles';
14import UserStore from '../../stores/UserStore';
13 15
14const messages = defineMessages({ 16const messages = defineMessages({
15 headline: { 17 headline: {
16 id: 'feature.delayApp.headline', 18 id: 'feature.delayApp.headline',
17 defaultMessage: '!!!Please purchase license to skip waiting', 19 defaultMessage: '!!!Please purchase license to skip waiting',
18 }, 20 },
21 headlineTrial: {
22 id: 'feature.delayApp.trial.headline',
23 defaultMessage: '!!!Get the free Franz Professional 14 day trial and skip the line',
24 },
19 action: { 25 action: {
20 id: 'feature.delayApp.action', 26 id: 'feature.delayApp.upgrade.action',
21 defaultMessage: '!!!Get a Franz Supporter License', 27 defaultMessage: '!!!Get a Franz Supporter License',
22 }, 28 },
29 actionTrial: {
30 id: 'feature.delayApp.trial.action',
31 defaultMessage: '!!!Yes, I want the free 14 day trial of Franz Professional',
32 },
23 text: { 33 text: {
24 id: 'feature.delayApp.text', 34 id: 'feature.delayApp.text',
25 defaultMessage: '!!!Franz will continue in {seconds} seconds.', 35 defaultMessage: '!!!Franz will continue in {seconds} seconds.',
26 }, 36 },
27}); 37});
28 38
29export default @inject('actions') @injectSheet(styles) @observer class DelayApp extends Component { 39export default @inject('stores', 'actions') @injectSheet(styles) @observer class DelayApp extends Component {
30 static propTypes = { 40 static propTypes = {
31 // eslint-disable-next-line 41 // eslint-disable-next-line
32 classes: PropTypes.object.isRequired, 42 classes: PropTypes.object.isRequired,
@@ -62,25 +72,37 @@ export default @inject('actions') @injectSheet(styles) @observer class DelayApp
62 } 72 }
63 73
64 handleCTAClick() { 74 handleCTAClick() {
65 const { actions } = this.props; 75 const { actions, stores } = this.props;
76 const { hadSubscription } = stores.user.data;
77 const { defaultTrialPlan } = stores.features.features;
78
79 if (!hadSubscription) {
80 console.log('directly activate trial');
81 actions.user.activateTrial({ planId: defaultTrialPlan });
66 82
67 actions.ui.openSettings({ path: 'user' }); 83 gaEvent('DelayApp', 'subscribe_click', 'Delay App Feature');
84 } else {
85 actions.ui.openSettings({ path: 'user' });
68 86
69 gaEvent('DelayApp', 'subscribe_click', 'Delay App Feature'); 87 gaEvent('DelayApp', 'subscribe_click', 'Delay App Feature');
88 }
70 } 89 }
71 90
72 render() { 91 render() {
73 const { classes } = this.props; 92 const { classes, stores } = this.props;
74 const { intl } = this.context; 93 const { intl } = this.context;
75 94
95 const { hadSubscription } = stores.user.data;
96
76 return ( 97 return (
77 <div className={`${classes.container}`}> 98 <div className={`${classes.container}`}>
78 <h1 className={classes.headline}>{intl.formatMessage(messages.headline)}</h1> 99 <h1 className={classes.headline}>{intl.formatMessage(hadSubscription ? messages.headline : messages.headlineTrial)}</h1>
79 <Button 100 <Button
80 label={intl.formatMessage(messages.action)} 101 label={intl.formatMessage(hadSubscription ? messages.action : messages.actionTrial)}
81 className={classes.button} 102 className={classes.button}
82 buttonType="inverted" 103 buttonType="inverted"
83 onClick={this.handleCTAClick.bind(this)} 104 onClick={this.handleCTAClick.bind(this)}
105 busy={stores.user.activateTrialRequest.isExecuting}
84 /> 106 />
85 <p className="footnote"> 107 <p className="footnote">
86 {intl.formatMessage(messages.text, { 108 {intl.formatMessage(messages.text, {
@@ -93,6 +115,9 @@ export default @inject('actions') @injectSheet(styles) @observer class DelayApp
93} 115}
94 116
95DelayApp.wrappedComponent.propTypes = { 117DelayApp.wrappedComponent.propTypes = {
118 stores: PropTypes.shape({
119 user: PropTypes.instanceOf(UserStore).isRequired,
120 }).isRequired,
96 actions: PropTypes.shape({ 121 actions: PropTypes.shape({
97 ui: PropTypes.shape({ 122 ui: PropTypes.shape({
98 openSettings: PropTypes.func.isRequired, 123 openSettings: PropTypes.func.isRequired,
diff --git a/src/features/delayApp/index.js b/src/features/delayApp/index.js
index 39fae3b20..627537de7 100644
--- a/src/features/delayApp/index.js
+++ b/src/features/delayApp/index.js
@@ -44,7 +44,7 @@ export default function init(stores) {
44 config.delayDuration = globalConfig.wait !== undefined ? globalConfig.wait : DEFAULT_FEATURES_CONFIG.needToWaitToProceedConfig.wait; 44 config.delayDuration = globalConfig.wait !== undefined ? globalConfig.wait : DEFAULT_FEATURES_CONFIG.needToWaitToProceedConfig.wait;
45 45
46 autorun(() => { 46 autorun(() => {
47 if (stores.services.all.length === 0) { 47 if (stores.services.allDisplayed.length === 0) {
48 debug('seas', stores.services.all.length); 48 debug('seas', stores.services.all.length);
49 shownAfterLaunch = true; 49 shownAfterLaunch = true;
50 return; 50 return;
diff --git a/src/i18n/locales/defaultMessages.json b/src/i18n/locales/defaultMessages.json
index 3d11a372d..930f6752e 100644
--- a/src/i18n/locales/defaultMessages.json
+++ b/src/i18n/locales/defaultMessages.json
@@ -417,55 +417,120 @@
417 { 417 {
418 "descriptors": [ 418 "descriptors": [
419 { 419 {
420 "defaultMessage": "!!!Support Franz", 420 "defaultMessage": "!!!Franz Professional",
421 "end": { 421 "end": {
422 "column": 3, 422 "column": 3,
423 "line": 16 423 "line": 18
424 }, 424 },
425 "file": "src/components/auth/Pricing.js", 425 "file": "src/components/auth/Pricing.js",
426 "id": "pricing.headline", 426 "id": "pricing.trial.headline",
427 "start": { 427 "start": {
428 "column": 12, 428 "column": 12,
429 "line": 13 429 "line": 15
430 } 430 }
431 }, 431 },
432 { 432 {
433 "defaultMessage": "!!!Select your support plan", 433 "defaultMessage": "!!!Your personal welcome offer:",
434 "end": { 434 "end": {
435 "column": 3, 435 "column": 3,
436 "line": 20 436 "line": 22
437 }, 437 },
438 "file": "src/components/auth/Pricing.js", 438 "file": "src/components/auth/Pricing.js",
439 "id": "pricing.support.label", 439 "id": "pricing.trial.subheadline",
440 "start": { 440 "start": {
441 "column": 23, 441 "column": 17,
442 "line": 17 442 "line": 19
443 } 443 }
444 }, 444 },
445 { 445 {
446 "defaultMessage": "!!!Support the development of Franz", 446 "defaultMessage": "!!!No strings attached",
447 "end": { 447 "end": {
448 "column": 3, 448 "column": 3,
449 "line": 24 449 "line": 26
450 },
451 "file": "src/components/auth/Pricing.js",
452 "id": "pricing.trial.terms.headline",
453 "start": {
454 "column": 29,
455 "line": 23
456 }
457 },
458 {
459 "defaultMessage": "!!!No credit card required",
460 "end": {
461 "column": 3,
462 "line": 30
463 },
464 "file": "src/components/auth/Pricing.js",
465 "id": "pricing.trial.terms.noCreditCard",
466 "start": {
467 "column": 16,
468 "line": 27
469 }
470 },
471 {
472 "defaultMessage": "!!!Your free trial ends automatically after 14 days",
473 "end": {
474 "column": 3,
475 "line": 34
450 }, 476 },
451 "file": "src/components/auth/Pricing.js", 477 "file": "src/components/auth/Pricing.js",
452 "id": "pricing.submit.label", 478 "id": "pricing.trial.terms.automaticTrialEnd",
453 "start": { 479 "start": {
454 "column": 21, 480 "column": 21,
455 "line": 21 481 "line": 31
456 } 482 }
457 }, 483 },
458 { 484 {
459 "defaultMessage": "!!!I don't want to support the development of Franz.", 485 "defaultMessage": "!!!Sorry, we could not activate your trial!",
460 "end": { 486 "end": {
461 "column": 3, 487 "column": 3,
462 "line": 28 488 "line": 38
463 }, 489 },
464 "file": "src/components/auth/Pricing.js", 490 "file": "src/components/auth/Pricing.js",
465 "id": "pricing.link.skipPayment", 491 "id": "pricing.trial.error",
466 "start": { 492 "start": {
467 "column": 15, 493 "column": 19,
468 "line": 25 494 "line": 35
495 }
496 },
497 {
498 "defaultMessage": "!!!Yes, upgrade my account to Franz Professional",
499 "end": {
500 "column": 3,
501 "line": 42
502 },
503 "file": "src/components/auth/Pricing.js",
504 "id": "pricing.trial.cta.accept",
505 "start": {
506 "column": 13,
507 "line": 39
508 }
509 },
510 {
511 "defaultMessage": "!!!Continue to Franz",
512 "end": {
513 "column": 3,
514 "line": 46
515 },
516 "file": "src/components/auth/Pricing.js",
517 "id": "pricing.trial.cta.skip",
518 "start": {
519 "column": 11,
520 "line": 43
521 }
522 },
523 {
524 "defaultMessage": "!!!Franz Professional includes:",
525 "end": {
526 "column": 3,
527 "line": 50
528 },
529 "file": "src/components/auth/Pricing.js",
530 "id": "pricing.trial.features.headline",
531 "start": {
532 "column": 20,
533 "line": 47
469 } 534 }
470 } 535 }
471 ], 536 ],
@@ -967,26 +1032,26 @@
967 "defaultMessage": "!!!Welcome to Franz", 1032 "defaultMessage": "!!!Welcome to Franz",
968 "end": { 1033 "end": {
969 "column": 3, 1034 "column": 3,
970 "line": 14 1035 "line": 17
971 }, 1036 },
972 "file": "src/components/services/content/Services.js", 1037 "file": "src/components/services/content/Services.js",
973 "id": "services.welcome", 1038 "id": "services.welcome",
974 "start": { 1039 "start": {
975 "column": 11, 1040 "column": 11,
976 "line": 11 1041 "line": 14
977 } 1042 }
978 }, 1043 },
979 { 1044 {
980 "defaultMessage": "!!!Get started", 1045 "defaultMessage": "!!!Get started",
981 "end": { 1046 "end": {
982 "column": 3, 1047 "column": 3,
983 "line": 18 1048 "line": 21
984 }, 1049 },
985 "file": "src/components/services/content/Services.js", 1050 "file": "src/components/services/content/Services.js",
986 "id": "services.getStarted", 1051 "id": "services.getStarted",
987 "start": { 1052 "start": {
988 "column": 14, 1053 "column": 14,
989 "line": 15 1054 "line": 18
990 } 1055 }
991 } 1056 }
992 ], 1057 ],
@@ -2807,6 +2872,141 @@
2807 { 2872 {
2808 "descriptors": [ 2873 "descriptors": [
2809 { 2874 {
2875 "defaultMessage": "!!!Add unlimited services",
2876 "end": {
2877 "column": 3,
2878 "line": 11
2879 },
2880 "file": "src/components/ui/FeatureList.js",
2881 "id": "pricing.features.unlimitedServices",
2882 "start": {
2883 "column": 21,
2884 "line": 8
2885 }
2886 },
2887 {
2888 "defaultMessage": "!!!Spellchecker support",
2889 "end": {
2890 "column": 3,
2891 "line": 15
2892 },
2893 "file": "src/components/ui/FeatureList.js",
2894 "id": "pricing.features.spellchecker",
2895 "start": {
2896 "column": 16,
2897 "line": 12
2898 }
2899 },
2900 {
2901 "defaultMessage": "!!!Workspaces",
2902 "end": {
2903 "column": 3,
2904 "line": 19
2905 },
2906 "file": "src/components/ui/FeatureList.js",
2907 "id": "pricing.features.workspaces",
2908 "start": {
2909 "column": 14,
2910 "line": 16
2911 }
2912 },
2913 {
2914 "defaultMessage": "!!!Add Custom Websites",
2915 "end": {
2916 "column": 3,
2917 "line": 23
2918 },
2919 "file": "src/components/ui/FeatureList.js",
2920 "id": "pricing.features.customWebsites",
2921 "start": {
2922 "column": 18,
2923 "line": 20
2924 }
2925 },
2926 {
2927 "defaultMessage": "!!!On-premise & other Hosted Services",
2928 "end": {
2929 "column": 3,
2930 "line": 27
2931 },
2932 "file": "src/components/ui/FeatureList.js",
2933 "id": "pricing.features.onPremise",
2934 "start": {
2935 "column": 13,
2936 "line": 24
2937 }
2938 },
2939 {
2940 "defaultMessage": "!!!Install 3rd party services",
2941 "end": {
2942 "column": 3,
2943 "line": 31
2944 },
2945 "file": "src/components/ui/FeatureList.js",
2946 "id": "pricing.features.thirdPartyServices",
2947 "start": {
2948 "column": 22,
2949 "line": 28
2950 }
2951 },
2952 {
2953 "defaultMessage": "!!!Service Proxies",
2954 "end": {
2955 "column": 3,
2956 "line": 35
2957 },
2958 "file": "src/components/ui/FeatureList.js",
2959 "id": "pricing.features.serviceProxies",
2960 "start": {
2961 "column": 18,
2962 "line": 32
2963 }
2964 },
2965 {
2966 "defaultMessage": "!!!Team Management",
2967 "end": {
2968 "column": 3,
2969 "line": 39
2970 },
2971 "file": "src/components/ui/FeatureList.js",
2972 "id": "pricing.features.teamManagement",
2973 "start": {
2974 "column": 18,
2975 "line": 36
2976 }
2977 },
2978 {
2979 "defaultMessage": "!!!No Waiting Screens",
2980 "end": {
2981 "column": 3,
2982 "line": 43
2983 },
2984 "file": "src/components/ui/FeatureList.js",
2985 "id": "pricing.features.appDelays",
2986 "start": {
2987 "column": 13,
2988 "line": 40
2989 }
2990 },
2991 {
2992 "defaultMessage": "!!!Forever ad-free",
2993 "end": {
2994 "column": 3,
2995 "line": 47
2996 },
2997 "file": "src/components/ui/FeatureList.js",
2998 "id": "pricing.features.adFree",
2999 "start": {
3000 "column": 10,
3001 "line": 44
3002 }
3003 }
3004 ],
3005 "path": "src/components/ui/FeatureList.json"
3006 },
3007 {
3008 "descriptors": [
3009 {
2810 "defaultMessage": "!!!Upgrade account", 3010 "defaultMessage": "!!!Upgrade account",
2811 "end": { 3011 "end": {
2812 "column": 3, 3012 "column": 3,
@@ -3378,39 +3578,65 @@
3378 "defaultMessage": "!!!Please purchase license to skip waiting", 3578 "defaultMessage": "!!!Please purchase license to skip waiting",
3379 "end": { 3579 "end": {
3380 "column": 3, 3580 "column": 3,
3381 "line": 18 3581 "line": 19
3382 }, 3582 },
3383 "file": "src/features/delayApp/Component.js", 3583 "file": "src/features/delayApp/Component.js",
3384 "id": "feature.delayApp.headline", 3584 "id": "feature.delayApp.headline",
3385 "start": { 3585 "start": {
3386 "column": 12, 3586 "column": 12,
3387 "line": 15 3587 "line": 16
3588 }
3589 },
3590 {
3591 "defaultMessage": "!!!Get the free Franz Professional 14 day trial and skip the line",
3592 "end": {
3593 "column": 3,
3594 "line": 23
3595 },
3596 "file": "src/features/delayApp/Component.js",
3597 "id": "feature.delayApp.trial.headline",
3598 "start": {
3599 "column": 17,
3600 "line": 20
3388 } 3601 }
3389 }, 3602 },
3390 { 3603 {
3391 "defaultMessage": "!!!Get a Franz Supporter License", 3604 "defaultMessage": "!!!Get a Franz Supporter License",
3392 "end": { 3605 "end": {
3393 "column": 3, 3606 "column": 3,
3394 "line": 22 3607 "line": 27
3395 }, 3608 },
3396 "file": "src/features/delayApp/Component.js", 3609 "file": "src/features/delayApp/Component.js",
3397 "id": "feature.delayApp.action", 3610 "id": "feature.delayApp.upgrade.action",
3398 "start": { 3611 "start": {
3399 "column": 10, 3612 "column": 10,
3400 "line": 19 3613 "line": 24
3614 }
3615 },
3616 {
3617 "defaultMessage": "!!!Yes, I want the free 14 day trial of Franz Professional",
3618 "end": {
3619 "column": 3,
3620 "line": 31
3621 },
3622 "file": "src/features/delayApp/Component.js",
3623 "id": "feature.delayApp.trial.action",
3624 "start": {
3625 "column": 15,
3626 "line": 28
3401 } 3627 }
3402 }, 3628 },
3403 { 3629 {
3404 "defaultMessage": "!!!Franz will continue in {seconds} seconds.", 3630 "defaultMessage": "!!!Franz will continue in {seconds} seconds.",
3405 "end": { 3631 "end": {
3406 "column": 3, 3632 "column": 3,
3407 "line": 26 3633 "line": 35
3408 }, 3634 },
3409 "file": "src/features/delayApp/Component.js", 3635 "file": "src/features/delayApp/Component.js",
3410 "id": "feature.delayApp.text", 3636 "id": "feature.delayApp.text",
3411 "start": { 3637 "start": {
3412 "column": 8, 3638 "column": 8,
3413 "line": 23 3639 "line": 32
3414 } 3640 }
3415 } 3641 }
3416 ], 3642 ],
diff --git a/src/i18n/locales/en-US.json b/src/i18n/locales/en-US.json
index 0a8e04b21..4049e9400 100644
--- a/src/i18n/locales/en-US.json
+++ b/src/i18n/locales/en-US.json
@@ -2,9 +2,11 @@
2 "app.errorHandler.action": "Reload", 2 "app.errorHandler.action": "Reload",
3 "app.errorHandler.headline": "Something went wrong", 3 "app.errorHandler.headline": "Something went wrong",
4 "feature.announcements.changelog.headline": "Changes in Franz {version}", 4 "feature.announcements.changelog.headline": "Changes in Franz {version}",
5 "feature.delayApp.action": "Get a Franz Supporter License",
6 "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",
7 "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",
8 "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",
8 "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.", 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.",
9 "feature.shareFranz.action.email": "Send as email", 11 "feature.shareFranz.action.email": "Send as email",
10 "feature.shareFranz.action.facebook": "Share on Facebook", 12 "feature.shareFranz.action.facebook": "Share on Facebook",
@@ -104,10 +106,25 @@
104 "password.submit.label": "Submit", 106 "password.submit.label": "Submit",
105 "password.successInfo": "Please check your email", 107 "password.successInfo": "Please check your email",
106 "premiumFeature.button.upgradeAccount": "Upgrade account", 108 "premiumFeature.button.upgradeAccount": "Upgrade account",
107 "pricing.headline": "Support Franz", 109 "pricing.features.adFree": "!!!Forever ad-free",
108 "pricing.link.skipPayment": "I don't want to support the development of Franz.", 110 "pricing.features.appDelays": "!!!No Waiting Screens",
109 "pricing.submit.label": "I want to support the development of Franz", 111 "pricing.features.customWebsites": "!!!Add Custom Websites",
110 "pricing.support.label": "Select your support plan", 112 "pricing.features.onPremise": "!!!On-premise & other Hosted Services",
113 "pricing.features.serviceProxies": "!!!Service Proxies",
114 "pricing.features.spellchecker": "!!!Spellchecker support",
115 "pricing.features.teamManagement": "!!!Team Management",
116 "pricing.features.thirdPartyServices": "!!!Install 3rd party services",
117 "pricing.features.unlimitedServices": "!!!Add unlimited services",
118 "pricing.features.workspaces": "!!!Workspaces",
119 "pricing.trial.cta.accept": "!!!Yes, upgrade my account to Franz Professional",
120 "pricing.trial.cta.skip": "!!!Continue to Franz",
121 "pricing.trial.error": "!!!Sorry, we could not activate your trial!",
122 "pricing.trial.features.headline": "!!!Franz Professional includes:",
123 "pricing.trial.headline": "!!!Franz Professional",
124 "pricing.trial.subheadline": "!!!Your personal welcome offer:",
125 "pricing.trial.terms.automaticTrialEnd": "!!!Your free trial ends automatically after 14 days",
126 "pricing.trial.terms.headline": "!!!No strings attached",
127 "pricing.trial.terms.noCreditCard": "!!!No credit card required",
111 "service.crashHandler.action": "Reload {name}", 128 "service.crashHandler.action": "Reload {name}",
112 "service.crashHandler.autoReload": "Trying to automatically restore {name} in {seconds} seconds", 129 "service.crashHandler.autoReload": "Trying to automatically restore {name} in {seconds} seconds",
113 "service.crashHandler.headline": "Oh no!", 130 "service.crashHandler.headline": "Oh no!",
@@ -341,4 +358,4 @@
341 "workspaceDrawer.workspaceFeatureInfo": "<p>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.</p><p>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.</p>", 358 "workspaceDrawer.workspaceFeatureInfo": "<p>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.</p><p>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.</p>",
342 "workspaceDrawer.workspacesSettingsTooltip": "Edit workspaces settings", 359 "workspaceDrawer.workspacesSettingsTooltip": "Edit workspaces settings",
343 "workspaces.switchingIndicator.switchingTo": "Switching to" 360 "workspaces.switchingIndicator.switchingTo": "Switching to"
344} 361} \ No newline at end of file
diff --git a/src/i18n/messages/src/components/TrialActivationInfoBar.json b/src/i18n/messages/src/components/TrialActivationInfoBar.json
new file mode 100644
index 000000000..65dd964a6
--- /dev/null
+++ b/src/i18n/messages/src/components/TrialActivationInfoBar.json
@@ -0,0 +1,15 @@
1[
2 {
3 "id": "infobar.trialActivated",
4 "defaultMessage": "!!!Your trial was successfully activated. Happy messaging!",
5 "file": "src/components/TrialActivationInfoBar.js",
6 "start": {
7 "line": 11,
8 "column": 11
9 },
10 "end": {
11 "line": 14,
12 "column": 3
13 }
14 }
15] \ No newline at end of file
diff --git a/src/i18n/messages/src/components/layout/AppLayout.json b/src/i18n/messages/src/components/layout/AppLayout.json
index 190c5dff7..b71889155 100644
--- a/src/i18n/messages/src/components/layout/AppLayout.json
+++ b/src/i18n/messages/src/components/layout/AppLayout.json
@@ -4,11 +4,11 @@
4 "defaultMessage": "!!!Your services have been updated.", 4 "defaultMessage": "!!!Your services have been updated.",
5 "file": "src/components/layout/AppLayout.js", 5 "file": "src/components/layout/AppLayout.js",
6 "start": { 6 "start": {
7 "line": 26, 7 "line": 27,
8 "column": 19 8 "column": 19
9 }, 9 },
10 "end": { 10 "end": {
11 "line": 29, 11 "line": 30,
12 "column": 3 12 "column": 3
13 } 13 }
14 }, 14 },
@@ -17,11 +17,11 @@
17 "defaultMessage": "!!!Reload services", 17 "defaultMessage": "!!!Reload services",
18 "file": "src/components/layout/AppLayout.js", 18 "file": "src/components/layout/AppLayout.js",
19 "start": { 19 "start": {
20 "line": 30, 20 "line": 31,
21 "column": 24 21 "column": 24
22 }, 22 },
23 "end": { 23 "end": {
24 "line": 33, 24 "line": 34,
25 "column": 3 25 "column": 3
26 } 26 }
27 }, 27 },
@@ -30,11 +30,11 @@
30 "defaultMessage": "!!!Could not load services and user information", 30 "defaultMessage": "!!!Could not load services and user information",
31 "file": "src/components/layout/AppLayout.js", 31 "file": "src/components/layout/AppLayout.js",
32 "start": { 32 "start": {
33 "line": 34, 33 "line": 35,
34 "column": 26 34 "column": 26
35 }, 35 },
36 "end": { 36 "end": {
37 "line": 37, 37 "line": 38,
38 "column": 3 38 "column": 3
39 } 39 }
40 } 40 }
diff --git a/src/i18n/messages/src/features/delayApp/Component.json b/src/i18n/messages/src/features/delayApp/Component.json
index bacd9444a..0d345a47b 100644
--- a/src/i18n/messages/src/features/delayApp/Component.json
+++ b/src/i18n/messages/src/features/delayApp/Component.json
@@ -4,24 +4,50 @@
4 "defaultMessage": "!!!Please purchase license to skip waiting", 4 "defaultMessage": "!!!Please purchase license to skip waiting",
5 "file": "src/features/delayApp/Component.js", 5 "file": "src/features/delayApp/Component.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 },
15 { 15 {
16 "id": "feature.delayApp.action", 16 "id": "feature.delayApp.trial.headline",
17 "defaultMessage": "!!!Get the free Franz Professional 14 day trial and skip the line",
18 "file": "src/features/delayApp/Component.js",
19 "start": {
20 "line": 21,
21 "column": 17
22 },
23 "end": {
24 "line": 24,
25 "column": 3
26 }
27 },
28 {
29 "id": "feature.delayApp.upgrade.action",
17 "defaultMessage": "!!!Get a Franz Supporter License", 30 "defaultMessage": "!!!Get a Franz Supporter License",
18 "file": "src/features/delayApp/Component.js", 31 "file": "src/features/delayApp/Component.js",
19 "start": { 32 "start": {
20 "line": 19, 33 "line": 25,
21 "column": 10 34 "column": 10
22 }, 35 },
23 "end": { 36 "end": {
24 "line": 22, 37 "line": 28,
38 "column": 3
39 }
40 },
41 {
42 "id": "feature.delayApp.trial.action",
43 "defaultMessage": "!!!Yes, I want the free 14 day trial of Franz Professional",
44 "file": "src/features/delayApp/Component.js",
45 "start": {
46 "line": 29,
47 "column": 15
48 },
49 "end": {
50 "line": 32,
25 "column": 3 51 "column": 3
26 } 52 }
27 }, 53 },
@@ -30,11 +56,11 @@
30 "defaultMessage": "!!!Franz will continue in {seconds} seconds.", 56 "defaultMessage": "!!!Franz will continue in {seconds} seconds.",
31 "file": "src/features/delayApp/Component.js", 57 "file": "src/features/delayApp/Component.js",
32 "start": { 58 "start": {
33 "line": 23, 59 "line": 33,
34 "column": 8 60 "column": 8
35 }, 61 },
36 "end": { 62 "end": {
37 "line": 26, 63 "line": 36,
38 "column": 3 64 "column": 3
39 } 65 }
40 } 66 }
diff --git a/src/models/User.js b/src/models/User.js
index bec78fc16..0a2b1f62a 100644
--- a/src/models/User.js
+++ b/src/models/User.js
@@ -20,6 +20,10 @@ export default class User {
20 20
21 @observable isSubscriptionOwner = false; 21 @observable isSubscriptionOwner = false;
22 22
23 @observable hasSubscription = false;
24
25 @observable hadSubscription = false;
26
23 @observable isPremium = false; 27 @observable isPremium = false;
24 28
25 @observable beta = false; 29 @observable beta = false;
@@ -32,6 +36,9 @@ export default class User {
32 36
33 @observable locale = false; 37 @observable locale = false;
34 38
39 @observable team = {};
40
41
35 constructor(data) { 42 constructor(data) {
36 if (!data.id) { 43 if (!data.id) {
37 throw Error('User requires Id'); 44 throw Error('User requires Id');
@@ -47,8 +54,13 @@ export default class User {
47 this.beta = data.beta || this.beta; 54 this.beta = data.beta || this.beta;
48 this.donor = data.donor || this.donor; 55 this.donor = data.donor || this.donor;
49 this.isDonor = data.isDonor || this.isDonor; 56 this.isDonor = data.isDonor || this.isDonor;
50 this.isSubscriptionOwner = data.isSubscriptionOwner || this.isSubscriptionOwner;
51 this.isMiner = data.isMiner || this.isMiner; 57 this.isMiner = data.isMiner || this.isMiner;
52 this.locale = data.locale || this.locale; 58 this.locale = data.locale || this.locale;
59
60 this.isSubscriptionOwner = data.isSubscriptionOwner || this.isSubscriptionOwner;
61 this.hasSubscription = data.hasSubscription || this.hasSubscription;
62 this.hadSubscription = data.hadSubscription || this.hadSubscription;
63
64 this.team = data.team || this.team;
53 } 65 }
54} 66}
diff --git a/src/stores/UserStore.js b/src/stores/UserStore.js
index 6d746254e..e7516e6e6 100644
--- a/src/stores/UserStore.js
+++ b/src/stores/UserStore.js
@@ -2,12 +2,14 @@ import { observable, computed, action } from 'mobx';
2import moment from 'moment'; 2import moment from 'moment';
3import jwt from 'jsonwebtoken'; 3import jwt from 'jsonwebtoken';
4import localStorage from 'mobx-localstorage'; 4import localStorage from 'mobx-localstorage';
5import ms from 'ms';
5 6
6import { isDevMode } from '../environment'; 7import { isDevMode } from '../environment';
7import Store from './lib/Store'; 8import Store from './lib/Store';
8import Request from './lib/Request'; 9import Request from './lib/Request';
9import CachedRequest from './lib/CachedRequest'; 10import CachedRequest from './lib/CachedRequest';
10import { gaEvent } from '../lib/analytics'; 11import { gaEvent } from '../lib/analytics';
12import { sleep } from '../helpers/async-helpers';
11 13
12const debug = require('debug')('Franz:UserStore'); 14const debug = require('debug')('Franz:UserStore');
13 15
@@ -61,6 +63,8 @@ export default class UserStore extends Store {
61 63
62 @observable hasCompletedSignup = false; 64 @observable hasCompletedSignup = false;
63 65
66 @observable hasActivatedTrial = false;
67
64 @observable userData = {}; 68 @observable userData = {};
65 69
66 @observable actionStatus = []; 70 @observable actionStatus = [];
@@ -90,6 +94,7 @@ export default class UserStore extends Store {
90 this.registerReactions([ 94 this.registerReactions([
91 this._requireAuthenticatedUser, 95 this._requireAuthenticatedUser,
92 this._getUserData.bind(this), 96 this._getUserData.bind(this),
97 this._resetTrialActivationState.bind(this),
93 ]); 98 ]);
94 } 99 }
95 100
@@ -211,7 +216,13 @@ export default class UserStore extends Store {
211 216
212 await this.activateTrialRequest._promise; 217 await this.activateTrialRequest._promise;
213 218
219 this.hasActivatedTrial = true;
220
221 console.log('hasActivatedTrial', this.hasActivatedTrial);
222
214 this.stores.features.featuresRequest.invalidate({ immediately: true }); 223 this.stores.features.featuresRequest.invalidate({ immediately: true });
224 this.stores.user.getUserInfoRequest.invalidate({ immediately: true });
225
215 226
216 gaEvent('User', 'activateTrial'); 227 gaEvent('User', 'activateTrial');
217 } 228 }
@@ -335,6 +346,16 @@ export default class UserStore extends Store {
335 } 346 }
336 } 347 }
337 348
349 async _resetTrialActivationState() {
350 if (this.hasActivatedTrial) {
351 await sleep(ms('12s'));
352
353 console.log('resetting this.hasActivatedTrial', this.hasActivatedTrial);
354
355 this.hasActivatedTrial = false;
356 }
357 }
358
338 // Helpers 359 // Helpers
339 _parseToken(authToken) { 360 _parseToken(authToken) {
340 try { 361 try {
diff --git a/src/styles/recipes.scss b/src/styles/recipes.scss
index 56a248e98..5bdc60a57 100644
--- a/src/styles/recipes.scss
+++ b/src/styles/recipes.scss
@@ -2,6 +2,7 @@
2 2
3.theme__dark .recipe-teaser { 3.theme__dark .recipe-teaser {
4 background-color: $dark-theme-gray-dark; 4 background-color: $dark-theme-gray-dark;
5 color: $dark-theme-text-color;
5 6
6 &:hover { background-color: $dark-theme-gray; } 7 &:hover { background-color: $dark-theme-gray; }
7} 8}