diff options
Diffstat (limited to 'src')
67 files changed, 3137 insertions, 943 deletions
diff --git a/src/actions/user.js b/src/actions/user.js index ccf1fa56a..5d7d9a899 100644 --- a/src/actions/user.js +++ b/src/actions/user.js | |||
@@ -17,6 +17,9 @@ export default { | |||
17 | retrievePassword: { | 17 | retrievePassword: { |
18 | email: PropTypes.string.isRequired, | 18 | email: PropTypes.string.isRequired, |
19 | }, | 19 | }, |
20 | activateTrial: { | ||
21 | planId: PropTypes.string.isRequired, | ||
22 | }, | ||
20 | invite: { | 23 | invite: { |
21 | invites: PropTypes.array.isRequired, | 24 | invites: PropTypes.array.isRequired, |
22 | }, | 25 | }, |
diff --git a/src/api/UserApi.js b/src/api/UserApi.js index edfb88988..8ba8cd1e9 100644 --- a/src/api/UserApi.js +++ b/src/api/UserApi.js | |||
@@ -25,6 +25,10 @@ export default class UserApi { | |||
25 | return this.server.retrievePassword(email); | 25 | return this.server.retrievePassword(email); |
26 | } | 26 | } |
27 | 27 | ||
28 | activateTrial(data) { | ||
29 | return this.server.activateTrial(data); | ||
30 | } | ||
31 | |||
28 | invite(data) { | 32 | invite(data) { |
29 | return this.server.inviteUser(data); | 33 | return this.server.inviteUser(data); |
30 | } | 34 | } |
diff --git a/src/api/server/ServerApi.js b/src/api/server/ServerApi.js index a9ce202ff..f56c7b6e4 100644 --- a/src/api/server/ServerApi.js +++ b/src/api/server/ServerApi.js | |||
@@ -77,6 +77,20 @@ export default class ServerApi { | |||
77 | return u.token; | 77 | return u.token; |
78 | } | 78 | } |
79 | 79 | ||
80 | async activateTrial(data) { | ||
81 | const request = await sendAuthRequest(`${API_URL}/payment/trial`, { | ||
82 | method: 'POST', | ||
83 | body: JSON.stringify(data), | ||
84 | }); | ||
85 | if (!request.ok) { | ||
86 | throw request; | ||
87 | } | ||
88 | const trial = await request.json(); | ||
89 | |||
90 | debug('ServerApi::signup resolves', trial); | ||
91 | return true; | ||
92 | } | ||
93 | |||
80 | async inviteUser(data) { | 94 | async inviteUser(data) { |
81 | const request = await sendAuthRequest(`${API_URL}/invite`, { | 95 | const request = await sendAuthRequest(`${API_URL}/invite`, { |
82 | method: 'POST', | 96 | method: 'POST', |
@@ -469,7 +483,7 @@ export default class ServerApi { | |||
469 | return services; | 483 | return services; |
470 | } | 484 | } |
471 | } catch (err) { | 485 | } catch (err) { |
472 | throw (new Error('ServerApi::getLegacyServices no config found')); | 486 | console.error('ServerApi::getLegacyServices no config found'); |
473 | } | 487 | } |
474 | 488 | ||
475 | return []; | 489 | return []; |
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/auth/Pricing.js b/src/components/auth/Pricing.js index 7ab14f429..cbeaaa5d9 100644 --- a/src/components/auth/Pricing.js +++ b/src/components/auth/Pricing.js | |||
@@ -1,40 +1,107 @@ | |||
1 | import React, { Component } from 'react'; | 1 | import React, { Component } from 'react'; |
2 | import PropTypes from 'prop-types'; | 2 | import PropTypes from 'prop-types'; |
3 | import { observer, PropTypes as MobxPropTypes } from 'mobx-react'; | 3 | import { observer } from 'mobx-react'; |
4 | import { defineMessages, intlShape } from 'react-intl'; | 4 | import { defineMessages, intlShape } from 'react-intl'; |
5 | // import { Link } from 'react-router'; | 5 | import injectSheet from 'react-jss'; |
6 | import { H2, Loader } from '@meetfranz/ui'; | ||
7 | import classnames from 'classnames'; | ||
8 | |||
9 | import { Button } from '@meetfranz/forms'; | ||
10 | import { FeatureItem } from '../ui/FeatureItem'; | ||
11 | import { FeatureList } from '../ui/FeatureList'; | ||
6 | 12 | ||
7 | // import Button from '../ui/Button'; | ||
8 | import Loader from '../ui/Loader'; | ||
9 | import Appear from '../ui/effects/Appear'; | ||
10 | import SubscriptionForm from '../../containers/subscription/SubscriptionFormScreen'; | ||
11 | 13 | ||
12 | const messages = defineMessages({ | 14 | const messages = defineMessages({ |
13 | headline: { | 15 | headline: { |
14 | id: 'pricing.headline', | 16 | id: 'pricing.trial.headline', |
15 | defaultMessage: '!!!Support Franz', | 17 | defaultMessage: '!!!Franz Professional', |
18 | }, | ||
19 | personalOffer: { | ||
20 | id: 'pricing.trial.subheadline', | ||
21 | defaultMessage: '!!!Your personal welcome offer:', | ||
22 | }, | ||
23 | noStringsAttachedHeadline: { | ||
24 | id: 'pricing.trial.terms.headline', | ||
25 | defaultMessage: '!!!No strings attached', | ||
26 | }, | ||
27 | noCreditCard: { | ||
28 | id: 'pricing.trial.terms.noCreditCard', | ||
29 | defaultMessage: '!!!No credit card required', | ||
16 | }, | 30 | }, |
17 | monthlySupportLabel: { | 31 | automaticTrialEnd: { |
18 | id: 'pricing.support.label', | 32 | id: 'pricing.trial.terms.automaticTrialEnd', |
19 | defaultMessage: '!!!Select your support plan', | 33 | defaultMessage: '!!!Your free trial ends automatically after 14 days', |
20 | }, | 34 | }, |
21 | submitButtonLabel: { | 35 | activationError: { |
22 | id: 'pricing.submit.label', | 36 | id: 'pricing.trial.error', |
23 | defaultMessage: '!!!Support the development of Franz', | 37 | defaultMessage: '!!!Sorry, we could not activate your trial!', |
24 | }, | 38 | }, |
25 | skipPayment: { | 39 | ctaAccept: { |
26 | id: 'pricing.link.skipPayment', | 40 | id: 'pricing.trial.cta.accept', |
27 | defaultMessage: '!!!I don\'t want to support the development of Franz.', | 41 | defaultMessage: '!!!Yes, upgrade my account to Franz Professional', |
42 | }, | ||
43 | ctaSkip: { | ||
44 | id: 'pricing.trial.cta.skip', | ||
45 | defaultMessage: '!!!Continue to Franz', | ||
46 | }, | ||
47 | featuresHeadline: { | ||
48 | id: 'pricing.trial.features.headline', | ||
49 | defaultMessage: '!!!Franz Professional includes:', | ||
28 | }, | 50 | }, |
29 | }); | 51 | }); |
30 | 52 | ||
31 | export default @observer class Signup extends Component { | 53 | const styles = theme => ({ |
54 | container: { | ||
55 | position: 'relative', | ||
56 | marginLeft: -150, | ||
57 | }, | ||
58 | welcomeOffer: { | ||
59 | textAlign: 'center', | ||
60 | fontWeight: 'bold', | ||
61 | }, | ||
62 | keyTerms: { | ||
63 | textAlign: 'center', | ||
64 | }, | ||
65 | content: { | ||
66 | position: 'relative', | ||
67 | zIndex: 20, | ||
68 | }, | ||
69 | featureContainer: { | ||
70 | width: 300, | ||
71 | position: 'absolute', | ||
72 | left: 'calc(100% / 2 + 225px)', | ||
73 | top: 155, | ||
74 | background: theme.signup.pricing.feature.background, | ||
75 | height: 'auto', | ||
76 | padding: 20, | ||
77 | borderTopRightRadius: theme.borderRadius, | ||
78 | borderBottomRightRadius: theme.borderRadius, | ||
79 | zIndex: 10, | ||
80 | }, | ||
81 | featureItem: { | ||
82 | borderBottom: [1, 'solid', theme.signup.pricing.feature.border], | ||
83 | }, | ||
84 | cta: { | ||
85 | marginTop: 40, | ||
86 | width: '100%', | ||
87 | }, | ||
88 | skipLink: { | ||
89 | textAlign: 'center', | ||
90 | marginTop: 10, | ||
91 | }, | ||
92 | error: { | ||
93 | margin: [20, 0, 0], | ||
94 | color: theme.styleTypes.danger.accent, | ||
95 | }, | ||
96 | }); | ||
97 | |||
98 | export default @observer @injectSheet(styles) class Signup extends Component { | ||
32 | static propTypes = { | 99 | static propTypes = { |
33 | donor: MobxPropTypes.objectOrObservableObject.isRequired, | 100 | onSubmit: PropTypes.func.isRequired, |
34 | isLoading: PropTypes.bool.isRequired, | 101 | isLoadingRequiredData: PropTypes.bool.isRequired, |
35 | isLoadingUser: PropTypes.bool.isRequired, | 102 | isActivatingTrial: PropTypes.bool.isRequired, |
36 | onCloseSubscriptionWindow: PropTypes.func.isRequired, | 103 | trialActivationError: PropTypes.bool.isRequired, |
37 | skipAction: PropTypes.func.isRequired, | 104 | classes: PropTypes.object.isRequired, |
38 | }; | 105 | }; |
39 | 106 | ||
40 | static contextTypes = { | 107 | static contextTypes = { |
@@ -43,70 +110,37 @@ export default @observer class Signup extends Component { | |||
43 | 110 | ||
44 | render() { | 111 | render() { |
45 | const { | 112 | const { |
46 | donor, | 113 | onSubmit, |
47 | isLoading, | 114 | isLoadingRequiredData, |
48 | isLoadingUser, | 115 | isActivatingTrial, |
49 | onCloseSubscriptionWindow, | 116 | trialActivationError, |
50 | skipAction, | 117 | classes, |
51 | } = this.props; | 118 | } = this.props; |
52 | const { intl } = this.context; | 119 | const { intl } = this.context; |
53 | 120 | ||
54 | return ( | 121 | return ( |
55 | <div className="auth__scroll-container"> | 122 | <div className={classnames('auth__scroll-container', classes.container)}> |
56 | <div className="auth__container auth__container--signup"> | 123 | <div className={classnames('auth__container', 'auth__container--signup', classes.content)}> |
57 | <form className="franz-form auth__form"> | 124 | <form className="franz-form auth__form"> |
58 | <img | 125 | {isLoadingRequiredData ? <Loader /> : ( |
59 | src="./assets/images/sm.png" | 126 | <img |
60 | className="auth__logo auth__logo--sm" | 127 | src="./assets/images/sm.png" |
61 | alt="" | 128 | className="auth__logo auth__logo--sm" |
62 | /> | 129 | alt="" |
130 | /> | ||
131 | )} | ||
132 | <p className={classes.welcomeOffer}>{intl.formatMessage(messages.personalOffer)}</p> | ||
63 | <h1>{intl.formatMessage(messages.headline)}</h1> | 133 | <h1>{intl.formatMessage(messages.headline)}</h1> |
64 | <div className="auth__letter"> | 134 | <div className="auth__letter"> |
65 | {isLoadingUser && ( | 135 | <p> |
66 | <p>Loading</p> | 136 | We built Franz with a lot of effort, manpower and love, |
67 | )} | 137 | to boost up your messaging experience. |
68 | {!isLoadingUser && ( | 138 | <br /> |
69 | donor.amount ? ( | 139 | </p> |
70 | <span> | 140 | <p> |
71 | <p> | 141 | Get the free 14 day Franz Professional trial and see your communication evolving. |
72 | Thank you so much for your previous donation of | 142 | <br /> |
73 | {' '} | 143 | </p> |
74 | <strong> | ||
75 | $ | ||
76 | {donor.amount} | ||
77 | </strong> | ||
78 | . | ||
79 | <br /> | ||
80 | Your support allowed us to get where we are today. | ||
81 | <br /> | ||
82 | </p> | ||
83 | <p> | ||
84 | As an early supporter, you get | ||
85 | {' '} | ||
86 | <strong>a lifetime premium supporter license</strong> | ||
87 | {' '} | ||
88 | without any | ||
89 | additional charges. | ||
90 | </p> | ||
91 | <p> | ||
92 | However, If you want to keep supporting us, you are more than welcome to subscribe to a plan. | ||
93 | <br /> | ||
94 | <br /> | ||
95 | </p> | ||
96 | </span> | ||
97 | ) : ( | ||
98 | <span> | ||
99 | <p> | ||
100 | We built Franz with a lot of effort, manpower and love, | ||
101 | to bring you the best messaging experience. | ||
102 | <br /> | ||
103 | </p> | ||
104 | <p> | ||
105 | Getting a Franz Premium Supporter License will allow us to keep improving Franz for you. | ||
106 | </p> | ||
107 | </span> | ||
108 | ) | ||
109 | )} | ||
110 | <p> | 144 | <p> |
111 | Thanks for being a hero. | 145 | Thanks for being a hero. |
112 | </p> | 146 | </p> |
@@ -114,20 +148,48 @@ export default @observer class Signup extends Component { | |||
114 | <strong>Stefan Malzner</strong> | 148 | <strong>Stefan Malzner</strong> |
115 | </p> | 149 | </p> |
116 | </div> | 150 | </div> |
117 | <Loader loaded={!isLoading}> | 151 | <div className={classes.keyTerms}> |
118 | <Appear transitionName="slideDown"> | 152 | <H2> |
119 | <span className="label">{intl.formatMessage(messages.monthlySupportLabel)}</span> | 153 | {intl.formatMessage(messages.noStringsAttachedHeadline)} |
120 | <SubscriptionForm | 154 | </H2> |
121 | onCloseWindow={onCloseSubscriptionWindow} | 155 | <ul className={classes.keyTermsList}> |
122 | showSkipOption | 156 | <FeatureItem icon="👉" name={intl.formatMessage(messages.noCreditCard)} /> |
123 | skipAction={skipAction} | 157 | <FeatureItem icon="👉" name={intl.formatMessage(messages.automaticTrialEnd)} /> |
124 | hideInfo={Boolean(donor.amount)} | 158 | </ul> |
125 | skipButtonLabel={intl.formatMessage(messages.skipPayment)} | 159 | </div> |
126 | /> | 160 | {trialActivationError && ( |
127 | </Appear> | 161 | <p className={classes.error}>{intl.formatMessage(messages.activationError)}</p> |
128 | </Loader> | 162 | )} |
163 | <Button | ||
164 | label={intl.formatMessage(messages.ctaAccept)} | ||
165 | className={classes.cta} | ||
166 | onClick={onSubmit} | ||
167 | busy={isActivatingTrial} | ||
168 | disabled={isLoadingRequiredData || isActivatingTrial} | ||
169 | /> | ||
170 | <p className={classes.skipLink}> | ||
171 | <a href="#/">{intl.formatMessage(messages.ctaSkip)}</a> | ||
172 | </p> | ||
129 | </form> | 173 | </form> |
130 | </div> | 174 | </div> |
175 | <div className={classes.featureContainer}> | ||
176 | <H2> | ||
177 | {intl.formatMessage(messages.featuresHeadline)} | ||
178 | </H2> | ||
179 | {/* <ul className={classes.features}> | ||
180 | <FeatureItem name="Add unlimited services" className={classes.featureItem} /> | ||
181 | <FeatureItem name="Spellchecker support" className={classes.featureItem} /> | ||
182 | <FeatureItem name="Workspaces" className={classes.featureItem} /> | ||
183 | <FeatureItem name="Add Custom Websites" className={classes.featureItem} /> | ||
184 | <FeatureItem name="On-premise & other Hosted Services" className={classes.featureItem} /> | ||
185 | <FeatureItem name="Install 3rd party services" className={classes.featureItem} /> | ||
186 | <FeatureItem name="Service Proxies" className={classes.featureItem} /> | ||
187 | <FeatureItem name="Team Management" className={classes.featureItem} /> | ||
188 | <FeatureItem name="No Waiting Screens" className={classes.featureItem} /> | ||
189 | <FeatureItem name="Forever ad-free" className={classes.featureItem} /> | ||
190 | </ul> */} | ||
191 | <FeatureList /> | ||
192 | </div> | ||
131 | </div> | 193 | </div> |
132 | ); | 194 | ); |
133 | } | 195 | } |
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/ServiceRestricted.js b/src/components/services/content/ServiceRestricted.js new file mode 100644 index 000000000..4b8d926aa --- /dev/null +++ b/src/components/services/content/ServiceRestricted.js | |||
@@ -0,0 +1,78 @@ | |||
1 | import React, { Component } from 'react'; | ||
2 | import PropTypes from 'prop-types'; | ||
3 | import { observer } from 'mobx-react'; | ||
4 | import { defineMessages, intlShape } from 'react-intl'; | ||
5 | |||
6 | import { serviceLimitStore } from '../../../features/serviceLimit'; | ||
7 | import Button from '../../ui/Button'; | ||
8 | import { RESTRICTION_TYPES } from '../../../models/Service'; | ||
9 | |||
10 | const messages = defineMessages({ | ||
11 | headlineServiceLimit: { | ||
12 | id: 'service.restrictedHandler.serviceLimit.headline', | ||
13 | defaultMessage: '!!!You have reached your service limit.', | ||
14 | }, | ||
15 | textServiceLimit: { | ||
16 | id: 'service.restrictedHandler.serviceLimit.text', | ||
17 | defaultMessage: '!!!Please upgrade your account to use more than {count} services.', | ||
18 | }, | ||
19 | headlineCustomUrl: { | ||
20 | id: 'service.restrictedHandler.customUrl.headline', | ||
21 | defaultMessage: '!!!Franz Professional Plan required', | ||
22 | }, | ||
23 | textCustomUrl: { | ||
24 | id: 'service.restrictedHandler.customUrl.text', | ||
25 | defaultMessage: '!!!Please upgrade to the Franz Professional plan to use custom urls & self hosted services.', | ||
26 | }, | ||
27 | action: { | ||
28 | id: 'service.restrictedHandler.action', | ||
29 | defaultMessage: '!!!Upgrade Account', | ||
30 | }, | ||
31 | }); | ||
32 | |||
33 | export default @observer class ServiceRestricted extends Component { | ||
34 | static propTypes = { | ||
35 | name: PropTypes.string.isRequired, | ||
36 | upgrade: PropTypes.func.isRequired, | ||
37 | type: PropTypes.number.isRequired, | ||
38 | }; | ||
39 | |||
40 | static contextTypes = { | ||
41 | intl: intlShape, | ||
42 | }; | ||
43 | |||
44 | countdownInterval = null; | ||
45 | |||
46 | countdownIntervalTimeout = 1000; | ||
47 | |||
48 | render() { | ||
49 | const { | ||
50 | name, | ||
51 | upgrade, | ||
52 | type, | ||
53 | } = this.props; | ||
54 | const { intl } = this.context; | ||
55 | |||
56 | return ( | ||
57 | <div className="services__info-layer"> | ||
58 | {type === RESTRICTION_TYPES.SERVICE_LIMIT && ( | ||
59 | <> | ||
60 | <h1>{intl.formatMessage(messages.headlineServiceLimit)}</h1> | ||
61 | <p>{intl.formatMessage(messages.textServiceLimit, { count: serviceLimitStore.serviceLimit })}</p> | ||
62 | </> | ||
63 | )} | ||
64 | {type === RESTRICTION_TYPES.CUSTOM_URL && ( | ||
65 | <> | ||
66 | <h1>{intl.formatMessage(messages.headlineCustomUrl)}</h1> | ||
67 | <p>{intl.formatMessage(messages.textCustomUrl)}</p> | ||
68 | </> | ||
69 | )} | ||
70 | <Button | ||
71 | label={intl.formatMessage(messages.action, { name })} | ||
72 | buttonType="inverted" | ||
73 | onClick={() => upgrade()} | ||
74 | /> | ||
75 | </div> | ||
76 | ); | ||
77 | } | ||
78 | } | ||
diff --git a/src/components/services/content/ServiceView.js b/src/components/services/content/ServiceView.js index 13148b9b3..f65f51346 100644 --- a/src/components/services/content/ServiceView.js +++ b/src/components/services/content/ServiceView.js | |||
@@ -10,6 +10,7 @@ import WebviewLoader from '../../ui/WebviewLoader'; | |||
10 | import WebviewCrashHandler from './WebviewCrashHandler'; | 10 | import WebviewCrashHandler from './WebviewCrashHandler'; |
11 | import WebviewErrorHandler from './ErrorHandlers/WebviewErrorHandler'; | 11 | import WebviewErrorHandler from './ErrorHandlers/WebviewErrorHandler'; |
12 | import ServiceDisabled from './ServiceDisabled'; | 12 | import ServiceDisabled from './ServiceDisabled'; |
13 | import ServiceRestricted from './ServiceRestricted'; | ||
13 | import ServiceWebview from './ServiceWebview'; | 14 | import ServiceWebview from './ServiceWebview'; |
14 | 15 | ||
15 | export default @observer class ServiceView extends Component { | 16 | export default @observer class ServiceView extends Component { |
@@ -21,6 +22,7 @@ export default @observer class ServiceView extends Component { | |||
21 | edit: PropTypes.func.isRequired, | 22 | edit: PropTypes.func.isRequired, |
22 | enable: PropTypes.func.isRequired, | 23 | enable: PropTypes.func.isRequired, |
23 | isActive: PropTypes.bool, | 24 | isActive: PropTypes.bool, |
25 | upgrade: PropTypes.func.isRequired, | ||
24 | }; | 26 | }; |
25 | 27 | ||
26 | static defaultProps = { | 28 | static defaultProps = { |
@@ -72,6 +74,7 @@ export default @observer class ServiceView extends Component { | |||
72 | reload, | 74 | reload, |
73 | edit, | 75 | edit, |
74 | enable, | 76 | enable, |
77 | upgrade, | ||
75 | } = this.props; | 78 | } = this.props; |
76 | 79 | ||
77 | const webviewClasses = classnames({ | 80 | const webviewClasses = classnames({ |
@@ -99,7 +102,7 @@ export default @observer class ServiceView extends Component { | |||
99 | reload={reload} | 102 | reload={reload} |
100 | /> | 103 | /> |
101 | )} | 104 | )} |
102 | {service.isEnabled && service.isLoading && service.isFirstLoad && ( | 105 | {service.isEnabled && service.isLoading && service.isFirstLoad && !service.isServiceAccessRestricted && ( |
103 | <WebviewLoader | 106 | <WebviewLoader |
104 | loaded={false} | 107 | loaded={false} |
105 | name={service.name} | 108 | name={service.name} |
@@ -126,11 +129,21 @@ export default @observer class ServiceView extends Component { | |||
126 | )} | 129 | )} |
127 | </Fragment> | 130 | </Fragment> |
128 | ) : ( | 131 | ) : ( |
129 | <ServiceWebview | 132 | <> |
130 | service={service} | 133 | {service.isServiceAccessRestricted ? ( |
131 | setWebviewReference={setWebviewReference} | 134 | <ServiceRestricted |
132 | detachService={detachService} | 135 | name={service.recipe.name} |
133 | /> | 136 | upgrade={upgrade} |
137 | type={service.restrictionType} | ||
138 | /> | ||
139 | ) : ( | ||
140 | <ServiceWebview | ||
141 | service={service} | ||
142 | setWebviewReference={setWebviewReference} | ||
143 | detachService={detachService} | ||
144 | /> | ||
145 | )} | ||
146 | </> | ||
134 | )} | 147 | )} |
135 | {statusBar} | 148 | {statusBar} |
136 | </div> | 149 | </div> |
diff --git a/src/components/services/content/Services.js b/src/components/services/content/Services.js index 8f8c38a11..b71ddd8e6 100644 --- a/src/components/services/content/Services.js +++ b/src/components/services/content/Services.js | |||
@@ -3,6 +3,9 @@ import PropTypes from 'prop-types'; | |||
3 | import { observer, PropTypes as MobxPropTypes } from 'mobx-react'; | 3 | import { observer, PropTypes as MobxPropTypes } from 'mobx-react'; |
4 | import { Link } from 'react-router'; | 4 | import { Link } from 'react-router'; |
5 | import { defineMessages, intlShape } from 'react-intl'; | 5 | import { defineMessages, intlShape } from 'react-intl'; |
6 | import Confetti from 'react-confetti'; | ||
7 | import ms from 'ms'; | ||
8 | import injectSheet from 'react-jss'; | ||
6 | 9 | ||
7 | import ServiceView from './ServiceView'; | 10 | import ServiceView from './ServiceView'; |
8 | import Appear from '../../ui/effects/Appear'; | 11 | import Appear from '../../ui/effects/Appear'; |
@@ -18,7 +21,17 @@ const messages = defineMessages({ | |||
18 | }, | 21 | }, |
19 | }); | 22 | }); |
20 | 23 | ||
21 | export default @observer class Services extends Component { | 24 | |
25 | const styles = { | ||
26 | confettiContainer: { | ||
27 | position: 'absolute', | ||
28 | width: '100%', | ||
29 | zIndex: 9999, | ||
30 | pointerEvents: 'none', | ||
31 | }, | ||
32 | }; | ||
33 | |||
34 | export default @observer @injectSheet(styles) class Services extends Component { | ||
22 | static propTypes = { | 35 | static propTypes = { |
23 | services: MobxPropTypes.arrayOrObservableArray, | 36 | services: MobxPropTypes.arrayOrObservableArray, |
24 | setWebviewReference: PropTypes.func.isRequired, | 37 | setWebviewReference: PropTypes.func.isRequired, |
@@ -28,6 +41,9 @@ export default @observer class Services extends Component { | |||
28 | reload: PropTypes.func.isRequired, | 41 | reload: PropTypes.func.isRequired, |
29 | openSettings: PropTypes.func.isRequired, | 42 | openSettings: PropTypes.func.isRequired, |
30 | update: PropTypes.func.isRequired, | 43 | update: PropTypes.func.isRequired, |
44 | userHasCompletedSignup: PropTypes.bool.isRequired, | ||
45 | hasActivatedTrial: PropTypes.bool.isRequired, | ||
46 | classes: PropTypes.object.isRequired, | ||
31 | }; | 47 | }; |
32 | 48 | ||
33 | static defaultProps = { | 49 | static defaultProps = { |
@@ -38,6 +54,18 @@ export default @observer class Services extends Component { | |||
38 | intl: intlShape, | 54 | intl: intlShape, |
39 | }; | 55 | }; |
40 | 56 | ||
57 | state = { | ||
58 | showConfetti: true, | ||
59 | } | ||
60 | |||
61 | componentDidMount() { | ||
62 | window.setTimeout(() => { | ||
63 | this.setState({ | ||
64 | showConfetti: false, | ||
65 | }); | ||
66 | }, ms('8s')); | ||
67 | } | ||
68 | |||
41 | render() { | 69 | render() { |
42 | const { | 70 | const { |
43 | services, | 71 | services, |
@@ -48,11 +76,30 @@ export default @observer class Services extends Component { | |||
48 | reload, | 76 | reload, |
49 | openSettings, | 77 | openSettings, |
50 | update, | 78 | update, |
79 | userHasCompletedSignup, | ||
80 | hasActivatedTrial, | ||
81 | classes, | ||
51 | } = this.props; | 82 | } = this.props; |
83 | |||
84 | const { | ||
85 | showConfetti, | ||
86 | } = this.state; | ||
87 | |||
52 | const { intl } = this.context; | 88 | const { intl } = this.context; |
53 | 89 | ||
90 | console.log('hasActivatedTrial', hasActivatedTrial, (userHasCompletedSignup || hasActivatedTrial)); | ||
91 | |||
54 | return ( | 92 | return ( |
55 | <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 | )} | ||
56 | {services.length === 0 && ( | 103 | {services.length === 0 && ( |
57 | <Appear | 104 | <Appear |
58 | timeout={1500} | 105 | timeout={1500} |
@@ -89,6 +136,7 @@ export default @observer class Services extends Component { | |||
89 | }, | 136 | }, |
90 | redirect: false, | 137 | redirect: false, |
91 | })} | 138 | })} |
139 | upgrade={() => openSettings({ path: 'user' })} | ||
92 | /> | 140 | /> |
93 | ))} | 141 | ))} |
94 | </div> | 142 | </div> |
diff --git a/src/components/settings/account/AccountDashboard.js b/src/components/settings/account/AccountDashboard.js index 3f6964b6b..079d50380 100644 --- a/src/components/settings/account/AccountDashboard.js +++ b/src/components/settings/account/AccountDashboard.js | |||
@@ -1,14 +1,18 @@ | |||
1 | import React, { Component, Fragment } from 'react'; | 1 | import React, { Component } from 'react'; |
2 | import PropTypes from 'prop-types'; | 2 | import PropTypes from 'prop-types'; |
3 | import { observer, PropTypes as MobxPropTypes } from 'mobx-react'; | 3 | import { observer, PropTypes as MobxPropTypes } from 'mobx-react'; |
4 | import { defineMessages, intlShape } from 'react-intl'; | 4 | import { defineMessages, intlShape } from 'react-intl'; |
5 | import ReactTooltip from 'react-tooltip'; | 5 | import ReactTooltip from 'react-tooltip'; |
6 | import { ProBadge } from '@meetfranz/ui'; | 6 | import { |
7 | ProBadge, H2, H1, H3, | ||
8 | } from '@meetfranz/ui'; | ||
9 | import moment from 'moment'; | ||
7 | 10 | ||
8 | import Loader from '../../ui/Loader'; | 11 | import Loader from '../../ui/Loader'; |
9 | import Button from '../../ui/Button'; | 12 | import Button from '../../ui/Button'; |
10 | import Infobox from '../../ui/Infobox'; | 13 | import Infobox from '../../ui/Infobox'; |
11 | import SubscriptionForm from '../../../containers/subscription/SubscriptionFormScreen'; | 14 | import SubscriptionForm from '../../../containers/subscription/SubscriptionFormScreen'; |
15 | import { i18nPlanName } from '../../../helpers/plan-helpers'; | ||
12 | 16 | ||
13 | const messages = defineMessages({ | 17 | const messages = defineMessages({ |
14 | headline: { | 18 | headline: { |
@@ -20,8 +24,8 @@ const messages = defineMessages({ | |||
20 | defaultMessage: '!!!Your Subscription', | 24 | defaultMessage: '!!!Your Subscription', |
21 | }, | 25 | }, |
22 | headlineUpgrade: { | 26 | headlineUpgrade: { |
23 | id: 'settings.account.headlineUpgrade', | 27 | id: 'settings.account.headlineTrialUpgrade', |
24 | defaultMessage: '!!!Upgrade your Account', | 28 | defaultMessage: '!!!Get the free 14 day Franz Professional Trial', |
25 | }, | 29 | }, |
26 | headlineDangerZone: { | 30 | headlineDangerZone: { |
27 | id: 'settings.account.headlineDangerZone', | 31 | id: 'settings.account.headlineDangerZone', |
@@ -71,6 +75,22 @@ const messages = defineMessages({ | |||
71 | id: 'settings.account.deleteEmailSent', | 75 | id: 'settings.account.deleteEmailSent', |
72 | defaultMessage: '!!!You have received an email with a link to confirm your account deletion. Your account and data cannot be restored!', | 76 | defaultMessage: '!!!You have received an email with a link to confirm your account deletion. Your account and data cannot be restored!', |
73 | }, | 77 | }, |
78 | trial: { | ||
79 | id: 'settings.account.trial', | ||
80 | defaultMessage: '!!!Free Trial', | ||
81 | }, | ||
82 | yourLicense: { | ||
83 | id: 'settings.account.yourLicense', | ||
84 | defaultMessage: '!!!Your license:', | ||
85 | }, | ||
86 | trialEndsIn: { | ||
87 | id: 'settings.account.trialEndsIn', | ||
88 | defaultMessage: '!!!Your free trial ends in {duration}.', | ||
89 | }, | ||
90 | trialUpdateBillingInformation: { | ||
91 | id: 'settings.account.trialUpdateBillingInfo', | ||
92 | defaultMessage: '!!!Please update your billing info to continue using {license} after your trial period.', | ||
93 | }, | ||
74 | }); | 94 | }); |
75 | 95 | ||
76 | export default @observer class AccountDashboard extends Component { | 96 | export default @observer class AccountDashboard extends Component { |
@@ -110,6 +130,13 @@ export default @observer class AccountDashboard extends Component { | |||
110 | } = this.props; | 130 | } = this.props; |
111 | const { intl } = this.context; | 131 | const { intl } = this.context; |
112 | 132 | ||
133 | let planName = ''; | ||
134 | |||
135 | if (user.team && user.team.plan) { | ||
136 | planName = i18nPlanName(user.team.plan, intl); | ||
137 | console.log(planName); | ||
138 | } | ||
139 | |||
113 | return ( | 140 | return ( |
114 | <div className="settings__main"> | 141 | <div className="settings__main"> |
115 | <div className="settings__header"> | 142 | <div className="settings__header"> |
@@ -135,82 +162,123 @@ export default @observer class AccountDashboard extends Component { | |||
135 | )} | 162 | )} |
136 | 163 | ||
137 | {!userInfoRequestFailed && ( | 164 | {!userInfoRequestFailed && ( |
138 | <Fragment> | 165 | <> |
139 | {!isLoading && ( | 166 | {!isLoading && ( |
140 | <div className="account"> | 167 | <> |
141 | <div className="account__box account__box--flex"> | 168 | <div className="account"> |
142 | <div className="account__avatar"> | 169 | <div className="account__box account__box--flex"> |
143 | <img | 170 | <div className="account__avatar"> |
144 | src="./assets/images/logo.svg" | 171 | <img |
145 | alt="" | 172 | src="./assets/images/logo.svg" |
146 | /> | 173 | alt="" |
147 | </div> | 174 | /> |
148 | <div className="account__info"> | 175 | </div> |
149 | <h2> | 176 | <div className="account__info"> |
150 | <span className="username">{`${user.firstname} ${user.lastname}`}</span> | 177 | <H1> |
178 | <span className="username">{`${user.firstname} ${user.lastname}`}</span> | ||
179 | {user.isPremium && ( | ||
180 | <> | ||
181 | {' '} | ||
182 | <ProBadge /> | ||
183 | {/* <span className="badge badge--premium">{intl.formatMessage(messages.accountTypePremium)}</span> */} | ||
184 | </> | ||
185 | )} | ||
186 | </H1> | ||
187 | <p> | ||
188 | {user.organization && `${user.organization}, `} | ||
189 | {user.email} | ||
190 | </p> | ||
151 | {user.isPremium && ( | 191 | {user.isPremium && ( |
192 | <div className="manage-user-links"> | ||
193 | <Button | ||
194 | label={intl.formatMessage(messages.accountEditButton)} | ||
195 | className="franz-form__button--inverted" | ||
196 | onClick={openEditAccount} | ||
197 | /> | ||
198 | {/* {user.isSubscriptionOwner && ( | ||
199 | <> | ||
200 | <Button | ||
201 | label={intl.formatMessage(messages.manageSubscriptionButtonLabel)} | ||
202 | className="franz-form__button--inverted" | ||
203 | onClick={openBilling} | ||
204 | /> | ||
205 | <Button | ||
206 | label={intl.formatMessage(messages.invoicesButton)} | ||
207 | className="franz-form__button--inverted" | ||
208 | onClick={openInvoices} | ||
209 | /> | ||
210 | </> | ||
211 | )} */} | ||
212 | </div> | ||
213 | )} | ||
214 | </div> | ||
215 | {!user.isPremium && ( | ||
216 | <Button | ||
217 | label={intl.formatMessage(messages.accountEditButton)} | ||
218 | className="franz-form__button--inverted" | ||
219 | onClick={openEditAccount} | ||
220 | /> | ||
221 | )} | ||
222 | </div> | ||
223 | </div> | ||
224 | {user.isSubscriptionOwner && ( | ||
225 | <div className="account"> | ||
226 | <div className="account__box"> | ||
227 | <H2> | ||
228 | {intl.formatMessage(messages.yourLicense)} | ||
229 | </H2> | ||
230 | <H3> | ||
231 | {planName} | ||
232 | {user.team.isTrial && ( | ||
233 | <> | ||
234 | {' – '} | ||
235 | {intl.formatMessage(messages.trial)} | ||
236 | </> | ||
237 | )} | ||
238 | </H3> | ||
239 | {user.team.isTrial && ( | ||
152 | <> | 240 | <> |
153 | {' '} | 241 | <p> |
154 | <ProBadge /> | 242 | {intl.formatMessage(messages.trialEndsIn, { |
155 | <span className="badge badge--premium">{intl.formatMessage(messages.accountTypePremium)}</span> | 243 | duration: moment.duration(moment().diff(user.team.trialEnd)).humanize(), |
244 | })} | ||
245 | </p> | ||
246 | <p> | ||
247 | {intl.formatMessage(messages.trialUpdateBillingInformation, { | ||
248 | license: planName, | ||
249 | })} | ||
250 | </p> | ||
156 | </> | 251 | </> |
157 | )} | 252 | )} |
158 | </h2> | ||
159 | {user.organization && `${user.organization}, `} | ||
160 | {user.email} | ||
161 | {user.isPremium && ( | ||
162 | <div className="manage-user-links"> | 253 | <div className="manage-user-links"> |
163 | <Button | 254 | <Button |
164 | label={intl.formatMessage(messages.accountEditButton)} | 255 | label={intl.formatMessage(messages.manageSubscriptionButtonLabel)} |
165 | className="franz-form__button--inverted" | 256 | className="franz-form__button--inverted" |
166 | onClick={openEditAccount} | 257 | onClick={openBilling} |
258 | /> | ||
259 | <Button | ||
260 | label={intl.formatMessage(messages.invoicesButton)} | ||
261 | className="franz-form__button--inverted" | ||
262 | onClick={openInvoices} | ||
167 | /> | 263 | /> |
168 | {user.isSubscriptionOwner && ( | ||
169 | <> | ||
170 | <Button | ||
171 | label={intl.formatMessage(messages.manageSubscriptionButtonLabel)} | ||
172 | className="franz-form__button--inverted" | ||
173 | onClick={openBilling} | ||
174 | /> | ||
175 | <Button | ||
176 | label={intl.formatMessage(messages.invoicesButton)} | ||
177 | className="franz-form__button--inverted" | ||
178 | onClick={openInvoices} | ||
179 | /> | ||
180 | </> | ||
181 | )} | ||
182 | </div> | 264 | </div> |
183 | )} | 265 | </div> |
184 | </div> | 266 | </div> |
185 | {!user.isPremium && ( | 267 | )} |
186 | <Button | 268 | {!user.isPremium && ( |
187 | label={intl.formatMessage(messages.accountEditButton)} | 269 | <div className="account franz-form"> |
188 | className="franz-form__button--inverted" | 270 | <div className="account__box"> |
189 | onClick={openEditAccount} | 271 | <H2>{intl.formatMessage(messages.headlineUpgrade)}</H2> |
190 | /> | 272 | <SubscriptionForm /> |
191 | )} | 273 | </div> |
192 | </div> | ||
193 | </div> | ||
194 | )} | ||
195 | |||
196 | {!user.isPremium && ( | ||
197 | isLoadingPlans ? ( | ||
198 | <Loader /> | ||
199 | ) : ( | ||
200 | <div className="account franz-form"> | ||
201 | <div className="account__box"> | ||
202 | <h2>{intl.formatMessage(messages.headlineUpgrade)}</h2> | ||
203 | <SubscriptionForm | ||
204 | onCloseWindow={onCloseSubscriptionWindow} | ||
205 | /> | ||
206 | </div> | 274 | </div> |
207 | </div> | 275 | )} |
208 | ) | 276 | </> |
209 | )} | 277 | )} |
210 | 278 | ||
211 | <div className="account franz-form"> | 279 | <div className="account franz-form"> |
212 | <div className="account__box"> | 280 | <div className="account__box"> |
213 | <h2>{intl.formatMessage(messages.headlineDangerZone)}</h2> | 281 | <H2>{intl.formatMessage(messages.headlineDangerZone)}</H2> |
214 | {!isDeleteAccountSuccessful && ( | 282 | {!isDeleteAccountSuccessful && ( |
215 | <div className="account__subscription"> | 283 | <div className="account__subscription"> |
216 | <p>{intl.formatMessage(messages.deleteInfo)}</p> | 284 | <p>{intl.formatMessage(messages.deleteInfo)}</p> |
@@ -227,7 +295,7 @@ export default @observer class AccountDashboard extends Component { | |||
227 | )} | 295 | )} |
228 | </div> | 296 | </div> |
229 | </div> | 297 | </div> |
230 | </Fragment> | 298 | </> |
231 | )} | 299 | )} |
232 | </div> | 300 | </div> |
233 | <ReactTooltip place="right" type="dark" effect="solid" /> | 301 | <ReactTooltip place="right" type="dark" effect="solid" /> |
diff --git a/src/components/settings/navigation/SettingsNavigation.js b/src/components/settings/navigation/SettingsNavigation.js index df4b3b3b2..4696b82eb 100644 --- a/src/components/settings/navigation/SettingsNavigation.js +++ b/src/components/settings/navigation/SettingsNavigation.js | |||
@@ -8,6 +8,7 @@ import Link from '../../ui/Link'; | |||
8 | import { workspaceStore } from '../../../features/workspaces'; | 8 | import { workspaceStore } from '../../../features/workspaces'; |
9 | import UIStore from '../../../stores/UIStore'; | 9 | import UIStore from '../../../stores/UIStore'; |
10 | import UserStore from '../../../stores/UserStore'; | 10 | import UserStore from '../../../stores/UserStore'; |
11 | import { serviceLimitStore } from '../../../features/serviceLimit'; | ||
11 | 12 | ||
12 | const messages = defineMessages({ | 13 | const messages = defineMessages({ |
13 | availableServices: { | 14 | availableServices: { |
@@ -80,7 +81,12 @@ export default @inject('stores') @observer class SettingsNavigation extends Comp | |||
80 | > | 81 | > |
81 | {intl.formatMessage(messages.yourServices)} | 82 | {intl.formatMessage(messages.yourServices)} |
82 | {' '} | 83 | {' '} |
83 | <span className="badge">{serviceCount}</span> | 84 | <span className="badge"> |
85 | {serviceCount} | ||
86 | {serviceLimitStore.serviceLimit !== 0 && ( | ||
87 | `/${serviceLimitStore.serviceLimit}` | ||
88 | )} | ||
89 | </span> | ||
84 | </Link> | 90 | </Link> |
85 | {workspaceStore.isFeatureEnabled ? ( | 91 | {workspaceStore.isFeatureEnabled ? ( |
86 | <Link | 92 | <Link |
diff --git a/src/components/settings/recipes/RecipeItem.js b/src/components/settings/recipes/RecipeItem.js index 3bb0852b2..12e3775f6 100644 --- a/src/components/settings/recipes/RecipeItem.js +++ b/src/components/settings/recipes/RecipeItem.js | |||
@@ -19,7 +19,7 @@ export default @observer class RecipeItem extends Component { | |||
19 | className="recipe-teaser" | 19 | className="recipe-teaser" |
20 | onClick={onClick} | 20 | onClick={onClick} |
21 | > | 21 | > |
22 | {recipe.local && ( | 22 | {recipe.isDevRecipe && ( |
23 | <span className="recipe-teaser__dev-badge">dev</span> | 23 | <span className="recipe-teaser__dev-badge">dev</span> |
24 | )} | 24 | )} |
25 | <img | 25 | <img |
diff --git a/src/components/settings/recipes/RecipesDashboard.js b/src/components/settings/recipes/RecipesDashboard.js index 00cd725cf..75e60b7ec 100644 --- a/src/components/settings/recipes/RecipesDashboard.js +++ b/src/components/settings/recipes/RecipesDashboard.js | |||
@@ -4,12 +4,17 @@ import { observer, PropTypes as MobxPropTypes } from 'mobx-react'; | |||
4 | import { defineMessages, intlShape } from 'react-intl'; | 4 | import { defineMessages, intlShape } from 'react-intl'; |
5 | import { Link } from 'react-router'; | 5 | import { Link } from 'react-router'; |
6 | 6 | ||
7 | import { Button, Input } from '@meetfranz/forms'; | ||
8 | import injectSheet from 'react-jss'; | ||
9 | import { H3, H2, ProBadge } from '@meetfranz/ui'; | ||
7 | import SearchInput from '../../ui/SearchInput'; | 10 | import SearchInput from '../../ui/SearchInput'; |
8 | import Infobox from '../../ui/Infobox'; | 11 | import Infobox from '../../ui/Infobox'; |
9 | import RecipeItem from './RecipeItem'; | 12 | import RecipeItem from './RecipeItem'; |
10 | import Loader from '../../ui/Loader'; | 13 | import Loader from '../../ui/Loader'; |
11 | import Appear from '../../ui/effects/Appear'; | 14 | import Appear from '../../ui/effects/Appear'; |
12 | import { FRANZ_SERVICE_REQUEST } from '../../../config'; | 15 | import { FRANZ_SERVICE_REQUEST } from '../../../config'; |
16 | import LimitReachedInfobox from '../../../features/serviceLimit/components/LimitReachedInfobox'; | ||
17 | import PremiumFeatureContainer from '../../ui/PremiumFeatureContainer'; | ||
13 | 18 | ||
14 | const messages = defineMessages({ | 19 | const messages = defineMessages({ |
15 | headline: { | 20 | headline: { |
@@ -28,9 +33,9 @@ const messages = defineMessages({ | |||
28 | id: 'settings.recipes.all', | 33 | id: 'settings.recipes.all', |
29 | defaultMessage: '!!!All services', | 34 | defaultMessage: '!!!All services', |
30 | }, | 35 | }, |
31 | devRecipes: { | 36 | customRecipes: { |
32 | id: 'settings.recipes.dev', | 37 | id: 'settings.recipes.custom', |
33 | defaultMessage: '!!!Development', | 38 | defaultMessage: '!!!Custom Services', |
34 | }, | 39 | }, |
35 | nothingFound: { | 40 | nothingFound: { |
36 | id: 'settings.recipes.nothingFound', | 41 | id: 'settings.recipes.nothingFound', |
@@ -44,9 +49,61 @@ const messages = defineMessages({ | |||
44 | id: 'settings.recipes.missingService', | 49 | id: 'settings.recipes.missingService', |
45 | defaultMessage: '!!!Missing a service?', | 50 | defaultMessage: '!!!Missing a service?', |
46 | }, | 51 | }, |
52 | customRecipeIntro: { | ||
53 | id: 'settings.recipes.customService.intro', | ||
54 | defaultMessage: '!!!To add a custom service, copy the recipe folder into:', | ||
55 | }, | ||
56 | openFolder: { | ||
57 | id: 'settings.recipes.customService.openFolder', | ||
58 | defaultMessage: '!!!Open directory', | ||
59 | }, | ||
60 | openDevDocs: { | ||
61 | id: 'settings.recipes.customService.openDevDocs', | ||
62 | defaultMessage: '!!!Developer Documentation', | ||
63 | }, | ||
64 | headlineCustomRecipes: { | ||
65 | id: 'settings.recipes.customService.headline.customRecipes', | ||
66 | defaultMessage: '!!!Custom Service Recipes', | ||
67 | }, | ||
68 | headlineCommunityRecipes: { | ||
69 | id: 'settings.recipes.customService.headline.communityRecipes', | ||
70 | defaultMessage: '!!!Community Services', | ||
71 | }, | ||
72 | headlineDevRecipes: { | ||
73 | id: 'settings.recipes.customService.headline.devRecipes', | ||
74 | defaultMessage: '!!!Your Development Service Recipes', | ||
75 | }, | ||
47 | }); | 76 | }); |
48 | 77 | ||
49 | export default @observer class RecipesDashboard extends Component { | 78 | const styles = { |
79 | devRecipeIntroContainer: { | ||
80 | textAlign: 'center', | ||
81 | width: '100%', | ||
82 | height: 'auto', | ||
83 | margin: [40, 0], | ||
84 | }, | ||
85 | path: { | ||
86 | marginTop: 20, | ||
87 | |||
88 | '& > div': { | ||
89 | fontFamily: 'SFMono-Regular,Consolas,Liberation Mono,Menlo,Courier,monospace', | ||
90 | }, | ||
91 | }, | ||
92 | actionContainer: { | ||
93 | '& button': { | ||
94 | margin: [0, 10], | ||
95 | }, | ||
96 | }, | ||
97 | devRecipeList: { | ||
98 | marginTop: 20, | ||
99 | height: 'auto', | ||
100 | }, | ||
101 | proBadge: { | ||
102 | marginLeft: '10px !important', | ||
103 | }, | ||
104 | }; | ||
105 | |||
106 | export default @injectSheet(styles) @observer class RecipesDashboard extends Component { | ||
50 | static propTypes = { | 107 | static propTypes = { |
51 | recipes: MobxPropTypes.arrayOrObservableArray.isRequired, | 108 | recipes: MobxPropTypes.arrayOrObservableArray.isRequired, |
52 | isLoading: PropTypes.bool.isRequired, | 109 | isLoading: PropTypes.bool.isRequired, |
@@ -55,12 +112,18 @@ export default @observer class RecipesDashboard extends Component { | |||
55 | searchRecipes: PropTypes.func.isRequired, | 112 | searchRecipes: PropTypes.func.isRequired, |
56 | resetSearch: PropTypes.func.isRequired, | 113 | resetSearch: PropTypes.func.isRequired, |
57 | serviceStatus: MobxPropTypes.arrayOrObservableArray.isRequired, | 114 | serviceStatus: MobxPropTypes.arrayOrObservableArray.isRequired, |
58 | devRecipesCount: PropTypes.number.isRequired, | ||
59 | searchNeedle: PropTypes.string, | 115 | searchNeedle: PropTypes.string, |
116 | recipeFilter: PropTypes.string, | ||
117 | recipeDirectory: PropTypes.string.isRequired, | ||
118 | openRecipeDirectory: PropTypes.func.isRequired, | ||
119 | openDevDocs: PropTypes.func.isRequired, | ||
120 | classes: PropTypes.object.isRequired, | ||
121 | isCommunityRecipesIncludedInCurrentPlan: PropTypes.bool.isRequired, | ||
60 | }; | 122 | }; |
61 | 123 | ||
62 | static defaultProps = { | 124 | static defaultProps = { |
63 | searchNeedle: '', | 125 | searchNeedle: '', |
126 | recipeFilter: 'all', | ||
64 | } | 127 | } |
65 | 128 | ||
66 | static contextTypes = { | 129 | static contextTypes = { |
@@ -76,16 +139,26 @@ export default @observer class RecipesDashboard extends Component { | |||
76 | searchRecipes, | 139 | searchRecipes, |
77 | resetSearch, | 140 | resetSearch, |
78 | serviceStatus, | 141 | serviceStatus, |
79 | devRecipesCount, | ||
80 | searchNeedle, | 142 | searchNeedle, |
143 | recipeFilter, | ||
144 | recipeDirectory, | ||
145 | openRecipeDirectory, | ||
146 | openDevDocs, | ||
147 | classes, | ||
148 | isCommunityRecipesIncludedInCurrentPlan, | ||
81 | } = this.props; | 149 | } = this.props; |
82 | const { intl } = this.context; | 150 | const { intl } = this.context; |
83 | 151 | ||
152 | |||
153 | const communityRecipes = recipes.filter(r => !r.isDevRecipe); | ||
154 | const devRecipes = recipes.filter(r => r.isDevRecipe); | ||
155 | |||
84 | return ( | 156 | return ( |
85 | <div className="settings__main"> | 157 | <div className="settings__main"> |
86 | <div className="settings__header"> | 158 | <div className="settings__header"> |
87 | <h1>{intl.formatMessage(messages.headline)}</h1> | 159 | <h1>{intl.formatMessage(messages.headline)}</h1> |
88 | </div> | 160 | </div> |
161 | <LimitReachedInfobox /> | ||
89 | <div className="settings__body recipes"> | 162 | <div className="settings__body recipes"> |
90 | {serviceStatus.length > 0 && serviceStatus.includes('created') && ( | 163 | {serviceStatus.length > 0 && serviceStatus.includes('created') && ( |
91 | <Appear> | 164 | <Appear> |
@@ -122,20 +195,14 @@ export default @observer class RecipesDashboard extends Component { | |||
122 | > | 195 | > |
123 | {intl.formatMessage(messages.allRecipes)} | 196 | {intl.formatMessage(messages.allRecipes)} |
124 | </Link> | 197 | </Link> |
125 | {devRecipesCount > 0 && ( | 198 | <Link |
126 | <Link | 199 | to="/settings/recipes/dev" |
127 | to="/settings/recipes/dev" | 200 | className="badge" |
128 | className="badge" | 201 | activeClassName={`${!searchNeedle ? 'badge--primary' : ''}`} |
129 | activeClassName={`${!searchNeedle ? 'badge--primary' : ''}`} | 202 | onClick={() => resetSearch()} |
130 | onClick={() => resetSearch()} | 203 | > |
131 | > | 204 | {intl.formatMessage(messages.customRecipes)} |
132 | {intl.formatMessage(messages.devRecipes)} | 205 | </Link> |
133 | {' '} | ||
134 | ( | ||
135 | {devRecipesCount} | ||
136 | ) | ||
137 | </Link> | ||
138 | )} | ||
139 | <a href={FRANZ_SERVICE_REQUEST} target="_blank" className="link recipes__service-request"> | 206 | <a href={FRANZ_SERVICE_REQUEST} target="_blank" className="link recipes__service-request"> |
140 | {intl.formatMessage(messages.missingService)} | 207 | {intl.formatMessage(messages.missingService)} |
141 | {' '} | 208 | {' '} |
@@ -146,23 +213,78 @@ export default @observer class RecipesDashboard extends Component { | |||
146 | {isLoading ? ( | 213 | {isLoading ? ( |
147 | <Loader /> | 214 | <Loader /> |
148 | ) : ( | 215 | ) : ( |
149 | <div className="recipes__list"> | 216 | <> |
150 | {hasLoadedRecipes && recipes.length === 0 && ( | 217 | {recipeFilter === 'dev' && ( |
151 | <p className="align-middle settings__empty-state"> | 218 | <> |
152 | <span className="emoji"> | 219 | <H2> |
153 | <img src="./assets/images/emoji/dontknow.png" alt="" /> | 220 | {intl.formatMessage(messages.headlineCustomRecipes)} |
154 | </span> | 221 | {isCommunityRecipesIncludedInCurrentPlan && ( |
155 | {intl.formatMessage(messages.nothingFound)} | 222 | <ProBadge className={classes.proBadge} /> |
156 | </p> | 223 | )} |
224 | </H2> | ||
225 | <div className={classes.devRecipeIntroContainer}> | ||
226 | <p> | ||
227 | {intl.formatMessage(messages.customRecipeIntro)} | ||
228 | </p> | ||
229 | <Input | ||
230 | value={recipeDirectory} | ||
231 | className={classes.path} | ||
232 | showLabel={false} | ||
233 | /> | ||
234 | <div className={classes.actionContainer}> | ||
235 | <Button | ||
236 | onClick={openRecipeDirectory} | ||
237 | buttonType="secondary" | ||
238 | label={intl.formatMessage(messages.openFolder)} | ||
239 | /> | ||
240 | <Button | ||
241 | onClick={openDevDocs} | ||
242 | buttonType="secondary" | ||
243 | label={intl.formatMessage(messages.openDevDocs)} | ||
244 | /> | ||
245 | </div> | ||
246 | </div> | ||
247 | </> | ||
248 | )} | ||
249 | <PremiumFeatureContainer | ||
250 | condition={(recipeFilter === 'dev' && communityRecipes.length > 0) && isCommunityRecipesIncludedInCurrentPlan} | ||
251 | > | ||
252 | {recipeFilter === 'dev' && communityRecipes.length > 0 && ( | ||
253 | <H3>{intl.formatMessage(messages.headlineCommunityRecipes)}</H3> | ||
254 | )} | ||
255 | <div className="recipes__list"> | ||
256 | {hasLoadedRecipes && recipes.length === 0 && recipeFilter !== 'dev' && ( | ||
257 | <p className="align-middle settings__empty-state"> | ||
258 | <span className="emoji"> | ||
259 | <img src="./assets/images/emoji/dontknow.png" alt="" /> | ||
260 | </span> | ||
261 | {intl.formatMessage(messages.nothingFound)} | ||
262 | </p> | ||
263 | )} | ||
264 | {communityRecipes.map(recipe => ( | ||
265 | <RecipeItem | ||
266 | key={recipe.id} | ||
267 | recipe={recipe} | ||
268 | onClick={() => showAddServiceInterface({ recipeId: recipe.id })} | ||
269 | /> | ||
270 | ))} | ||
271 | </div> | ||
272 | </PremiumFeatureContainer> | ||
273 | {recipeFilter === 'dev' && devRecipes.length > 0 && ( | ||
274 | <div className={classes.devRecipeList}> | ||
275 | <H3>{intl.formatMessage(messages.headlineDevRecipes)}</H3> | ||
276 | <div className="recipes__list"> | ||
277 | {devRecipes.map(recipe => ( | ||
278 | <RecipeItem | ||
279 | key={recipe.id} | ||
280 | recipe={recipe} | ||
281 | onClick={() => showAddServiceInterface({ recipeId: recipe.id })} | ||
282 | /> | ||
283 | ))} | ||
284 | </div> | ||
285 | </div> | ||
157 | )} | 286 | )} |
158 | {recipes.map(recipe => ( | 287 | </> |
159 | <RecipeItem | ||
160 | key={recipe.id} | ||
161 | recipe={recipe} | ||
162 | onClick={() => showAddServiceInterface({ recipeId: recipe.id })} | ||
163 | /> | ||
164 | ))} | ||
165 | </div> | ||
166 | )} | 288 | )} |
167 | </div> | 289 | </div> |
168 | </div> | 290 | </div> |
diff --git a/src/components/settings/services/EditServiceForm.js b/src/components/settings/services/EditServiceForm.js index 4ba2eb844..5cde0db8e 100644 --- a/src/components/settings/services/EditServiceForm.js +++ b/src/components/settings/services/EditServiceForm.js | |||
@@ -17,6 +17,8 @@ import ImageUpload from '../../ui/ImageUpload'; | |||
17 | import Select from '../../ui/Select'; | 17 | import Select from '../../ui/Select'; |
18 | 18 | ||
19 | import PremiumFeatureContainer from '../../ui/PremiumFeatureContainer'; | 19 | import PremiumFeatureContainer from '../../ui/PremiumFeatureContainer'; |
20 | import LimitReachedInfobox from '../../../features/serviceLimit/components/LimitReachedInfobox'; | ||
21 | import { serviceLimitStore } from '../../../features/serviceLimit'; | ||
20 | 22 | ||
21 | const messages = defineMessages({ | 23 | const messages = defineMessages({ |
22 | saveService: { | 24 | saveService: { |
@@ -128,8 +130,8 @@ export default @observer class EditServiceForm extends Component { | |||
128 | isSaving: PropTypes.bool.isRequired, | 130 | isSaving: PropTypes.bool.isRequired, |
129 | isDeleting: PropTypes.bool.isRequired, | 131 | isDeleting: PropTypes.bool.isRequired, |
130 | isProxyFeatureEnabled: PropTypes.bool.isRequired, | 132 | isProxyFeatureEnabled: PropTypes.bool.isRequired, |
131 | isProxyPremiumFeature: PropTypes.bool.isRequired, | 133 | isServiceProxyIncludedInCurrentPlan: PropTypes.bool.isRequired, |
132 | isSpellcheckerPremiumFeature: PropTypes.bool.isRequired, | 134 | isSpellcheckerIncludedInCurrentPlan: PropTypes.bool.isRequired, |
133 | }; | 135 | }; |
134 | 136 | ||
135 | static defaultProps = { | 137 | static defaultProps = { |
@@ -192,8 +194,8 @@ export default @observer class EditServiceForm extends Component { | |||
192 | isDeleting, | 194 | isDeleting, |
193 | onDelete, | 195 | onDelete, |
194 | isProxyFeatureEnabled, | 196 | isProxyFeatureEnabled, |
195 | isProxyPremiumFeature, | 197 | isServiceProxyIncludedInCurrentPlan, |
196 | isSpellcheckerPremiumFeature, | 198 | isSpellcheckerIncludedInCurrentPlan, |
197 | } = this.props; | 199 | } = this.props; |
198 | const { intl } = this.context; | 200 | const { intl } = this.context; |
199 | 201 | ||
@@ -252,6 +254,7 @@ export default @observer class EditServiceForm extends Component { | |||
252 | )} | 254 | )} |
253 | </span> | 255 | </span> |
254 | </div> | 256 | </div> |
257 | <LimitReachedInfobox /> | ||
255 | <div className="settings__body"> | 258 | <div className="settings__body"> |
256 | <form onSubmit={e => this.submit(e)} id="form"> | 259 | <form onSubmit={e => this.submit(e)} id="form"> |
257 | <div className="service-name"> | 260 | <div className="service-name"> |
@@ -342,7 +345,7 @@ export default @observer class EditServiceForm extends Component { | |||
342 | </div> | 345 | </div> |
343 | 346 | ||
344 | <PremiumFeatureContainer | 347 | <PremiumFeatureContainer |
345 | condition={isSpellcheckerPremiumFeature} | 348 | condition={!isSpellcheckerIncludedInCurrentPlan} |
346 | gaEventInfo={{ category: 'User', event: 'upgrade', label: 'spellchecker' }} | 349 | gaEventInfo={{ category: 'User', event: 'upgrade', label: 'spellchecker' }} |
347 | > | 350 | > |
348 | <div className="settings__settings-group"> | 351 | <div className="settings__settings-group"> |
@@ -352,7 +355,7 @@ export default @observer class EditServiceForm extends Component { | |||
352 | 355 | ||
353 | {isProxyFeatureEnabled && ( | 356 | {isProxyFeatureEnabled && ( |
354 | <PremiumFeatureContainer | 357 | <PremiumFeatureContainer |
355 | condition={isProxyPremiumFeature} | 358 | condition={!isServiceProxyIncludedInCurrentPlan} |
356 | gaEventInfo={{ category: 'User', event: 'upgrade', label: 'proxy' }} | 359 | gaEventInfo={{ category: 'User', event: 'upgrade', label: 'proxy' }} |
357 | > | 360 | > |
358 | <div className="settings__settings-group"> | 361 | <div className="settings__settings-group"> |
@@ -418,7 +421,7 @@ export default @observer class EditServiceForm extends Component { | |||
418 | type="submit" | 421 | type="submit" |
419 | label={intl.formatMessage(messages.saveService)} | 422 | label={intl.formatMessage(messages.saveService)} |
420 | htmlForm="form" | 423 | htmlForm="form" |
421 | disabled={action !== 'edit' && form.isPristine && requiresUserInput} | 424 | disabled={action !== 'edit' && ((form.isPristine && requiresUserInput) || serviceLimitStore.userHasReachedServiceLimit)} |
422 | /> | 425 | /> |
423 | )} | 426 | )} |
424 | </div> | 427 | </div> |
diff --git a/src/components/settings/services/ServicesDashboard.js b/src/components/settings/services/ServicesDashboard.js index 53bae12df..78038e86a 100644 --- a/src/components/settings/services/ServicesDashboard.js +++ b/src/components/settings/services/ServicesDashboard.js | |||
@@ -9,6 +9,7 @@ import Infobox from '../../ui/Infobox'; | |||
9 | import Loader from '../../ui/Loader'; | 9 | import Loader from '../../ui/Loader'; |
10 | import ServiceItem from './ServiceItem'; | 10 | import ServiceItem from './ServiceItem'; |
11 | import Appear from '../../ui/effects/Appear'; | 11 | import Appear from '../../ui/effects/Appear'; |
12 | import LimitReachedInfobox from '../../../features/serviceLimit/components/LimitReachedInfobox'; | ||
12 | 13 | ||
13 | const messages = defineMessages({ | 14 | const messages = defineMessages({ |
14 | headline: { | 15 | headline: { |
@@ -91,6 +92,7 @@ export default @observer class ServicesDashboard extends Component { | |||
91 | <div className="settings__header"> | 92 | <div className="settings__header"> |
92 | <h1>{intl.formatMessage(messages.headline)}</h1> | 93 | <h1>{intl.formatMessage(messages.headline)}</h1> |
93 | </div> | 94 | </div> |
95 | <LimitReachedInfobox /> | ||
94 | <div className="settings__body"> | 96 | <div className="settings__body"> |
95 | {!isLoading && ( | 97 | {!isLoading && ( |
96 | <SearchInput | 98 | <SearchInput |
diff --git a/src/components/settings/settings/EditSettingsForm.js b/src/components/settings/settings/EditSettingsForm.js index efd453356..3f9e0a6bc 100644 --- a/src/components/settings/settings/EditSettingsForm.js +++ b/src/components/settings/settings/EditSettingsForm.js | |||
@@ -100,7 +100,7 @@ export default @observer class EditSettingsForm extends Component { | |||
100 | isClearingAllCache: PropTypes.bool.isRequired, | 100 | isClearingAllCache: PropTypes.bool.isRequired, |
101 | onClearAllCache: PropTypes.func.isRequired, | 101 | onClearAllCache: PropTypes.func.isRequired, |
102 | cacheSize: PropTypes.string.isRequired, | 102 | cacheSize: PropTypes.string.isRequired, |
103 | isSpellcheckerPremiumFeature: PropTypes.bool.isRequired, | 103 | isSpellcheckerIncludedInCurrentPlan: PropTypes.bool.isRequired, |
104 | }; | 104 | }; |
105 | 105 | ||
106 | static contextTypes = { | 106 | static contextTypes = { |
@@ -130,7 +130,7 @@ export default @observer class EditSettingsForm extends Component { | |||
130 | isClearingAllCache, | 130 | isClearingAllCache, |
131 | onClearAllCache, | 131 | onClearAllCache, |
132 | cacheSize, | 132 | cacheSize, |
133 | isSpellcheckerPremiumFeature, | 133 | isSpellcheckerIncludedInCurrentPlan, |
134 | } = this.props; | 134 | } = this.props; |
135 | const { intl } = this.context; | 135 | const { intl } = this.context; |
136 | 136 | ||
@@ -173,7 +173,7 @@ export default @observer class EditSettingsForm extends Component { | |||
173 | <h2 id="language">{intl.formatMessage(messages.headlineLanguage)}</h2> | 173 | <h2 id="language">{intl.formatMessage(messages.headlineLanguage)}</h2> |
174 | <Select field={form.$('locale')} showLabel={false} /> | 174 | <Select field={form.$('locale')} showLabel={false} /> |
175 | <PremiumFeatureContainer | 175 | <PremiumFeatureContainer |
176 | condition={isSpellcheckerPremiumFeature} | 176 | condition={!isSpellcheckerIncludedInCurrentPlan} |
177 | gaEventInfo={{ category: 'User', event: 'upgrade', label: 'spellchecker' }} | 177 | gaEventInfo={{ category: 'User', event: 'upgrade', label: 'spellchecker' }} |
178 | > | 178 | > |
179 | <Fragment> | 179 | <Fragment> |
diff --git a/src/components/subscription/SubscriptionForm.js b/src/components/subscription/SubscriptionForm.js index 50f1e0522..0c630f047 100644 --- a/src/components/subscription/SubscriptionForm.js +++ b/src/components/subscription/SubscriptionForm.js | |||
@@ -1,214 +1,94 @@ | |||
1 | import React, { Component, Fragment } from 'react'; | 1 | import React, { Component } from 'react'; |
2 | import PropTypes from 'prop-types'; | 2 | import PropTypes from 'prop-types'; |
3 | import { observer, PropTypes as MobxPropTypes } from 'mobx-react'; | 3 | import { 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 | 6 | ||
6 | import Form from '../../lib/Form'; | 7 | import { H3 } from '@meetfranz/ui'; |
7 | import Radio from '../ui/Radio'; | ||
8 | import Button from '../ui/Button'; | ||
9 | import Loader from '../ui/Loader'; | ||
10 | 8 | ||
11 | import { required } from '../../helpers/validation-helpers'; | 9 | import { Button } from '@meetfranz/forms'; |
10 | import { FeatureList } from '../ui/FeatureList'; | ||
11 | import { FeatureItem } from '../ui/FeatureItem'; | ||
12 | 12 | ||
13 | const messages = defineMessages({ | 13 | const messages = defineMessages({ |
14 | submitButtonLabel: { | 14 | submitButtonLabel: { |
15 | id: 'subscription.submit.label', | 15 | id: 'subscription.cta.activateTrial', |
16 | defaultMessage: '!!!Support the development of Franz', | 16 | defaultMessage: '!!!Yes, upgrade my account to Franz Professional', |
17 | }, | ||
18 | paymentSessionError: { | ||
19 | id: 'subscription.paymentSessionError', | ||
20 | defaultMessage: '!!!Could not initialize payment form', | ||
21 | }, | ||
22 | typeFree: { | ||
23 | id: 'subscription.type.free', | ||
24 | defaultMessage: '!!!free', | ||
25 | }, | ||
26 | typeMonthly: { | ||
27 | id: 'subscription.type.month', | ||
28 | defaultMessage: '!!!month', | ||
29 | }, | ||
30 | typeYearly: { | ||
31 | id: 'subscription.type.year', | ||
32 | defaultMessage: '!!!year', | ||
33 | }, | 17 | }, |
34 | includedFeatures: { | 18 | includedFeatures: { |
35 | id: 'subscription.includedFeatures', | 19 | id: 'subscription.includedProFeatures', |
36 | defaultMessage: '!!!The Franz Premium Supporter Account includes', | 20 | defaultMessage: '!!!The Franz Professional Plan includes:', |
37 | }, | ||
38 | onpremise: { | ||
39 | id: 'subscription.features.onpremise.mattermost', | ||
40 | defaultMessage: '!!!Add on-premise/hosted services like Mattermost', | ||
41 | }, | ||
42 | noInterruptions: { | ||
43 | id: 'subscription.features.noInterruptions', | ||
44 | defaultMessage: '!!!No app delays & nagging to upgrade license', | ||
45 | }, | 21 | }, |
46 | proxy: { | 22 | noStringsAttachedHeadline: { |
47 | id: 'subscription.features.proxy', | 23 | id: 'pricing.trial.terms.headline', |
48 | defaultMessage: '!!!Proxy support for services', | 24 | defaultMessage: '!!!No strings attached', |
49 | }, | 25 | }, |
50 | spellchecker: { | 26 | noCreditCard: { |
51 | id: 'subscription.features.spellchecker', | 27 | id: 'pricing.trial.terms.noCreditCard', |
52 | defaultMessage: '!!!Support for Spellchecker', | 28 | defaultMessage: '!!!No credit card required', |
53 | }, | 29 | }, |
54 | workspaces: { | 30 | automaticTrialEnd: { |
55 | id: 'subscription.features.workspaces', | 31 | id: 'pricing.trial.terms.automaticTrialEnd', |
56 | defaultMessage: '!!!Organize your services in workspaces', | 32 | defaultMessage: '!!!Your free trial ends automatically after 14 days', |
57 | }, | 33 | }, |
58 | ads: { | 34 | }); |
59 | id: 'subscription.features.ads', | 35 | |
60 | defaultMessage: '!!!No ads, ever!', | 36 | const styles = () => ({ |
61 | }, | 37 | activateTrialButton: { |
62 | comingSoon: { | 38 | margin: [40, 0, 50], |
63 | id: 'subscription.features.comingSoon', | ||
64 | defaultMessage: '!!!coming soon', | ||
65 | }, | 39 | }, |
66 | euTaxInfo: { | 40 | keyTerms: { |
67 | id: 'subscription.euTaxInfo', | 41 | marginTop: 20, |
68 | defaultMessage: '!!!EU residents: local sales tax may apply', | ||
69 | }, | 42 | }, |
70 | }); | 43 | }); |
71 | 44 | ||
72 | export default @observer class SubscriptionForm extends Component { | 45 | export default @observer @injectSheet(styles) class SubscriptionForm extends Component { |
73 | static propTypes = { | 46 | static propTypes = { |
74 | plan: MobxPropTypes.objectOrObservableObject.isRequired, | 47 | activateTrial: PropTypes.func.isRequired, |
75 | isLoading: PropTypes.bool.isRequired, | 48 | isActivatingTrial: PropTypes.bool.isRequired, |
76 | handlePayment: PropTypes.func.isRequired, | 49 | classes: PropTypes.object.isRequired, |
77 | retryPlanRequest: PropTypes.func.isRequired, | ||
78 | isCreatingHostedPage: PropTypes.bool.isRequired, | ||
79 | error: PropTypes.bool.isRequired, | ||
80 | showSkipOption: PropTypes.bool, | ||
81 | skipAction: PropTypes.func, | ||
82 | skipButtonLabel: PropTypes.string, | ||
83 | hideInfo: PropTypes.bool.isRequired, | ||
84 | }; | ||
85 | |||
86 | static defaultProps = { | ||
87 | showSkipOption: false, | ||
88 | skipAction: () => null, | ||
89 | skipButtonLabel: '', | ||
90 | }; | 50 | }; |
91 | 51 | ||
92 | static contextTypes = { | 52 | static contextTypes = { |
93 | intl: intlShape, | 53 | intl: intlShape, |
94 | }; | 54 | }; |
95 | 55 | ||
96 | componentWillMount() { | ||
97 | this.form = this.prepareForm(); | ||
98 | } | ||
99 | |||
100 | prepareForm() { | ||
101 | const { intl } = this.context; | ||
102 | |||
103 | const form = { | ||
104 | fields: { | ||
105 | paymentTier: { | ||
106 | value: 'year', | ||
107 | validators: [required], | ||
108 | options: [{ | ||
109 | value: 'month', | ||
110 | label: `€ ${Object.hasOwnProperty.call(this.props.plan, 'month') | ||
111 | ? `${this.props.plan.month.price} / ${intl.formatMessage(messages.typeMonthly)}` | ||
112 | : 'monthly'}`, | ||
113 | }, { | ||
114 | value: 'year', | ||
115 | label: `€ ${Object.hasOwnProperty.call(this.props.plan, 'year') | ||
116 | ? `${this.props.plan.year.price} / ${intl.formatMessage(messages.typeYearly)}` | ||
117 | : 'yearly'}`, | ||
118 | }], | ||
119 | }, | ||
120 | }, | ||
121 | }; | ||
122 | |||
123 | if (this.props.showSkipOption) { | ||
124 | form.fields.paymentTier.options.unshift({ | ||
125 | value: 'skip', | ||
126 | label: `€ 0 / ${intl.formatMessage(messages.typeFree)}`, | ||
127 | }); | ||
128 | } | ||
129 | |||
130 | return new Form(form, this.context.intl); | ||
131 | } | ||
132 | |||
133 | render() { | 56 | render() { |
134 | const { | 57 | const { |
135 | isLoading, | 58 | isActivatingTrial, |
136 | isCreatingHostedPage, | 59 | activateTrial, |
137 | handlePayment, | 60 | classes, |
138 | retryPlanRequest, | ||
139 | error, | ||
140 | showSkipOption, | ||
141 | skipAction, | ||
142 | skipButtonLabel, | ||
143 | hideInfo, | ||
144 | } = this.props; | 61 | } = this.props; |
145 | const { intl } = this.context; | 62 | const { intl } = this.context; |
146 | 63 | ||
147 | if (error) { | 64 | console.log('isActivatingTrial', isActivatingTrial); |
148 | return ( | ||
149 | <Button | ||
150 | label="Reload" | ||
151 | onClick={retryPlanRequest} | ||
152 | isLoaded={!isLoading} | ||
153 | /> | ||
154 | ); | ||
155 | } | ||
156 | 65 | ||
157 | return ( | 66 | return ( |
158 | <Loader loaded={!isLoading}> | 67 | <> |
159 | <Radio field={this.form.$('paymentTier')} showLabel={false} className="paymentTiers" /> | 68 | <H3 className={classes.keyTerms}> |
160 | {!hideInfo && ( | 69 | {intl.formatMessage(messages.noStringsAttachedHeadline)} |
161 | <div className="subscription__premium-info"> | 70 | </H3> |
162 | <p> | 71 | <ul> |
163 | <strong>{intl.formatMessage(messages.includedFeatures)}</strong> | 72 | <FeatureItem icon="👉" name={intl.formatMessage(messages.noCreditCard)} /> |
164 | </p> | 73 | <FeatureItem icon="👉" name={intl.formatMessage(messages.automaticTrialEnd)} /> |
165 | <div className="subscription"> | 74 | </ul> |
166 | <ul className="subscription__premium-features"> | 75 | |
167 | <li>{intl.formatMessage(messages.onpremise)}</li> | 76 | <Button |
168 | <li> | 77 | label={intl.formatMessage(messages.submitButtonLabel)} |
169 | {intl.formatMessage(messages.noInterruptions)} | 78 | className={classes.activateTrialButton} |
170 | </li> | 79 | busy={isActivatingTrial} |
171 | <li> | 80 | onClick={activateTrial} |
172 | {intl.formatMessage(messages.spellchecker)} | 81 | stretch |
173 | </li> | 82 | /> |
174 | <li> | 83 | <div className="subscription__premium-info"> |
175 | {intl.formatMessage(messages.proxy)} | 84 | <H3> |
176 | </li> | 85 | {intl.formatMessage(messages.includedFeatures)} |
177 | <li> | 86 | </H3> |
178 | {intl.formatMessage(messages.workspaces)} | 87 | <div className="subscription"> |
179 | </li> | 88 | <FeatureList /> |
180 | <li> | ||
181 | {intl.formatMessage(messages.ads)} | ||
182 | </li> | ||
183 | </ul> | ||
184 | </div> | ||
185 | </div> | 89 | </div> |
186 | )} | 90 | </div> |
187 | <Fragment> | 91 | </> |
188 | {error.code === 'no-payment-session' && ( | ||
189 | <p className="error-message center">{intl.formatMessage(messages.paymentSessionError)}</p> | ||
190 | )} | ||
191 | </Fragment> | ||
192 | {showSkipOption && this.form.$('paymentTier').value === 'skip' ? ( | ||
193 | <Button | ||
194 | label={skipButtonLabel} | ||
195 | className="auth__button" | ||
196 | onClick={skipAction} | ||
197 | /> | ||
198 | ) : ( | ||
199 | <Button | ||
200 | label={intl.formatMessage(messages.submitButtonLabel)} | ||
201 | className="auth__button" | ||
202 | loaded={!isCreatingHostedPage} | ||
203 | onClick={() => handlePayment(this.form.$('paymentTier').value)} | ||
204 | /> | ||
205 | )} | ||
206 | {this.form.$('paymentTier').value !== 'skip' && ( | ||
207 | <p className="legal"> | ||
208 | {intl.formatMessage(messages.euTaxInfo)} | ||
209 | </p> | ||
210 | )} | ||
211 | </Loader> | ||
212 | ); | 92 | ); |
213 | } | 93 | } |
214 | } | 94 | } |
diff --git a/src/components/ui/FeatureItem.js b/src/components/ui/FeatureItem.js new file mode 100644 index 000000000..a63f5f7b5 --- /dev/null +++ b/src/components/ui/FeatureItem.js | |||
@@ -0,0 +1,36 @@ | |||
1 | import React from 'react'; | ||
2 | import injectSheet from 'react-jss'; | ||
3 | import { Icon } from '@meetfranz/ui'; | ||
4 | import classnames from 'classnames'; | ||
5 | |||
6 | const styles = theme => ({ | ||
7 | featureItem: { | ||
8 | borderBottom: [1, 'solid', theme.legacyStyles.themeGrayDark], | ||
9 | padding: [8, 0], | ||
10 | display: 'flex', | ||
11 | alignItems: 'center', | ||
12 | }, | ||
13 | featureIcon: { | ||
14 | fill: theme.brandSuccess, | ||
15 | marginRight: 10, | ||
16 | }, | ||
17 | }); | ||
18 | |||
19 | export const FeatureItem = injectSheet(styles)(({ | ||
20 | classes, className, name, icon, | ||
21 | }) => ( | ||
22 | <li className={classnames({ | ||
23 | [classes.featureItem]: true, | ||
24 | [className]: className, | ||
25 | })} | ||
26 | > | ||
27 | {icon ? ( | ||
28 | <span className={classes.featureIcon}>{icon}</span> | ||
29 | ) : ( | ||
30 | <Icon icon="mdiCheckCircle" className={classes.featureIcon} size={1.5} /> | ||
31 | )} | ||
32 | {name} | ||
33 | </li> | ||
34 | )); | ||
35 | |||
36 | export default FeatureItem; | ||
diff --git a/src/components/ui/FeatureList.js b/src/components/ui/FeatureList.js new file mode 100644 index 000000000..62944ad75 --- /dev/null +++ b/src/components/ui/FeatureList.js | |||
@@ -0,0 +1,89 @@ | |||
1 | import React, { Component } from 'react'; | ||
2 | import PropTypes from 'prop-types'; | ||
3 | import { defineMessages, intlShape } from 'react-intl'; | ||
4 | |||
5 | import { FeatureItem } from './FeatureItem'; | ||
6 | |||
7 | const messages = defineMessages({ | ||
8 | unlimitedServices: { | ||
9 | id: 'pricing.features.unlimitedServices', | ||
10 | defaultMessage: '!!!Add unlimited services', | ||
11 | }, | ||
12 | spellchecker: { | ||
13 | id: 'pricing.features.spellchecker', | ||
14 | defaultMessage: '!!!Spellchecker support', | ||
15 | }, | ||
16 | workspaces: { | ||
17 | id: 'pricing.features.workspaces', | ||
18 | defaultMessage: '!!!Workspaces', | ||
19 | }, | ||
20 | customWebsites: { | ||
21 | id: 'pricing.features.customWebsites', | ||
22 | defaultMessage: '!!!Add Custom Websites', | ||
23 | }, | ||
24 | onPremise: { | ||
25 | id: 'pricing.features.onPremise', | ||
26 | defaultMessage: '!!!On-premise & other Hosted Services', | ||
27 | }, | ||
28 | thirdPartyServices: { | ||
29 | id: 'pricing.features.thirdPartyServices', | ||
30 | defaultMessage: '!!!Install 3rd party services', | ||
31 | }, | ||
32 | serviceProxies: { | ||
33 | id: 'pricing.features.serviceProxies', | ||
34 | defaultMessage: '!!!Service Proxies', | ||
35 | }, | ||
36 | teamManagement: { | ||
37 | id: 'pricing.features.teamManagement', | ||
38 | defaultMessage: '!!!Team Management', | ||
39 | }, | ||
40 | appDelays: { | ||
41 | id: 'pricing.features.appDelays', | ||
42 | defaultMessage: '!!!No Waiting Screens', | ||
43 | }, | ||
44 | adFree: { | ||
45 | id: 'pricing.features.adFree', | ||
46 | defaultMessage: '!!!Forever ad-free', | ||
47 | }, | ||
48 | }); | ||
49 | |||
50 | export class FeatureList extends Component { | ||
51 | static propTypes = { | ||
52 | className: PropTypes.string, | ||
53 | featureClassName: PropTypes.string, | ||
54 | }; | ||
55 | |||
56 | static defaultProps = { | ||
57 | className: '', | ||
58 | featureClassName: '', | ||
59 | } | ||
60 | |||
61 | static contextTypes = { | ||
62 | intl: intlShape, | ||
63 | }; | ||
64 | |||
65 | render() { | ||
66 | const { | ||
67 | className, | ||
68 | featureClassName, | ||
69 | } = this.props; | ||
70 | const { intl } = this.context; | ||
71 | |||
72 | return ( | ||
73 | <ul className={className}> | ||
74 | <FeatureItem name={intl.formatMessage(messages.unlimitedServices)} className={featureClassName} /> | ||
75 | <FeatureItem name={intl.formatMessage(messages.spellchecker)} className={featureClassName} /> | ||
76 | <FeatureItem name={intl.formatMessage(messages.workspaces)} className={featureClassName} /> | ||
77 | <FeatureItem name={intl.formatMessage(messages.customWebsites)} className={featureClassName} /> | ||
78 | <FeatureItem name={intl.formatMessage(messages.onPremise)} className={featureClassName} /> | ||
79 | <FeatureItem name={intl.formatMessage(messages.thirdPartyServices)} className={featureClassName} /> | ||
80 | <FeatureItem name={intl.formatMessage(messages.serviceProxies)} className={featureClassName} /> | ||
81 | <FeatureItem name={intl.formatMessage(messages.teamManagement)} className={featureClassName} /> | ||
82 | <FeatureItem name={intl.formatMessage(messages.appDelays)} className={featureClassName} /> | ||
83 | <FeatureItem name={intl.formatMessage(messages.adFree)} className={featureClassName} /> | ||
84 | </ul> | ||
85 | ); | ||
86 | } | ||
87 | } | ||
88 | |||
89 | export default FeatureList; | ||
diff --git a/src/config.js b/src/config.js index 5bc318545..edcae9df1 100644 --- a/src/config.js +++ b/src/config.js | |||
@@ -45,16 +45,16 @@ export const DEFAULT_APP_SETTINGS = { | |||
45 | }; | 45 | }; |
46 | 46 | ||
47 | export const DEFAULT_FEATURES_CONFIG = { | 47 | export const DEFAULT_FEATURES_CONFIG = { |
48 | isSpellcheckerPremiumFeature: false, | 48 | isSpellcheckerIncludedInCurrentPlan: true, |
49 | needToWaitToProceed: false, | 49 | needToWaitToProceed: false, |
50 | needToWaitToProceedConfig: { | 50 | needToWaitToProceedConfig: { |
51 | delayOffset: ms('1h'), | 51 | delayOffset: ms('1h'), |
52 | wait: ms('10s'), | 52 | wait: ms('10s'), |
53 | }, | 53 | }, |
54 | isServiceProxyEnabled: false, | 54 | isServiceProxyEnabled: false, |
55 | isServiceProxyPremiumFeature: true, | 55 | isServiceProxyIncludedInCurrentPlan: false, |
56 | isAnnouncementsEnabled: true, | 56 | isAnnouncementsEnabled: true, |
57 | isWorkspacePremiumFeature: true, | 57 | isWorkspaceIncludedInCurrentPlan: true, |
58 | isWorkspaceEnabled: false, | 58 | isWorkspaceEnabled: false, |
59 | }; | 59 | }; |
60 | 60 | ||
@@ -67,6 +67,7 @@ export const DEFAULT_WINDOW_OPTIONS = { | |||
67 | 67 | ||
68 | export const FRANZ_SERVICE_REQUEST = 'https://bit.ly/franz-plugin-docs'; | 68 | export const FRANZ_SERVICE_REQUEST = 'https://bit.ly/franz-plugin-docs'; |
69 | export const FRANZ_TRANSLATION = 'https://bit.ly/franz-translate'; | 69 | export const FRANZ_TRANSLATION = 'https://bit.ly/franz-translate'; |
70 | export const FRANZ_DEV_DOCS = 'http://bit.ly/franz-dev-hub'; | ||
70 | 71 | ||
71 | export const FILE_SYSTEM_SETTINGS_TYPES = [ | 72 | export const FILE_SYSTEM_SETTINGS_TYPES = [ |
72 | 'app', | 73 | 'app', |
@@ -83,3 +84,27 @@ export const ALLOWED_PROTOCOLS = [ | |||
83 | 'http:', | 84 | 'http:', |
84 | 'ftp:', | 85 | 'ftp:', |
85 | ]; | 86 | ]; |
87 | |||
88 | export const PLANS = { | ||
89 | PERSONAL_MONTHLY: 'PERSONAL_MONTHLY', | ||
90 | PERSONAL_YEARLY: 'PERSONAL_YEARLY', | ||
91 | PRO_MONTHLY: 'PRO_MONTHLY', | ||
92 | PRO_YEARLY: 'PRO_YEARLY', | ||
93 | LEGACY: 'LEGACY', | ||
94 | FREE: 'FREE', | ||
95 | }; | ||
96 | |||
97 | export const PLANS_MAPPING = { | ||
98 | 'franz-personal-monthly': PLANS.PERSONAL_MONTHLY, | ||
99 | 'franz-personal-yearly': PLANS.PERSONAL_YEARLY, | ||
100 | 'franz-pro-monthly': PLANS.PRO_MONTHLY, | ||
101 | 'franz-pro-yearly': PLANS.PRO_YEARLY, | ||
102 | 'franz-supporter-license': PLANS.LEGACY, | ||
103 | 'franz-supporter-license-x1': PLANS.LEGACY, | ||
104 | 'franz-supporter-license-x2': PLANS.LEGACY, | ||
105 | 'franz-supporter-license-year': PLANS.LEGACY, | ||
106 | 'franz-supporter-license-year-x1': PLANS.LEGACY, | ||
107 | 'franz-supporter-license-year-x2': PLANS.LEGACY, | ||
108 | 'franz-supporter-license-year-2019': PLANS.LEGACY, | ||
109 | free: PLANS.FREE, | ||
110 | }; | ||
diff --git a/src/containers/auth/PricingScreen.js b/src/containers/auth/PricingScreen.js index 8d179a170..af1651931 100644 --- a/src/containers/auth/PricingScreen.js +++ b/src/containers/auth/PricingScreen.js | |||
@@ -5,7 +5,6 @@ import { RouterStore } from 'mobx-react-router'; | |||
5 | 5 | ||
6 | import Pricing from '../../components/auth/Pricing'; | 6 | import Pricing from '../../components/auth/Pricing'; |
7 | import UserStore from '../../stores/UserStore'; | 7 | import UserStore from '../../stores/UserStore'; |
8 | import PaymentStore from '../../stores/PaymentStore'; | ||
9 | 8 | ||
10 | import { globalError as globalErrorPropType } from '../../prop-types'; | 9 | import { globalError as globalErrorPropType } from '../../prop-types'; |
11 | 10 | ||
@@ -14,20 +13,40 @@ export default @inject('stores', 'actions') @observer class PricingScreen extend | |||
14 | error: globalErrorPropType.isRequired, | 13 | error: globalErrorPropType.isRequired, |
15 | }; | 14 | }; |
16 | 15 | ||
16 | async submit() { | ||
17 | const { | ||
18 | actions, | ||
19 | stores, | ||
20 | } = this.props; | ||
21 | |||
22 | const { activateTrialRequest } = stores.user; | ||
23 | const { defaultTrialPlan } = stores.features.features; | ||
24 | |||
25 | actions.user.activateTrial({ planId: defaultTrialPlan }); | ||
26 | await activateTrialRequest._promise; | ||
27 | |||
28 | if (!activateTrialRequest.isError) { | ||
29 | stores.router.push('/'); | ||
30 | stores.user.hasCompletedSignup = true; | ||
31 | } | ||
32 | } | ||
33 | |||
17 | render() { | 34 | render() { |
18 | const { actions, stores, error } = this.props; | 35 | const { |
36 | error, | ||
37 | stores, | ||
38 | } = this.props; | ||
19 | 39 | ||
20 | const nextStepRoute = stores.user.legacyServices.length ? stores.user.importRoute : stores.user.inviteRoute; | 40 | const { getUserInfoRequest, activateTrialRequest } = stores.user; |
41 | const { featuresRequest } = stores.features; | ||
21 | 42 | ||
22 | return ( | 43 | return ( |
23 | <Pricing | 44 | <Pricing |
24 | donor={stores.user.data.donor || {}} | 45 | onSubmit={this.submit.bind(this)} |
25 | onSubmit={actions.user.signup} | 46 | isLoadingRequiredData={(getUserInfoRequest.isExecuting || !getUserInfoRequest.wasExecuted) || (featuresRequest.isExecuting || !featuresRequest.wasExecuted)} |
26 | onCloseSubscriptionWindow={() => this.props.stores.router.push(nextStepRoute)} | 47 | isActivatingTrial={activateTrialRequest.isExecuting} |
27 | isLoading={stores.payment.plansRequest.isExecuting} | 48 | trialActivationError={activateTrialRequest.isError} |
28 | isLoadingUser={stores.user.getUserInfoRequest.isExecuting} | ||
29 | error={error} | 49 | error={error} |
30 | skipAction={() => this.props.stores.router.push(nextStepRoute)} | ||
31 | /> | 50 | /> |
32 | ); | 51 | ); |
33 | } | 52 | } |
@@ -36,12 +55,11 @@ export default @inject('stores', 'actions') @observer class PricingScreen extend | |||
36 | PricingScreen.wrappedComponent.propTypes = { | 55 | PricingScreen.wrappedComponent.propTypes = { |
37 | actions: PropTypes.shape({ | 56 | actions: PropTypes.shape({ |
38 | user: PropTypes.shape({ | 57 | user: PropTypes.shape({ |
39 | signup: PropTypes.func.isRequired, | 58 | activateTrial: PropTypes.func.isRequired, |
40 | }).isRequired, | 59 | }).isRequired, |
41 | }).isRequired, | 60 | }).isRequired, |
42 | stores: PropTypes.shape({ | 61 | stores: PropTypes.shape({ |
43 | user: PropTypes.instanceOf(UserStore).isRequired, | 62 | user: PropTypes.instanceOf(UserStore).isRequired, |
44 | payment: PropTypes.instanceOf(PaymentStore).isRequired, | ||
45 | router: PropTypes.instanceOf(RouterStore).isRequired, | 63 | router: PropTypes.instanceOf(RouterStore).isRequired, |
46 | }).isRequired, | 64 | }).isRequired, |
47 | }; | 65 | }; |
diff --git a/src/containers/layout/AppLayoutContainer.js b/src/containers/layout/AppLayoutContainer.js index cf3da71e8..a14a98554 100644 --- a/src/containers/layout/AppLayoutContainer.js +++ b/src/containers/layout/AppLayoutContainer.js | |||
@@ -10,6 +10,7 @@ import FeaturesStore from '../../stores/FeaturesStore'; | |||
10 | import UIStore from '../../stores/UIStore'; | 10 | import UIStore from '../../stores/UIStore'; |
11 | import NewsStore from '../../stores/NewsStore'; | 11 | import NewsStore from '../../stores/NewsStore'; |
12 | import SettingsStore from '../../stores/SettingsStore'; | 12 | import SettingsStore from '../../stores/SettingsStore'; |
13 | import UserStore from '../../stores/UserStore'; | ||
13 | import RequestStore from '../../stores/RequestStore'; | 14 | import RequestStore from '../../stores/RequestStore'; |
14 | import GlobalErrorStore from '../../stores/GlobalErrorStore'; | 15 | import GlobalErrorStore from '../../stores/GlobalErrorStore'; |
15 | 16 | ||
@@ -39,6 +40,7 @@ export default @inject('stores', 'actions') @observer class AppLayoutContainer e | |||
39 | settings, | 40 | settings, |
40 | globalError, | 41 | globalError, |
41 | requests, | 42 | requests, |
43 | user, | ||
42 | } = this.props.stores; | 44 | } = this.props.stores; |
43 | 45 | ||
44 | const { | 46 | const { |
@@ -125,6 +127,8 @@ export default @inject('stores', 'actions') @observer class AppLayoutContainer e | |||
125 | reload={reload} | 127 | reload={reload} |
126 | openSettings={openSettings} | 128 | openSettings={openSettings} |
127 | update={updateService} | 129 | update={updateService} |
130 | userHasCompletedSignup={user.hasCompletedSignup} | ||
131 | hasActivatedTrial={user.hasActivatedTrial} | ||
128 | /> | 132 | /> |
129 | ); | 133 | ); |
130 | 134 | ||
@@ -149,6 +153,7 @@ export default @inject('stores', 'actions') @observer class AppLayoutContainer e | |||
149 | retryRequiredRequests={retryRequiredRequests} | 153 | retryRequiredRequests={retryRequiredRequests} |
150 | areRequiredRequestsLoading={requests.areRequiredRequestsLoading} | 154 | areRequiredRequestsLoading={requests.areRequiredRequestsLoading} |
151 | isDelayAppScreenVisible={delayAppState.isDelayAppScreenVisible} | 155 | isDelayAppScreenVisible={delayAppState.isDelayAppScreenVisible} |
156 | hasActivatedTrial={user.hasActivatedTrial} | ||
152 | > | 157 | > |
153 | {React.Children.count(children) > 0 ? children : null} | 158 | {React.Children.count(children) > 0 ? children : null} |
154 | </AppLayout> | 159 | </AppLayout> |
@@ -166,6 +171,7 @@ AppLayoutContainer.wrappedComponent.propTypes = { | |||
166 | ui: PropTypes.instanceOf(UIStore).isRequired, | 171 | ui: PropTypes.instanceOf(UIStore).isRequired, |
167 | news: PropTypes.instanceOf(NewsStore).isRequired, | 172 | news: PropTypes.instanceOf(NewsStore).isRequired, |
168 | settings: PropTypes.instanceOf(SettingsStore).isRequired, | 173 | settings: PropTypes.instanceOf(SettingsStore).isRequired, |
174 | user: PropTypes.instanceOf(UserStore).isRequired, | ||
169 | requests: PropTypes.instanceOf(RequestStore).isRequired, | 175 | requests: PropTypes.instanceOf(RequestStore).isRequired, |
170 | globalError: PropTypes.instanceOf(GlobalErrorStore).isRequired, | 176 | globalError: PropTypes.instanceOf(GlobalErrorStore).isRequired, |
171 | }).isRequired, | 177 | }).isRequired, |
diff --git a/src/containers/settings/EditServiceScreen.js b/src/containers/settings/EditServiceScreen.js index 870ca4ecd..e4ff03bb3 100644 --- a/src/containers/settings/EditServiceScreen.js +++ b/src/containers/settings/EditServiceScreen.js | |||
@@ -330,8 +330,8 @@ export default @inject('stores', 'actions') @observer class EditServiceScreen ex | |||
330 | onSubmit={d => this.onSubmit(d)} | 330 | onSubmit={d => this.onSubmit(d)} |
331 | onDelete={() => this.deleteService()} | 331 | onDelete={() => this.deleteService()} |
332 | isProxyFeatureEnabled={proxyFeature.isEnabled} | 332 | isProxyFeatureEnabled={proxyFeature.isEnabled} |
333 | isProxyPremiumFeature={proxyFeature.isPremium} | 333 | isServiceProxyIncludedInCurrentPlan={proxyFeature.isIncludedInCurrentPlan} |
334 | isSpellcheckerPremiumFeature={spellcheckerFeature.isPremium} | 334 | isSpellcheckerIncludedInCurrentPlan={spellcheckerFeature.isIncludedInCurrentPlan} |
335 | /> | 335 | /> |
336 | </ErrorBoundary> | 336 | </ErrorBoundary> |
337 | ); | 337 | ); |
diff --git a/src/containers/settings/EditSettingsScreen.js b/src/containers/settings/EditSettingsScreen.js index 97c1fa3b1..67d52f102 100644 --- a/src/containers/settings/EditSettingsScreen.js +++ b/src/containers/settings/EditSettingsScreen.js | |||
@@ -159,8 +159,8 @@ export default @inject('stores', 'actions') @observer class EditSettingsScreen e | |||
159 | }, | 159 | }, |
160 | enableSpellchecking: { | 160 | enableSpellchecking: { |
161 | label: intl.formatMessage(messages.enableSpellchecking), | 161 | label: intl.formatMessage(messages.enableSpellchecking), |
162 | value: !this.props.stores.user.data.isPremium && spellcheckerConfig.isPremium ? false : settings.all.app.enableSpellchecking, | 162 | value: !this.props.stores.user.data.isPremium && !spellcheckerConfig.isIncludedInCurrentPlan ? false : settings.all.app.enableSpellchecking, |
163 | default: !this.props.stores.user.data.isPremium && spellcheckerConfig.isPremium ? false : DEFAULT_APP_SETTINGS.enableSpellchecking, | 163 | default: !this.props.stores.user.data.isPremium && !spellcheckerConfig.isIncludedInCurrentPlan ? false : DEFAULT_APP_SETTINGS.enableSpellchecking, |
164 | }, | 164 | }, |
165 | spellcheckerLanguage: { | 165 | spellcheckerLanguage: { |
166 | label: intl.formatMessage(globalMessages.spellcheckerLanguage), | 166 | label: intl.formatMessage(globalMessages.spellcheckerLanguage), |
@@ -223,7 +223,7 @@ export default @inject('stores', 'actions') @observer class EditSettingsScreen e | |||
223 | cacheSize={cacheSize} | 223 | cacheSize={cacheSize} |
224 | isClearingAllCache={isClearingAllCache} | 224 | isClearingAllCache={isClearingAllCache} |
225 | onClearAllCache={clearAllCache} | 225 | onClearAllCache={clearAllCache} |
226 | isSpellcheckerPremiumFeature={spellcheckerConfig.isPremium} | 226 | isSpellcheckerIncludedInCurrentPlan={spellcheckerConfig.isIncludedInCurrentPlan} |
227 | /> | 227 | /> |
228 | </ErrorBoundary> | 228 | </ErrorBoundary> |
229 | ); | 229 | ); |
diff --git a/src/containers/settings/RecipesScreen.js b/src/containers/settings/RecipesScreen.js index eda5ae54c..132820b6f 100644 --- a/src/containers/settings/RecipesScreen.js +++ b/src/containers/settings/RecipesScreen.js | |||
@@ -1,7 +1,9 @@ | |||
1 | import { remote, shell } from 'electron'; | ||
1 | import React, { Component } from 'react'; | 2 | import React, { Component } from 'react'; |
2 | import PropTypes from 'prop-types'; | 3 | import PropTypes from 'prop-types'; |
3 | import { autorun } from 'mobx'; | 4 | import { autorun } from 'mobx'; |
4 | import { inject, observer } from 'mobx-react'; | 5 | import { inject, observer } from 'mobx-react'; |
6 | import path from 'path'; | ||
5 | 7 | ||
6 | import RecipePreviewsStore from '../../stores/RecipePreviewsStore'; | 8 | import RecipePreviewsStore from '../../stores/RecipePreviewsStore'; |
7 | import RecipeStore from '../../stores/RecipesStore'; | 9 | import RecipeStore from '../../stores/RecipesStore'; |
@@ -10,6 +12,11 @@ import UserStore from '../../stores/UserStore'; | |||
10 | 12 | ||
11 | import RecipesDashboard from '../../components/settings/recipes/RecipesDashboard'; | 13 | import RecipesDashboard from '../../components/settings/recipes/RecipesDashboard'; |
12 | import ErrorBoundary from '../../components/util/ErrorBoundary'; | 14 | import ErrorBoundary from '../../components/util/ErrorBoundary'; |
15 | import { FRANZ_DEV_DOCS } from '../../config'; | ||
16 | import { gaEvent } from '../../lib/analytics'; | ||
17 | import { communityRecipesStore } from '../../features/communityRecipes'; | ||
18 | |||
19 | const { app } = remote; | ||
13 | 20 | ||
14 | export default @inject('stores', 'actions') @observer class RecipesScreen extends Component { | 21 | export default @inject('stores', 'actions') @observer class RecipesScreen extends Component { |
15 | static propTypes = { | 22 | static propTypes = { |
@@ -67,9 +74,16 @@ export default @inject('stores', 'actions') @observer class RecipesScreen extend | |||
67 | 74 | ||
68 | render() { | 75 | render() { |
69 | const { | 76 | const { |
70 | recipePreviews, recipes, services, user, | 77 | recipePreviews, |
78 | recipes, | ||
79 | services, | ||
80 | user, | ||
71 | } = this.props.stores; | 81 | } = this.props.stores; |
72 | const { showAddServiceInterface } = this.props.actions.service; | 82 | |
83 | const { | ||
84 | app: appActions, | ||
85 | service: serviceActions, | ||
86 | } = this.props.actions; | ||
73 | 87 | ||
74 | const { filter } = this.props.params; | 88 | const { filter } = this.props.params; |
75 | let recipeFilter; | 89 | let recipeFilter; |
@@ -77,7 +91,7 @@ export default @inject('stores', 'actions') @observer class RecipesScreen extend | |||
77 | if (filter === 'all') { | 91 | if (filter === 'all') { |
78 | recipeFilter = recipePreviews.all; | 92 | recipeFilter = recipePreviews.all; |
79 | } else if (filter === 'dev') { | 93 | } else if (filter === 'dev') { |
80 | recipeFilter = recipePreviews.dev; | 94 | recipeFilter = communityRecipesStore.communityRecipes; |
81 | } else { | 95 | } else { |
82 | recipeFilter = recipePreviews.featured; | 96 | recipeFilter = recipePreviews.featured; |
83 | } | 97 | } |
@@ -89,6 +103,8 @@ export default @inject('stores', 'actions') @observer class RecipesScreen extend | |||
89 | || recipes.installRecipeRequest.isExecuting | 103 | || recipes.installRecipeRequest.isExecuting |
90 | || recipePreviews.searchRecipePreviewsRequest.isExecuting; | 104 | || recipePreviews.searchRecipePreviewsRequest.isExecuting; |
91 | 105 | ||
106 | const recipeDirectory = path.join(app.getPath('userData'), 'recipes', 'dev'); | ||
107 | |||
92 | return ( | 108 | return ( |
93 | <ErrorBoundary> | 109 | <ErrorBoundary> |
94 | <RecipesDashboard | 110 | <RecipesDashboard |
@@ -97,12 +113,23 @@ export default @inject('stores', 'actions') @observer class RecipesScreen extend | |||
97 | addedServiceCount={services.all.length} | 113 | addedServiceCount={services.all.length} |
98 | isPremium={user.data.isPremium} | 114 | isPremium={user.data.isPremium} |
99 | hasLoadedRecipes={recipePreviews.featuredRecipePreviewsRequest.wasExecuted} | 115 | hasLoadedRecipes={recipePreviews.featuredRecipePreviewsRequest.wasExecuted} |
100 | showAddServiceInterface={showAddServiceInterface} | 116 | showAddServiceInterface={serviceActions.showAddServiceInterface} |
101 | searchRecipes={e => this.searchRecipes(e)} | 117 | searchRecipes={e => this.searchRecipes(e)} |
102 | resetSearch={() => this.resetSearch()} | 118 | resetSearch={() => this.resetSearch()} |
103 | searchNeedle={this.state.needle} | 119 | searchNeedle={this.state.needle} |
104 | serviceStatus={services.actionStatus} | 120 | serviceStatus={services.actionStatus} |
105 | devRecipesCount={recipePreviews.dev.length} | 121 | recipeFilter={filter} |
122 | recipeDirectory={recipeDirectory} | ||
123 | openRecipeDirectory={() => { | ||
124 | shell.openItem(recipeDirectory); | ||
125 | gaEvent('Recipe', 'open-recipe-folder', 'Open Folder'); | ||
126 | }} | ||
127 | openDevDocs={() => { | ||
128 | appActions.openExternalUrl({ url: FRANZ_DEV_DOCS }); | ||
129 | gaEvent('Recipe', 'open-dev-docs', 'Developer Documentation'); | ||
130 | }} | ||
131 | isCommunityRecipesIncludedInCurrentPlan={communityRecipesStore.isCommunityRecipesIncludedInCurrentPlan} | ||
132 | isUserPremiumUser={user.isPremium} | ||
106 | /> | 133 | /> |
107 | </ErrorBoundary> | 134 | </ErrorBoundary> |
108 | ); | 135 | ); |
@@ -117,6 +144,9 @@ RecipesScreen.wrappedComponent.propTypes = { | |||
117 | user: PropTypes.instanceOf(UserStore).isRequired, | 144 | user: PropTypes.instanceOf(UserStore).isRequired, |
118 | }).isRequired, | 145 | }).isRequired, |
119 | actions: PropTypes.shape({ | 146 | actions: PropTypes.shape({ |
147 | app: PropTypes.shape({ | ||
148 | openExternalUrl: PropTypes.func.isRequired, | ||
149 | }).isRequired, | ||
120 | service: PropTypes.shape({ | 150 | service: PropTypes.shape({ |
121 | showAddServiceInterface: PropTypes.func.isRequired, | 151 | showAddServiceInterface: PropTypes.func.isRequired, |
122 | }).isRequired, | 152 | }).isRequired, |
diff --git a/src/containers/subscription/SubscriptionFormScreen.js b/src/containers/subscription/SubscriptionFormScreen.js index aa1166f5e..7486cc498 100644 --- a/src/containers/subscription/SubscriptionFormScreen.js +++ b/src/containers/subscription/SubscriptionFormScreen.js | |||
@@ -74,28 +74,14 @@ export default @inject('stores', 'actions') @observer class SubscriptionFormScre | |||
74 | 74 | ||
75 | render() { | 75 | render() { |
76 | const { | 76 | const { |
77 | content, | ||
78 | actions, | 77 | actions, |
79 | stores, | 78 | stores, |
80 | showSkipOption, | ||
81 | skipAction, | ||
82 | skipButtonLabel, | ||
83 | hideInfo, | ||
84 | } = this.props; | 79 | } = this.props; |
85 | return ( | 80 | return ( |
86 | <SubscriptionForm | 81 | <SubscriptionForm |
87 | plan={stores.payment.plan} | 82 | plan={stores.payment.plan} |
88 | isLoading={stores.payment.plansRequest.isExecuting} | 83 | activateTrial={() => actions.user.activateTrial({ planId: stores.features.features.defaultTrialPlan })} |
89 | retryPlanRequest={() => stores.payment.plansRequest.reload()} | 84 | isActivatingTrial={stores.user.activateTrialRequest.isExecuting || stores.user.getUserInfoRequest.isExecuting} |
90 | isCreatingHostedPage={stores.payment.createHostedPageRequest.isExecuting} | ||
91 | handlePayment={price => this.handlePayment(price)} | ||
92 | content={content} | ||
93 | error={stores.payment.plansRequest.isError} | ||
94 | showSkipOption={showSkipOption} | ||
95 | skipAction={skipAction} | ||
96 | skipButtonLabel={skipButtonLabel} | ||
97 | hideInfo={hideInfo} | ||
98 | openExternalUrl={actions.app.openExternalUrl} | ||
99 | /> | 85 | /> |
100 | ); | 86 | ); |
101 | } | 87 | } |
diff --git a/src/features/communityRecipes/index.js b/src/features/communityRecipes/index.js new file mode 100644 index 000000000..4d050f90e --- /dev/null +++ b/src/features/communityRecipes/index.js | |||
@@ -0,0 +1,28 @@ | |||
1 | import { reaction } from 'mobx'; | ||
2 | import { CommunityRecipesStore } from './store'; | ||
3 | |||
4 | const debug = require('debug')('Franz:feature:communityRecipes'); | ||
5 | |||
6 | export const DEFAULT_SERVICE_LIMIT = 3; | ||
7 | |||
8 | export const communityRecipesStore = new CommunityRecipesStore(); | ||
9 | |||
10 | export default function initCommunityRecipes(stores, actions) { | ||
11 | const { features } = stores; | ||
12 | |||
13 | communityRecipesStore.start(stores, actions); | ||
14 | |||
15 | // Toggle communityRecipe premium status | ||
16 | reaction( | ||
17 | () => ( | ||
18 | features.features.isCommunityRecipesIncludedInCurrentPlan | ||
19 | ), | ||
20 | (isPremiumFeature) => { | ||
21 | debug('Community recipes is premium feature: ', isPremiumFeature); | ||
22 | communityRecipesStore.isCommunityRecipesIncludedInCurrentPlan = isPremiumFeature; | ||
23 | }, | ||
24 | { | ||
25 | fireImmediately: true, | ||
26 | }, | ||
27 | ); | ||
28 | } | ||
diff --git a/src/features/communityRecipes/store.js b/src/features/communityRecipes/store.js new file mode 100644 index 000000000..4d45c3b33 --- /dev/null +++ b/src/features/communityRecipes/store.js | |||
@@ -0,0 +1,31 @@ | |||
1 | import { computed, observable } from 'mobx'; | ||
2 | import { FeatureStore } from '../utils/FeatureStore'; | ||
3 | |||
4 | const debug = require('debug')('Franz:feature:communityRecipes:store'); | ||
5 | |||
6 | export class CommunityRecipesStore extends FeatureStore { | ||
7 | @observable isCommunityRecipesIncludedInCurrentPlan = false; | ||
8 | |||
9 | start(stores, actions) { | ||
10 | debug('start'); | ||
11 | this.stores = stores; | ||
12 | this.actions = actions; | ||
13 | } | ||
14 | |||
15 | stop() { | ||
16 | debug('stop'); | ||
17 | super.stop(); | ||
18 | } | ||
19 | |||
20 | @computed get communityRecipes() { | ||
21 | if (!this.stores) return []; | ||
22 | |||
23 | return this.stores.recipePreviews.dev.map((r) => { | ||
24 | r.isDevRecipe = !!r.author.find(a => a.email === this.stores.user.data.email); | ||
25 | |||
26 | return r; | ||
27 | }); | ||
28 | } | ||
29 | } | ||
30 | |||
31 | export default CommunityRecipesStore; | ||
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/features/serviceLimit/components/LimitReachedInfobox.js b/src/features/serviceLimit/components/LimitReachedInfobox.js new file mode 100644 index 000000000..fc54dcf85 --- /dev/null +++ b/src/features/serviceLimit/components/LimitReachedInfobox.js | |||
@@ -0,0 +1,78 @@ | |||
1 | import React, { Component } from 'react'; | ||
2 | import PropTypes from 'prop-types'; | ||
3 | import { inject, observer } from 'mobx-react'; | ||
4 | import { defineMessages, intlShape } from 'react-intl'; | ||
5 | import injectSheet from 'react-jss'; | ||
6 | import { Infobox } from '@meetfranz/ui'; | ||
7 | |||
8 | import { gaEvent } from '../../../lib/analytics'; | ||
9 | |||
10 | const messages = defineMessages({ | ||
11 | limitReached: { | ||
12 | id: 'feature.serviceLimit.limitReached', | ||
13 | defaultMessage: '!!!You have added {amount} of {limit} services. Please upgrade your account to add more services.', | ||
14 | }, | ||
15 | action: { | ||
16 | id: 'premiumFeature.button.upgradeAccount', | ||
17 | defaultMessage: '!!!Upgrade account', | ||
18 | }, | ||
19 | }); | ||
20 | |||
21 | const styles = theme => ({ | ||
22 | container: { | ||
23 | height: 'auto', | ||
24 | background: theme.styleTypes.primary.accent, | ||
25 | color: theme.styleTypes.primary.contrast, | ||
26 | borderRadius: 0, | ||
27 | marginBottom: 0, | ||
28 | |||
29 | '& > div': { | ||
30 | marginBottom: 0, | ||
31 | }, | ||
32 | |||
33 | '& button': { | ||
34 | color: theme.styleTypes.primary.contrast, | ||
35 | }, | ||
36 | }, | ||
37 | }); | ||
38 | |||
39 | |||
40 | @inject('stores', 'actions') @injectSheet(styles) @observer | ||
41 | class LimitReachedInfobox extends Component { | ||
42 | static propTypes = { | ||
43 | classes: PropTypes.object.isRequired, | ||
44 | stores: PropTypes.object.isRequired, | ||
45 | actions: PropTypes.object.isRequired, | ||
46 | }; | ||
47 | |||
48 | static contextTypes = { | ||
49 | intl: intlShape, | ||
50 | }; | ||
51 | |||
52 | render() { | ||
53 | const { classes, stores, actions } = this.props; | ||
54 | const { intl } = this.context; | ||
55 | |||
56 | const { | ||
57 | serviceLimit, | ||
58 | } = stores; | ||
59 | |||
60 | if (!serviceLimit.userHasReachedServiceLimit) return null; | ||
61 | |||
62 | return ( | ||
63 | <Infobox | ||
64 | icon="mdiInformation" | ||
65 | className={classes.container} | ||
66 | ctaLabel={intl.formatMessage(messages.action)} | ||
67 | ctaOnClick={() => { | ||
68 | actions.ui.openSettings({ path: 'user' }); | ||
69 | gaEvent('Service Limit', 'upgrade', 'Upgrade account'); | ||
70 | }} | ||
71 | > | ||
72 | {intl.formatMessage(messages.limitReached, { amount: serviceLimit.serviceCount, limit: serviceLimit.serviceLimit })} | ||
73 | </Infobox> | ||
74 | ); | ||
75 | } | ||
76 | } | ||
77 | |||
78 | export default LimitReachedInfobox; | ||
diff --git a/src/features/serviceLimit/index.js b/src/features/serviceLimit/index.js new file mode 100644 index 000000000..92ad8bb98 --- /dev/null +++ b/src/features/serviceLimit/index.js | |||
@@ -0,0 +1,33 @@ | |||
1 | import { reaction } from 'mobx'; | ||
2 | import { ServiceLimitStore } from './store'; | ||
3 | |||
4 | const debug = require('debug')('Franz:feature:serviceLimit'); | ||
5 | |||
6 | export const DEFAULT_SERVICE_LIMIT = 3; | ||
7 | |||
8 | let store = null; | ||
9 | |||
10 | export const serviceLimitStore = new ServiceLimitStore(); | ||
11 | |||
12 | export default function initServiceLimit(stores, actions) { | ||
13 | const { features } = stores; | ||
14 | |||
15 | // Toggle serviceLimit feature | ||
16 | reaction( | ||
17 | () => ( | ||
18 | features.features.isServiceLimitEnabled | ||
19 | ), | ||
20 | (isEnabled) => { | ||
21 | if (isEnabled) { | ||
22 | debug('Initializing `serviceLimit` feature'); | ||
23 | store = serviceLimitStore.start(stores, actions); | ||
24 | } else if (store) { | ||
25 | debug('Disabling `serviceLimit` feature'); | ||
26 | serviceLimitStore.stop(); | ||
27 | } | ||
28 | }, | ||
29 | { | ||
30 | fireImmediately: true, | ||
31 | }, | ||
32 | ); | ||
33 | } | ||
diff --git a/src/features/serviceLimit/store.js b/src/features/serviceLimit/store.js new file mode 100644 index 000000000..9836c5f51 --- /dev/null +++ b/src/features/serviceLimit/store.js | |||
@@ -0,0 +1,41 @@ | |||
1 | import { computed, observable } from 'mobx'; | ||
2 | import { FeatureStore } from '../utils/FeatureStore'; | ||
3 | import { DEFAULT_SERVICE_LIMIT } from '.'; | ||
4 | |||
5 | const debug = require('debug')('Franz:feature:serviceLimit:store'); | ||
6 | |||
7 | export class ServiceLimitStore extends FeatureStore { | ||
8 | @observable isServiceLimitEnabled = false; | ||
9 | |||
10 | start(stores, actions) { | ||
11 | debug('start'); | ||
12 | this.stores = stores; | ||
13 | this.actions = actions; | ||
14 | |||
15 | this.isServiceLimitEnabled = true; | ||
16 | } | ||
17 | |||
18 | stop() { | ||
19 | super.stop(); | ||
20 | |||
21 | this.isServiceLimitEnabled = false; | ||
22 | } | ||
23 | |||
24 | @computed get userHasReachedServiceLimit() { | ||
25 | if (!this.isServiceLimitEnabled) return false; | ||
26 | |||
27 | return this.serviceLimit !== 0 && this.serviceCount >= this.serviceLimit; | ||
28 | } | ||
29 | |||
30 | @computed get serviceLimit() { | ||
31 | if (!this.isServiceLimitEnabled || this.stores.features.features.serviceLimitCount === 0) return 0; | ||
32 | |||
33 | return this.stores.features.features.serviceLimitCount || DEFAULT_SERVICE_LIMIT; | ||
34 | } | ||
35 | |||
36 | @computed get serviceCount() { | ||
37 | return this.stores.services.all.length; | ||
38 | } | ||
39 | } | ||
40 | |||
41 | export default ServiceLimitStore; | ||
diff --git a/src/features/serviceProxy/index.js b/src/features/serviceProxy/index.js index 4bea327ad..55c600de4 100644 --- a/src/features/serviceProxy/index.js +++ b/src/features/serviceProxy/index.js | |||
@@ -9,17 +9,17 @@ const debug = require('debug')('Franz:feature:serviceProxy'); | |||
9 | 9 | ||
10 | export const config = observable({ | 10 | export const config = observable({ |
11 | isEnabled: DEFAULT_FEATURES_CONFIG.isServiceProxyEnabled, | 11 | isEnabled: DEFAULT_FEATURES_CONFIG.isServiceProxyEnabled, |
12 | isPremium: DEFAULT_FEATURES_CONFIG.isServiceProxyPremiumFeature, | 12 | isPremium: DEFAULT_FEATURES_CONFIG.isServiceProxyIncludedInCurrentPlan, |
13 | }); | 13 | }); |
14 | 14 | ||
15 | export default function init(stores) { | 15 | export default function init(stores) { |
16 | debug('Initializing `serviceProxy` feature'); | 16 | debug('Initializing `serviceProxy` feature'); |
17 | 17 | ||
18 | autorun(() => { | 18 | autorun(() => { |
19 | const { isServiceProxyEnabled, isServiceProxyPremiumFeature } = stores.features.features; | 19 | const { isServiceProxyEnabled, isServiceProxyIncludedInCurrentPlan } = stores.features.features; |
20 | 20 | ||
21 | config.isEnabled = isServiceProxyEnabled !== undefined ? isServiceProxyEnabled : DEFAULT_FEATURES_CONFIG.isServiceProxyEnabled; | 21 | config.isEnabled = isServiceProxyEnabled !== undefined ? isServiceProxyEnabled : DEFAULT_FEATURES_CONFIG.isServiceProxyEnabled; |
22 | config.isPremium = isServiceProxyPremiumFeature !== undefined ? isServiceProxyPremiumFeature : DEFAULT_FEATURES_CONFIG.isServiceProxyPremiumFeature; | 22 | config.isIncludedInCurrentPlan = isServiceProxyIncludedInCurrentPlan !== undefined ? isServiceProxyIncludedInCurrentPlan : DEFAULT_FEATURES_CONFIG.isServiceProxyIncludedInCurrentPlan; |
23 | 23 | ||
24 | const services = stores.services.enabled; | 24 | const services = stores.services.enabled; |
25 | const isPremiumUser = stores.user.data.isPremium; | 25 | const isPremiumUser = stores.user.data.isPremium; |
@@ -30,7 +30,7 @@ export default function init(stores) { | |||
30 | services.forEach((service) => { | 30 | services.forEach((service) => { |
31 | const s = session.fromPartition(`persist:service-${service.id}`); | 31 | const s = session.fromPartition(`persist:service-${service.id}`); |
32 | 32 | ||
33 | if (config.isEnabled && (isPremiumUser || !config.isPremium)) { | 33 | if (config.isEnabled && (isPremiumUser || !config.isIncludedInCurrentPlan)) { |
34 | const serviceProxyConfig = proxySettings[service.id]; | 34 | const serviceProxyConfig = proxySettings[service.id]; |
35 | 35 | ||
36 | if (serviceProxyConfig && serviceProxyConfig.isEnabled && serviceProxyConfig.host) { | 36 | if (serviceProxyConfig && serviceProxyConfig.isEnabled && serviceProxyConfig.host) { |
diff --git a/src/features/spellchecker/index.js b/src/features/spellchecker/index.js index 79a2172b4..a07f9f63a 100644 --- a/src/features/spellchecker/index.js +++ b/src/features/spellchecker/index.js | |||
@@ -5,18 +5,18 @@ import { DEFAULT_FEATURES_CONFIG } from '../../config'; | |||
5 | const debug = require('debug')('Franz:feature:spellchecker'); | 5 | const debug = require('debug')('Franz:feature:spellchecker'); |
6 | 6 | ||
7 | export const config = observable({ | 7 | export const config = observable({ |
8 | isPremium: DEFAULT_FEATURES_CONFIG.isSpellcheckerPremiumFeature, | 8 | isIncludedInCurrentPlan: DEFAULT_FEATURES_CONFIG.isSpellcheckerIncludedInCurrentPlan, |
9 | }); | 9 | }); |
10 | 10 | ||
11 | export default function init(stores) { | 11 | export default function init(stores) { |
12 | debug('Initializing `spellchecker` feature'); | 12 | debug('Initializing `spellchecker` feature'); |
13 | 13 | ||
14 | autorun(() => { | 14 | autorun(() => { |
15 | const { isSpellcheckerPremiumFeature } = stores.features.features; | 15 | const { isSpellcheckerIncludedInCurrentPlan } = stores.features.features; |
16 | 16 | ||
17 | config.isPremium = isSpellcheckerPremiumFeature !== undefined ? isSpellcheckerPremiumFeature : DEFAULT_FEATURES_CONFIG.isSpellcheckerPremiumFeature; | 17 | config.isIncludedInCurrentPlan = isSpellcheckerIncludedInCurrentPlan !== undefined ? isSpellcheckerIncludedInCurrentPlan : DEFAULT_FEATURES_CONFIG.isSpellcheckerIncludedInCurrentPlan; |
18 | 18 | ||
19 | if (!stores.user.data.isPremium && config.isPremium && stores.settings.app.enableSpellchecking) { | 19 | if (!stores.user.data.isPremium && config.isIncludedInCurrentPlan && stores.settings.app.enableSpellchecking) { |
20 | debug('Override settings.spellcheckerEnabled flag to false'); | 20 | debug('Override settings.spellcheckerEnabled flag to false'); |
21 | 21 | ||
22 | Object.assign(stores.settings.app, { | 22 | Object.assign(stores.settings.app, { |
diff --git a/src/features/workspaces/store.js b/src/features/workspaces/store.js index a82f6895c..caa73619e 100644 --- a/src/features/workspaces/store.js +++ b/src/features/workspaces/store.js | |||
@@ -255,9 +255,9 @@ export default class WorkspacesStore extends FeatureStore { | |||
255 | _setIsPremiumFeatureReaction = () => { | 255 | _setIsPremiumFeatureReaction = () => { |
256 | const { features, user } = this.stores; | 256 | const { features, user } = this.stores; |
257 | const { isPremium } = user.data; | 257 | const { isPremium } = user.data; |
258 | const { isWorkspacePremiumFeature } = features.features; | 258 | const { isWorkspaceIncludedInCurrentPlan } = features.features; |
259 | this.isPremiumFeature = isWorkspacePremiumFeature; | 259 | this.isPremiumFeature = isWorkspaceIncludedInCurrentPlan; |
260 | this.isPremiumUpgradeRequired = isWorkspacePremiumFeature && !isPremium; | 260 | this.isPremiumUpgradeRequired = isWorkspaceIncludedInCurrentPlan && !isPremium; |
261 | }; | 261 | }; |
262 | 262 | ||
263 | _setWorkspaceBeingEditedReaction = () => { | 263 | _setWorkspaceBeingEditedReaction = () => { |
diff --git a/src/helpers/plan-helpers.js b/src/helpers/plan-helpers.js new file mode 100644 index 000000000..37a4457af --- /dev/null +++ b/src/helpers/plan-helpers.js | |||
@@ -0,0 +1,43 @@ | |||
1 | import { defineMessages } from 'react-intl'; | ||
2 | import { PLANS_MAPPING, PLANS } from '../config'; | ||
3 | |||
4 | const messages = defineMessages({ | ||
5 | [PLANS.PRO_YEARLY]: { | ||
6 | id: 'pricing.plan.pro-yearly', | ||
7 | defaultMessage: '!!!Franz Professional Yearly', | ||
8 | }, | ||
9 | [PLANS.PRO_MONTHLY]: { | ||
10 | id: 'pricing.plan.pro-monthly', | ||
11 | defaultMessage: '!!!Franz Professional Monthly', | ||
12 | }, | ||
13 | [PLANS.PERSONAL_YEARLY]: { | ||
14 | id: 'pricing.plan.personal-yearly', | ||
15 | defaultMessage: '!!!Franz Personal Yearly', | ||
16 | }, | ||
17 | [PLANS.PERSONAL_MONTHLY]: { | ||
18 | id: 'pricing.plan.personal-monthly', | ||
19 | defaultMessage: '!!!Franz Personal Monthly', | ||
20 | }, | ||
21 | [PLANS.FREE]: { | ||
22 | id: 'pricing.plan.free', | ||
23 | defaultMessage: '!!!Franz Free', | ||
24 | }, | ||
25 | [PLANS.LEGACY]: { | ||
26 | id: 'pricing.plan.legacy', | ||
27 | defaultMessage: '!!!Franz Premium', | ||
28 | }, | ||
29 | }); | ||
30 | |||
31 | export function i18nPlanName(planId, intl) { | ||
32 | if (!planId) { | ||
33 | throw new Error('planId is required'); | ||
34 | } | ||
35 | |||
36 | if (!intl) { | ||
37 | throw new Error('intl context is required'); | ||
38 | } | ||
39 | |||
40 | const plan = PLANS_MAPPING[planId]; | ||
41 | |||
42 | return intl.formatMessage(messages[plan]); | ||
43 | } | ||
diff --git a/src/i18n/locales/defaultMessages.json b/src/i18n/locales/defaultMessages.json index eca3062c2..bdb1def11 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 | }, | 450 | }, |
451 | "file": "src/components/auth/Pricing.js", | 451 | "file": "src/components/auth/Pricing.js", |
452 | "id": "pricing.submit.label", | 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 | ||
476 | }, | ||
477 | "file": "src/components/auth/Pricing.js", | ||
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 | ], |
@@ -669,39 +734,39 @@ | |||
669 | "defaultMessage": "!!!Your services have been updated.", | 734 | "defaultMessage": "!!!Your services have been updated.", |
670 | "end": { | 735 | "end": { |
671 | "column": 3, | 736 | "column": 3, |
672 | "line": 29 | 737 | "line": 30 |
673 | }, | 738 | }, |
674 | "file": "src/components/layout/AppLayout.js", | 739 | "file": "src/components/layout/AppLayout.js", |
675 | "id": "infobar.servicesUpdated", | 740 | "id": "infobar.servicesUpdated", |
676 | "start": { | 741 | "start": { |
677 | "column": 19, | 742 | "column": 19, |
678 | "line": 26 | 743 | "line": 27 |
679 | } | 744 | } |
680 | }, | 745 | }, |
681 | { | 746 | { |
682 | "defaultMessage": "!!!Reload services", | 747 | "defaultMessage": "!!!Reload services", |
683 | "end": { | 748 | "end": { |
684 | "column": 3, | 749 | "column": 3, |
685 | "line": 33 | 750 | "line": 34 |
686 | }, | 751 | }, |
687 | "file": "src/components/layout/AppLayout.js", | 752 | "file": "src/components/layout/AppLayout.js", |
688 | "id": "infobar.buttonReloadServices", | 753 | "id": "infobar.buttonReloadServices", |
689 | "start": { | 754 | "start": { |
690 | "column": 24, | 755 | "column": 24, |
691 | "line": 30 | 756 | "line": 31 |
692 | } | 757 | } |
693 | }, | 758 | }, |
694 | { | 759 | { |
695 | "defaultMessage": "!!!Could not load services and user information", | 760 | "defaultMessage": "!!!Could not load services and user information", |
696 | "end": { | 761 | "end": { |
697 | "column": 3, | 762 | "column": 3, |
698 | "line": 37 | 763 | "line": 38 |
699 | }, | 764 | }, |
700 | "file": "src/components/layout/AppLayout.js", | 765 | "file": "src/components/layout/AppLayout.js", |
701 | "id": "infobar.requiredRequestsFailed", | 766 | "id": "infobar.requiredRequestsFailed", |
702 | "start": { | 767 | "start": { |
703 | "column": 26, | 768 | "column": 26, |
704 | "line": 34 | 769 | "line": 35 |
705 | } | 770 | } |
706 | } | 771 | } |
707 | ], | 772 | ], |
@@ -894,29 +959,99 @@ | |||
894 | { | 959 | { |
895 | "descriptors": [ | 960 | "descriptors": [ |
896 | { | 961 | { |
897 | "defaultMessage": "!!!Welcome to Franz", | 962 | "defaultMessage": "!!!You have reached your service limit.", |
898 | "end": { | 963 | "end": { |
899 | "column": 3, | 964 | "column": 3, |
900 | "line": 14 | 965 | "line": 14 |
901 | }, | 966 | }, |
967 | "file": "src/components/services/content/ServiceRestricted.js", | ||
968 | "id": "service.restrictedHandler.serviceLimit.headline", | ||
969 | "start": { | ||
970 | "column": 24, | ||
971 | "line": 11 | ||
972 | } | ||
973 | }, | ||
974 | { | ||
975 | "defaultMessage": "!!!Please upgrade your account to use more than {count} services.", | ||
976 | "end": { | ||
977 | "column": 3, | ||
978 | "line": 18 | ||
979 | }, | ||
980 | "file": "src/components/services/content/ServiceRestricted.js", | ||
981 | "id": "service.restrictedHandler.serviceLimit.text", | ||
982 | "start": { | ||
983 | "column": 20, | ||
984 | "line": 15 | ||
985 | } | ||
986 | }, | ||
987 | { | ||
988 | "defaultMessage": "!!!Franz Professional Plan required", | ||
989 | "end": { | ||
990 | "column": 3, | ||
991 | "line": 22 | ||
992 | }, | ||
993 | "file": "src/components/services/content/ServiceRestricted.js", | ||
994 | "id": "service.restrictedHandler.customUrl.headline", | ||
995 | "start": { | ||
996 | "column": 21, | ||
997 | "line": 19 | ||
998 | } | ||
999 | }, | ||
1000 | { | ||
1001 | "defaultMessage": "!!!Please upgrade to the Franz Professional plan to use custom urls & self hosted services.", | ||
1002 | "end": { | ||
1003 | "column": 3, | ||
1004 | "line": 26 | ||
1005 | }, | ||
1006 | "file": "src/components/services/content/ServiceRestricted.js", | ||
1007 | "id": "service.restrictedHandler.customUrl.text", | ||
1008 | "start": { | ||
1009 | "column": 17, | ||
1010 | "line": 23 | ||
1011 | } | ||
1012 | }, | ||
1013 | { | ||
1014 | "defaultMessage": "!!!Upgrade Account", | ||
1015 | "end": { | ||
1016 | "column": 3, | ||
1017 | "line": 30 | ||
1018 | }, | ||
1019 | "file": "src/components/services/content/ServiceRestricted.js", | ||
1020 | "id": "service.restrictedHandler.action", | ||
1021 | "start": { | ||
1022 | "column": 10, | ||
1023 | "line": 27 | ||
1024 | } | ||
1025 | } | ||
1026 | ], | ||
1027 | "path": "src/components/services/content/ServiceRestricted.json" | ||
1028 | }, | ||
1029 | { | ||
1030 | "descriptors": [ | ||
1031 | { | ||
1032 | "defaultMessage": "!!!Welcome to Franz", | ||
1033 | "end": { | ||
1034 | "column": 3, | ||
1035 | "line": 17 | ||
1036 | }, | ||
902 | "file": "src/components/services/content/Services.js", | 1037 | "file": "src/components/services/content/Services.js", |
903 | "id": "services.welcome", | 1038 | "id": "services.welcome", |
904 | "start": { | 1039 | "start": { |
905 | "column": 11, | 1040 | "column": 11, |
906 | "line": 11 | 1041 | "line": 14 |
907 | } | 1042 | } |
908 | }, | 1043 | }, |
909 | { | 1044 | { |
910 | "defaultMessage": "!!!Get started", | 1045 | "defaultMessage": "!!!Get started", |
911 | "end": { | 1046 | "end": { |
912 | "column": 3, | 1047 | "column": 3, |
913 | "line": 18 | 1048 | "line": 21 |
914 | }, | 1049 | }, |
915 | "file": "src/components/services/content/Services.js", | 1050 | "file": "src/components/services/content/Services.js", |
916 | "id": "services.getStarted", | 1051 | "id": "services.getStarted", |
917 | "start": { | 1052 | "start": { |
918 | "column": 14, | 1053 | "column": 14, |
919 | "line": 15 | 1054 | "line": 18 |
920 | } | 1055 | } |
921 | } | 1056 | } |
922 | ], | 1057 | ], |
@@ -1107,195 +1242,247 @@ | |||
1107 | "defaultMessage": "!!!Account", | 1242 | "defaultMessage": "!!!Account", |
1108 | "end": { | 1243 | "end": { |
1109 | "column": 3, | 1244 | "column": 3, |
1110 | "line": 17 | 1245 | "line": 19 |
1111 | }, | 1246 | }, |
1112 | "file": "src/components/settings/account/AccountDashboard.js", | 1247 | "file": "src/components/settings/account/AccountDashboard.js", |
1113 | "id": "settings.account.headline", | 1248 | "id": "settings.account.headline", |
1114 | "start": { | 1249 | "start": { |
1115 | "column": 12, | 1250 | "column": 12, |
1116 | "line": 14 | 1251 | "line": 16 |
1117 | } | 1252 | } |
1118 | }, | 1253 | }, |
1119 | { | 1254 | { |
1120 | "defaultMessage": "!!!Your Subscription", | 1255 | "defaultMessage": "!!!Your Subscription", |
1121 | "end": { | 1256 | "end": { |
1122 | "column": 3, | 1257 | "column": 3, |
1123 | "line": 21 | 1258 | "line": 23 |
1124 | }, | 1259 | }, |
1125 | "file": "src/components/settings/account/AccountDashboard.js", | 1260 | "file": "src/components/settings/account/AccountDashboard.js", |
1126 | "id": "settings.account.headlineSubscription", | 1261 | "id": "settings.account.headlineSubscription", |
1127 | "start": { | 1262 | "start": { |
1128 | "column": 24, | 1263 | "column": 24, |
1129 | "line": 18 | 1264 | "line": 20 |
1130 | } | 1265 | } |
1131 | }, | 1266 | }, |
1132 | { | 1267 | { |
1133 | "defaultMessage": "!!!Upgrade your Account", | 1268 | "defaultMessage": "!!!Upgrade your Account", |
1134 | "end": { | 1269 | "end": { |
1135 | "column": 3, | 1270 | "column": 3, |
1136 | "line": 25 | 1271 | "line": 27 |
1137 | }, | 1272 | }, |
1138 | "file": "src/components/settings/account/AccountDashboard.js", | 1273 | "file": "src/components/settings/account/AccountDashboard.js", |
1139 | "id": "settings.account.headlineUpgrade", | 1274 | "id": "settings.account.headlineUpgrade", |
1140 | "start": { | 1275 | "start": { |
1141 | "column": 19, | 1276 | "column": 19, |
1142 | "line": 22 | 1277 | "line": 24 |
1143 | } | 1278 | } |
1144 | }, | 1279 | }, |
1145 | { | 1280 | { |
1146 | "defaultMessage": "!!Danger Zone", | 1281 | "defaultMessage": "!!Danger Zone", |
1147 | "end": { | 1282 | "end": { |
1148 | "column": 3, | 1283 | "column": 3, |
1149 | "line": 29 | 1284 | "line": 31 |
1150 | }, | 1285 | }, |
1151 | "file": "src/components/settings/account/AccountDashboard.js", | 1286 | "file": "src/components/settings/account/AccountDashboard.js", |
1152 | "id": "settings.account.headlineDangerZone", | 1287 | "id": "settings.account.headlineDangerZone", |
1153 | "start": { | 1288 | "start": { |
1154 | "column": 22, | 1289 | "column": 22, |
1155 | "line": 26 | 1290 | "line": 28 |
1156 | } | 1291 | } |
1157 | }, | 1292 | }, |
1158 | { | 1293 | { |
1159 | "defaultMessage": "!!!Manage your subscription", | 1294 | "defaultMessage": "!!!Manage your subscription", |
1160 | "end": { | 1295 | "end": { |
1161 | "column": 3, | 1296 | "column": 3, |
1162 | "line": 33 | 1297 | "line": 35 |
1163 | }, | 1298 | }, |
1164 | "file": "src/components/settings/account/AccountDashboard.js", | 1299 | "file": "src/components/settings/account/AccountDashboard.js", |
1165 | "id": "settings.account.manageSubscription.label", | 1300 | "id": "settings.account.manageSubscription.label", |
1166 | "start": { | 1301 | "start": { |
1167 | "column": 33, | 1302 | "column": 33, |
1168 | "line": 30 | 1303 | "line": 32 |
1169 | } | 1304 | } |
1170 | }, | 1305 | }, |
1171 | { | 1306 | { |
1172 | "defaultMessage": "!!!Basic Account", | 1307 | "defaultMessage": "!!!Basic Account", |
1173 | "end": { | 1308 | "end": { |
1174 | "column": 3, | 1309 | "column": 3, |
1175 | "line": 37 | 1310 | "line": 39 |
1176 | }, | 1311 | }, |
1177 | "file": "src/components/settings/account/AccountDashboard.js", | 1312 | "file": "src/components/settings/account/AccountDashboard.js", |
1178 | "id": "settings.account.accountType.basic", | 1313 | "id": "settings.account.accountType.basic", |
1179 | "start": { | 1314 | "start": { |
1180 | "column": 20, | 1315 | "column": 20, |
1181 | "line": 34 | 1316 | "line": 36 |
1182 | } | 1317 | } |
1183 | }, | 1318 | }, |
1184 | { | 1319 | { |
1185 | "defaultMessage": "!!!Premium Supporter Account", | 1320 | "defaultMessage": "!!!Premium Supporter Account", |
1186 | "end": { | 1321 | "end": { |
1187 | "column": 3, | 1322 | "column": 3, |
1188 | "line": 41 | 1323 | "line": 43 |
1189 | }, | 1324 | }, |
1190 | "file": "src/components/settings/account/AccountDashboard.js", | 1325 | "file": "src/components/settings/account/AccountDashboard.js", |
1191 | "id": "settings.account.accountType.premium", | 1326 | "id": "settings.account.accountType.premium", |
1192 | "start": { | 1327 | "start": { |
1193 | "column": 22, | 1328 | "column": 22, |
1194 | "line": 38 | 1329 | "line": 40 |
1195 | } | 1330 | } |
1196 | }, | 1331 | }, |
1197 | { | 1332 | { |
1198 | "defaultMessage": "!!!Edit Account", | 1333 | "defaultMessage": "!!!Edit Account", |
1199 | "end": { | 1334 | "end": { |
1200 | "column": 3, | 1335 | "column": 3, |
1201 | "line": 45 | 1336 | "line": 47 |
1202 | }, | 1337 | }, |
1203 | "file": "src/components/settings/account/AccountDashboard.js", | 1338 | "file": "src/components/settings/account/AccountDashboard.js", |
1204 | "id": "settings.account.account.editButton", | 1339 | "id": "settings.account.account.editButton", |
1205 | "start": { | 1340 | "start": { |
1206 | "column": 21, | 1341 | "column": 21, |
1207 | "line": 42 | 1342 | "line": 44 |
1208 | } | 1343 | } |
1209 | }, | 1344 | }, |
1210 | { | 1345 | { |
1211 | "defaultMessage": "!!Invoices", | 1346 | "defaultMessage": "!!Invoices", |
1212 | "end": { | 1347 | "end": { |
1213 | "column": 3, | 1348 | "column": 3, |
1214 | "line": 49 | 1349 | "line": 51 |
1215 | }, | 1350 | }, |
1216 | "file": "src/components/settings/account/AccountDashboard.js", | 1351 | "file": "src/components/settings/account/AccountDashboard.js", |
1217 | "id": "settings.account.headlineInvoices", | 1352 | "id": "settings.account.headlineInvoices", |
1218 | "start": { | 1353 | "start": { |
1219 | "column": 18, | 1354 | "column": 18, |
1220 | "line": 46 | 1355 | "line": 48 |
1221 | } | 1356 | } |
1222 | }, | 1357 | }, |
1223 | { | 1358 | { |
1224 | "defaultMessage": "!!!Download", | 1359 | "defaultMessage": "!!!Download", |
1225 | "end": { | 1360 | "end": { |
1226 | "column": 3, | 1361 | "column": 3, |
1227 | "line": 53 | 1362 | "line": 55 |
1228 | }, | 1363 | }, |
1229 | "file": "src/components/settings/account/AccountDashboard.js", | 1364 | "file": "src/components/settings/account/AccountDashboard.js", |
1230 | "id": "settings.account.invoiceDownload", | 1365 | "id": "settings.account.invoiceDownload", |
1231 | "start": { | 1366 | "start": { |
1232 | "column": 19, | 1367 | "column": 19, |
1233 | "line": 50 | 1368 | "line": 52 |
1234 | } | 1369 | } |
1235 | }, | 1370 | }, |
1236 | { | 1371 | { |
1237 | "defaultMessage": "!!!Could not load user information", | 1372 | "defaultMessage": "!!!Could not load user information", |
1238 | "end": { | 1373 | "end": { |
1239 | "column": 3, | 1374 | "column": 3, |
1240 | "line": 57 | 1375 | "line": 59 |
1241 | }, | 1376 | }, |
1242 | "file": "src/components/settings/account/AccountDashboard.js", | 1377 | "file": "src/components/settings/account/AccountDashboard.js", |
1243 | "id": "settings.account.userInfoRequestFailed", | 1378 | "id": "settings.account.userInfoRequestFailed", |
1244 | "start": { | 1379 | "start": { |
1245 | "column": 25, | 1380 | "column": 25, |
1246 | "line": 54 | 1381 | "line": 56 |
1247 | } | 1382 | } |
1248 | }, | 1383 | }, |
1249 | { | 1384 | { |
1250 | "defaultMessage": "!!!Try again", | 1385 | "defaultMessage": "!!!Try again", |
1251 | "end": { | 1386 | "end": { |
1252 | "column": 3, | 1387 | "column": 3, |
1253 | "line": 61 | 1388 | "line": 63 |
1254 | }, | 1389 | }, |
1255 | "file": "src/components/settings/account/AccountDashboard.js", | 1390 | "file": "src/components/settings/account/AccountDashboard.js", |
1256 | "id": "settings.account.tryReloadUserInfoRequest", | 1391 | "id": "settings.account.tryReloadUserInfoRequest", |
1257 | "start": { | 1392 | "start": { |
1258 | "column": 28, | 1393 | "column": 28, |
1259 | "line": 58 | 1394 | "line": 60 |
1260 | } | 1395 | } |
1261 | }, | 1396 | }, |
1262 | { | 1397 | { |
1263 | "defaultMessage": "!!!Delete account", | 1398 | "defaultMessage": "!!!Delete account", |
1264 | "end": { | 1399 | "end": { |
1265 | "column": 3, | 1400 | "column": 3, |
1266 | "line": 65 | 1401 | "line": 67 |
1267 | }, | 1402 | }, |
1268 | "file": "src/components/settings/account/AccountDashboard.js", | 1403 | "file": "src/components/settings/account/AccountDashboard.js", |
1269 | "id": "settings.account.deleteAccount", | 1404 | "id": "settings.account.deleteAccount", |
1270 | "start": { | 1405 | "start": { |
1271 | "column": 17, | 1406 | "column": 17, |
1272 | "line": 62 | 1407 | "line": 64 |
1273 | } | 1408 | } |
1274 | }, | 1409 | }, |
1275 | { | 1410 | { |
1276 | "defaultMessage": "!!!If you don't need your Franz account any longer, you can delete your account and all related data here.", | 1411 | "defaultMessage": "!!!If you don't need your Franz account any longer, you can delete your account and all related data here.", |
1277 | "end": { | 1412 | "end": { |
1278 | "column": 3, | 1413 | "column": 3, |
1279 | "line": 69 | 1414 | "line": 71 |
1280 | }, | 1415 | }, |
1281 | "file": "src/components/settings/account/AccountDashboard.js", | 1416 | "file": "src/components/settings/account/AccountDashboard.js", |
1282 | "id": "settings.account.deleteInfo", | 1417 | "id": "settings.account.deleteInfo", |
1283 | "start": { | 1418 | "start": { |
1284 | "column": 14, | 1419 | "column": 14, |
1285 | "line": 66 | 1420 | "line": 68 |
1286 | } | 1421 | } |
1287 | }, | 1422 | }, |
1288 | { | 1423 | { |
1289 | "defaultMessage": "!!!You have received an email with a link to confirm your account deletion. Your account and data cannot be restored!", | 1424 | "defaultMessage": "!!!You have received an email with a link to confirm your account deletion. Your account and data cannot be restored!", |
1290 | "end": { | 1425 | "end": { |
1291 | "column": 3, | 1426 | "column": 3, |
1292 | "line": 73 | 1427 | "line": 75 |
1293 | }, | 1428 | }, |
1294 | "file": "src/components/settings/account/AccountDashboard.js", | 1429 | "file": "src/components/settings/account/AccountDashboard.js", |
1295 | "id": "settings.account.deleteEmailSent", | 1430 | "id": "settings.account.deleteEmailSent", |
1296 | "start": { | 1431 | "start": { |
1297 | "column": 19, | 1432 | "column": 19, |
1298 | "line": 70 | 1433 | "line": 72 |
1434 | } | ||
1435 | }, | ||
1436 | { | ||
1437 | "defaultMessage": "!!!Free Trial", | ||
1438 | "end": { | ||
1439 | "column": 3, | ||
1440 | "line": 79 | ||
1441 | }, | ||
1442 | "file": "src/components/settings/account/AccountDashboard.js", | ||
1443 | "id": "settings.account.trial", | ||
1444 | "start": { | ||
1445 | "column": 9, | ||
1446 | "line": 76 | ||
1447 | } | ||
1448 | }, | ||
1449 | { | ||
1450 | "defaultMessage": "!!!Your license:", | ||
1451 | "end": { | ||
1452 | "column": 3, | ||
1453 | "line": 83 | ||
1454 | }, | ||
1455 | "file": "src/components/settings/account/AccountDashboard.js", | ||
1456 | "id": "settings.account.yourLicense", | ||
1457 | "start": { | ||
1458 | "column": 15, | ||
1459 | "line": 80 | ||
1460 | } | ||
1461 | }, | ||
1462 | { | ||
1463 | "defaultMessage": "!!!Your free trial ends in {duration}.", | ||
1464 | "end": { | ||
1465 | "column": 3, | ||
1466 | "line": 87 | ||
1467 | }, | ||
1468 | "file": "src/components/settings/account/AccountDashboard.js", | ||
1469 | "id": "settings.account.trialEndsIn", | ||
1470 | "start": { | ||
1471 | "column": 15, | ||
1472 | "line": 84 | ||
1473 | } | ||
1474 | }, | ||
1475 | { | ||
1476 | "defaultMessage": "!!!Please update your billing info to continue using {license} after your trial period.", | ||
1477 | "end": { | ||
1478 | "column": 3, | ||
1479 | "line": 91 | ||
1480 | }, | ||
1481 | "file": "src/components/settings/account/AccountDashboard.js", | ||
1482 | "id": "settings.account.trialUpdateBillingInfo", | ||
1483 | "start": { | ||
1484 | "column": 33, | ||
1485 | "line": 88 | ||
1299 | } | 1486 | } |
1300 | } | 1487 | } |
1301 | ], | 1488 | ], |
@@ -1307,104 +1494,104 @@ | |||
1307 | "defaultMessage": "!!!Available services", | 1494 | "defaultMessage": "!!!Available services", |
1308 | "end": { | 1495 | "end": { |
1309 | "column": 3, | 1496 | "column": 3, |
1310 | "line": 16 | 1497 | "line": 17 |
1311 | }, | 1498 | }, |
1312 | "file": "src/components/settings/navigation/SettingsNavigation.js", | 1499 | "file": "src/components/settings/navigation/SettingsNavigation.js", |
1313 | "id": "settings.navigation.availableServices", | 1500 | "id": "settings.navigation.availableServices", |
1314 | "start": { | 1501 | "start": { |
1315 | "column": 21, | 1502 | "column": 21, |
1316 | "line": 13 | 1503 | "line": 14 |
1317 | } | 1504 | } |
1318 | }, | 1505 | }, |
1319 | { | 1506 | { |
1320 | "defaultMessage": "!!!Your services", | 1507 | "defaultMessage": "!!!Your services", |
1321 | "end": { | 1508 | "end": { |
1322 | "column": 3, | 1509 | "column": 3, |
1323 | "line": 20 | 1510 | "line": 21 |
1324 | }, | 1511 | }, |
1325 | "file": "src/components/settings/navigation/SettingsNavigation.js", | 1512 | "file": "src/components/settings/navigation/SettingsNavigation.js", |
1326 | "id": "settings.navigation.yourServices", | 1513 | "id": "settings.navigation.yourServices", |
1327 | "start": { | 1514 | "start": { |
1328 | "column": 16, | 1515 | "column": 16, |
1329 | "line": 17 | 1516 | "line": 18 |
1330 | } | 1517 | } |
1331 | }, | 1518 | }, |
1332 | { | 1519 | { |
1333 | "defaultMessage": "!!!Your workspaces", | 1520 | "defaultMessage": "!!!Your workspaces", |
1334 | "end": { | 1521 | "end": { |
1335 | "column": 3, | 1522 | "column": 3, |
1336 | "line": 24 | 1523 | "line": 25 |
1337 | }, | 1524 | }, |
1338 | "file": "src/components/settings/navigation/SettingsNavigation.js", | 1525 | "file": "src/components/settings/navigation/SettingsNavigation.js", |
1339 | "id": "settings.navigation.yourWorkspaces", | 1526 | "id": "settings.navigation.yourWorkspaces", |
1340 | "start": { | 1527 | "start": { |
1341 | "column": 18, | 1528 | "column": 18, |
1342 | "line": 21 | 1529 | "line": 22 |
1343 | } | 1530 | } |
1344 | }, | 1531 | }, |
1345 | { | 1532 | { |
1346 | "defaultMessage": "!!!Account", | 1533 | "defaultMessage": "!!!Account", |
1347 | "end": { | 1534 | "end": { |
1348 | "column": 3, | 1535 | "column": 3, |
1349 | "line": 28 | 1536 | "line": 29 |
1350 | }, | 1537 | }, |
1351 | "file": "src/components/settings/navigation/SettingsNavigation.js", | 1538 | "file": "src/components/settings/navigation/SettingsNavigation.js", |
1352 | "id": "settings.navigation.account", | 1539 | "id": "settings.navigation.account", |
1353 | "start": { | 1540 | "start": { |
1354 | "column": 11, | 1541 | "column": 11, |
1355 | "line": 25 | 1542 | "line": 26 |
1356 | } | 1543 | } |
1357 | }, | 1544 | }, |
1358 | { | 1545 | { |
1359 | "defaultMessage": "!!!Manage Team", | 1546 | "defaultMessage": "!!!Manage Team", |
1360 | "end": { | 1547 | "end": { |
1361 | "column": 3, | 1548 | "column": 3, |
1362 | "line": 32 | 1549 | "line": 33 |
1363 | }, | 1550 | }, |
1364 | "file": "src/components/settings/navigation/SettingsNavigation.js", | 1551 | "file": "src/components/settings/navigation/SettingsNavigation.js", |
1365 | "id": "settings.navigation.team", | 1552 | "id": "settings.navigation.team", |
1366 | "start": { | 1553 | "start": { |
1367 | "column": 8, | 1554 | "column": 8, |
1368 | "line": 29 | 1555 | "line": 30 |
1369 | } | 1556 | } |
1370 | }, | 1557 | }, |
1371 | { | 1558 | { |
1372 | "defaultMessage": "!!!Settings", | 1559 | "defaultMessage": "!!!Settings", |
1373 | "end": { | 1560 | "end": { |
1374 | "column": 3, | 1561 | "column": 3, |
1375 | "line": 36 | 1562 | "line": 37 |
1376 | }, | 1563 | }, |
1377 | "file": "src/components/settings/navigation/SettingsNavigation.js", | 1564 | "file": "src/components/settings/navigation/SettingsNavigation.js", |
1378 | "id": "settings.navigation.settings", | 1565 | "id": "settings.navigation.settings", |
1379 | "start": { | 1566 | "start": { |
1380 | "column": 12, | 1567 | "column": 12, |
1381 | "line": 33 | 1568 | "line": 34 |
1382 | } | 1569 | } |
1383 | }, | 1570 | }, |
1384 | { | 1571 | { |
1385 | "defaultMessage": "!!!Invite Friends", | 1572 | "defaultMessage": "!!!Invite Friends", |
1386 | "end": { | 1573 | "end": { |
1387 | "column": 3, | 1574 | "column": 3, |
1388 | "line": 40 | 1575 | "line": 41 |
1389 | }, | 1576 | }, |
1390 | "file": "src/components/settings/navigation/SettingsNavigation.js", | 1577 | "file": "src/components/settings/navigation/SettingsNavigation.js", |
1391 | "id": "settings.navigation.inviteFriends", | 1578 | "id": "settings.navigation.inviteFriends", |
1392 | "start": { | 1579 | "start": { |
1393 | "column": 17, | 1580 | "column": 17, |
1394 | "line": 37 | 1581 | "line": 38 |
1395 | } | 1582 | } |
1396 | }, | 1583 | }, |
1397 | { | 1584 | { |
1398 | "defaultMessage": "!!!Logout", | 1585 | "defaultMessage": "!!!Logout", |
1399 | "end": { | 1586 | "end": { |
1400 | "column": 3, | 1587 | "column": 3, |
1401 | "line": 44 | 1588 | "line": 45 |
1402 | }, | 1589 | }, |
1403 | "file": "src/components/settings/navigation/SettingsNavigation.js", | 1590 | "file": "src/components/settings/navigation/SettingsNavigation.js", |
1404 | "id": "settings.navigation.logout", | 1591 | "id": "settings.navigation.logout", |
1405 | "start": { | 1592 | "start": { |
1406 | "column": 10, | 1593 | "column": 10, |
1407 | "line": 41 | 1594 | "line": 42 |
1408 | } | 1595 | } |
1409 | } | 1596 | } |
1410 | ], | 1597 | ], |
@@ -1416,104 +1603,182 @@ | |||
1416 | "defaultMessage": "!!!Available Services", | 1603 | "defaultMessage": "!!!Available Services", |
1417 | "end": { | 1604 | "end": { |
1418 | "column": 3, | 1605 | "column": 3, |
1419 | "line": 18 | 1606 | "line": 23 |
1420 | }, | 1607 | }, |
1421 | "file": "src/components/settings/recipes/RecipesDashboard.js", | 1608 | "file": "src/components/settings/recipes/RecipesDashboard.js", |
1422 | "id": "settings.recipes.headline", | 1609 | "id": "settings.recipes.headline", |
1423 | "start": { | 1610 | "start": { |
1424 | "column": 12, | 1611 | "column": 12, |
1425 | "line": 15 | 1612 | "line": 20 |
1426 | } | 1613 | } |
1427 | }, | 1614 | }, |
1428 | { | 1615 | { |
1429 | "defaultMessage": "!!!Search service", | 1616 | "defaultMessage": "!!!Search service", |
1430 | "end": { | 1617 | "end": { |
1431 | "column": 3, | 1618 | "column": 3, |
1432 | "line": 22 | 1619 | "line": 27 |
1433 | }, | 1620 | }, |
1434 | "file": "src/components/settings/recipes/RecipesDashboard.js", | 1621 | "file": "src/components/settings/recipes/RecipesDashboard.js", |
1435 | "id": "settings.searchService", | 1622 | "id": "settings.searchService", |
1436 | "start": { | 1623 | "start": { |
1437 | "column": 17, | 1624 | "column": 17, |
1438 | "line": 19 | 1625 | "line": 24 |
1439 | } | 1626 | } |
1440 | }, | 1627 | }, |
1441 | { | 1628 | { |
1442 | "defaultMessage": "!!!Most popular", | 1629 | "defaultMessage": "!!!Most popular", |
1443 | "end": { | 1630 | "end": { |
1444 | "column": 3, | 1631 | "column": 3, |
1445 | "line": 26 | 1632 | "line": 31 |
1446 | }, | 1633 | }, |
1447 | "file": "src/components/settings/recipes/RecipesDashboard.js", | 1634 | "file": "src/components/settings/recipes/RecipesDashboard.js", |
1448 | "id": "settings.recipes.mostPopular", | 1635 | "id": "settings.recipes.mostPopular", |
1449 | "start": { | 1636 | "start": { |
1450 | "column": 22, | 1637 | "column": 22, |
1451 | "line": 23 | 1638 | "line": 28 |
1452 | } | 1639 | } |
1453 | }, | 1640 | }, |
1454 | { | 1641 | { |
1455 | "defaultMessage": "!!!All services", | 1642 | "defaultMessage": "!!!All services", |
1456 | "end": { | 1643 | "end": { |
1457 | "column": 3, | 1644 | "column": 3, |
1458 | "line": 30 | 1645 | "line": 35 |
1459 | }, | 1646 | }, |
1460 | "file": "src/components/settings/recipes/RecipesDashboard.js", | 1647 | "file": "src/components/settings/recipes/RecipesDashboard.js", |
1461 | "id": "settings.recipes.all", | 1648 | "id": "settings.recipes.all", |
1462 | "start": { | 1649 | "start": { |
1463 | "column": 14, | 1650 | "column": 14, |
1464 | "line": 27 | 1651 | "line": 32 |
1465 | } | 1652 | } |
1466 | }, | 1653 | }, |
1467 | { | 1654 | { |
1468 | "defaultMessage": "!!!Development", | 1655 | "defaultMessage": "!!!Custom Services", |
1469 | "end": { | 1656 | "end": { |
1470 | "column": 3, | 1657 | "column": 3, |
1471 | "line": 34 | 1658 | "line": 39 |
1472 | }, | 1659 | }, |
1473 | "file": "src/components/settings/recipes/RecipesDashboard.js", | 1660 | "file": "src/components/settings/recipes/RecipesDashboard.js", |
1474 | "id": "settings.recipes.dev", | 1661 | "id": "settings.recipes.custom", |
1475 | "start": { | 1662 | "start": { |
1476 | "column": 14, | 1663 | "column": 17, |
1477 | "line": 31 | 1664 | "line": 36 |
1478 | } | 1665 | } |
1479 | }, | 1666 | }, |
1480 | { | 1667 | { |
1481 | "defaultMessage": "!!!Sorry, but no service matched your search term.", | 1668 | "defaultMessage": "!!!Sorry, but no service matched your search term.", |
1482 | "end": { | 1669 | "end": { |
1483 | "column": 3, | 1670 | "column": 3, |
1484 | "line": 38 | 1671 | "line": 43 |
1485 | }, | 1672 | }, |
1486 | "file": "src/components/settings/recipes/RecipesDashboard.js", | 1673 | "file": "src/components/settings/recipes/RecipesDashboard.js", |
1487 | "id": "settings.recipes.nothingFound", | 1674 | "id": "settings.recipes.nothingFound", |
1488 | "start": { | 1675 | "start": { |
1489 | "column": 16, | 1676 | "column": 16, |
1490 | "line": 35 | 1677 | "line": 40 |
1491 | } | 1678 | } |
1492 | }, | 1679 | }, |
1493 | { | 1680 | { |
1494 | "defaultMessage": "!!!Service successfully added", | 1681 | "defaultMessage": "!!!Service successfully added", |
1495 | "end": { | 1682 | "end": { |
1496 | "column": 3, | 1683 | "column": 3, |
1497 | "line": 42 | 1684 | "line": 47 |
1498 | }, | 1685 | }, |
1499 | "file": "src/components/settings/recipes/RecipesDashboard.js", | 1686 | "file": "src/components/settings/recipes/RecipesDashboard.js", |
1500 | "id": "settings.recipes.servicesSuccessfulAddedInfo", | 1687 | "id": "settings.recipes.servicesSuccessfulAddedInfo", |
1501 | "start": { | 1688 | "start": { |
1502 | "column": 31, | 1689 | "column": 31, |
1503 | "line": 39 | 1690 | "line": 44 |
1504 | } | 1691 | } |
1505 | }, | 1692 | }, |
1506 | { | 1693 | { |
1507 | "defaultMessage": "!!!Missing a service?", | 1694 | "defaultMessage": "!!!Missing a service?", |
1508 | "end": { | 1695 | "end": { |
1509 | "column": 3, | 1696 | "column": 3, |
1510 | "line": 46 | 1697 | "line": 51 |
1511 | }, | 1698 | }, |
1512 | "file": "src/components/settings/recipes/RecipesDashboard.js", | 1699 | "file": "src/components/settings/recipes/RecipesDashboard.js", |
1513 | "id": "settings.recipes.missingService", | 1700 | "id": "settings.recipes.missingService", |
1514 | "start": { | 1701 | "start": { |
1515 | "column": 18, | 1702 | "column": 18, |
1516 | "line": 43 | 1703 | "line": 48 |
1704 | } | ||
1705 | }, | ||
1706 | { | ||
1707 | "defaultMessage": "!!!To add a custom service, copy the recipe folder into:", | ||
1708 | "end": { | ||
1709 | "column": 3, | ||
1710 | "line": 55 | ||
1711 | }, | ||
1712 | "file": "src/components/settings/recipes/RecipesDashboard.js", | ||
1713 | "id": "settings.recipes.customService.intro", | ||
1714 | "start": { | ||
1715 | "column": 21, | ||
1716 | "line": 52 | ||
1717 | } | ||
1718 | }, | ||
1719 | { | ||
1720 | "defaultMessage": "!!!Open directory", | ||
1721 | "end": { | ||
1722 | "column": 3, | ||
1723 | "line": 59 | ||
1724 | }, | ||
1725 | "file": "src/components/settings/recipes/RecipesDashboard.js", | ||
1726 | "id": "settings.recipes.customService.openFolder", | ||
1727 | "start": { | ||
1728 | "column": 14, | ||
1729 | "line": 56 | ||
1730 | } | ||
1731 | }, | ||
1732 | { | ||
1733 | "defaultMessage": "!!!Developer Documentation", | ||
1734 | "end": { | ||
1735 | "column": 3, | ||
1736 | "line": 63 | ||
1737 | }, | ||
1738 | "file": "src/components/settings/recipes/RecipesDashboard.js", | ||
1739 | "id": "settings.recipes.customService.openDevDocs", | ||
1740 | "start": { | ||
1741 | "column": 15, | ||
1742 | "line": 60 | ||
1743 | } | ||
1744 | }, | ||
1745 | { | ||
1746 | "defaultMessage": "!!!Custom Service Recipes", | ||
1747 | "end": { | ||
1748 | "column": 3, | ||
1749 | "line": 67 | ||
1750 | }, | ||
1751 | "file": "src/components/settings/recipes/RecipesDashboard.js", | ||
1752 | "id": "settings.recipes.customService.headline.customRecipes", | ||
1753 | "start": { | ||
1754 | "column": 25, | ||
1755 | "line": 64 | ||
1756 | } | ||
1757 | }, | ||
1758 | { | ||
1759 | "defaultMessage": "!!!Community Services", | ||
1760 | "end": { | ||
1761 | "column": 3, | ||
1762 | "line": 71 | ||
1763 | }, | ||
1764 | "file": "src/components/settings/recipes/RecipesDashboard.js", | ||
1765 | "id": "settings.recipes.customService.headline.communityRecipes", | ||
1766 | "start": { | ||
1767 | "column": 28, | ||
1768 | "line": 68 | ||
1769 | } | ||
1770 | }, | ||
1771 | { | ||
1772 | "defaultMessage": "!!!Your Development Service Recipes", | ||
1773 | "end": { | ||
1774 | "column": 3, | ||
1775 | "line": 75 | ||
1776 | }, | ||
1777 | "file": "src/components/settings/recipes/RecipesDashboard.js", | ||
1778 | "id": "settings.recipes.customService.headline.devRecipes", | ||
1779 | "start": { | ||
1780 | "column": 22, | ||
1781 | "line": 72 | ||
1517 | } | 1782 | } |
1518 | } | 1783 | } |
1519 | ], | 1784 | ], |
@@ -1525,286 +1790,286 @@ | |||
1525 | "defaultMessage": "!!!Save service", | 1790 | "defaultMessage": "!!!Save service", |
1526 | "end": { | 1791 | "end": { |
1527 | "column": 3, | 1792 | "column": 3, |
1528 | "line": 25 | 1793 | "line": 27 |
1529 | }, | 1794 | }, |
1530 | "file": "src/components/settings/services/EditServiceForm.js", | 1795 | "file": "src/components/settings/services/EditServiceForm.js", |
1531 | "id": "settings.service.form.saveButton", | 1796 | "id": "settings.service.form.saveButton", |
1532 | "start": { | 1797 | "start": { |
1533 | "column": 15, | 1798 | "column": 15, |
1534 | "line": 22 | 1799 | "line": 24 |
1535 | } | 1800 | } |
1536 | }, | 1801 | }, |
1537 | { | 1802 | { |
1538 | "defaultMessage": "!!!Delete Service", | 1803 | "defaultMessage": "!!!Delete Service", |
1539 | "end": { | 1804 | "end": { |
1540 | "column": 3, | 1805 | "column": 3, |
1541 | "line": 29 | 1806 | "line": 31 |
1542 | }, | 1807 | }, |
1543 | "file": "src/components/settings/services/EditServiceForm.js", | 1808 | "file": "src/components/settings/services/EditServiceForm.js", |
1544 | "id": "settings.service.form.deleteButton", | 1809 | "id": "settings.service.form.deleteButton", |
1545 | "start": { | 1810 | "start": { |
1546 | "column": 17, | 1811 | "column": 17, |
1547 | "line": 26 | 1812 | "line": 28 |
1548 | } | 1813 | } |
1549 | }, | 1814 | }, |
1550 | { | 1815 | { |
1551 | "defaultMessage": "!!!Available services", | 1816 | "defaultMessage": "!!!Available services", |
1552 | "end": { | 1817 | "end": { |
1553 | "column": 3, | 1818 | "column": 3, |
1554 | "line": 33 | 1819 | "line": 35 |
1555 | }, | 1820 | }, |
1556 | "file": "src/components/settings/services/EditServiceForm.js", | 1821 | "file": "src/components/settings/services/EditServiceForm.js", |
1557 | "id": "settings.service.form.availableServices", | 1822 | "id": "settings.service.form.availableServices", |
1558 | "start": { | 1823 | "start": { |
1559 | "column": 21, | 1824 | "column": 21, |
1560 | "line": 30 | 1825 | "line": 32 |
1561 | } | 1826 | } |
1562 | }, | 1827 | }, |
1563 | { | 1828 | { |
1564 | "defaultMessage": "!!!Your services", | 1829 | "defaultMessage": "!!!Your services", |
1565 | "end": { | 1830 | "end": { |
1566 | "column": 3, | 1831 | "column": 3, |
1567 | "line": 37 | 1832 | "line": 39 |
1568 | }, | 1833 | }, |
1569 | "file": "src/components/settings/services/EditServiceForm.js", | 1834 | "file": "src/components/settings/services/EditServiceForm.js", |
1570 | "id": "settings.service.form.yourServices", | 1835 | "id": "settings.service.form.yourServices", |
1571 | "start": { | 1836 | "start": { |
1572 | "column": 16, | 1837 | "column": 16, |
1573 | "line": 34 | 1838 | "line": 36 |
1574 | } | 1839 | } |
1575 | }, | 1840 | }, |
1576 | { | 1841 | { |
1577 | "defaultMessage": "!!!Add {name}", | 1842 | "defaultMessage": "!!!Add {name}", |
1578 | "end": { | 1843 | "end": { |
1579 | "column": 3, | 1844 | "column": 3, |
1580 | "line": 41 | 1845 | "line": 43 |
1581 | }, | 1846 | }, |
1582 | "file": "src/components/settings/services/EditServiceForm.js", | 1847 | "file": "src/components/settings/services/EditServiceForm.js", |
1583 | "id": "settings.service.form.addServiceHeadline", | 1848 | "id": "settings.service.form.addServiceHeadline", |
1584 | "start": { | 1849 | "start": { |
1585 | "column": 22, | 1850 | "column": 22, |
1586 | "line": 38 | 1851 | "line": 40 |
1587 | } | 1852 | } |
1588 | }, | 1853 | }, |
1589 | { | 1854 | { |
1590 | "defaultMessage": "!!!Edit {name}", | 1855 | "defaultMessage": "!!!Edit {name}", |
1591 | "end": { | 1856 | "end": { |
1592 | "column": 3, | 1857 | "column": 3, |
1593 | "line": 45 | 1858 | "line": 47 |
1594 | }, | 1859 | }, |
1595 | "file": "src/components/settings/services/EditServiceForm.js", | 1860 | "file": "src/components/settings/services/EditServiceForm.js", |
1596 | "id": "settings.service.form.editServiceHeadline", | 1861 | "id": "settings.service.form.editServiceHeadline", |
1597 | "start": { | 1862 | "start": { |
1598 | "column": 23, | 1863 | "column": 23, |
1599 | "line": 42 | 1864 | "line": 44 |
1600 | } | 1865 | } |
1601 | }, | 1866 | }, |
1602 | { | 1867 | { |
1603 | "defaultMessage": "!!!Hosted", | 1868 | "defaultMessage": "!!!Hosted", |
1604 | "end": { | 1869 | "end": { |
1605 | "column": 3, | 1870 | "column": 3, |
1606 | "line": 49 | 1871 | "line": 51 |
1607 | }, | 1872 | }, |
1608 | "file": "src/components/settings/services/EditServiceForm.js", | 1873 | "file": "src/components/settings/services/EditServiceForm.js", |
1609 | "id": "settings.service.form.tabHosted", | 1874 | "id": "settings.service.form.tabHosted", |
1610 | "start": { | 1875 | "start": { |
1611 | "column": 13, | 1876 | "column": 13, |
1612 | "line": 46 | 1877 | "line": 48 |
1613 | } | 1878 | } |
1614 | }, | 1879 | }, |
1615 | { | 1880 | { |
1616 | "defaultMessage": "!!!Self hosted ⭐️", | 1881 | "defaultMessage": "!!!Self hosted ⭐️", |
1617 | "end": { | 1882 | "end": { |
1618 | "column": 3, | 1883 | "column": 3, |
1619 | "line": 53 | 1884 | "line": 55 |
1620 | }, | 1885 | }, |
1621 | "file": "src/components/settings/services/EditServiceForm.js", | 1886 | "file": "src/components/settings/services/EditServiceForm.js", |
1622 | "id": "settings.service.form.tabOnPremise", | 1887 | "id": "settings.service.form.tabOnPremise", |
1623 | "start": { | 1888 | "start": { |
1624 | "column": 16, | 1889 | "column": 16, |
1625 | "line": 50 | 1890 | "line": 52 |
1626 | } | 1891 | } |
1627 | }, | 1892 | }, |
1628 | { | 1893 | { |
1629 | "defaultMessage": "!!!Use the hosted {name} service.", | 1894 | "defaultMessage": "!!!Use the hosted {name} service.", |
1630 | "end": { | 1895 | "end": { |
1631 | "column": 3, | 1896 | "column": 3, |
1632 | "line": 57 | 1897 | "line": 59 |
1633 | }, | 1898 | }, |
1634 | "file": "src/components/settings/services/EditServiceForm.js", | 1899 | "file": "src/components/settings/services/EditServiceForm.js", |
1635 | "id": "settings.service.form.useHostedService", | 1900 | "id": "settings.service.form.useHostedService", |
1636 | "start": { | 1901 | "start": { |
1637 | "column": 20, | 1902 | "column": 20, |
1638 | "line": 54 | 1903 | "line": 56 |
1639 | } | 1904 | } |
1640 | }, | 1905 | }, |
1641 | { | 1906 | { |
1642 | "defaultMessage": "!!!Could not validate custom {name} server.", | 1907 | "defaultMessage": "!!!Could not validate custom {name} server.", |
1643 | "end": { | 1908 | "end": { |
1644 | "column": 3, | 1909 | "column": 3, |
1645 | "line": 61 | 1910 | "line": 63 |
1646 | }, | 1911 | }, |
1647 | "file": "src/components/settings/services/EditServiceForm.js", | 1912 | "file": "src/components/settings/services/EditServiceForm.js", |
1648 | "id": "settings.service.form.customUrlValidationError", | 1913 | "id": "settings.service.form.customUrlValidationError", |
1649 | "start": { | 1914 | "start": { |
1650 | "column": 28, | 1915 | "column": 28, |
1651 | "line": 58 | 1916 | "line": 60 |
1652 | } | 1917 | } |
1653 | }, | 1918 | }, |
1654 | { | 1919 | { |
1655 | "defaultMessage": "!!!To add self hosted services, you need a Franz Premium Supporter Account.", | 1920 | "defaultMessage": "!!!To add self hosted services, you need a Franz Premium Supporter Account.", |
1656 | "end": { | 1921 | "end": { |
1657 | "column": 3, | 1922 | "column": 3, |
1658 | "line": 65 | 1923 | "line": 67 |
1659 | }, | 1924 | }, |
1660 | "file": "src/components/settings/services/EditServiceForm.js", | 1925 | "file": "src/components/settings/services/EditServiceForm.js", |
1661 | "id": "settings.service.form.customUrlPremiumInfo", | 1926 | "id": "settings.service.form.customUrlPremiumInfo", |
1662 | "start": { | 1927 | "start": { |
1663 | "column": 24, | 1928 | "column": 24, |
1664 | "line": 62 | 1929 | "line": 64 |
1665 | } | 1930 | } |
1666 | }, | 1931 | }, |
1667 | { | 1932 | { |
1668 | "defaultMessage": "!!!Upgrade your account", | 1933 | "defaultMessage": "!!!Upgrade your account", |
1669 | "end": { | 1934 | "end": { |
1670 | "column": 3, | 1935 | "column": 3, |
1671 | "line": 69 | 1936 | "line": 71 |
1672 | }, | 1937 | }, |
1673 | "file": "src/components/settings/services/EditServiceForm.js", | 1938 | "file": "src/components/settings/services/EditServiceForm.js", |
1674 | "id": "settings.service.form.customUrlUpgradeAccount", | 1939 | "id": "settings.service.form.customUrlUpgradeAccount", |
1675 | "start": { | 1940 | "start": { |
1676 | "column": 27, | 1941 | "column": 27, |
1677 | "line": 66 | 1942 | "line": 68 |
1678 | } | 1943 | } |
1679 | }, | 1944 | }, |
1680 | { | 1945 | { |
1681 | "defaultMessage": "!!!You will be notified about all new messages in a channel, not just @username, @channel, @here, ...", | 1946 | "defaultMessage": "!!!You will be notified about all new messages in a channel, not just @username, @channel, @here, ...", |
1682 | "end": { | 1947 | "end": { |
1683 | "column": 3, | 1948 | "column": 3, |
1684 | "line": 73 | 1949 | "line": 75 |
1685 | }, | 1950 | }, |
1686 | "file": "src/components/settings/services/EditServiceForm.js", | 1951 | "file": "src/components/settings/services/EditServiceForm.js", |
1687 | "id": "settings.service.form.indirectMessageInfo", | 1952 | "id": "settings.service.form.indirectMessageInfo", |
1688 | "start": { | 1953 | "start": { |
1689 | "column": 23, | 1954 | "column": 23, |
1690 | "line": 70 | 1955 | "line": 72 |
1691 | } | 1956 | } |
1692 | }, | 1957 | }, |
1693 | { | 1958 | { |
1694 | "defaultMessage": "!!!When disabled, all notification sounds and audio playback are muted", | 1959 | "defaultMessage": "!!!When disabled, all notification sounds and audio playback are muted", |
1695 | "end": { | 1960 | "end": { |
1696 | "column": 3, | 1961 | "column": 3, |
1697 | "line": 77 | 1962 | "line": 79 |
1698 | }, | 1963 | }, |
1699 | "file": "src/components/settings/services/EditServiceForm.js", | 1964 | "file": "src/components/settings/services/EditServiceForm.js", |
1700 | "id": "settings.service.form.isMutedInfo", | 1965 | "id": "settings.service.form.isMutedInfo", |
1701 | "start": { | 1966 | "start": { |
1702 | "column": 15, | 1967 | "column": 15, |
1703 | "line": 74 | 1968 | "line": 76 |
1704 | } | 1969 | } |
1705 | }, | 1970 | }, |
1706 | { | 1971 | { |
1707 | "defaultMessage": "!!!Notifications", | 1972 | "defaultMessage": "!!!Notifications", |
1708 | "end": { | 1973 | "end": { |
1709 | "column": 3, | 1974 | "column": 3, |
1710 | "line": 81 | 1975 | "line": 83 |
1711 | }, | 1976 | }, |
1712 | "file": "src/components/settings/services/EditServiceForm.js", | 1977 | "file": "src/components/settings/services/EditServiceForm.js", |
1713 | "id": "settings.service.form.headlineNotifications", | 1978 | "id": "settings.service.form.headlineNotifications", |
1714 | "start": { | 1979 | "start": { |
1715 | "column": 25, | 1980 | "column": 25, |
1716 | "line": 78 | 1981 | "line": 80 |
1717 | } | 1982 | } |
1718 | }, | 1983 | }, |
1719 | { | 1984 | { |
1720 | "defaultMessage": "!!!Unread message badges", | 1985 | "defaultMessage": "!!!Unread message badges", |
1721 | "end": { | 1986 | "end": { |
1722 | "column": 3, | 1987 | "column": 3, |
1723 | "line": 85 | 1988 | "line": 87 |
1724 | }, | 1989 | }, |
1725 | "file": "src/components/settings/services/EditServiceForm.js", | 1990 | "file": "src/components/settings/services/EditServiceForm.js", |
1726 | "id": "settings.service.form.headlineBadges", | 1991 | "id": "settings.service.form.headlineBadges", |
1727 | "start": { | 1992 | "start": { |
1728 | "column": 18, | 1993 | "column": 18, |
1729 | "line": 82 | 1994 | "line": 84 |
1730 | } | 1995 | } |
1731 | }, | 1996 | }, |
1732 | { | 1997 | { |
1733 | "defaultMessage": "!!!General", | 1998 | "defaultMessage": "!!!General", |
1734 | "end": { | 1999 | "end": { |
1735 | "column": 3, | 2000 | "column": 3, |
1736 | "line": 89 | 2001 | "line": 91 |
1737 | }, | 2002 | }, |
1738 | "file": "src/components/settings/services/EditServiceForm.js", | 2003 | "file": "src/components/settings/services/EditServiceForm.js", |
1739 | "id": "settings.service.form.headlineGeneral", | 2004 | "id": "settings.service.form.headlineGeneral", |
1740 | "start": { | 2005 | "start": { |
1741 | "column": 19, | 2006 | "column": 19, |
1742 | "line": 86 | 2007 | "line": 88 |
1743 | } | 2008 | } |
1744 | }, | 2009 | }, |
1745 | { | 2010 | { |
1746 | "defaultMessage": "!!!Delete", | 2011 | "defaultMessage": "!!!Delete", |
1747 | "end": { | 2012 | "end": { |
1748 | "column": 3, | 2013 | "column": 3, |
1749 | "line": 93 | 2014 | "line": 95 |
1750 | }, | 2015 | }, |
1751 | "file": "src/components/settings/services/EditServiceForm.js", | 2016 | "file": "src/components/settings/services/EditServiceForm.js", |
1752 | "id": "settings.service.form.iconDelete", | 2017 | "id": "settings.service.form.iconDelete", |
1753 | "start": { | 2018 | "start": { |
1754 | "column": 14, | 2019 | "column": 14, |
1755 | "line": 90 | 2020 | "line": 92 |
1756 | } | 2021 | } |
1757 | }, | 2022 | }, |
1758 | { | 2023 | { |
1759 | "defaultMessage": "!!!Drop your image, or click here", | 2024 | "defaultMessage": "!!!Drop your image, or click here", |
1760 | "end": { | 2025 | "end": { |
1761 | "column": 3, | 2026 | "column": 3, |
1762 | "line": 97 | 2027 | "line": 99 |
1763 | }, | 2028 | }, |
1764 | "file": "src/components/settings/services/EditServiceForm.js", | 2029 | "file": "src/components/settings/services/EditServiceForm.js", |
1765 | "id": "settings.service.form.iconUpload", | 2030 | "id": "settings.service.form.iconUpload", |
1766 | "start": { | 2031 | "start": { |
1767 | "column": 14, | 2032 | "column": 14, |
1768 | "line": 94 | 2033 | "line": 96 |
1769 | } | 2034 | } |
1770 | }, | 2035 | }, |
1771 | { | 2036 | { |
1772 | "defaultMessage": "!!!HTTP/HTTPS Proxy Settings", | 2037 | "defaultMessage": "!!!HTTP/HTTPS Proxy Settings", |
1773 | "end": { | 2038 | "end": { |
1774 | "column": 3, | 2039 | "column": 3, |
1775 | "line": 101 | 2040 | "line": 103 |
1776 | }, | 2041 | }, |
1777 | "file": "src/components/settings/services/EditServiceForm.js", | 2042 | "file": "src/components/settings/services/EditServiceForm.js", |
1778 | "id": "settings.service.form.proxy.headline", | 2043 | "id": "settings.service.form.proxy.headline", |
1779 | "start": { | 2044 | "start": { |
1780 | "column": 17, | 2045 | "column": 17, |
1781 | "line": 98 | 2046 | "line": 100 |
1782 | } | 2047 | } |
1783 | }, | 2048 | }, |
1784 | { | 2049 | { |
1785 | "defaultMessage": "!!!Please restart Franz after changing proxy Settings.", | 2050 | "defaultMessage": "!!!Please restart Franz after changing proxy Settings.", |
1786 | "end": { | 2051 | "end": { |
1787 | "column": 3, | 2052 | "column": 3, |
1788 | "line": 105 | 2053 | "line": 107 |
1789 | }, | 2054 | }, |
1790 | "file": "src/components/settings/services/EditServiceForm.js", | 2055 | "file": "src/components/settings/services/EditServiceForm.js", |
1791 | "id": "settings.service.form.proxy.restartInfo", | 2056 | "id": "settings.service.form.proxy.restartInfo", |
1792 | "start": { | 2057 | "start": { |
1793 | "column": 20, | 2058 | "column": 20, |
1794 | "line": 102 | 2059 | "line": 104 |
1795 | } | 2060 | } |
1796 | }, | 2061 | }, |
1797 | { | 2062 | { |
1798 | "defaultMessage": "!!!Proxy settings will not be synchronized with the Franz servers.", | 2063 | "defaultMessage": "!!!Proxy settings will not be synchronized with the Franz servers.", |
1799 | "end": { | 2064 | "end": { |
1800 | "column": 3, | 2065 | "column": 3, |
1801 | "line": 109 | 2066 | "line": 111 |
1802 | }, | 2067 | }, |
1803 | "file": "src/components/settings/services/EditServiceForm.js", | 2068 | "file": "src/components/settings/services/EditServiceForm.js", |
1804 | "id": "settings.service.form.proxy.info", | 2069 | "id": "settings.service.form.proxy.info", |
1805 | "start": { | 2070 | "start": { |
1806 | "column": 13, | 2071 | "column": 13, |
1807 | "line": 106 | 2072 | "line": 108 |
1808 | } | 2073 | } |
1809 | } | 2074 | } |
1810 | ], | 2075 | ], |
@@ -1917,117 +2182,117 @@ | |||
1917 | "defaultMessage": "!!!Your services", | 2182 | "defaultMessage": "!!!Your services", |
1918 | "end": { | 2183 | "end": { |
1919 | "column": 3, | 2184 | "column": 3, |
1920 | "line": 17 | 2185 | "line": 18 |
1921 | }, | 2186 | }, |
1922 | "file": "src/components/settings/services/ServicesDashboard.js", | 2187 | "file": "src/components/settings/services/ServicesDashboard.js", |
1923 | "id": "settings.services.headline", | 2188 | "id": "settings.services.headline", |
1924 | "start": { | 2189 | "start": { |
1925 | "column": 12, | 2190 | "column": 12, |
1926 | "line": 14 | 2191 | "line": 15 |
1927 | } | 2192 | } |
1928 | }, | 2193 | }, |
1929 | { | 2194 | { |
1930 | "defaultMessage": "!!!Search service", | 2195 | "defaultMessage": "!!!Search service", |
1931 | "end": { | 2196 | "end": { |
1932 | "column": 3, | 2197 | "column": 3, |
1933 | "line": 21 | 2198 | "line": 22 |
1934 | }, | 2199 | }, |
1935 | "file": "src/components/settings/services/ServicesDashboard.js", | 2200 | "file": "src/components/settings/services/ServicesDashboard.js", |
1936 | "id": "settings.searchService", | 2201 | "id": "settings.searchService", |
1937 | "start": { | 2202 | "start": { |
1938 | "column": 17, | 2203 | "column": 17, |
1939 | "line": 18 | 2204 | "line": 19 |
1940 | } | 2205 | } |
1941 | }, | 2206 | }, |
1942 | { | 2207 | { |
1943 | "defaultMessage": "!!!You haven't added any services yet.", | 2208 | "defaultMessage": "!!!You haven't added any services yet.", |
1944 | "end": { | 2209 | "end": { |
1945 | "column": 3, | 2210 | "column": 3, |
1946 | "line": 25 | 2211 | "line": 26 |
1947 | }, | 2212 | }, |
1948 | "file": "src/components/settings/services/ServicesDashboard.js", | 2213 | "file": "src/components/settings/services/ServicesDashboard.js", |
1949 | "id": "settings.services.noServicesAdded", | 2214 | "id": "settings.services.noServicesAdded", |
1950 | "start": { | 2215 | "start": { |
1951 | "column": 19, | 2216 | "column": 19, |
1952 | "line": 22 | 2217 | "line": 23 |
1953 | } | 2218 | } |
1954 | }, | 2219 | }, |
1955 | { | 2220 | { |
1956 | "defaultMessage": "!!!Sorry, but no service matched your search term.", | 2221 | "defaultMessage": "!!!Sorry, but no service matched your search term.", |
1957 | "end": { | 2222 | "end": { |
1958 | "column": 3, | 2223 | "column": 3, |
1959 | "line": 29 | 2224 | "line": 30 |
1960 | }, | 2225 | }, |
1961 | "file": "src/components/settings/services/ServicesDashboard.js", | 2226 | "file": "src/components/settings/services/ServicesDashboard.js", |
1962 | "id": "settings.recipes.nothingFound", | 2227 | "id": "settings.recipes.nothingFound", |
1963 | "start": { | 2228 | "start": { |
1964 | "column": 18, | 2229 | "column": 18, |
1965 | "line": 26 | 2230 | "line": 27 |
1966 | } | 2231 | } |
1967 | }, | 2232 | }, |
1968 | { | 2233 | { |
1969 | "defaultMessage": "!!!Discover services", | 2234 | "defaultMessage": "!!!Discover services", |
1970 | "end": { | 2235 | "end": { |
1971 | "column": 3, | 2236 | "column": 3, |
1972 | "line": 33 | 2237 | "line": 34 |
1973 | }, | 2238 | }, |
1974 | "file": "src/components/settings/services/ServicesDashboard.js", | 2239 | "file": "src/components/settings/services/ServicesDashboard.js", |
1975 | "id": "settings.services.discoverServices", | 2240 | "id": "settings.services.discoverServices", |
1976 | "start": { | 2241 | "start": { |
1977 | "column": 20, | 2242 | "column": 20, |
1978 | "line": 30 | 2243 | "line": 31 |
1979 | } | 2244 | } |
1980 | }, | 2245 | }, |
1981 | { | 2246 | { |
1982 | "defaultMessage": "!!!Could not load your services", | 2247 | "defaultMessage": "!!!Could not load your services", |
1983 | "end": { | 2248 | "end": { |
1984 | "column": 3, | 2249 | "column": 3, |
1985 | "line": 37 | 2250 | "line": 38 |
1986 | }, | 2251 | }, |
1987 | "file": "src/components/settings/services/ServicesDashboard.js", | 2252 | "file": "src/components/settings/services/ServicesDashboard.js", |
1988 | "id": "settings.services.servicesRequestFailed", | 2253 | "id": "settings.services.servicesRequestFailed", |
1989 | "start": { | 2254 | "start": { |
1990 | "column": 25, | 2255 | "column": 25, |
1991 | "line": 34 | 2256 | "line": 35 |
1992 | } | 2257 | } |
1993 | }, | 2258 | }, |
1994 | { | 2259 | { |
1995 | "defaultMessage": "!!!Try again", | 2260 | "defaultMessage": "!!!Try again", |
1996 | "end": { | 2261 | "end": { |
1997 | "column": 3, | 2262 | "column": 3, |
1998 | "line": 41 | 2263 | "line": 42 |
1999 | }, | 2264 | }, |
2000 | "file": "src/components/settings/services/ServicesDashboard.js", | 2265 | "file": "src/components/settings/services/ServicesDashboard.js", |
2001 | "id": "settings.account.tryReloadServices", | 2266 | "id": "settings.account.tryReloadServices", |
2002 | "start": { | 2267 | "start": { |
2003 | "column": 21, | 2268 | "column": 21, |
2004 | "line": 38 | 2269 | "line": 39 |
2005 | } | 2270 | } |
2006 | }, | 2271 | }, |
2007 | { | 2272 | { |
2008 | "defaultMessage": "!!!Your changes have been saved", | 2273 | "defaultMessage": "!!!Your changes have been saved", |
2009 | "end": { | 2274 | "end": { |
2010 | "column": 3, | 2275 | "column": 3, |
2011 | "line": 45 | 2276 | "line": 46 |
2012 | }, | 2277 | }, |
2013 | "file": "src/components/settings/services/ServicesDashboard.js", | 2278 | "file": "src/components/settings/services/ServicesDashboard.js", |
2014 | "id": "settings.services.updatedInfo", | 2279 | "id": "settings.services.updatedInfo", |
2015 | "start": { | 2280 | "start": { |
2016 | "column": 15, | 2281 | "column": 15, |
2017 | "line": 42 | 2282 | "line": 43 |
2018 | } | 2283 | } |
2019 | }, | 2284 | }, |
2020 | { | 2285 | { |
2021 | "defaultMessage": "!!!Service has been deleted", | 2286 | "defaultMessage": "!!!Service has been deleted", |
2022 | "end": { | 2287 | "end": { |
2023 | "column": 3, | 2288 | "column": 3, |
2024 | "line": 49 | 2289 | "line": 50 |
2025 | }, | 2290 | }, |
2026 | "file": "src/components/settings/services/ServicesDashboard.js", | 2291 | "file": "src/components/settings/services/ServicesDashboard.js", |
2027 | "id": "settings.services.deletedInfo", | 2292 | "id": "settings.services.deletedInfo", |
2028 | "start": { | 2293 | "start": { |
2029 | "column": 15, | 2294 | "column": 15, |
2030 | "line": 46 | 2295 | "line": 47 |
2031 | } | 2296 | } |
2032 | } | 2297 | } |
2033 | ], | 2298 | ], |
@@ -2659,6 +2924,159 @@ | |||
2659 | { | 2924 | { |
2660 | "descriptors": [ | 2925 | "descriptors": [ |
2661 | { | 2926 | { |
2927 | "defaultMessage": "!!!Your trial was successfully activated. Happy messaging!", | ||
2928 | "end": { | ||
2929 | "column": 3, | ||
2930 | "line": 14 | ||
2931 | }, | ||
2932 | "file": "src/components/TrialActivationInfoBar.js", | ||
2933 | "id": "infobar.trialActivated", | ||
2934 | "start": { | ||
2935 | "column": 11, | ||
2936 | "line": 11 | ||
2937 | } | ||
2938 | } | ||
2939 | ], | ||
2940 | "path": "src/components/TrialActivationInfoBar.json" | ||
2941 | }, | ||
2942 | { | ||
2943 | "descriptors": [ | ||
2944 | { | ||
2945 | "defaultMessage": "!!!Add unlimited services", | ||
2946 | "end": { | ||
2947 | "column": 3, | ||
2948 | "line": 11 | ||
2949 | }, | ||
2950 | "file": "src/components/ui/FeatureList.js", | ||
2951 | "id": "pricing.features.unlimitedServices", | ||
2952 | "start": { | ||
2953 | "column": 21, | ||
2954 | "line": 8 | ||
2955 | } | ||
2956 | }, | ||
2957 | { | ||
2958 | "defaultMessage": "!!!Spellchecker support", | ||
2959 | "end": { | ||
2960 | "column": 3, | ||
2961 | "line": 15 | ||
2962 | }, | ||
2963 | "file": "src/components/ui/FeatureList.js", | ||
2964 | "id": "pricing.features.spellchecker", | ||
2965 | "start": { | ||
2966 | "column": 16, | ||
2967 | "line": 12 | ||
2968 | } | ||
2969 | }, | ||
2970 | { | ||
2971 | "defaultMessage": "!!!Workspaces", | ||
2972 | "end": { | ||
2973 | "column": 3, | ||
2974 | "line": 19 | ||
2975 | }, | ||
2976 | "file": "src/components/ui/FeatureList.js", | ||
2977 | "id": "pricing.features.workspaces", | ||
2978 | "start": { | ||
2979 | "column": 14, | ||
2980 | "line": 16 | ||
2981 | } | ||
2982 | }, | ||
2983 | { | ||
2984 | "defaultMessage": "!!!Add Custom Websites", | ||
2985 | "end": { | ||
2986 | "column": 3, | ||
2987 | "line": 23 | ||
2988 | }, | ||
2989 | "file": "src/components/ui/FeatureList.js", | ||
2990 | "id": "pricing.features.customWebsites", | ||
2991 | "start": { | ||
2992 | "column": 18, | ||
2993 | "line": 20 | ||
2994 | } | ||
2995 | }, | ||
2996 | { | ||
2997 | "defaultMessage": "!!!On-premise & other Hosted Services", | ||
2998 | "end": { | ||
2999 | "column": 3, | ||
3000 | "line": 27 | ||
3001 | }, | ||
3002 | "file": "src/components/ui/FeatureList.js", | ||
3003 | "id": "pricing.features.onPremise", | ||
3004 | "start": { | ||
3005 | "column": 13, | ||
3006 | "line": 24 | ||
3007 | } | ||
3008 | }, | ||
3009 | { | ||
3010 | "defaultMessage": "!!!Install 3rd party services", | ||
3011 | "end": { | ||
3012 | "column": 3, | ||
3013 | "line": 31 | ||
3014 | }, | ||
3015 | "file": "src/components/ui/FeatureList.js", | ||
3016 | "id": "pricing.features.thirdPartyServices", | ||
3017 | "start": { | ||
3018 | "column": 22, | ||
3019 | "line": 28 | ||
3020 | } | ||
3021 | }, | ||
3022 | { | ||
3023 | "defaultMessage": "!!!Service Proxies", | ||
3024 | "end": { | ||
3025 | "column": 3, | ||
3026 | "line": 35 | ||
3027 | }, | ||
3028 | "file": "src/components/ui/FeatureList.js", | ||
3029 | "id": "pricing.features.serviceProxies", | ||
3030 | "start": { | ||
3031 | "column": 18, | ||
3032 | "line": 32 | ||
3033 | } | ||
3034 | }, | ||
3035 | { | ||
3036 | "defaultMessage": "!!!Team Management", | ||
3037 | "end": { | ||
3038 | "column": 3, | ||
3039 | "line": 39 | ||
3040 | }, | ||
3041 | "file": "src/components/ui/FeatureList.js", | ||
3042 | "id": "pricing.features.teamManagement", | ||
3043 | "start": { | ||
3044 | "column": 18, | ||
3045 | "line": 36 | ||
3046 | } | ||
3047 | }, | ||
3048 | { | ||
3049 | "defaultMessage": "!!!No Waiting Screens", | ||
3050 | "end": { | ||
3051 | "column": 3, | ||
3052 | "line": 43 | ||
3053 | }, | ||
3054 | "file": "src/components/ui/FeatureList.js", | ||
3055 | "id": "pricing.features.appDelays", | ||
3056 | "start": { | ||
3057 | "column": 13, | ||
3058 | "line": 40 | ||
3059 | } | ||
3060 | }, | ||
3061 | { | ||
3062 | "defaultMessage": "!!!Forever ad-free", | ||
3063 | "end": { | ||
3064 | "column": 3, | ||
3065 | "line": 47 | ||
3066 | }, | ||
3067 | "file": "src/components/ui/FeatureList.js", | ||
3068 | "id": "pricing.features.adFree", | ||
3069 | "start": { | ||
3070 | "column": 10, | ||
3071 | "line": 44 | ||
3072 | } | ||
3073 | } | ||
3074 | ], | ||
3075 | "path": "src/components/ui/FeatureList.json" | ||
3076 | }, | ||
3077 | { | ||
3078 | "descriptors": [ | ||
3079 | { | ||
2662 | "defaultMessage": "!!!Upgrade account", | 3080 | "defaultMessage": "!!!Upgrade account", |
2663 | "end": { | 3081 | "end": { |
2664 | "column": 3, | 3082 | "column": 3, |
@@ -3230,39 +3648,65 @@ | |||
3230 | "defaultMessage": "!!!Please purchase license to skip waiting", | 3648 | "defaultMessage": "!!!Please purchase license to skip waiting", |
3231 | "end": { | 3649 | "end": { |
3232 | "column": 3, | 3650 | "column": 3, |
3233 | "line": 18 | 3651 | "line": 20 |
3234 | }, | 3652 | }, |
3235 | "file": "src/features/delayApp/Component.js", | 3653 | "file": "src/features/delayApp/Component.js", |
3236 | "id": "feature.delayApp.headline", | 3654 | "id": "feature.delayApp.headline", |
3237 | "start": { | 3655 | "start": { |
3238 | "column": 12, | 3656 | "column": 12, |
3239 | "line": 15 | 3657 | "line": 17 |
3658 | } | ||
3659 | }, | ||
3660 | { | ||
3661 | "defaultMessage": "!!!Get the free Franz Professional 14 day trial and skip the line", | ||
3662 | "end": { | ||
3663 | "column": 3, | ||
3664 | "line": 24 | ||
3665 | }, | ||
3666 | "file": "src/features/delayApp/Component.js", | ||
3667 | "id": "feature.delayApp.trial.headline", | ||
3668 | "start": { | ||
3669 | "column": 17, | ||
3670 | "line": 21 | ||
3240 | } | 3671 | } |
3241 | }, | 3672 | }, |
3242 | { | 3673 | { |
3243 | "defaultMessage": "!!!Get a Franz Supporter License", | 3674 | "defaultMessage": "!!!Get a Franz Supporter License", |
3244 | "end": { | 3675 | "end": { |
3245 | "column": 3, | 3676 | "column": 3, |
3246 | "line": 22 | 3677 | "line": 28 |
3247 | }, | 3678 | }, |
3248 | "file": "src/features/delayApp/Component.js", | 3679 | "file": "src/features/delayApp/Component.js", |
3249 | "id": "feature.delayApp.action", | 3680 | "id": "feature.delayApp.upgrade.action", |
3250 | "start": { | 3681 | "start": { |
3251 | "column": 10, | 3682 | "column": 10, |
3252 | "line": 19 | 3683 | "line": 25 |
3684 | } | ||
3685 | }, | ||
3686 | { | ||
3687 | "defaultMessage": "!!!Yes, I want the free 14 day trial of Franz Professional", | ||
3688 | "end": { | ||
3689 | "column": 3, | ||
3690 | "line": 32 | ||
3691 | }, | ||
3692 | "file": "src/features/delayApp/Component.js", | ||
3693 | "id": "feature.delayApp.trial.action", | ||
3694 | "start": { | ||
3695 | "column": 15, | ||
3696 | "line": 29 | ||
3253 | } | 3697 | } |
3254 | }, | 3698 | }, |
3255 | { | 3699 | { |
3256 | "defaultMessage": "!!!Franz will continue in {seconds} seconds.", | 3700 | "defaultMessage": "!!!Franz will continue in {seconds} seconds.", |
3257 | "end": { | 3701 | "end": { |
3258 | "column": 3, | 3702 | "column": 3, |
3259 | "line": 26 | 3703 | "line": 36 |
3260 | }, | 3704 | }, |
3261 | "file": "src/features/delayApp/Component.js", | 3705 | "file": "src/features/delayApp/Component.js", |
3262 | "id": "feature.delayApp.text", | 3706 | "id": "feature.delayApp.text", |
3263 | "start": { | 3707 | "start": { |
3264 | "column": 8, | 3708 | "column": 8, |
3265 | "line": 23 | 3709 | "line": 33 |
3266 | } | 3710 | } |
3267 | } | 3711 | } |
3268 | ], | 3712 | ], |
@@ -3271,6 +3715,55 @@ | |||
3271 | { | 3715 | { |
3272 | "descriptors": [ | 3716 | "descriptors": [ |
3273 | { | 3717 | { |
3718 | "defaultMessage": "!!!Changes in Franz {version}", | ||
3719 | "end": { | ||
3720 | "column": 3, | ||
3721 | "line": 23 | ||
3722 | }, | ||
3723 | "file": "src/features/serviceLimit/components/AnnouncementScreen.js", | ||
3724 | "id": "feature.announcements.changelog.headline", | ||
3725 | "start": { | ||
3726 | "column": 12, | ||
3727 | "line": 20 | ||
3728 | } | ||
3729 | } | ||
3730 | ], | ||
3731 | "path": "src/features/serviceLimit/components/AnnouncementScreen.json" | ||
3732 | }, | ||
3733 | { | ||
3734 | "descriptors": [ | ||
3735 | { | ||
3736 | "defaultMessage": "!!!You have added {amount} of {limit} services. Please upgrade your account to add more services.", | ||
3737 | "end": { | ||
3738 | "column": 3, | ||
3739 | "line": 14 | ||
3740 | }, | ||
3741 | "file": "src/features/serviceLimit/components/LimitReachedInfobox.js", | ||
3742 | "id": "feature.serviceLimit.limitReached", | ||
3743 | "start": { | ||
3744 | "column": 16, | ||
3745 | "line": 11 | ||
3746 | } | ||
3747 | }, | ||
3748 | { | ||
3749 | "defaultMessage": "!!!Upgrade account", | ||
3750 | "end": { | ||
3751 | "column": 3, | ||
3752 | "line": 18 | ||
3753 | }, | ||
3754 | "file": "src/features/serviceLimit/components/LimitReachedInfobox.js", | ||
3755 | "id": "premiumFeature.button.upgradeAccount", | ||
3756 | "start": { | ||
3757 | "column": 10, | ||
3758 | "line": 15 | ||
3759 | } | ||
3760 | } | ||
3761 | ], | ||
3762 | "path": "src/features/serviceLimit/components/LimitReachedInfobox.json" | ||
3763 | }, | ||
3764 | { | ||
3765 | "descriptors": [ | ||
3766 | { | ||
3274 | "defaultMessage": "!!!Franz is better together!", | 3767 | "defaultMessage": "!!!Franz is better together!", |
3275 | "end": { | 3768 | "end": { |
3276 | "column": 3, | 3769 | "column": 3, |
@@ -3761,6 +4254,172 @@ | |||
3761 | { | 4254 | { |
3762 | "descriptors": [ | 4255 | "descriptors": [ |
3763 | { | 4256 | { |
4257 | "defaultMessage": "!!!Franz Professional Yearly", | ||
4258 | "end": { | ||
4259 | "column": 3, | ||
4260 | "line": 8 | ||
4261 | }, | ||
4262 | "file": "src/helpers/plan-helpers.js", | ||
4263 | "id": "pricing.plan.pro-yearly", | ||
4264 | "start": { | ||
4265 | "column": 22, | ||
4266 | "line": 5 | ||
4267 | } | ||
4268 | }, | ||
4269 | { | ||
4270 | "defaultMessage": "!!!Franz Professional Monthly", | ||
4271 | "end": { | ||
4272 | "column": 3, | ||
4273 | "line": 12 | ||
4274 | }, | ||
4275 | "file": "src/helpers/plan-helpers.js", | ||
4276 | "id": "pricing.plan.pro-monthly", | ||
4277 | "start": { | ||
4278 | "column": 23, | ||
4279 | "line": 9 | ||
4280 | } | ||
4281 | }, | ||
4282 | { | ||
4283 | "defaultMessage": "!!!Franz Personal Yearly", | ||
4284 | "end": { | ||
4285 | "column": 3, | ||
4286 | "line": 16 | ||
4287 | }, | ||
4288 | "file": "src/helpers/plan-helpers.js", | ||
4289 | "id": "pricing.plan.personal-yearly", | ||
4290 | "start": { | ||
4291 | "column": 27, | ||
4292 | "line": 13 | ||
4293 | } | ||
4294 | }, | ||
4295 | { | ||
4296 | "defaultMessage": "!!!Franz Personal Monthly", | ||
4297 | "end": { | ||
4298 | "column": 3, | ||
4299 | "line": 20 | ||
4300 | }, | ||
4301 | "file": "src/helpers/plan-helpers.js", | ||
4302 | "id": "pricing.plan.personal-monthly", | ||
4303 | "start": { | ||
4304 | "column": 28, | ||
4305 | "line": 17 | ||
4306 | } | ||
4307 | }, | ||
4308 | { | ||
4309 | "defaultMessage": "!!!Franz Free", | ||
4310 | "end": { | ||
4311 | "column": 3, | ||
4312 | "line": 24 | ||
4313 | }, | ||
4314 | "file": "src/helpers/plan-helpers.js", | ||
4315 | "id": "pricing.plan.free", | ||
4316 | "start": { | ||
4317 | "column": 16, | ||
4318 | "line": 21 | ||
4319 | } | ||
4320 | }, | ||
4321 | { | ||
4322 | "defaultMessage": "!!!Franz Premium", | ||
4323 | "end": { | ||
4324 | "column": 3, | ||
4325 | "line": 28 | ||
4326 | }, | ||
4327 | "file": "src/helpers/plan-helpers.js", | ||
4328 | "id": "pricing.plan.legacy", | ||
4329 | "start": { | ||
4330 | "column": 18, | ||
4331 | "line": 25 | ||
4332 | } | ||
4333 | } | ||
4334 | ], | ||
4335 | "path": "src/helpers/plan-helpers.json" | ||
4336 | }, | ||
4337 | { | ||
4338 | "descriptors": [ | ||
4339 | { | ||
4340 | "defaultMessage": "!!!Franz Professional Yearly", | ||
4341 | "end": { | ||
4342 | "column": 3, | ||
4343 | "line": 8 | ||
4344 | }, | ||
4345 | "file": "src/helpers/pricing-helpers.js", | ||
4346 | "id": "pricing.plan.pro-yearly", | ||
4347 | "start": { | ||
4348 | "column": 22, | ||
4349 | "line": 5 | ||
4350 | } | ||
4351 | }, | ||
4352 | { | ||
4353 | "defaultMessage": "!!!Franz Professional Monthly", | ||
4354 | "end": { | ||
4355 | "column": 3, | ||
4356 | "line": 12 | ||
4357 | }, | ||
4358 | "file": "src/helpers/pricing-helpers.js", | ||
4359 | "id": "pricing.plan.pro-monthly", | ||
4360 | "start": { | ||
4361 | "column": 23, | ||
4362 | "line": 9 | ||
4363 | } | ||
4364 | }, | ||
4365 | { | ||
4366 | "defaultMessage": "!!!Franz Personal Yearly", | ||
4367 | "end": { | ||
4368 | "column": 3, | ||
4369 | "line": 16 | ||
4370 | }, | ||
4371 | "file": "src/helpers/pricing-helpers.js", | ||
4372 | "id": "pricing.plan.personal-yearly", | ||
4373 | "start": { | ||
4374 | "column": 27, | ||
4375 | "line": 13 | ||
4376 | } | ||
4377 | }, | ||
4378 | { | ||
4379 | "defaultMessage": "!!!Franz Personal Monthly", | ||
4380 | "end": { | ||
4381 | "column": 3, | ||
4382 | "line": 20 | ||
4383 | }, | ||
4384 | "file": "src/helpers/pricing-helpers.js", | ||
4385 | "id": "pricing.plan.personal-monthly", | ||
4386 | "start": { | ||
4387 | "column": 28, | ||
4388 | "line": 17 | ||
4389 | } | ||
4390 | }, | ||
4391 | { | ||
4392 | "defaultMessage": "!!!Franz Free", | ||
4393 | "end": { | ||
4394 | "column": 3, | ||
4395 | "line": 24 | ||
4396 | }, | ||
4397 | "file": "src/helpers/pricing-helpers.js", | ||
4398 | "id": "pricing.plan.free", | ||
4399 | "start": { | ||
4400 | "column": 16, | ||
4401 | "line": 21 | ||
4402 | } | ||
4403 | }, | ||
4404 | { | ||
4405 | "defaultMessage": "!!!Franz Premium", | ||
4406 | "end": { | ||
4407 | "column": 3, | ||
4408 | "line": 28 | ||
4409 | }, | ||
4410 | "file": "src/helpers/pricing-helpers.js", | ||
4411 | "id": "pricing.plan.legacy", | ||
4412 | "start": { | ||
4413 | "column": 18, | ||
4414 | "line": 25 | ||
4415 | } | ||
4416 | } | ||
4417 | ], | ||
4418 | "path": "src/helpers/pricing-helpers.json" | ||
4419 | }, | ||
4420 | { | ||
4421 | "descriptors": [ | ||
4422 | { | ||
3764 | "defaultMessage": "!!!Field is required", | 4423 | "defaultMessage": "!!!Field is required", |
3765 | "end": { | 4424 | "end": { |
3766 | "column": 3, | 4425 | "column": 3, |
diff --git a/src/i18n/locales/en-US.json b/src/i18n/locales/en-US.json index 27987e5b7..cd1e39543 100644 --- a/src/i18n/locales/en-US.json +++ b/src/i18n/locales/en-US.json | |||
@@ -2,9 +2,12 @@ | |||
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", | ||
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.", | ||
8 | "feature.shareFranz.action.email": "Send as email", | 11 | "feature.shareFranz.action.email": "Send as email", |
9 | "feature.shareFranz.action.facebook": "Share on Facebook", | 12 | "feature.shareFranz.action.facebook": "Share on Facebook", |
10 | "feature.shareFranz.action.twitter": "Share on Twitter", | 13 | "feature.shareFranz.action.twitter": "Share on Twitter", |
@@ -27,6 +30,7 @@ | |||
27 | "infobar.buttonReloadServices": "Reload services", | 30 | "infobar.buttonReloadServices": "Reload services", |
28 | "infobar.requiredRequestsFailed": "Could not load services and user information", | 31 | "infobar.requiredRequestsFailed": "Could not load services and user information", |
29 | "infobar.servicesUpdated": "Your services have been updated.", | 32 | "infobar.servicesUpdated": "Your services have been updated.", |
33 | "infobar.trialActivated": "Your trial was successfully activated. Happy messaging!", | ||
30 | "infobar.updateAvailable": "A new update for Franz is available.", | 34 | "infobar.updateAvailable": "A new update for Franz is available.", |
31 | "invite.email.label": "Email address", | 35 | "invite.email.label": "Email address", |
32 | "invite.headline.friends": "Invite 3 of your friends or colleagues", | 36 | "invite.headline.friends": "Invite 3 of your friends or colleagues", |
@@ -106,10 +110,31 @@ | |||
106 | "password.submit.label": "Submit", | 110 | "password.submit.label": "Submit", |
107 | "password.successInfo": "Please check your email", | 111 | "password.successInfo": "Please check your email", |
108 | "premiumFeature.button.upgradeAccount": "Upgrade account", | 112 | "premiumFeature.button.upgradeAccount": "Upgrade account", |
109 | "pricing.headline": "Support Franz", | 113 | "pricing.features.adFree": "Forever ad-free", |
110 | "pricing.link.skipPayment": "I don't want to support the development of Franz.", | 114 | "pricing.features.appDelays": "No Waiting Screens", |
111 | "pricing.submit.label": "I want to support the development of Franz", | 115 | "pricing.features.customWebsites": "Add Custom Websites", |
112 | "pricing.support.label": "Select your support plan", | 116 | "pricing.features.onPremise": "On-premise & other Hosted Services", |
117 | "pricing.features.serviceProxies": "Service Proxies", | ||
118 | "pricing.features.spellchecker": "Spellchecker support", | ||
119 | "pricing.features.teamManagement": "Team Management", | ||
120 | "pricing.features.thirdPartyServices": "Install 3rd party services", | ||
121 | "pricing.features.unlimitedServices": "Add unlimited services", | ||
122 | "pricing.features.workspaces": "Workspaces", | ||
123 | "pricing.plan.free": "Franz Free", | ||
124 | "pricing.plan.legacy": "Franz Premium", | ||
125 | "pricing.plan.personal-monthly": "Franz Personal Monthly", | ||
126 | "pricing.plan.personal-yearly": "Franz Personal Yearly", | ||
127 | "pricing.plan.pro-monthly": "Franz Professional Monthly", | ||
128 | "pricing.plan.pro-yearly": "Franz Professional Yearly", | ||
129 | "pricing.trial.cta.accept": "Yes, upgrade my account to Franz Professional", | ||
130 | "pricing.trial.cta.skip": "Continue to Franz", | ||
131 | "pricing.trial.error": "Sorry, we could not activate your trial!", | ||
132 | "pricing.trial.features.headline": "Franz Professional includes:", | ||
133 | "pricing.trial.headline": "Franz Professional", | ||
134 | "pricing.trial.subheadline": "Your personal welcome offer:", | ||
135 | "pricing.trial.terms.automaticTrialEnd": "Your free trial ends automatically after 14 days", | ||
136 | "pricing.trial.terms.headline": "No strings attached", | ||
137 | "pricing.trial.terms.noCreditCard": "No credit card required", | ||
113 | "service.crashHandler.action": "Reload {name}", | 138 | "service.crashHandler.action": "Reload {name}", |
114 | "service.crashHandler.autoReload": "Trying to automatically restore {name} in {seconds} seconds", | 139 | "service.crashHandler.autoReload": "Trying to automatically restore {name} in {seconds} seconds", |
115 | "service.crashHandler.headline": "Oh no!", | 140 | "service.crashHandler.headline": "Oh no!", |
@@ -121,6 +146,11 @@ | |||
121 | "service.errorHandler.headline": "Oh no!", | 146 | "service.errorHandler.headline": "Oh no!", |
122 | "service.errorHandler.message": "Error", | 147 | "service.errorHandler.message": "Error", |
123 | "service.errorHandler.text": "{name} has failed to load.", | 148 | "service.errorHandler.text": "{name} has failed to load.", |
149 | "service.restrictedHandler.action": "Upgrade Account", | ||
150 | "service.restrictedHandler.customUrl.headline": "Franz Professional Plan required", | ||
151 | "service.restrictedHandler.customUrl.text": "Please upgrade to the Franz Professional plan to use custom urls & self hosted services.", | ||
152 | "service.restrictedHandler.serviceLimit.headline": "You have reached your service limit.", | ||
153 | "service.restrictedHandler.serviceLimit.text": "Please upgrade your account to use more than {count} services.", | ||
124 | "service.webviewLoader.loading": "Loading", | 154 | "service.webviewLoader.loading": "Loading", |
125 | "services.getStarted": "Get started", | 155 | "services.getStarted": "Get started", |
126 | "services.welcome": "Welcome to Franz", | 156 | "services.welcome": "Welcome to Franz", |
@@ -142,9 +172,13 @@ | |||
142 | "settings.account.invoiceDownload": "Download", | 172 | "settings.account.invoiceDownload": "Download", |
143 | "settings.account.manageSubscription.label": "Manage your subscription", | 173 | "settings.account.manageSubscription.label": "Manage your subscription", |
144 | "settings.account.successInfo": "Your changes have been saved", | 174 | "settings.account.successInfo": "Your changes have been saved", |
175 | "settings.account.trial": "Free Trial", | ||
176 | "settings.account.trialEndsIn": "Your free trial ends in {duration}.", | ||
177 | "settings.account.trialUpdateBillingInfo": "Please update your billing info to continue using {license} after your trial period.", | ||
145 | "settings.account.tryReloadServices": "Try again", | 178 | "settings.account.tryReloadServices": "Try again", |
146 | "settings.account.tryReloadUserInfoRequest": "Try again", | 179 | "settings.account.tryReloadUserInfoRequest": "Try again", |
147 | "settings.account.userInfoRequestFailed": "Could not load user information", | 180 | "settings.account.userInfoRequestFailed": "Could not load user information", |
181 | "settings.account.yourLicense": "Your license:", | ||
148 | "settings.app.buttonClearAllCache": "Clear cache", | 182 | "settings.app.buttonClearAllCache": "Clear cache", |
149 | "settings.app.buttonInstallUpdate": "Restart & install update", | 183 | "settings.app.buttonInstallUpdate": "Restart & install update", |
150 | "settings.app.buttonSearchForUpdate": "Check for updates", | 184 | "settings.app.buttonSearchForUpdate": "Check for updates", |
@@ -185,7 +219,13 @@ | |||
185 | "settings.navigation.yourServices": "Your services", | 219 | "settings.navigation.yourServices": "Your services", |
186 | "settings.navigation.yourWorkspaces": "Your workspaces", | 220 | "settings.navigation.yourWorkspaces": "Your workspaces", |
187 | "settings.recipes.all": "All services", | 221 | "settings.recipes.all": "All services", |
188 | "settings.recipes.dev": "Development", | 222 | "settings.recipes.custom": "Custom Services", |
223 | "settings.recipes.customService.headline.communityRecipes": "Community Services", | ||
224 | "settings.recipes.customService.headline.customRecipes": "Custom Service Recipes", | ||
225 | "settings.recipes.customService.headline.devRecipes": "Your Development Service Recipes", | ||
226 | "settings.recipes.customService.intro": "To add a custom service, copy the service recipe to:", | ||
227 | "settings.recipes.customService.openDevDocs": "Developer Documentation", | ||
228 | "settings.recipes.customService.openFolder": "Open folder", | ||
189 | "settings.recipes.headline": "Available services", | 229 | "settings.recipes.headline": "Available services", |
190 | "settings.recipes.missingService": "Missing a service?", | 230 | "settings.recipes.missingService": "Missing a service?", |
191 | "settings.recipes.mostPopular": "Most popular", | 231 | "settings.recipes.mostPopular": "Most popular", |
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/auth/Pricing.json b/src/i18n/messages/src/components/auth/Pricing.json index f711a55b4..f15617ca5 100644 --- a/src/i18n/messages/src/components/auth/Pricing.json +++ b/src/i18n/messages/src/components/auth/Pricing.json | |||
@@ -1,53 +1,118 @@ | |||
1 | [ | 1 | [ |
2 | { | 2 | { |
3 | "id": "pricing.headline", | 3 | "id": "pricing.trial.headline", |
4 | "defaultMessage": "!!!Support Franz", | 4 | "defaultMessage": "!!!Franz Professional", |
5 | "file": "src/components/auth/Pricing.js", | 5 | "file": "src/components/auth/Pricing.js", |
6 | "start": { | 6 | "start": { |
7 | "line": 13, | 7 | "line": 15, |
8 | "column": 12 | 8 | "column": 12 |
9 | }, | 9 | }, |
10 | "end": { | 10 | "end": { |
11 | "line": 16, | 11 | "line": 18, |
12 | "column": 3 | 12 | "column": 3 |
13 | } | 13 | } |
14 | }, | 14 | }, |
15 | { | 15 | { |
16 | "id": "pricing.support.label", | 16 | "id": "pricing.trial.subheadline", |
17 | "defaultMessage": "!!!Select your support plan", | 17 | "defaultMessage": "!!!Your personal welcome offer:", |
18 | "file": "src/components/auth/Pricing.js", | 18 | "file": "src/components/auth/Pricing.js", |
19 | "start": { | 19 | "start": { |
20 | "line": 17, | 20 | "line": 19, |
21 | "column": 23 | 21 | "column": 17 |
22 | }, | 22 | }, |
23 | "end": { | 23 | "end": { |
24 | "line": 20, | 24 | "line": 22, |
25 | "column": 3 | 25 | "column": 3 |
26 | } | 26 | } |
27 | }, | 27 | }, |
28 | { | 28 | { |
29 | "id": "pricing.submit.label", | 29 | "id": "pricing.trial.terms.headline", |
30 | "defaultMessage": "!!!Support the development of Franz", | 30 | "defaultMessage": "!!!No strings attached", |
31 | "file": "src/components/auth/Pricing.js", | 31 | "file": "src/components/auth/Pricing.js", |
32 | "start": { | 32 | "start": { |
33 | "line": 21, | 33 | "line": 23, |
34 | "column": 29 | ||
35 | }, | ||
36 | "end": { | ||
37 | "line": 26, | ||
38 | "column": 3 | ||
39 | } | ||
40 | }, | ||
41 | { | ||
42 | "id": "pricing.trial.terms.noCreditCard", | ||
43 | "defaultMessage": "!!!No credit card required", | ||
44 | "file": "src/components/auth/Pricing.js", | ||
45 | "start": { | ||
46 | "line": 27, | ||
47 | "column": 16 | ||
48 | }, | ||
49 | "end": { | ||
50 | "line": 30, | ||
51 | "column": 3 | ||
52 | } | ||
53 | }, | ||
54 | { | ||
55 | "id": "pricing.trial.terms.automaticTrialEnd", | ||
56 | "defaultMessage": "!!!Your free trial ends automatically after 14 days", | ||
57 | "file": "src/components/auth/Pricing.js", | ||
58 | "start": { | ||
59 | "line": 31, | ||
34 | "column": 21 | 60 | "column": 21 |
35 | }, | 61 | }, |
36 | "end": { | 62 | "end": { |
37 | "line": 24, | 63 | "line": 34, |
64 | "column": 3 | ||
65 | } | ||
66 | }, | ||
67 | { | ||
68 | "id": "pricing.trial.error", | ||
69 | "defaultMessage": "!!!Sorry, we could not activate your trial!", | ||
70 | "file": "src/components/auth/Pricing.js", | ||
71 | "start": { | ||
72 | "line": 35, | ||
73 | "column": 19 | ||
74 | }, | ||
75 | "end": { | ||
76 | "line": 38, | ||
77 | "column": 3 | ||
78 | } | ||
79 | }, | ||
80 | { | ||
81 | "id": "pricing.trial.cta.accept", | ||
82 | "defaultMessage": "!!!Yes, upgrade my account to Franz Professional", | ||
83 | "file": "src/components/auth/Pricing.js", | ||
84 | "start": { | ||
85 | "line": 39, | ||
86 | "column": 13 | ||
87 | }, | ||
88 | "end": { | ||
89 | "line": 42, | ||
90 | "column": 3 | ||
91 | } | ||
92 | }, | ||
93 | { | ||
94 | "id": "pricing.trial.cta.skip", | ||
95 | "defaultMessage": "!!!Continue to Franz", | ||
96 | "file": "src/components/auth/Pricing.js", | ||
97 | "start": { | ||
98 | "line": 43, | ||
99 | "column": 11 | ||
100 | }, | ||
101 | "end": { | ||
102 | "line": 46, | ||
38 | "column": 3 | 103 | "column": 3 |
39 | } | 104 | } |
40 | }, | 105 | }, |
41 | { | 106 | { |
42 | "id": "pricing.link.skipPayment", | 107 | "id": "pricing.trial.features.headline", |
43 | "defaultMessage": "!!!I don't want to support the development of Franz.", | 108 | "defaultMessage": "!!!Franz Professional includes:", |
44 | "file": "src/components/auth/Pricing.js", | 109 | "file": "src/components/auth/Pricing.js", |
45 | "start": { | 110 | "start": { |
46 | "line": 25, | 111 | "line": 47, |
47 | "column": 15 | 112 | "column": 20 |
48 | }, | 113 | }, |
49 | "end": { | 114 | "end": { |
50 | "line": 28, | 115 | "line": 50, |
51 | "column": 3 | 116 | "column": 3 |
52 | } | 117 | } |
53 | } | 118 | } |
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/components/services/content/ServiceRestricted.json b/src/i18n/messages/src/components/services/content/ServiceRestricted.json new file mode 100644 index 000000000..c1984afe3 --- /dev/null +++ b/src/i18n/messages/src/components/services/content/ServiceRestricted.json | |||
@@ -0,0 +1,67 @@ | |||
1 | [ | ||
2 | { | ||
3 | "id": "service.restrictedHandler.serviceLimit.headline", | ||
4 | "defaultMessage": "!!!You have reached your service limit.", | ||
5 | "file": "src/components/services/content/ServiceRestricted.js", | ||
6 | "start": { | ||
7 | "line": 11, | ||
8 | "column": 24 | ||
9 | }, | ||
10 | "end": { | ||
11 | "line": 14, | ||
12 | "column": 3 | ||
13 | } | ||
14 | }, | ||
15 | { | ||
16 | "id": "service.restrictedHandler.serviceLimit.text", | ||
17 | "defaultMessage": "!!!Please upgrade your account to use more than {count} services.", | ||
18 | "file": "src/components/services/content/ServiceRestricted.js", | ||
19 | "start": { | ||
20 | "line": 15, | ||
21 | "column": 20 | ||
22 | }, | ||
23 | "end": { | ||
24 | "line": 18, | ||
25 | "column": 3 | ||
26 | } | ||
27 | }, | ||
28 | { | ||
29 | "id": "service.restrictedHandler.customUrl.headline", | ||
30 | "defaultMessage": "!!!Franz Professional Plan required", | ||
31 | "file": "src/components/services/content/ServiceRestricted.js", | ||
32 | "start": { | ||
33 | "line": 19, | ||
34 | "column": 21 | ||
35 | }, | ||
36 | "end": { | ||
37 | "line": 22, | ||
38 | "column": 3 | ||
39 | } | ||
40 | }, | ||
41 | { | ||
42 | "id": "service.restrictedHandler.customUrl.text", | ||
43 | "defaultMessage": "!!!Please upgrade to the Franz Professional plan to use custom urls & self hosted services.", | ||
44 | "file": "src/components/services/content/ServiceRestricted.js", | ||
45 | "start": { | ||
46 | "line": 23, | ||
47 | "column": 17 | ||
48 | }, | ||
49 | "end": { | ||
50 | "line": 26, | ||
51 | "column": 3 | ||
52 | } | ||
53 | }, | ||
54 | { | ||
55 | "id": "service.restrictedHandler.action", | ||
56 | "defaultMessage": "!!!Upgrade Account", | ||
57 | "file": "src/components/services/content/ServiceRestricted.js", | ||
58 | "start": { | ||
59 | "line": 27, | ||
60 | "column": 10 | ||
61 | }, | ||
62 | "end": { | ||
63 | "line": 30, | ||
64 | "column": 3 | ||
65 | } | ||
66 | } | ||
67 | ] \ No newline at end of file | ||
diff --git a/src/i18n/messages/src/components/services/content/Services.json b/src/i18n/messages/src/components/services/content/Services.json index 884ab0c90..eb466c0ac 100644 --- a/src/i18n/messages/src/components/services/content/Services.json +++ b/src/i18n/messages/src/components/services/content/Services.json | |||
@@ -4,11 +4,11 @@ | |||
4 | "defaultMessage": "!!!Welcome to Franz", | 4 | "defaultMessage": "!!!Welcome to Franz", |
5 | "file": "src/components/services/content/Services.js", | 5 | "file": "src/components/services/content/Services.js", |
6 | "start": { | 6 | "start": { |
7 | "line": 11, | 7 | "line": 14, |
8 | "column": 11 | 8 | "column": 11 |
9 | }, | 9 | }, |
10 | "end": { | 10 | "end": { |
11 | "line": 14, | 11 | "line": 17, |
12 | "column": 3 | 12 | "column": 3 |
13 | } | 13 | } |
14 | }, | 14 | }, |
@@ -17,11 +17,11 @@ | |||
17 | "defaultMessage": "!!!Get started", | 17 | "defaultMessage": "!!!Get started", |
18 | "file": "src/components/services/content/Services.js", | 18 | "file": "src/components/services/content/Services.js", |
19 | "start": { | 19 | "start": { |
20 | "line": 15, | 20 | "line": 18, |
21 | "column": 14 | 21 | "column": 14 |
22 | }, | 22 | }, |
23 | "end": { | 23 | "end": { |
24 | "line": 18, | 24 | "line": 21, |
25 | "column": 3 | 25 | "column": 3 |
26 | } | 26 | } |
27 | } | 27 | } |
diff --git a/src/i18n/messages/src/components/settings/account/AccountDashboard.json b/src/i18n/messages/src/components/settings/account/AccountDashboard.json index 4969db910..1e21bad69 100644 --- a/src/i18n/messages/src/components/settings/account/AccountDashboard.json +++ b/src/i18n/messages/src/components/settings/account/AccountDashboard.json | |||
@@ -4,11 +4,11 @@ | |||
4 | "defaultMessage": "!!!Account", | 4 | "defaultMessage": "!!!Account", |
5 | "file": "src/components/settings/account/AccountDashboard.js", | 5 | "file": "src/components/settings/account/AccountDashboard.js", |
6 | "start": { | 6 | "start": { |
7 | "line": 14, | 7 | "line": 18, |
8 | "column": 12 | 8 | "column": 12 |
9 | }, | 9 | }, |
10 | "end": { | 10 | "end": { |
11 | "line": 17, | 11 | "line": 21, |
12 | "column": 3 | 12 | "column": 3 |
13 | } | 13 | } |
14 | }, | 14 | }, |
@@ -17,24 +17,24 @@ | |||
17 | "defaultMessage": "!!!Your Subscription", | 17 | "defaultMessage": "!!!Your Subscription", |
18 | "file": "src/components/settings/account/AccountDashboard.js", | 18 | "file": "src/components/settings/account/AccountDashboard.js", |
19 | "start": { | 19 | "start": { |
20 | "line": 18, | 20 | "line": 22, |
21 | "column": 24 | 21 | "column": 24 |
22 | }, | 22 | }, |
23 | "end": { | 23 | "end": { |
24 | "line": 21, | 24 | "line": 25, |
25 | "column": 3 | 25 | "column": 3 |
26 | } | 26 | } |
27 | }, | 27 | }, |
28 | { | 28 | { |
29 | "id": "settings.account.headlineUpgrade", | 29 | "id": "settings.account.headlineTrialUpgrade", |
30 | "defaultMessage": "!!!Upgrade your Account", | 30 | "defaultMessage": "!!!Get the free 14 day Franz Professional Trial", |
31 | "file": "src/components/settings/account/AccountDashboard.js", | 31 | "file": "src/components/settings/account/AccountDashboard.js", |
32 | "start": { | 32 | "start": { |
33 | "line": 22, | 33 | "line": 26, |
34 | "column": 19 | 34 | "column": 19 |
35 | }, | 35 | }, |
36 | "end": { | 36 | "end": { |
37 | "line": 25, | 37 | "line": 29, |
38 | "column": 3 | 38 | "column": 3 |
39 | } | 39 | } |
40 | }, | 40 | }, |
@@ -43,11 +43,11 @@ | |||
43 | "defaultMessage": "!!Danger Zone", | 43 | "defaultMessage": "!!Danger Zone", |
44 | "file": "src/components/settings/account/AccountDashboard.js", | 44 | "file": "src/components/settings/account/AccountDashboard.js", |
45 | "start": { | 45 | "start": { |
46 | "line": 26, | 46 | "line": 30, |
47 | "column": 22 | 47 | "column": 22 |
48 | }, | 48 | }, |
49 | "end": { | 49 | "end": { |
50 | "line": 29, | 50 | "line": 33, |
51 | "column": 3 | 51 | "column": 3 |
52 | } | 52 | } |
53 | }, | 53 | }, |
@@ -56,11 +56,11 @@ | |||
56 | "defaultMessage": "!!!Manage your subscription", | 56 | "defaultMessage": "!!!Manage your subscription", |
57 | "file": "src/components/settings/account/AccountDashboard.js", | 57 | "file": "src/components/settings/account/AccountDashboard.js", |
58 | "start": { | 58 | "start": { |
59 | "line": 30, | 59 | "line": 34, |
60 | "column": 33 | 60 | "column": 33 |
61 | }, | 61 | }, |
62 | "end": { | 62 | "end": { |
63 | "line": 33, | 63 | "line": 37, |
64 | "column": 3 | 64 | "column": 3 |
65 | } | 65 | } |
66 | }, | 66 | }, |
@@ -69,11 +69,11 @@ | |||
69 | "defaultMessage": "!!!Basic Account", | 69 | "defaultMessage": "!!!Basic Account", |
70 | "file": "src/components/settings/account/AccountDashboard.js", | 70 | "file": "src/components/settings/account/AccountDashboard.js", |
71 | "start": { | 71 | "start": { |
72 | "line": 34, | 72 | "line": 38, |
73 | "column": 20 | 73 | "column": 20 |
74 | }, | 74 | }, |
75 | "end": { | 75 | "end": { |
76 | "line": 37, | 76 | "line": 41, |
77 | "column": 3 | 77 | "column": 3 |
78 | } | 78 | } |
79 | }, | 79 | }, |
@@ -82,11 +82,11 @@ | |||
82 | "defaultMessage": "!!!Premium Supporter Account", | 82 | "defaultMessage": "!!!Premium Supporter Account", |
83 | "file": "src/components/settings/account/AccountDashboard.js", | 83 | "file": "src/components/settings/account/AccountDashboard.js", |
84 | "start": { | 84 | "start": { |
85 | "line": 38, | 85 | "line": 42, |
86 | "column": 22 | 86 | "column": 22 |
87 | }, | 87 | }, |
88 | "end": { | 88 | "end": { |
89 | "line": 41, | 89 | "line": 45, |
90 | "column": 3 | 90 | "column": 3 |
91 | } | 91 | } |
92 | }, | 92 | }, |
@@ -95,11 +95,11 @@ | |||
95 | "defaultMessage": "!!!Edit Account", | 95 | "defaultMessage": "!!!Edit Account", |
96 | "file": "src/components/settings/account/AccountDashboard.js", | 96 | "file": "src/components/settings/account/AccountDashboard.js", |
97 | "start": { | 97 | "start": { |
98 | "line": 42, | 98 | "line": 46, |
99 | "column": 21 | 99 | "column": 21 |
100 | }, | 100 | }, |
101 | "end": { | 101 | "end": { |
102 | "line": 45, | 102 | "line": 49, |
103 | "column": 3 | 103 | "column": 3 |
104 | } | 104 | } |
105 | }, | 105 | }, |
@@ -108,11 +108,11 @@ | |||
108 | "defaultMessage": "!!Invoices", | 108 | "defaultMessage": "!!Invoices", |
109 | "file": "src/components/settings/account/AccountDashboard.js", | 109 | "file": "src/components/settings/account/AccountDashboard.js", |
110 | "start": { | 110 | "start": { |
111 | "line": 46, | 111 | "line": 50, |
112 | "column": 18 | 112 | "column": 18 |
113 | }, | 113 | }, |
114 | "end": { | 114 | "end": { |
115 | "line": 49, | 115 | "line": 53, |
116 | "column": 3 | 116 | "column": 3 |
117 | } | 117 | } |
118 | }, | 118 | }, |
@@ -121,11 +121,11 @@ | |||
121 | "defaultMessage": "!!!Download", | 121 | "defaultMessage": "!!!Download", |
122 | "file": "src/components/settings/account/AccountDashboard.js", | 122 | "file": "src/components/settings/account/AccountDashboard.js", |
123 | "start": { | 123 | "start": { |
124 | "line": 50, | 124 | "line": 54, |
125 | "column": 19 | 125 | "column": 19 |
126 | }, | 126 | }, |
127 | "end": { | 127 | "end": { |
128 | "line": 53, | 128 | "line": 57, |
129 | "column": 3 | 129 | "column": 3 |
130 | } | 130 | } |
131 | }, | 131 | }, |
@@ -134,11 +134,11 @@ | |||
134 | "defaultMessage": "!!!Could not load user information", | 134 | "defaultMessage": "!!!Could not load user information", |
135 | "file": "src/components/settings/account/AccountDashboard.js", | 135 | "file": "src/components/settings/account/AccountDashboard.js", |
136 | "start": { | 136 | "start": { |
137 | "line": 54, | 137 | "line": 58, |
138 | "column": 25 | 138 | "column": 25 |
139 | }, | 139 | }, |
140 | "end": { | 140 | "end": { |
141 | "line": 57, | 141 | "line": 61, |
142 | "column": 3 | 142 | "column": 3 |
143 | } | 143 | } |
144 | }, | 144 | }, |
@@ -147,11 +147,11 @@ | |||
147 | "defaultMessage": "!!!Try again", | 147 | "defaultMessage": "!!!Try again", |
148 | "file": "src/components/settings/account/AccountDashboard.js", | 148 | "file": "src/components/settings/account/AccountDashboard.js", |
149 | "start": { | 149 | "start": { |
150 | "line": 58, | 150 | "line": 62, |
151 | "column": 28 | 151 | "column": 28 |
152 | }, | 152 | }, |
153 | "end": { | 153 | "end": { |
154 | "line": 61, | 154 | "line": 65, |
155 | "column": 3 | 155 | "column": 3 |
156 | } | 156 | } |
157 | }, | 157 | }, |
@@ -160,11 +160,11 @@ | |||
160 | "defaultMessage": "!!!Delete account", | 160 | "defaultMessage": "!!!Delete account", |
161 | "file": "src/components/settings/account/AccountDashboard.js", | 161 | "file": "src/components/settings/account/AccountDashboard.js", |
162 | "start": { | 162 | "start": { |
163 | "line": 62, | 163 | "line": 66, |
164 | "column": 17 | 164 | "column": 17 |
165 | }, | 165 | }, |
166 | "end": { | 166 | "end": { |
167 | "line": 65, | 167 | "line": 69, |
168 | "column": 3 | 168 | "column": 3 |
169 | } | 169 | } |
170 | }, | 170 | }, |
@@ -173,11 +173,11 @@ | |||
173 | "defaultMessage": "!!!If you don't need your Franz account any longer, you can delete your account and all related data here.", | 173 | "defaultMessage": "!!!If you don't need your Franz account any longer, you can delete your account and all related data here.", |
174 | "file": "src/components/settings/account/AccountDashboard.js", | 174 | "file": "src/components/settings/account/AccountDashboard.js", |
175 | "start": { | 175 | "start": { |
176 | "line": 66, | 176 | "line": 70, |
177 | "column": 14 | 177 | "column": 14 |
178 | }, | 178 | }, |
179 | "end": { | 179 | "end": { |
180 | "line": 69, | 180 | "line": 73, |
181 | "column": 3 | 181 | "column": 3 |
182 | } | 182 | } |
183 | }, | 183 | }, |
@@ -186,11 +186,63 @@ | |||
186 | "defaultMessage": "!!!You have received an email with a link to confirm your account deletion. Your account and data cannot be restored!", | 186 | "defaultMessage": "!!!You have received an email with a link to confirm your account deletion. Your account and data cannot be restored!", |
187 | "file": "src/components/settings/account/AccountDashboard.js", | 187 | "file": "src/components/settings/account/AccountDashboard.js", |
188 | "start": { | 188 | "start": { |
189 | "line": 70, | 189 | "line": 74, |
190 | "column": 19 | 190 | "column": 19 |
191 | }, | 191 | }, |
192 | "end": { | 192 | "end": { |
193 | "line": 73, | 193 | "line": 77, |
194 | "column": 3 | ||
195 | } | ||
196 | }, | ||
197 | { | ||
198 | "id": "settings.account.trial", | ||
199 | "defaultMessage": "!!!Free Trial", | ||
200 | "file": "src/components/settings/account/AccountDashboard.js", | ||
201 | "start": { | ||
202 | "line": 78, | ||
203 | "column": 9 | ||
204 | }, | ||
205 | "end": { | ||
206 | "line": 81, | ||
207 | "column": 3 | ||
208 | } | ||
209 | }, | ||
210 | { | ||
211 | "id": "settings.account.yourLicense", | ||
212 | "defaultMessage": "!!!Your license:", | ||
213 | "file": "src/components/settings/account/AccountDashboard.js", | ||
214 | "start": { | ||
215 | "line": 82, | ||
216 | "column": 15 | ||
217 | }, | ||
218 | "end": { | ||
219 | "line": 85, | ||
220 | "column": 3 | ||
221 | } | ||
222 | }, | ||
223 | { | ||
224 | "id": "settings.account.trialEndsIn", | ||
225 | "defaultMessage": "!!!Your free trial ends in {duration}.", | ||
226 | "file": "src/components/settings/account/AccountDashboard.js", | ||
227 | "start": { | ||
228 | "line": 86, | ||
229 | "column": 15 | ||
230 | }, | ||
231 | "end": { | ||
232 | "line": 89, | ||
233 | "column": 3 | ||
234 | } | ||
235 | }, | ||
236 | { | ||
237 | "id": "settings.account.trialUpdateBillingInfo", | ||
238 | "defaultMessage": "!!!Please update your billing info to continue using {license} after your trial period.", | ||
239 | "file": "src/components/settings/account/AccountDashboard.js", | ||
240 | "start": { | ||
241 | "line": 90, | ||
242 | "column": 33 | ||
243 | }, | ||
244 | "end": { | ||
245 | "line": 93, | ||
194 | "column": 3 | 246 | "column": 3 |
195 | } | 247 | } |
196 | } | 248 | } |
diff --git a/src/i18n/messages/src/components/settings/navigation/SettingsNavigation.json b/src/i18n/messages/src/components/settings/navigation/SettingsNavigation.json index 70a989211..7dfb3ce04 100644 --- a/src/i18n/messages/src/components/settings/navigation/SettingsNavigation.json +++ b/src/i18n/messages/src/components/settings/navigation/SettingsNavigation.json | |||
@@ -4,11 +4,11 @@ | |||
4 | "defaultMessage": "!!!Available services", | 4 | "defaultMessage": "!!!Available services", |
5 | "file": "src/components/settings/navigation/SettingsNavigation.js", | 5 | "file": "src/components/settings/navigation/SettingsNavigation.js", |
6 | "start": { | 6 | "start": { |
7 | "line": 13, | 7 | "line": 14, |
8 | "column": 21 | 8 | "column": 21 |
9 | }, | 9 | }, |
10 | "end": { | 10 | "end": { |
11 | "line": 16, | 11 | "line": 17, |
12 | "column": 3 | 12 | "column": 3 |
13 | } | 13 | } |
14 | }, | 14 | }, |
@@ -17,11 +17,11 @@ | |||
17 | "defaultMessage": "!!!Your services", | 17 | "defaultMessage": "!!!Your services", |
18 | "file": "src/components/settings/navigation/SettingsNavigation.js", | 18 | "file": "src/components/settings/navigation/SettingsNavigation.js", |
19 | "start": { | 19 | "start": { |
20 | "line": 17, | 20 | "line": 18, |
21 | "column": 16 | 21 | "column": 16 |
22 | }, | 22 | }, |
23 | "end": { | 23 | "end": { |
24 | "line": 20, | 24 | "line": 21, |
25 | "column": 3 | 25 | "column": 3 |
26 | } | 26 | } |
27 | }, | 27 | }, |
@@ -30,11 +30,11 @@ | |||
30 | "defaultMessage": "!!!Your workspaces", | 30 | "defaultMessage": "!!!Your workspaces", |
31 | "file": "src/components/settings/navigation/SettingsNavigation.js", | 31 | "file": "src/components/settings/navigation/SettingsNavigation.js", |
32 | "start": { | 32 | "start": { |
33 | "line": 21, | 33 | "line": 22, |
34 | "column": 18 | 34 | "column": 18 |
35 | }, | 35 | }, |
36 | "end": { | 36 | "end": { |
37 | "line": 24, | 37 | "line": 25, |
38 | "column": 3 | 38 | "column": 3 |
39 | } | 39 | } |
40 | }, | 40 | }, |
@@ -43,11 +43,11 @@ | |||
43 | "defaultMessage": "!!!Account", | 43 | "defaultMessage": "!!!Account", |
44 | "file": "src/components/settings/navigation/SettingsNavigation.js", | 44 | "file": "src/components/settings/navigation/SettingsNavigation.js", |
45 | "start": { | 45 | "start": { |
46 | "line": 25, | 46 | "line": 26, |
47 | "column": 11 | 47 | "column": 11 |
48 | }, | 48 | }, |
49 | "end": { | 49 | "end": { |
50 | "line": 28, | 50 | "line": 29, |
51 | "column": 3 | 51 | "column": 3 |
52 | } | 52 | } |
53 | }, | 53 | }, |
@@ -56,11 +56,11 @@ | |||
56 | "defaultMessage": "!!!Manage Team", | 56 | "defaultMessage": "!!!Manage Team", |
57 | "file": "src/components/settings/navigation/SettingsNavigation.js", | 57 | "file": "src/components/settings/navigation/SettingsNavigation.js", |
58 | "start": { | 58 | "start": { |
59 | "line": 29, | 59 | "line": 30, |
60 | "column": 8 | 60 | "column": 8 |
61 | }, | 61 | }, |
62 | "end": { | 62 | "end": { |
63 | "line": 32, | 63 | "line": 33, |
64 | "column": 3 | 64 | "column": 3 |
65 | } | 65 | } |
66 | }, | 66 | }, |
@@ -69,11 +69,11 @@ | |||
69 | "defaultMessage": "!!!Settings", | 69 | "defaultMessage": "!!!Settings", |
70 | "file": "src/components/settings/navigation/SettingsNavigation.js", | 70 | "file": "src/components/settings/navigation/SettingsNavigation.js", |
71 | "start": { | 71 | "start": { |
72 | "line": 33, | 72 | "line": 34, |
73 | "column": 12 | 73 | "column": 12 |
74 | }, | 74 | }, |
75 | "end": { | 75 | "end": { |
76 | "line": 36, | 76 | "line": 37, |
77 | "column": 3 | 77 | "column": 3 |
78 | } | 78 | } |
79 | }, | 79 | }, |
@@ -82,11 +82,11 @@ | |||
82 | "defaultMessage": "!!!Invite Friends", | 82 | "defaultMessage": "!!!Invite Friends", |
83 | "file": "src/components/settings/navigation/SettingsNavigation.js", | 83 | "file": "src/components/settings/navigation/SettingsNavigation.js", |
84 | "start": { | 84 | "start": { |
85 | "line": 37, | 85 | "line": 38, |
86 | "column": 17 | 86 | "column": 17 |
87 | }, | 87 | }, |
88 | "end": { | 88 | "end": { |
89 | "line": 40, | 89 | "line": 41, |
90 | "column": 3 | 90 | "column": 3 |
91 | } | 91 | } |
92 | }, | 92 | }, |
@@ -95,11 +95,11 @@ | |||
95 | "defaultMessage": "!!!Logout", | 95 | "defaultMessage": "!!!Logout", |
96 | "file": "src/components/settings/navigation/SettingsNavigation.js", | 96 | "file": "src/components/settings/navigation/SettingsNavigation.js", |
97 | "start": { | 97 | "start": { |
98 | "line": 41, | 98 | "line": 42, |
99 | "column": 10 | 99 | "column": 10 |
100 | }, | 100 | }, |
101 | "end": { | 101 | "end": { |
102 | "line": 44, | 102 | "line": 45, |
103 | "column": 3 | 103 | "column": 3 |
104 | } | 104 | } |
105 | } | 105 | } |
diff --git a/src/i18n/messages/src/components/settings/recipes/RecipesDashboard.json b/src/i18n/messages/src/components/settings/recipes/RecipesDashboard.json index 7d9ed3283..8afaaed50 100644 --- a/src/i18n/messages/src/components/settings/recipes/RecipesDashboard.json +++ b/src/i18n/messages/src/components/settings/recipes/RecipesDashboard.json | |||
@@ -4,11 +4,11 @@ | |||
4 | "defaultMessage": "!!!Available Services", | 4 | "defaultMessage": "!!!Available Services", |
5 | "file": "src/components/settings/recipes/RecipesDashboard.js", | 5 | "file": "src/components/settings/recipes/RecipesDashboard.js", |
6 | "start": { | 6 | "start": { |
7 | "line": 15, | 7 | "line": 20, |
8 | "column": 12 | 8 | "column": 12 |
9 | }, | 9 | }, |
10 | "end": { | 10 | "end": { |
11 | "line": 18, | 11 | "line": 23, |
12 | "column": 3 | 12 | "column": 3 |
13 | } | 13 | } |
14 | }, | 14 | }, |
@@ -17,11 +17,11 @@ | |||
17 | "defaultMessage": "!!!Search service", | 17 | "defaultMessage": "!!!Search service", |
18 | "file": "src/components/settings/recipes/RecipesDashboard.js", | 18 | "file": "src/components/settings/recipes/RecipesDashboard.js", |
19 | "start": { | 19 | "start": { |
20 | "line": 19, | 20 | "line": 24, |
21 | "column": 17 | 21 | "column": 17 |
22 | }, | 22 | }, |
23 | "end": { | 23 | "end": { |
24 | "line": 22, | 24 | "line": 27, |
25 | "column": 3 | 25 | "column": 3 |
26 | } | 26 | } |
27 | }, | 27 | }, |
@@ -30,11 +30,11 @@ | |||
30 | "defaultMessage": "!!!Most popular", | 30 | "defaultMessage": "!!!Most popular", |
31 | "file": "src/components/settings/recipes/RecipesDashboard.js", | 31 | "file": "src/components/settings/recipes/RecipesDashboard.js", |
32 | "start": { | 32 | "start": { |
33 | "line": 23, | 33 | "line": 28, |
34 | "column": 22 | 34 | "column": 22 |
35 | }, | 35 | }, |
36 | "end": { | 36 | "end": { |
37 | "line": 26, | 37 | "line": 31, |
38 | "column": 3 | 38 | "column": 3 |
39 | } | 39 | } |
40 | }, | 40 | }, |
@@ -43,24 +43,24 @@ | |||
43 | "defaultMessage": "!!!All services", | 43 | "defaultMessage": "!!!All services", |
44 | "file": "src/components/settings/recipes/RecipesDashboard.js", | 44 | "file": "src/components/settings/recipes/RecipesDashboard.js", |
45 | "start": { | 45 | "start": { |
46 | "line": 27, | 46 | "line": 32, |
47 | "column": 14 | 47 | "column": 14 |
48 | }, | 48 | }, |
49 | "end": { | 49 | "end": { |
50 | "line": 30, | 50 | "line": 35, |
51 | "column": 3 | 51 | "column": 3 |
52 | } | 52 | } |
53 | }, | 53 | }, |
54 | { | 54 | { |
55 | "id": "settings.recipes.dev", | 55 | "id": "settings.recipes.custom", |
56 | "defaultMessage": "!!!Development", | 56 | "defaultMessage": "!!!Custom Services", |
57 | "file": "src/components/settings/recipes/RecipesDashboard.js", | 57 | "file": "src/components/settings/recipes/RecipesDashboard.js", |
58 | "start": { | 58 | "start": { |
59 | "line": 31, | 59 | "line": 36, |
60 | "column": 14 | 60 | "column": 17 |
61 | }, | 61 | }, |
62 | "end": { | 62 | "end": { |
63 | "line": 34, | 63 | "line": 39, |
64 | "column": 3 | 64 | "column": 3 |
65 | } | 65 | } |
66 | }, | 66 | }, |
@@ -69,11 +69,11 @@ | |||
69 | "defaultMessage": "!!!Sorry, but no service matched your search term.", | 69 | "defaultMessage": "!!!Sorry, but no service matched your search term.", |
70 | "file": "src/components/settings/recipes/RecipesDashboard.js", | 70 | "file": "src/components/settings/recipes/RecipesDashboard.js", |
71 | "start": { | 71 | "start": { |
72 | "line": 35, | 72 | "line": 40, |
73 | "column": 16 | 73 | "column": 16 |
74 | }, | 74 | }, |
75 | "end": { | 75 | "end": { |
76 | "line": 38, | 76 | "line": 43, |
77 | "column": 3 | 77 | "column": 3 |
78 | } | 78 | } |
79 | }, | 79 | }, |
@@ -82,11 +82,11 @@ | |||
82 | "defaultMessage": "!!!Service successfully added", | 82 | "defaultMessage": "!!!Service successfully added", |
83 | "file": "src/components/settings/recipes/RecipesDashboard.js", | 83 | "file": "src/components/settings/recipes/RecipesDashboard.js", |
84 | "start": { | 84 | "start": { |
85 | "line": 39, | 85 | "line": 44, |
86 | "column": 31 | 86 | "column": 31 |
87 | }, | 87 | }, |
88 | "end": { | 88 | "end": { |
89 | "line": 42, | 89 | "line": 47, |
90 | "column": 3 | 90 | "column": 3 |
91 | } | 91 | } |
92 | }, | 92 | }, |
@@ -95,11 +95,89 @@ | |||
95 | "defaultMessage": "!!!Missing a service?", | 95 | "defaultMessage": "!!!Missing a service?", |
96 | "file": "src/components/settings/recipes/RecipesDashboard.js", | 96 | "file": "src/components/settings/recipes/RecipesDashboard.js", |
97 | "start": { | 97 | "start": { |
98 | "line": 43, | 98 | "line": 48, |
99 | "column": 18 | 99 | "column": 18 |
100 | }, | 100 | }, |
101 | "end": { | 101 | "end": { |
102 | "line": 46, | 102 | "line": 51, |
103 | "column": 3 | ||
104 | } | ||
105 | }, | ||
106 | { | ||
107 | "id": "settings.recipes.customService.intro", | ||
108 | "defaultMessage": "!!!To add a custom service, copy the recipe folder into:", | ||
109 | "file": "src/components/settings/recipes/RecipesDashboard.js", | ||
110 | "start": { | ||
111 | "line": 52, | ||
112 | "column": 21 | ||
113 | }, | ||
114 | "end": { | ||
115 | "line": 55, | ||
116 | "column": 3 | ||
117 | } | ||
118 | }, | ||
119 | { | ||
120 | "id": "settings.recipes.customService.openFolder", | ||
121 | "defaultMessage": "!!!Open directory", | ||
122 | "file": "src/components/settings/recipes/RecipesDashboard.js", | ||
123 | "start": { | ||
124 | "line": 56, | ||
125 | "column": 14 | ||
126 | }, | ||
127 | "end": { | ||
128 | "line": 59, | ||
129 | "column": 3 | ||
130 | } | ||
131 | }, | ||
132 | { | ||
133 | "id": "settings.recipes.customService.openDevDocs", | ||
134 | "defaultMessage": "!!!Developer Documentation", | ||
135 | "file": "src/components/settings/recipes/RecipesDashboard.js", | ||
136 | "start": { | ||
137 | "line": 60, | ||
138 | "column": 15 | ||
139 | }, | ||
140 | "end": { | ||
141 | "line": 63, | ||
142 | "column": 3 | ||
143 | } | ||
144 | }, | ||
145 | { | ||
146 | "id": "settings.recipes.customService.headline.customRecipes", | ||
147 | "defaultMessage": "!!!Custom Service Recipes", | ||
148 | "file": "src/components/settings/recipes/RecipesDashboard.js", | ||
149 | "start": { | ||
150 | "line": 64, | ||
151 | "column": 25 | ||
152 | }, | ||
153 | "end": { | ||
154 | "line": 67, | ||
155 | "column": 3 | ||
156 | } | ||
157 | }, | ||
158 | { | ||
159 | "id": "settings.recipes.customService.headline.communityRecipes", | ||
160 | "defaultMessage": "!!!Community Services", | ||
161 | "file": "src/components/settings/recipes/RecipesDashboard.js", | ||
162 | "start": { | ||
163 | "line": 68, | ||
164 | "column": 28 | ||
165 | }, | ||
166 | "end": { | ||
167 | "line": 71, | ||
168 | "column": 3 | ||
169 | } | ||
170 | }, | ||
171 | { | ||
172 | "id": "settings.recipes.customService.headline.devRecipes", | ||
173 | "defaultMessage": "!!!Your Development Service Recipes", | ||
174 | "file": "src/components/settings/recipes/RecipesDashboard.js", | ||
175 | "start": { | ||
176 | "line": 72, | ||
177 | "column": 22 | ||
178 | }, | ||
179 | "end": { | ||
180 | "line": 75, | ||
103 | "column": 3 | 181 | "column": 3 |
104 | } | 182 | } |
105 | } | 183 | } |
diff --git a/src/i18n/messages/src/components/settings/services/EditServiceForm.json b/src/i18n/messages/src/components/settings/services/EditServiceForm.json index 42b741b7a..e66db807d 100644 --- a/src/i18n/messages/src/components/settings/services/EditServiceForm.json +++ b/src/i18n/messages/src/components/settings/services/EditServiceForm.json | |||
@@ -4,11 +4,11 @@ | |||
4 | "defaultMessage": "!!!Save service", | 4 | "defaultMessage": "!!!Save service", |
5 | "file": "src/components/settings/services/EditServiceForm.js", | 5 | "file": "src/components/settings/services/EditServiceForm.js", |
6 | "start": { | 6 | "start": { |
7 | "line": 22, | 7 | "line": 24, |
8 | "column": 15 | 8 | "column": 15 |
9 | }, | 9 | }, |
10 | "end": { | 10 | "end": { |
11 | "line": 25, | 11 | "line": 27, |
12 | "column": 3 | 12 | "column": 3 |
13 | } | 13 | } |
14 | }, | 14 | }, |
@@ -17,11 +17,11 @@ | |||
17 | "defaultMessage": "!!!Delete Service", | 17 | "defaultMessage": "!!!Delete Service", |
18 | "file": "src/components/settings/services/EditServiceForm.js", | 18 | "file": "src/components/settings/services/EditServiceForm.js", |
19 | "start": { | 19 | "start": { |
20 | "line": 26, | 20 | "line": 28, |
21 | "column": 17 | 21 | "column": 17 |
22 | }, | 22 | }, |
23 | "end": { | 23 | "end": { |
24 | "line": 29, | 24 | "line": 31, |
25 | "column": 3 | 25 | "column": 3 |
26 | } | 26 | } |
27 | }, | 27 | }, |
@@ -30,11 +30,11 @@ | |||
30 | "defaultMessage": "!!!Available services", | 30 | "defaultMessage": "!!!Available services", |
31 | "file": "src/components/settings/services/EditServiceForm.js", | 31 | "file": "src/components/settings/services/EditServiceForm.js", |
32 | "start": { | 32 | "start": { |
33 | "line": 30, | 33 | "line": 32, |
34 | "column": 21 | 34 | "column": 21 |
35 | }, | 35 | }, |
36 | "end": { | 36 | "end": { |
37 | "line": 33, | 37 | "line": 35, |
38 | "column": 3 | 38 | "column": 3 |
39 | } | 39 | } |
40 | }, | 40 | }, |
@@ -43,11 +43,11 @@ | |||
43 | "defaultMessage": "!!!Your services", | 43 | "defaultMessage": "!!!Your services", |
44 | "file": "src/components/settings/services/EditServiceForm.js", | 44 | "file": "src/components/settings/services/EditServiceForm.js", |
45 | "start": { | 45 | "start": { |
46 | "line": 34, | 46 | "line": 36, |
47 | "column": 16 | 47 | "column": 16 |
48 | }, | 48 | }, |
49 | "end": { | 49 | "end": { |
50 | "line": 37, | 50 | "line": 39, |
51 | "column": 3 | 51 | "column": 3 |
52 | } | 52 | } |
53 | }, | 53 | }, |
@@ -56,11 +56,11 @@ | |||
56 | "defaultMessage": "!!!Add {name}", | 56 | "defaultMessage": "!!!Add {name}", |
57 | "file": "src/components/settings/services/EditServiceForm.js", | 57 | "file": "src/components/settings/services/EditServiceForm.js", |
58 | "start": { | 58 | "start": { |
59 | "line": 38, | 59 | "line": 40, |
60 | "column": 22 | 60 | "column": 22 |
61 | }, | 61 | }, |
62 | "end": { | 62 | "end": { |
63 | "line": 41, | 63 | "line": 43, |
64 | "column": 3 | 64 | "column": 3 |
65 | } | 65 | } |
66 | }, | 66 | }, |
@@ -69,11 +69,11 @@ | |||
69 | "defaultMessage": "!!!Edit {name}", | 69 | "defaultMessage": "!!!Edit {name}", |
70 | "file": "src/components/settings/services/EditServiceForm.js", | 70 | "file": "src/components/settings/services/EditServiceForm.js", |
71 | "start": { | 71 | "start": { |
72 | "line": 42, | 72 | "line": 44, |
73 | "column": 23 | 73 | "column": 23 |
74 | }, | 74 | }, |
75 | "end": { | 75 | "end": { |
76 | "line": 45, | 76 | "line": 47, |
77 | "column": 3 | 77 | "column": 3 |
78 | } | 78 | } |
79 | }, | 79 | }, |
@@ -82,11 +82,11 @@ | |||
82 | "defaultMessage": "!!!Hosted", | 82 | "defaultMessage": "!!!Hosted", |
83 | "file": "src/components/settings/services/EditServiceForm.js", | 83 | "file": "src/components/settings/services/EditServiceForm.js", |
84 | "start": { | 84 | "start": { |
85 | "line": 46, | 85 | "line": 48, |
86 | "column": 13 | 86 | "column": 13 |
87 | }, | 87 | }, |
88 | "end": { | 88 | "end": { |
89 | "line": 49, | 89 | "line": 51, |
90 | "column": 3 | 90 | "column": 3 |
91 | } | 91 | } |
92 | }, | 92 | }, |
@@ -95,11 +95,11 @@ | |||
95 | "defaultMessage": "!!!Self hosted ⭐️", | 95 | "defaultMessage": "!!!Self hosted ⭐️", |
96 | "file": "src/components/settings/services/EditServiceForm.js", | 96 | "file": "src/components/settings/services/EditServiceForm.js", |
97 | "start": { | 97 | "start": { |
98 | "line": 50, | 98 | "line": 52, |
99 | "column": 16 | 99 | "column": 16 |
100 | }, | 100 | }, |
101 | "end": { | 101 | "end": { |
102 | "line": 53, | 102 | "line": 55, |
103 | "column": 3 | 103 | "column": 3 |
104 | } | 104 | } |
105 | }, | 105 | }, |
@@ -108,11 +108,11 @@ | |||
108 | "defaultMessage": "!!!Use the hosted {name} service.", | 108 | "defaultMessage": "!!!Use the hosted {name} service.", |
109 | "file": "src/components/settings/services/EditServiceForm.js", | 109 | "file": "src/components/settings/services/EditServiceForm.js", |
110 | "start": { | 110 | "start": { |
111 | "line": 54, | 111 | "line": 56, |
112 | "column": 20 | 112 | "column": 20 |
113 | }, | 113 | }, |
114 | "end": { | 114 | "end": { |
115 | "line": 57, | 115 | "line": 59, |
116 | "column": 3 | 116 | "column": 3 |
117 | } | 117 | } |
118 | }, | 118 | }, |
@@ -121,11 +121,11 @@ | |||
121 | "defaultMessage": "!!!Could not validate custom {name} server.", | 121 | "defaultMessage": "!!!Could not validate custom {name} server.", |
122 | "file": "src/components/settings/services/EditServiceForm.js", | 122 | "file": "src/components/settings/services/EditServiceForm.js", |
123 | "start": { | 123 | "start": { |
124 | "line": 58, | 124 | "line": 60, |
125 | "column": 28 | 125 | "column": 28 |
126 | }, | 126 | }, |
127 | "end": { | 127 | "end": { |
128 | "line": 61, | 128 | "line": 63, |
129 | "column": 3 | 129 | "column": 3 |
130 | } | 130 | } |
131 | }, | 131 | }, |
@@ -134,11 +134,11 @@ | |||
134 | "defaultMessage": "!!!To add self hosted services, you need a Franz Premium Supporter Account.", | 134 | "defaultMessage": "!!!To add self hosted services, you need a Franz Premium Supporter Account.", |
135 | "file": "src/components/settings/services/EditServiceForm.js", | 135 | "file": "src/components/settings/services/EditServiceForm.js", |
136 | "start": { | 136 | "start": { |
137 | "line": 62, | 137 | "line": 64, |
138 | "column": 24 | 138 | "column": 24 |
139 | }, | 139 | }, |
140 | "end": { | 140 | "end": { |
141 | "line": 65, | 141 | "line": 67, |
142 | "column": 3 | 142 | "column": 3 |
143 | } | 143 | } |
144 | }, | 144 | }, |
@@ -147,11 +147,11 @@ | |||
147 | "defaultMessage": "!!!Upgrade your account", | 147 | "defaultMessage": "!!!Upgrade your account", |
148 | "file": "src/components/settings/services/EditServiceForm.js", | 148 | "file": "src/components/settings/services/EditServiceForm.js", |
149 | "start": { | 149 | "start": { |
150 | "line": 66, | 150 | "line": 68, |
151 | "column": 27 | 151 | "column": 27 |
152 | }, | 152 | }, |
153 | "end": { | 153 | "end": { |
154 | "line": 69, | 154 | "line": 71, |
155 | "column": 3 | 155 | "column": 3 |
156 | } | 156 | } |
157 | }, | 157 | }, |
@@ -160,11 +160,11 @@ | |||
160 | "defaultMessage": "!!!You will be notified about all new messages in a channel, not just @username, @channel, @here, ...", | 160 | "defaultMessage": "!!!You will be notified about all new messages in a channel, not just @username, @channel, @here, ...", |
161 | "file": "src/components/settings/services/EditServiceForm.js", | 161 | "file": "src/components/settings/services/EditServiceForm.js", |
162 | "start": { | 162 | "start": { |
163 | "line": 70, | 163 | "line": 72, |
164 | "column": 23 | 164 | "column": 23 |
165 | }, | 165 | }, |
166 | "end": { | 166 | "end": { |
167 | "line": 73, | 167 | "line": 75, |
168 | "column": 3 | 168 | "column": 3 |
169 | } | 169 | } |
170 | }, | 170 | }, |
@@ -173,11 +173,11 @@ | |||
173 | "defaultMessage": "!!!When disabled, all notification sounds and audio playback are muted", | 173 | "defaultMessage": "!!!When disabled, all notification sounds and audio playback are muted", |
174 | "file": "src/components/settings/services/EditServiceForm.js", | 174 | "file": "src/components/settings/services/EditServiceForm.js", |
175 | "start": { | 175 | "start": { |
176 | "line": 74, | 176 | "line": 76, |
177 | "column": 15 | 177 | "column": 15 |
178 | }, | 178 | }, |
179 | "end": { | 179 | "end": { |
180 | "line": 77, | 180 | "line": 79, |
181 | "column": 3 | 181 | "column": 3 |
182 | } | 182 | } |
183 | }, | 183 | }, |
@@ -186,11 +186,11 @@ | |||
186 | "defaultMessage": "!!!Notifications", | 186 | "defaultMessage": "!!!Notifications", |
187 | "file": "src/components/settings/services/EditServiceForm.js", | 187 | "file": "src/components/settings/services/EditServiceForm.js", |
188 | "start": { | 188 | "start": { |
189 | "line": 78, | 189 | "line": 80, |
190 | "column": 25 | 190 | "column": 25 |
191 | }, | 191 | }, |
192 | "end": { | 192 | "end": { |
193 | "line": 81, | 193 | "line": 83, |
194 | "column": 3 | 194 | "column": 3 |
195 | } | 195 | } |
196 | }, | 196 | }, |
@@ -199,11 +199,11 @@ | |||
199 | "defaultMessage": "!!!Unread message badges", | 199 | "defaultMessage": "!!!Unread message badges", |
200 | "file": "src/components/settings/services/EditServiceForm.js", | 200 | "file": "src/components/settings/services/EditServiceForm.js", |
201 | "start": { | 201 | "start": { |
202 | "line": 82, | 202 | "line": 84, |
203 | "column": 18 | 203 | "column": 18 |
204 | }, | 204 | }, |
205 | "end": { | 205 | "end": { |
206 | "line": 85, | 206 | "line": 87, |
207 | "column": 3 | 207 | "column": 3 |
208 | } | 208 | } |
209 | }, | 209 | }, |
@@ -212,11 +212,11 @@ | |||
212 | "defaultMessage": "!!!General", | 212 | "defaultMessage": "!!!General", |
213 | "file": "src/components/settings/services/EditServiceForm.js", | 213 | "file": "src/components/settings/services/EditServiceForm.js", |
214 | "start": { | 214 | "start": { |
215 | "line": 86, | 215 | "line": 88, |
216 | "column": 19 | 216 | "column": 19 |
217 | }, | 217 | }, |
218 | "end": { | 218 | "end": { |
219 | "line": 89, | 219 | "line": 91, |
220 | "column": 3 | 220 | "column": 3 |
221 | } | 221 | } |
222 | }, | 222 | }, |
@@ -225,11 +225,11 @@ | |||
225 | "defaultMessage": "!!!Delete", | 225 | "defaultMessage": "!!!Delete", |
226 | "file": "src/components/settings/services/EditServiceForm.js", | 226 | "file": "src/components/settings/services/EditServiceForm.js", |
227 | "start": { | 227 | "start": { |
228 | "line": 90, | 228 | "line": 92, |
229 | "column": 14 | 229 | "column": 14 |
230 | }, | 230 | }, |
231 | "end": { | 231 | "end": { |
232 | "line": 93, | 232 | "line": 95, |
233 | "column": 3 | 233 | "column": 3 |
234 | } | 234 | } |
235 | }, | 235 | }, |
@@ -238,11 +238,11 @@ | |||
238 | "defaultMessage": "!!!Drop your image, or click here", | 238 | "defaultMessage": "!!!Drop your image, or click here", |
239 | "file": "src/components/settings/services/EditServiceForm.js", | 239 | "file": "src/components/settings/services/EditServiceForm.js", |
240 | "start": { | 240 | "start": { |
241 | "line": 94, | 241 | "line": 96, |
242 | "column": 14 | 242 | "column": 14 |
243 | }, | 243 | }, |
244 | "end": { | 244 | "end": { |
245 | "line": 97, | 245 | "line": 99, |
246 | "column": 3 | 246 | "column": 3 |
247 | } | 247 | } |
248 | }, | 248 | }, |
@@ -251,11 +251,11 @@ | |||
251 | "defaultMessage": "!!!HTTP/HTTPS Proxy Settings", | 251 | "defaultMessage": "!!!HTTP/HTTPS Proxy Settings", |
252 | "file": "src/components/settings/services/EditServiceForm.js", | 252 | "file": "src/components/settings/services/EditServiceForm.js", |
253 | "start": { | 253 | "start": { |
254 | "line": 98, | 254 | "line": 100, |
255 | "column": 17 | 255 | "column": 17 |
256 | }, | 256 | }, |
257 | "end": { | 257 | "end": { |
258 | "line": 101, | 258 | "line": 103, |
259 | "column": 3 | 259 | "column": 3 |
260 | } | 260 | } |
261 | }, | 261 | }, |
@@ -264,11 +264,11 @@ | |||
264 | "defaultMessage": "!!!Please restart Franz after changing proxy Settings.", | 264 | "defaultMessage": "!!!Please restart Franz after changing proxy Settings.", |
265 | "file": "src/components/settings/services/EditServiceForm.js", | 265 | "file": "src/components/settings/services/EditServiceForm.js", |
266 | "start": { | 266 | "start": { |
267 | "line": 102, | 267 | "line": 104, |
268 | "column": 20 | 268 | "column": 20 |
269 | }, | 269 | }, |
270 | "end": { | 270 | "end": { |
271 | "line": 105, | 271 | "line": 107, |
272 | "column": 3 | 272 | "column": 3 |
273 | } | 273 | } |
274 | }, | 274 | }, |
@@ -277,11 +277,11 @@ | |||
277 | "defaultMessage": "!!!Proxy settings will not be synchronized with the Franz servers.", | 277 | "defaultMessage": "!!!Proxy settings will not be synchronized with the Franz servers.", |
278 | "file": "src/components/settings/services/EditServiceForm.js", | 278 | "file": "src/components/settings/services/EditServiceForm.js", |
279 | "start": { | 279 | "start": { |
280 | "line": 106, | 280 | "line": 108, |
281 | "column": 13 | 281 | "column": 13 |
282 | }, | 282 | }, |
283 | "end": { | 283 | "end": { |
284 | "line": 109, | 284 | "line": 111, |
285 | "column": 3 | 285 | "column": 3 |
286 | } | 286 | } |
287 | } | 287 | } |
diff --git a/src/i18n/messages/src/components/settings/services/ServicesDashboard.json b/src/i18n/messages/src/components/settings/services/ServicesDashboard.json index 3803c6512..fa661ea2f 100644 --- a/src/i18n/messages/src/components/settings/services/ServicesDashboard.json +++ b/src/i18n/messages/src/components/settings/services/ServicesDashboard.json | |||
@@ -4,11 +4,11 @@ | |||
4 | "defaultMessage": "!!!Your services", | 4 | "defaultMessage": "!!!Your services", |
5 | "file": "src/components/settings/services/ServicesDashboard.js", | 5 | "file": "src/components/settings/services/ServicesDashboard.js", |
6 | "start": { | 6 | "start": { |
7 | "line": 14, | 7 | "line": 15, |
8 | "column": 12 | 8 | "column": 12 |
9 | }, | 9 | }, |
10 | "end": { | 10 | "end": { |
11 | "line": 17, | 11 | "line": 18, |
12 | "column": 3 | 12 | "column": 3 |
13 | } | 13 | } |
14 | }, | 14 | }, |
@@ -17,11 +17,11 @@ | |||
17 | "defaultMessage": "!!!Search service", | 17 | "defaultMessage": "!!!Search service", |
18 | "file": "src/components/settings/services/ServicesDashboard.js", | 18 | "file": "src/components/settings/services/ServicesDashboard.js", |
19 | "start": { | 19 | "start": { |
20 | "line": 18, | 20 | "line": 19, |
21 | "column": 17 | 21 | "column": 17 |
22 | }, | 22 | }, |
23 | "end": { | 23 | "end": { |
24 | "line": 21, | 24 | "line": 22, |
25 | "column": 3 | 25 | "column": 3 |
26 | } | 26 | } |
27 | }, | 27 | }, |
@@ -30,11 +30,11 @@ | |||
30 | "defaultMessage": "!!!You haven't added any services yet.", | 30 | "defaultMessage": "!!!You haven't added any services yet.", |
31 | "file": "src/components/settings/services/ServicesDashboard.js", | 31 | "file": "src/components/settings/services/ServicesDashboard.js", |
32 | "start": { | 32 | "start": { |
33 | "line": 22, | 33 | "line": 23, |
34 | "column": 19 | 34 | "column": 19 |
35 | }, | 35 | }, |
36 | "end": { | 36 | "end": { |
37 | "line": 25, | 37 | "line": 26, |
38 | "column": 3 | 38 | "column": 3 |
39 | } | 39 | } |
40 | }, | 40 | }, |
@@ -43,11 +43,11 @@ | |||
43 | "defaultMessage": "!!!Sorry, but no service matched your search term.", | 43 | "defaultMessage": "!!!Sorry, but no service matched your search term.", |
44 | "file": "src/components/settings/services/ServicesDashboard.js", | 44 | "file": "src/components/settings/services/ServicesDashboard.js", |
45 | "start": { | 45 | "start": { |
46 | "line": 26, | 46 | "line": 27, |
47 | "column": 18 | 47 | "column": 18 |
48 | }, | 48 | }, |
49 | "end": { | 49 | "end": { |
50 | "line": 29, | 50 | "line": 30, |
51 | "column": 3 | 51 | "column": 3 |
52 | } | 52 | } |
53 | }, | 53 | }, |
@@ -56,11 +56,11 @@ | |||
56 | "defaultMessage": "!!!Discover services", | 56 | "defaultMessage": "!!!Discover services", |
57 | "file": "src/components/settings/services/ServicesDashboard.js", | 57 | "file": "src/components/settings/services/ServicesDashboard.js", |
58 | "start": { | 58 | "start": { |
59 | "line": 30, | 59 | "line": 31, |
60 | "column": 20 | 60 | "column": 20 |
61 | }, | 61 | }, |
62 | "end": { | 62 | "end": { |
63 | "line": 33, | 63 | "line": 34, |
64 | "column": 3 | 64 | "column": 3 |
65 | } | 65 | } |
66 | }, | 66 | }, |
@@ -69,11 +69,11 @@ | |||
69 | "defaultMessage": "!!!Could not load your services", | 69 | "defaultMessage": "!!!Could not load your services", |
70 | "file": "src/components/settings/services/ServicesDashboard.js", | 70 | "file": "src/components/settings/services/ServicesDashboard.js", |
71 | "start": { | 71 | "start": { |
72 | "line": 34, | 72 | "line": 35, |
73 | "column": 25 | 73 | "column": 25 |
74 | }, | 74 | }, |
75 | "end": { | 75 | "end": { |
76 | "line": 37, | 76 | "line": 38, |
77 | "column": 3 | 77 | "column": 3 |
78 | } | 78 | } |
79 | }, | 79 | }, |
@@ -82,11 +82,11 @@ | |||
82 | "defaultMessage": "!!!Try again", | 82 | "defaultMessage": "!!!Try again", |
83 | "file": "src/components/settings/services/ServicesDashboard.js", | 83 | "file": "src/components/settings/services/ServicesDashboard.js", |
84 | "start": { | 84 | "start": { |
85 | "line": 38, | 85 | "line": 39, |
86 | "column": 21 | 86 | "column": 21 |
87 | }, | 87 | }, |
88 | "end": { | 88 | "end": { |
89 | "line": 41, | 89 | "line": 42, |
90 | "column": 3 | 90 | "column": 3 |
91 | } | 91 | } |
92 | }, | 92 | }, |
@@ -95,11 +95,11 @@ | |||
95 | "defaultMessage": "!!!Your changes have been saved", | 95 | "defaultMessage": "!!!Your changes have been saved", |
96 | "file": "src/components/settings/services/ServicesDashboard.js", | 96 | "file": "src/components/settings/services/ServicesDashboard.js", |
97 | "start": { | 97 | "start": { |
98 | "line": 42, | 98 | "line": 43, |
99 | "column": 15 | 99 | "column": 15 |
100 | }, | 100 | }, |
101 | "end": { | 101 | "end": { |
102 | "line": 45, | 102 | "line": 46, |
103 | "column": 3 | 103 | "column": 3 |
104 | } | 104 | } |
105 | }, | 105 | }, |
@@ -108,11 +108,11 @@ | |||
108 | "defaultMessage": "!!!Service has been deleted", | 108 | "defaultMessage": "!!!Service has been deleted", |
109 | "file": "src/components/settings/services/ServicesDashboard.js", | 109 | "file": "src/components/settings/services/ServicesDashboard.js", |
110 | "start": { | 110 | "start": { |
111 | "line": 46, | 111 | "line": 47, |
112 | "column": 15 | 112 | "column": 15 |
113 | }, | 113 | }, |
114 | "end": { | 114 | "end": { |
115 | "line": 49, | 115 | "line": 50, |
116 | "column": 3 | 116 | "column": 3 |
117 | } | 117 | } |
118 | } | 118 | } |
diff --git a/src/i18n/messages/src/components/subscription/SubscriptionForm.json b/src/i18n/messages/src/components/subscription/SubscriptionForm.json index f98eb986f..224a78c4c 100644 --- a/src/i18n/messages/src/components/subscription/SubscriptionForm.json +++ b/src/i18n/messages/src/components/subscription/SubscriptionForm.json | |||
@@ -1,7 +1,7 @@ | |||
1 | [ | 1 | [ |
2 | { | 2 | { |
3 | "id": "subscription.submit.label", | 3 | "id": "subscription.cta.activateTrial", |
4 | "defaultMessage": "!!!Support the development of Franz", | 4 | "defaultMessage": "!!!Yes, upgrade my account to Franz Professional", |
5 | "file": "src/components/subscription/SubscriptionForm.js", | 5 | "file": "src/components/subscription/SubscriptionForm.js", |
6 | "start": { | 6 | "start": { |
7 | "line": 14, | 7 | "line": 14, |
@@ -13,12 +13,12 @@ | |||
13 | } | 13 | } |
14 | }, | 14 | }, |
15 | { | 15 | { |
16 | "id": "subscription.paymentSessionError", | 16 | "id": "subscription.includedProFeatures", |
17 | "defaultMessage": "!!!Could not initialize payment form", | 17 | "defaultMessage": "!!!The Franz Professional Plan includes:", |
18 | "file": "src/components/subscription/SubscriptionForm.js", | 18 | "file": "src/components/subscription/SubscriptionForm.js", |
19 | "start": { | 19 | "start": { |
20 | "line": 18, | 20 | "line": 18, |
21 | "column": 23 | 21 | "column": 20 |
22 | }, | 22 | }, |
23 | "end": { | 23 | "end": { |
24 | "line": 21, | 24 | "line": 21, |
@@ -26,12 +26,12 @@ | |||
26 | } | 26 | } |
27 | }, | 27 | }, |
28 | { | 28 | { |
29 | "id": "subscription.type.free", | 29 | "id": "pricing.trial.terms.headline", |
30 | "defaultMessage": "!!!free", | 30 | "defaultMessage": "!!!No strings attached", |
31 | "file": "src/components/subscription/SubscriptionForm.js", | 31 | "file": "src/components/subscription/SubscriptionForm.js", |
32 | "start": { | 32 | "start": { |
33 | "line": 22, | 33 | "line": 22, |
34 | "column": 12 | 34 | "column": 29 |
35 | }, | 35 | }, |
36 | "end": { | 36 | "end": { |
37 | "line": 25, | 37 | "line": 25, |
@@ -39,12 +39,12 @@ | |||
39 | } | 39 | } |
40 | }, | 40 | }, |
41 | { | 41 | { |
42 | "id": "subscription.type.month", | 42 | "id": "pricing.trial.terms.noCreditCard", |
43 | "defaultMessage": "!!!month", | 43 | "defaultMessage": "!!!No credit card required", |
44 | "file": "src/components/subscription/SubscriptionForm.js", | 44 | "file": "src/components/subscription/SubscriptionForm.js", |
45 | "start": { | 45 | "start": { |
46 | "line": 26, | 46 | "line": 26, |
47 | "column": 15 | 47 | "column": 16 |
48 | }, | 48 | }, |
49 | "end": { | 49 | "end": { |
50 | "line": 29, | 50 | "line": 29, |
@@ -52,133 +52,16 @@ | |||
52 | } | 52 | } |
53 | }, | 53 | }, |
54 | { | 54 | { |
55 | "id": "subscription.type.year", | 55 | "id": "pricing.trial.terms.automaticTrialEnd", |
56 | "defaultMessage": "!!!year", | 56 | "defaultMessage": "!!!Your free trial ends automatically after 14 days", |
57 | "file": "src/components/subscription/SubscriptionForm.js", | 57 | "file": "src/components/subscription/SubscriptionForm.js", |
58 | "start": { | 58 | "start": { |
59 | "line": 30, | 59 | "line": 30, |
60 | "column": 14 | 60 | "column": 21 |
61 | }, | 61 | }, |
62 | "end": { | 62 | "end": { |
63 | "line": 33, | 63 | "line": 33, |
64 | "column": 3 | 64 | "column": 3 |
65 | } | 65 | } |
66 | }, | ||
67 | { | ||
68 | "id": "subscription.includedFeatures", | ||
69 | "defaultMessage": "!!!The Franz Premium Supporter Account includes", | ||
70 | "file": "src/components/subscription/SubscriptionForm.js", | ||
71 | "start": { | ||
72 | "line": 34, | ||
73 | "column": 20 | ||
74 | }, | ||
75 | "end": { | ||
76 | "line": 37, | ||
77 | "column": 3 | ||
78 | } | ||
79 | }, | ||
80 | { | ||
81 | "id": "subscription.features.onpremise.mattermost", | ||
82 | "defaultMessage": "!!!Add on-premise/hosted services like Mattermost", | ||
83 | "file": "src/components/subscription/SubscriptionForm.js", | ||
84 | "start": { | ||
85 | "line": 38, | ||
86 | "column": 13 | ||
87 | }, | ||
88 | "end": { | ||
89 | "line": 41, | ||
90 | "column": 3 | ||
91 | } | ||
92 | }, | ||
93 | { | ||
94 | "id": "subscription.features.noInterruptions", | ||
95 | "defaultMessage": "!!!No app delays & nagging to upgrade license", | ||
96 | "file": "src/components/subscription/SubscriptionForm.js", | ||
97 | "start": { | ||
98 | "line": 42, | ||
99 | "column": 19 | ||
100 | }, | ||
101 | "end": { | ||
102 | "line": 45, | ||
103 | "column": 3 | ||
104 | } | ||
105 | }, | ||
106 | { | ||
107 | "id": "subscription.features.proxy", | ||
108 | "defaultMessage": "!!!Proxy support for services", | ||
109 | "file": "src/components/subscription/SubscriptionForm.js", | ||
110 | "start": { | ||
111 | "line": 46, | ||
112 | "column": 9 | ||
113 | }, | ||
114 | "end": { | ||
115 | "line": 49, | ||
116 | "column": 3 | ||
117 | } | ||
118 | }, | ||
119 | { | ||
120 | "id": "subscription.features.spellchecker", | ||
121 | "defaultMessage": "!!!Support for Spellchecker", | ||
122 | "file": "src/components/subscription/SubscriptionForm.js", | ||
123 | "start": { | ||
124 | "line": 50, | ||
125 | "column": 16 | ||
126 | }, | ||
127 | "end": { | ||
128 | "line": 53, | ||
129 | "column": 3 | ||
130 | } | ||
131 | }, | ||
132 | { | ||
133 | "id": "subscription.features.workspaces", | ||
134 | "defaultMessage": "!!!Organize your services in workspaces", | ||
135 | "file": "src/components/subscription/SubscriptionForm.js", | ||
136 | "start": { | ||
137 | "line": 54, | ||
138 | "column": 14 | ||
139 | }, | ||
140 | "end": { | ||
141 | "line": 57, | ||
142 | "column": 3 | ||
143 | } | ||
144 | }, | ||
145 | { | ||
146 | "id": "subscription.features.ads", | ||
147 | "defaultMessage": "!!!No ads, ever!", | ||
148 | "file": "src/components/subscription/SubscriptionForm.js", | ||
149 | "start": { | ||
150 | "line": 58, | ||
151 | "column": 7 | ||
152 | }, | ||
153 | "end": { | ||
154 | "line": 61, | ||
155 | "column": 3 | ||
156 | } | ||
157 | }, | ||
158 | { | ||
159 | "id": "subscription.features.comingSoon", | ||
160 | "defaultMessage": "!!!coming soon", | ||
161 | "file": "src/components/subscription/SubscriptionForm.js", | ||
162 | "start": { | ||
163 | "line": 62, | ||
164 | "column": 14 | ||
165 | }, | ||
166 | "end": { | ||
167 | "line": 65, | ||
168 | "column": 3 | ||
169 | } | ||
170 | }, | ||
171 | { | ||
172 | "id": "subscription.euTaxInfo", | ||
173 | "defaultMessage": "!!!EU residents: local sales tax may apply", | ||
174 | "file": "src/components/subscription/SubscriptionForm.js", | ||
175 | "start": { | ||
176 | "line": 66, | ||
177 | "column": 13 | ||
178 | }, | ||
179 | "end": { | ||
180 | "line": 69, | ||
181 | "column": 3 | ||
182 | } | ||
183 | } | 66 | } |
184 | ] \ No newline at end of file | 67 | ] \ No newline at end of file |
diff --git a/src/i18n/messages/src/components/ui/FeatureList.json b/src/i18n/messages/src/components/ui/FeatureList.json new file mode 100644 index 000000000..497e299a4 --- /dev/null +++ b/src/i18n/messages/src/components/ui/FeatureList.json | |||
@@ -0,0 +1,132 @@ | |||
1 | [ | ||
2 | { | ||
3 | "id": "pricing.features.unlimitedServices", | ||
4 | "defaultMessage": "!!!Add unlimited services", | ||
5 | "file": "src/components/ui/FeatureList.js", | ||
6 | "start": { | ||
7 | "line": 8, | ||
8 | "column": 21 | ||
9 | }, | ||
10 | "end": { | ||
11 | "line": 11, | ||
12 | "column": 3 | ||
13 | } | ||
14 | }, | ||
15 | { | ||
16 | "id": "pricing.features.spellchecker", | ||
17 | "defaultMessage": "!!!Spellchecker support", | ||
18 | "file": "src/components/ui/FeatureList.js", | ||
19 | "start": { | ||
20 | "line": 12, | ||
21 | "column": 16 | ||
22 | }, | ||
23 | "end": { | ||
24 | "line": 15, | ||
25 | "column": 3 | ||
26 | } | ||
27 | }, | ||
28 | { | ||
29 | "id": "pricing.features.workspaces", | ||
30 | "defaultMessage": "!!!Workspaces", | ||
31 | "file": "src/components/ui/FeatureList.js", | ||
32 | "start": { | ||
33 | "line": 16, | ||
34 | "column": 14 | ||
35 | }, | ||
36 | "end": { | ||
37 | "line": 19, | ||
38 | "column": 3 | ||
39 | } | ||
40 | }, | ||
41 | { | ||
42 | "id": "pricing.features.customWebsites", | ||
43 | "defaultMessage": "!!!Add Custom Websites", | ||
44 | "file": "src/components/ui/FeatureList.js", | ||
45 | "start": { | ||
46 | "line": 20, | ||
47 | "column": 18 | ||
48 | }, | ||
49 | "end": { | ||
50 | "line": 23, | ||
51 | "column": 3 | ||
52 | } | ||
53 | }, | ||
54 | { | ||
55 | "id": "pricing.features.onPremise", | ||
56 | "defaultMessage": "!!!On-premise & other Hosted Services", | ||
57 | "file": "src/components/ui/FeatureList.js", | ||
58 | "start": { | ||
59 | "line": 24, | ||
60 | "column": 13 | ||
61 | }, | ||
62 | "end": { | ||
63 | "line": 27, | ||
64 | "column": 3 | ||
65 | } | ||
66 | }, | ||
67 | { | ||
68 | "id": "pricing.features.thirdPartyServices", | ||
69 | "defaultMessage": "!!!Install 3rd party services", | ||
70 | "file": "src/components/ui/FeatureList.js", | ||
71 | "start": { | ||
72 | "line": 28, | ||
73 | "column": 22 | ||
74 | }, | ||
75 | "end": { | ||
76 | "line": 31, | ||
77 | "column": 3 | ||
78 | } | ||
79 | }, | ||
80 | { | ||
81 | "id": "pricing.features.serviceProxies", | ||
82 | "defaultMessage": "!!!Service Proxies", | ||
83 | "file": "src/components/ui/FeatureList.js", | ||
84 | "start": { | ||
85 | "line": 32, | ||
86 | "column": 18 | ||
87 | }, | ||
88 | "end": { | ||
89 | "line": 35, | ||
90 | "column": 3 | ||
91 | } | ||
92 | }, | ||
93 | { | ||
94 | "id": "pricing.features.teamManagement", | ||
95 | "defaultMessage": "!!!Team Management", | ||
96 | "file": "src/components/ui/FeatureList.js", | ||
97 | "start": { | ||
98 | "line": 36, | ||
99 | "column": 18 | ||
100 | }, | ||
101 | "end": { | ||
102 | "line": 39, | ||
103 | "column": 3 | ||
104 | } | ||
105 | }, | ||
106 | { | ||
107 | "id": "pricing.features.appDelays", | ||
108 | "defaultMessage": "!!!No Waiting Screens", | ||
109 | "file": "src/components/ui/FeatureList.js", | ||
110 | "start": { | ||
111 | "line": 40, | ||
112 | "column": 13 | ||
113 | }, | ||
114 | "end": { | ||
115 | "line": 43, | ||
116 | "column": 3 | ||
117 | } | ||
118 | }, | ||
119 | { | ||
120 | "id": "pricing.features.adFree", | ||
121 | "defaultMessage": "!!!Forever ad-free", | ||
122 | "file": "src/components/ui/FeatureList.js", | ||
123 | "start": { | ||
124 | "line": 44, | ||
125 | "column": 10 | ||
126 | }, | ||
127 | "end": { | ||
128 | "line": 47, | ||
129 | "column": 3 | ||
130 | } | ||
131 | } | ||
132 | ] \ No newline at end of file | ||
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/i18n/messages/src/features/serviceLimit/components/AnnouncementScreen.json b/src/i18n/messages/src/features/serviceLimit/components/AnnouncementScreen.json new file mode 100644 index 000000000..e6e3cef99 --- /dev/null +++ b/src/i18n/messages/src/features/serviceLimit/components/AnnouncementScreen.json | |||
@@ -0,0 +1,15 @@ | |||
1 | [ | ||
2 | { | ||
3 | "id": "feature.announcements.changelog.headline", | ||
4 | "defaultMessage": "!!!Changes in Franz {version}", | ||
5 | "file": "src/features/serviceLimit/components/AnnouncementScreen.js", | ||
6 | "start": { | ||
7 | "line": 20, | ||
8 | "column": 12 | ||
9 | }, | ||
10 | "end": { | ||
11 | "line": 23, | ||
12 | "column": 3 | ||
13 | } | ||
14 | } | ||
15 | ] \ No newline at end of file | ||
diff --git a/src/i18n/messages/src/features/serviceLimit/components/LimitReachedInfobox.json b/src/i18n/messages/src/features/serviceLimit/components/LimitReachedInfobox.json new file mode 100644 index 000000000..df5bc03e8 --- /dev/null +++ b/src/i18n/messages/src/features/serviceLimit/components/LimitReachedInfobox.json | |||
@@ -0,0 +1,28 @@ | |||
1 | [ | ||
2 | { | ||
3 | "id": "feature.serviceLimit.limitReached", | ||
4 | "defaultMessage": "!!!You have added {amount} of {limit} services. Please upgrade your account to add more services.", | ||
5 | "file": "src/features/serviceLimit/components/LimitReachedInfobox.js", | ||
6 | "start": { | ||
7 | "line": 11, | ||
8 | "column": 16 | ||
9 | }, | ||
10 | "end": { | ||
11 | "line": 14, | ||
12 | "column": 3 | ||
13 | } | ||
14 | }, | ||
15 | { | ||
16 | "id": "premiumFeature.button.upgradeAccount", | ||
17 | "defaultMessage": "!!!Upgrade account", | ||
18 | "file": "src/features/serviceLimit/components/LimitReachedInfobox.js", | ||
19 | "start": { | ||
20 | "line": 15, | ||
21 | "column": 10 | ||
22 | }, | ||
23 | "end": { | ||
24 | "line": 18, | ||
25 | "column": 3 | ||
26 | } | ||
27 | } | ||
28 | ] \ No newline at end of file | ||
diff --git a/src/i18n/messages/src/helpers/plan-helpers.json b/src/i18n/messages/src/helpers/plan-helpers.json new file mode 100644 index 000000000..de27dfcfd --- /dev/null +++ b/src/i18n/messages/src/helpers/plan-helpers.json | |||
@@ -0,0 +1,80 @@ | |||
1 | [ | ||
2 | { | ||
3 | "id": "pricing.plan.pro-yearly", | ||
4 | "defaultMessage": "!!!Franz Professional Yearly", | ||
5 | "file": "src/helpers/plan-helpers.js", | ||
6 | "start": { | ||
7 | "line": 5, | ||
8 | "column": 22 | ||
9 | }, | ||
10 | "end": { | ||
11 | "line": 8, | ||
12 | "column": 3 | ||
13 | } | ||
14 | }, | ||
15 | { | ||
16 | "id": "pricing.plan.pro-monthly", | ||
17 | "defaultMessage": "!!!Franz Professional Monthly", | ||
18 | "file": "src/helpers/plan-helpers.js", | ||
19 | "start": { | ||
20 | "line": 9, | ||
21 | "column": 23 | ||
22 | }, | ||
23 | "end": { | ||
24 | "line": 12, | ||
25 | "column": 3 | ||
26 | } | ||
27 | }, | ||
28 | { | ||
29 | "id": "pricing.plan.personal-yearly", | ||
30 | "defaultMessage": "!!!Franz Personal Yearly", | ||
31 | "file": "src/helpers/plan-helpers.js", | ||
32 | "start": { | ||
33 | "line": 13, | ||
34 | "column": 27 | ||
35 | }, | ||
36 | "end": { | ||
37 | "line": 16, | ||
38 | "column": 3 | ||
39 | } | ||
40 | }, | ||
41 | { | ||
42 | "id": "pricing.plan.personal-monthly", | ||
43 | "defaultMessage": "!!!Franz Personal Monthly", | ||
44 | "file": "src/helpers/plan-helpers.js", | ||
45 | "start": { | ||
46 | "line": 17, | ||
47 | "column": 28 | ||
48 | }, | ||
49 | "end": { | ||
50 | "line": 20, | ||
51 | "column": 3 | ||
52 | } | ||
53 | }, | ||
54 | { | ||
55 | "id": "pricing.plan.free", | ||
56 | "defaultMessage": "!!!Franz Free", | ||
57 | "file": "src/helpers/plan-helpers.js", | ||
58 | "start": { | ||
59 | "line": 21, | ||
60 | "column": 16 | ||
61 | }, | ||
62 | "end": { | ||
63 | "line": 24, | ||
64 | "column": 3 | ||
65 | } | ||
66 | }, | ||
67 | { | ||
68 | "id": "pricing.plan.legacy", | ||
69 | "defaultMessage": "!!!Franz Premium", | ||
70 | "file": "src/helpers/plan-helpers.js", | ||
71 | "start": { | ||
72 | "line": 25, | ||
73 | "column": 18 | ||
74 | }, | ||
75 | "end": { | ||
76 | "line": 28, | ||
77 | "column": 3 | ||
78 | } | ||
79 | } | ||
80 | ] \ No newline at end of file | ||
diff --git a/src/i18n/messages/src/helpers/pricing-helpers.json b/src/i18n/messages/src/helpers/pricing-helpers.json new file mode 100644 index 000000000..4030a3e3b --- /dev/null +++ b/src/i18n/messages/src/helpers/pricing-helpers.json | |||
@@ -0,0 +1,80 @@ | |||
1 | [ | ||
2 | { | ||
3 | "id": "pricing.plan.pro-yearly", | ||
4 | "defaultMessage": "!!!Franz Professional Yearly", | ||
5 | "file": "src/helpers/pricing-helpers.js", | ||
6 | "start": { | ||
7 | "line": 5, | ||
8 | "column": 22 | ||
9 | }, | ||
10 | "end": { | ||
11 | "line": 8, | ||
12 | "column": 3 | ||
13 | } | ||
14 | }, | ||
15 | { | ||
16 | "id": "pricing.plan.pro-monthly", | ||
17 | "defaultMessage": "!!!Franz Professional Monthly", | ||
18 | "file": "src/helpers/pricing-helpers.js", | ||
19 | "start": { | ||
20 | "line": 9, | ||
21 | "column": 23 | ||
22 | }, | ||
23 | "end": { | ||
24 | "line": 12, | ||
25 | "column": 3 | ||
26 | } | ||
27 | }, | ||
28 | { | ||
29 | "id": "pricing.plan.personal-yearly", | ||
30 | "defaultMessage": "!!!Franz Personal Yearly", | ||
31 | "file": "src/helpers/pricing-helpers.js", | ||
32 | "start": { | ||
33 | "line": 13, | ||
34 | "column": 27 | ||
35 | }, | ||
36 | "end": { | ||
37 | "line": 16, | ||
38 | "column": 3 | ||
39 | } | ||
40 | }, | ||
41 | { | ||
42 | "id": "pricing.plan.personal-monthly", | ||
43 | "defaultMessage": "!!!Franz Personal Monthly", | ||
44 | "file": "src/helpers/pricing-helpers.js", | ||
45 | "start": { | ||
46 | "line": 17, | ||
47 | "column": 28 | ||
48 | }, | ||
49 | "end": { | ||
50 | "line": 20, | ||
51 | "column": 3 | ||
52 | } | ||
53 | }, | ||
54 | { | ||
55 | "id": "pricing.plan.free", | ||
56 | "defaultMessage": "!!!Franz Free", | ||
57 | "file": "src/helpers/pricing-helpers.js", | ||
58 | "start": { | ||
59 | "line": 21, | ||
60 | "column": 16 | ||
61 | }, | ||
62 | "end": { | ||
63 | "line": 24, | ||
64 | "column": 3 | ||
65 | } | ||
66 | }, | ||
67 | { | ||
68 | "id": "pricing.plan.legacy", | ||
69 | "defaultMessage": "!!!Franz Premium", | ||
70 | "file": "src/helpers/pricing-helpers.js", | ||
71 | "start": { | ||
72 | "line": 25, | ||
73 | "column": 18 | ||
74 | }, | ||
75 | "end": { | ||
76 | "line": 28, | ||
77 | "column": 3 | ||
78 | } | ||
79 | } | ||
80 | ] \ No newline at end of file | ||
diff --git a/src/models/Service.js b/src/models/Service.js index 88bce3360..848a84aa2 100644 --- a/src/models/Service.js +++ b/src/models/Service.js | |||
@@ -4,6 +4,11 @@ import normalizeUrl from 'normalize-url'; | |||
4 | 4 | ||
5 | const debug = require('debug')('Franz:Service'); | 5 | const debug = require('debug')('Franz:Service'); |
6 | 6 | ||
7 | export const RESTRICTION_TYPES = { | ||
8 | SERVICE_LIMIT: 0, | ||
9 | CUSTOM_URL: 1, | ||
10 | }; | ||
11 | |||
7 | export default class Service { | 12 | export default class Service { |
8 | id = ''; | 13 | id = ''; |
9 | 14 | ||
@@ -59,6 +64,12 @@ export default class Service { | |||
59 | 64 | ||
60 | @observable errorMessage = ''; | 65 | @observable errorMessage = ''; |
61 | 66 | ||
67 | @observable isUsingCustomUrl = false; | ||
68 | |||
69 | @observable isServiceAccessRestricted = false; | ||
70 | |||
71 | @observable restrictionType = null; | ||
72 | |||
62 | constructor(data, recipe) { | 73 | constructor(data, recipe) { |
63 | if (!data) { | 74 | if (!data) { |
64 | console.error('Service config not valid'); | 75 | console.error('Service config not valid'); |
@@ -111,6 +122,10 @@ export default class Service { | |||
111 | this.unreadDirectMessageCount = 0; | 122 | this.unreadDirectMessageCount = 0; |
112 | this.unreadIndirectMessageCount = 0; | 123 | this.unreadIndirectMessageCount = 0; |
113 | } | 124 | } |
125 | |||
126 | if (this.recipe.hasCustomUrl && this.customUrl) { | ||
127 | this.isUsingCustomUrl = true; | ||
128 | } | ||
114 | }); | 129 | }); |
115 | } | 130 | } |
116 | 131 | ||
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/AppStore.js b/src/stores/AppStore.js index 2ac306a2a..6054e6721 100644 --- a/src/stores/AppStore.js +++ b/src/stores/AppStore.js | |||
@@ -357,6 +357,8 @@ export default class AppStore extends Store { | |||
357 | this.locale = this._getDefaultLocale(); | 357 | this.locale = this._getDefaultLocale(); |
358 | } | 358 | } |
359 | 359 | ||
360 | moment.locale(this.locale); | ||
361 | |||
360 | debug(`Set locale to "${this.locale}"`); | 362 | debug(`Set locale to "${this.locale}"`); |
361 | } | 363 | } |
362 | 364 | ||
diff --git a/src/stores/FeaturesStore.js b/src/stores/FeaturesStore.js index e7832088b..27334c9a2 100644 --- a/src/stores/FeaturesStore.js +++ b/src/stores/FeaturesStore.js | |||
@@ -16,6 +16,8 @@ import workspaces from '../features/workspaces'; | |||
16 | import shareFranz from '../features/shareFranz'; | 16 | import shareFranz from '../features/shareFranz'; |
17 | import announcements from '../features/announcements'; | 17 | import announcements from '../features/announcements'; |
18 | import settingsWS from '../features/settingsWS'; | 18 | import settingsWS from '../features/settingsWS'; |
19 | import serviceLimit from '../features/serviceLimit'; | ||
20 | import communityRecipes from '../features/communityRecipes'; | ||
19 | 21 | ||
20 | import { DEFAULT_FEATURES_CONFIG } from '../config'; | 22 | import { DEFAULT_FEATURES_CONFIG } from '../config'; |
21 | 23 | ||
@@ -75,5 +77,7 @@ export default class FeaturesStore extends Store { | |||
75 | shareFranz(this.stores, this.actions); | 77 | shareFranz(this.stores, this.actions); |
76 | announcements(this.stores, this.actions); | 78 | announcements(this.stores, this.actions); |
77 | settingsWS(this.stores, this.actions); | 79 | settingsWS(this.stores, this.actions); |
80 | serviceLimit(this.stores, this.actions); | ||
81 | communityRecipes(this.stores, this.actions); | ||
78 | } | 82 | } |
79 | } | 83 | } |
diff --git a/src/stores/ServicesStore.js b/src/stores/ServicesStore.js index 109ac5cd7..e3b3fcf21 100644 --- a/src/stores/ServicesStore.js +++ b/src/stores/ServicesStore.js | |||
@@ -13,6 +13,8 @@ import CachedRequest from './lib/CachedRequest'; | |||
13 | import { matchRoute } from '../helpers/routing-helpers'; | 13 | import { matchRoute } from '../helpers/routing-helpers'; |
14 | import { gaEvent, statsEvent } from '../lib/analytics'; | 14 | import { gaEvent, statsEvent } from '../lib/analytics'; |
15 | import { workspaceStore } from '../features/workspaces'; | 15 | import { workspaceStore } from '../features/workspaces'; |
16 | import { serviceLimitStore } from '../features/serviceLimit'; | ||
17 | import { RESTRICTION_TYPES } from '../models/Service'; | ||
16 | 18 | ||
17 | const debug = require('debug')('Franz:ServiceStore'); | 19 | const debug = require('debug')('Franz:ServiceStore'); |
18 | 20 | ||
@@ -75,6 +77,7 @@ export default class ServicesStore extends Store { | |||
75 | this._saveActiveService.bind(this), | 77 | this._saveActiveService.bind(this), |
76 | this._logoutReaction.bind(this), | 78 | this._logoutReaction.bind(this), |
77 | this._handleMuteSettings.bind(this), | 79 | this._handleMuteSettings.bind(this), |
80 | this._restrictServiceAccess.bind(this), | ||
78 | ]); | 81 | ]); |
79 | 82 | ||
80 | // Just bind this | 83 | // Just bind this |
@@ -98,7 +101,10 @@ export default class ServicesStore extends Store { | |||
98 | if (this.stores.user.isLoggedIn) { | 101 | if (this.stores.user.isLoggedIn) { |
99 | const services = this.allServicesRequest.execute().result; | 102 | const services = this.allServicesRequest.execute().result; |
100 | if (services) { | 103 | if (services) { |
101 | return observable(services.slice().slice().sort((a, b) => a.order - b.order)); | 104 | return observable(services.slice().slice().sort((a, b) => a.order - b.order).map((s, index) => { |
105 | s.index = index; | ||
106 | return s; | ||
107 | })); | ||
102 | } | 108 | } |
103 | } | 109 | } |
104 | return []; | 110 | return []; |
@@ -153,6 +159,8 @@ export default class ServicesStore extends Store { | |||
153 | 159 | ||
154 | // Actions | 160 | // Actions |
155 | @action async _createService({ recipeId, serviceData, redirect = true }) { | 161 | @action async _createService({ recipeId, serviceData, redirect = true }) { |
162 | if (serviceLimitStore.userHasReachedServiceLimit) return; | ||
163 | |||
156 | const data = this._cleanUpTeamIdAndCustomUrl(recipeId, serviceData); | 164 | const data = this._cleanUpTeamIdAndCustomUrl(recipeId, serviceData); |
157 | 165 | ||
158 | const response = await this.createServiceRequest.execute(recipeId, data)._promise; | 166 | const response = await this.createServiceRequest.execute(recipeId, data)._promise; |
@@ -678,6 +686,35 @@ export default class ServicesStore extends Store { | |||
678 | return serviceData; | 686 | return serviceData; |
679 | } | 687 | } |
680 | 688 | ||
689 | _restrictServiceAccess() { | ||
690 | const { features } = this.stores.features; | ||
691 | const { userHasReachedServiceLimit, serviceLimit } = this.stores.serviceLimit; | ||
692 | |||
693 | this.all.map((service, index) => { | ||
694 | if (userHasReachedServiceLimit) { | ||
695 | service.isServiceAccessRestricted = index >= serviceLimit; | ||
696 | |||
697 | if (service.isServiceAccessRestricted) { | ||
698 | service.restrictionType = RESTRICTION_TYPES.SERVICE_LIMIT; | ||
699 | |||
700 | debug('Restricting access to server due to service limit'); | ||
701 | } | ||
702 | } | ||
703 | |||
704 | if (service.isUsingCustomUrl) { | ||
705 | service.isServiceAccessRestricted = !features.isCustomUrlIncludedInCurrentPlan; | ||
706 | |||
707 | if (service.isServiceAccessRestricted) { | ||
708 | service.restrictionType = RESTRICTION_TYPES.CUSTOM_URL; | ||
709 | |||
710 | debug('Restricting access to server due to custom url'); | ||
711 | } | ||
712 | } | ||
713 | |||
714 | return service; | ||
715 | }); | ||
716 | } | ||
717 | |||
681 | // Helper | 718 | // Helper |
682 | _initializeServiceRecipeInWebview(serviceId) { | 719 | _initializeServiceRecipeInWebview(serviceId) { |
683 | const service = this.one(serviceId); | 720 | const service = this.one(serviceId); |
diff --git a/src/stores/UserStore.js b/src/stores/UserStore.js index b5423af3b..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 | ||
@@ -37,6 +39,8 @@ export default class UserStore extends Store { | |||
37 | 39 | ||
38 | @observable passwordRequest = new Request(this.api.user, 'password'); | 40 | @observable passwordRequest = new Request(this.api.user, 'password'); |
39 | 41 | ||
42 | @observable activateTrialRequest = new Request(this.api.user, 'activateTrial'); | ||
43 | |||
40 | @observable inviteRequest = new Request(this.api.user, 'invite'); | 44 | @observable inviteRequest = new Request(this.api.user, 'invite'); |
41 | 45 | ||
42 | @observable getUserInfoRequest = new CachedRequest(this.api.user, 'getInfo'); | 46 | @observable getUserInfoRequest = new CachedRequest(this.api.user, 'getInfo'); |
@@ -57,7 +61,9 @@ export default class UserStore extends Store { | |||
57 | 61 | ||
58 | @observable accountType; | 62 | @observable accountType; |
59 | 63 | ||
60 | @observable hasCompletedSignup = null; | 64 | @observable hasCompletedSignup = false; |
65 | |||
66 | @observable hasActivatedTrial = false; | ||
61 | 67 | ||
62 | @observable userData = {}; | 68 | @observable userData = {}; |
63 | 69 | ||
@@ -77,6 +83,7 @@ export default class UserStore extends Store { | |||
77 | this.actions.user.retrievePassword.listen(this._retrievePassword.bind(this)); | 83 | this.actions.user.retrievePassword.listen(this._retrievePassword.bind(this)); |
78 | this.actions.user.logout.listen(this._logout.bind(this)); | 84 | this.actions.user.logout.listen(this._logout.bind(this)); |
79 | this.actions.user.signup.listen(this._signup.bind(this)); | 85 | this.actions.user.signup.listen(this._signup.bind(this)); |
86 | this.actions.user.activateTrial.listen(this._activateTrial.bind(this)); | ||
80 | this.actions.user.invite.listen(this._invite.bind(this)); | 87 | this.actions.user.invite.listen(this._invite.bind(this)); |
81 | this.actions.user.update.listen(this._update.bind(this)); | 88 | this.actions.user.update.listen(this._update.bind(this)); |
82 | this.actions.user.resetStatus.listen(this._resetStatus.bind(this)); | 89 | this.actions.user.resetStatus.listen(this._resetStatus.bind(this)); |
@@ -87,6 +94,7 @@ export default class UserStore extends Store { | |||
87 | this.registerReactions([ | 94 | this.registerReactions([ |
88 | this._requireAuthenticatedUser, | 95 | this._requireAuthenticatedUser, |
89 | this._getUserData.bind(this), | 96 | this._getUserData.bind(this), |
97 | this._resetTrialActivationState.bind(this), | ||
90 | ]); | 98 | ]); |
91 | } | 99 | } |
92 | 100 | ||
@@ -199,6 +207,26 @@ export default class UserStore extends Store { | |||
199 | gaEvent('User', 'retrievePassword'); | 207 | gaEvent('User', 'retrievePassword'); |
200 | } | 208 | } |
201 | 209 | ||
210 | @action async _activateTrial({ planId }) { | ||
211 | debug('activate trial', planId); | ||
212 | |||
213 | this.activateTrialRequest.execute({ | ||
214 | plan: planId, | ||
215 | }); | ||
216 | |||
217 | await this.activateTrialRequest._promise; | ||
218 | |||
219 | this.hasActivatedTrial = true; | ||
220 | |||
221 | console.log('hasActivatedTrial', this.hasActivatedTrial); | ||
222 | |||
223 | this.stores.features.featuresRequest.invalidate({ immediately: true }); | ||
224 | this.stores.user.getUserInfoRequest.invalidate({ immediately: true }); | ||
225 | |||
226 | |||
227 | gaEvent('User', 'activateTrial'); | ||
228 | } | ||
229 | |||
202 | @action async _invite({ invites }) { | 230 | @action async _invite({ invites }) { |
203 | const data = invites.filter(invite => invite.email !== ''); | 231 | const data = invites.filter(invite => invite.email !== ''); |
204 | 232 | ||
@@ -318,6 +346,16 @@ export default class UserStore extends Store { | |||
318 | } | 346 | } |
319 | } | 347 | } |
320 | 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 | |||
321 | // Helpers | 359 | // Helpers |
322 | _parseToken(authToken) { | 360 | _parseToken(authToken) { |
323 | try { | 361 | try { |
diff --git a/src/stores/index.js b/src/stores/index.js index 1912418a2..c9ec77612 100644 --- a/src/stores/index.js +++ b/src/stores/index.js | |||
@@ -12,6 +12,8 @@ import RequestStore from './RequestStore'; | |||
12 | import GlobalErrorStore from './GlobalErrorStore'; | 12 | import GlobalErrorStore from './GlobalErrorStore'; |
13 | import { workspaceStore } from '../features/workspaces'; | 13 | import { workspaceStore } from '../features/workspaces'; |
14 | import { announcementsStore } from '../features/announcements'; | 14 | import { announcementsStore } from '../features/announcements'; |
15 | import { serviceLimitStore } from '../features/serviceLimit'; | ||
16 | import { communityRecipesStore } from '../features/communityRecipes'; | ||
15 | 17 | ||
16 | export default (api, actions, router) => { | 18 | export default (api, actions, router) => { |
17 | const stores = {}; | 19 | const stores = {}; |
@@ -31,6 +33,8 @@ export default (api, actions, router) => { | |||
31 | globalError: new GlobalErrorStore(stores, api, actions), | 33 | globalError: new GlobalErrorStore(stores, api, actions), |
32 | workspaces: workspaceStore, | 34 | workspaces: workspaceStore, |
33 | announcements: announcementsStore, | 35 | announcements: announcementsStore, |
36 | serviceLimit: serviceLimitStore, | ||
37 | communityRecipes: communityRecipesStore, | ||
34 | }); | 38 | }); |
35 | // Initialize all stores | 39 | // Initialize all stores |
36 | Object.keys(stores).forEach((name) => { | 40 | Object.keys(stores).forEach((name) => { |
diff --git a/src/styles/auth.scss b/src/styles/auth.scss index 0a075036a..154a71a36 100644 --- a/src/styles/auth.scss +++ b/src/styles/auth.scss | |||
@@ -9,7 +9,7 @@ | |||
9 | } | 9 | } |
10 | 10 | ||
11 | .auth__logo.auth__logo--sm { | 11 | .auth__logo.auth__logo--sm { |
12 | border: 4px solid $dark-theme-black; | 12 | border: none; |
13 | box-shadow: 0 0 6px rgba($dark-theme-black, .5); | 13 | box-shadow: 0 0 6px rgba($dark-theme-black, .5); |
14 | } | 14 | } |
15 | 15 | ||
diff --git a/src/styles/recipes.scss b/src/styles/recipes.scss index 84222e1fe..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 | } |
@@ -12,7 +13,7 @@ | |||
12 | display: flex; | 13 | display: flex; |
13 | flex-flow: row wrap; | 14 | flex-flow: row wrap; |
14 | height: auto; | 15 | height: auto; |
15 | min-height: 70%; | 16 | // min-height: 70%; |
16 | 17 | ||
17 | &.recipes__list--disabled { | 18 | &.recipes__list--disabled { |
18 | filter: grayscale(100%); | 19 | filter: grayscale(100%); |
diff --git a/src/styles/reset.scss b/src/styles/reset.scss index f46ede4a2..d87ce652a 100644 --- a/src/styles/reset.scss +++ b/src/styles/reset.scss | |||
@@ -51,7 +51,6 @@ button { | |||
51 | padding: 0; | 51 | padding: 0; |
52 | 52 | ||
53 | &:focus { outline: 0; } | 53 | &:focus { outline: 0; } |
54 | .theme__dark & { color: $dark-theme-gray-smoke; } | ||
55 | } | 54 | } |
56 | 55 | ||
57 | html { | 56 | html { |
diff --git a/src/styles/settings.scss b/src/styles/settings.scss index 1baff8b54..0955aaa0c 100644 --- a/src/styles/settings.scss +++ b/src/styles/settings.scss | |||
@@ -360,6 +360,7 @@ | |||
360 | .account__subscription-button { margin-left: auto; } | 360 | .account__subscription-button { margin-left: auto; } |
361 | .franz-form__button { white-space: nowrap; } | 361 | .franz-form__button { white-space: nowrap; } |
362 | div { height: auto; } | 362 | div { height: auto; } |
363 | [data-type="franz-button"] div { height: 100% } | ||
363 | 364 | ||
364 | .invoices { | 365 | .invoices { |
365 | width: 100%; | 366 | width: 100%; |