diff options
author | 2019-08-05 13:24:35 +0200 | |
---|---|---|
committer | 2019-08-05 13:24:35 +0200 | |
commit | 76559f2895012803aed3256ce521b9cfff2f63b8 (patch) | |
tree | f511ed44ab8cb16af257e58ff960da1fd60c5876 | |
parent | Add trial onboarding during signup (diff) | |
download | ferdium-app-76559f2895012803aed3256ce521b9cfff2f63b8.tar.gz ferdium-app-76559f2895012803aed3256ce521b9cfff2f63b8.tar.zst ferdium-app-76559f2895012803aed3256ce521b9cfff2f63b8.zip |
WIP: add option to activate trial
-rw-r--r-- | src/api/server/ServerApi.js | 2 | ||||
-rw-r--r-- | src/components/TrialActivationInfoBar.js | 94 | ||||
-rw-r--r-- | src/components/layout/AppLayout.js | 37 | ||||
-rw-r--r-- | src/components/services/content/Services.js | 61 | ||||
-rw-r--r-- | src/components/settings/account/AccountDashboard.js | 134 | ||||
-rw-r--r-- | src/components/settings/settings/EditSettingsForm.js | 2 | ||||
-rw-r--r-- | src/containers/layout/AppLayoutContainer.js | 2 | ||||
-rw-r--r-- | src/features/delayApp/Component.js | 43 | ||||
-rw-r--r-- | src/features/delayApp/index.js | 2 | ||||
-rw-r--r-- | src/i18n/locales/defaultMessages.json | 284 | ||||
-rw-r--r-- | src/i18n/locales/en-US.json | 29 | ||||
-rw-r--r-- | src/i18n/messages/src/components/TrialActivationInfoBar.json | 15 | ||||
-rw-r--r-- | src/i18n/messages/src/components/layout/AppLayout.json | 12 | ||||
-rw-r--r-- | src/i18n/messages/src/features/delayApp/Component.json | 40 | ||||
-rw-r--r-- | src/models/User.js | 14 | ||||
-rw-r--r-- | src/stores/UserStore.js | 21 | ||||
-rw-r--r-- | src/styles/recipes.scss | 1 |
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 @@ | |||
1 | import React, { Component } from 'react'; | ||
2 | import PropTypes from 'prop-types'; | ||
3 | import { defineMessages, intlShape } from 'react-intl'; | ||
4 | import ms from 'ms'; | ||
5 | import injectSheet from 'react-jss'; | ||
6 | import classnames from 'classnames'; | ||
7 | |||
8 | import InfoBar from './ui/InfoBar'; | ||
9 | |||
10 | const messages = defineMessages({ | ||
11 | message: { | ||
12 | id: 'infobar.trialActivated', | ||
13 | defaultMessage: '!!!Your trial was successfully activated. Happy messaging!', | ||
14 | }, | ||
15 | }); | ||
16 | |||
17 | const 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) | ||
32 | class 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 | |||
94 | export 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'; | |||
17 | import WorkspaceSwitchingIndicator from '../../features/workspaces/components/WorkspaceSwitchingIndicator'; | 17 | import WorkspaceSwitchingIndicator from '../../features/workspaces/components/WorkspaceSwitchingIndicator'; |
18 | import { workspaceStore } from '../../features/workspaces'; | 18 | import { workspaceStore } from '../../features/workspaces'; |
19 | import AppUpdateInfoBar from '../AppUpdateInfoBar'; | 19 | import AppUpdateInfoBar from '../AppUpdateInfoBar'; |
20 | import TrialActivationInfoBar from '../TrialActivationInfoBar'; | ||
20 | 21 | ||
21 | function createMarkup(HTMLString) { | 22 | function 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'; | |||
4 | import { defineMessages, intlShape } from 'react-intl'; | 4 | import { defineMessages, intlShape } from 'react-intl'; |
5 | import injectSheet from 'react-jss'; | 5 | import injectSheet from 'react-jss'; |
6 | 6 | ||
7 | import { Button } from '@meetfranz/forms'; | ||
7 | import { gaEvent } from '../../lib/analytics'; | 8 | import { gaEvent } from '../../lib/analytics'; |
8 | 9 | ||
9 | import Button from '../../components/ui/Button'; | 10 | // import Button from '../../components/ui/Button'; |
10 | 11 | ||
11 | import { config } from '.'; | 12 | import { config } from '.'; |
12 | import styles from './styles'; | 13 | import styles from './styles'; |
14 | import UserStore from '../../stores/UserStore'; | ||
13 | 15 | ||
14 | const messages = defineMessages({ | 16 | const 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 | ||
29 | export default @inject('actions') @injectSheet(styles) @observer class DelayApp extends Component { | 39 | export 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 | ||
95 | DelayApp.wrappedComponent.propTypes = { | 117 | DelayApp.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'; | |||
2 | import moment from 'moment'; | 2 | import moment from 'moment'; |
3 | import jwt from 'jsonwebtoken'; | 3 | import jwt from 'jsonwebtoken'; |
4 | import localStorage from 'mobx-localstorage'; | 4 | import localStorage from 'mobx-localstorage'; |
5 | import ms from 'ms'; | ||
5 | 6 | ||
6 | import { isDevMode } from '../environment'; | 7 | import { isDevMode } from '../environment'; |
7 | import Store from './lib/Store'; | 8 | import Store from './lib/Store'; |
8 | import Request from './lib/Request'; | 9 | import Request from './lib/Request'; |
9 | import CachedRequest from './lib/CachedRequest'; | 10 | import CachedRequest from './lib/CachedRequest'; |
10 | import { gaEvent } from '../lib/analytics'; | 11 | import { gaEvent } from '../lib/analytics'; |
12 | import { sleep } from '../helpers/async-helpers'; | ||
11 | 13 | ||
12 | const debug = require('debug')('Franz:UserStore'); | 14 | const 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 | } |