aboutsummaryrefslogtreecommitdiffstats
path: root/src/components
diff options
context:
space:
mode:
Diffstat (limited to 'src/components')
-rw-r--r--src/components/settings/account/AccountDashboard.js19
-rw-r--r--src/components/settings/recipes/RecipesDashboard.js4
-rw-r--r--src/components/subscription/TrialForm.js3
-rw-r--r--src/components/ui/ActivateTrialButton/index.js115
-rw-r--r--src/components/ui/FeatureItem.js2
-rw-r--r--src/components/ui/PremiumFeatureContainer/index.js22
6 files changed, 152 insertions, 13 deletions
diff --git a/src/components/settings/account/AccountDashboard.js b/src/components/settings/account/AccountDashboard.js
index 900a83a78..4fd1e8163 100644
--- a/src/components/settings/account/AccountDashboard.js
+++ b/src/components/settings/account/AccountDashboard.js
@@ -93,9 +93,11 @@ const messages = defineMessages({
93 }, 93 },
94}); 94});
95 95
96export default @observer class AccountDashboard extends Component { 96@observer
97class AccountDashboard extends Component {
97 static propTypes = { 98 static propTypes = {
98 user: MobxPropTypes.observableObject.isRequired, 99 user: MobxPropTypes.observableObject.isRequired,
100 isProUser: PropTypes.bool.isRequired,
99 isLoading: PropTypes.bool.isRequired, 101 isLoading: PropTypes.bool.isRequired,
100 userInfoRequestFailed: PropTypes.bool.isRequired, 102 userInfoRequestFailed: PropTypes.bool.isRequired,
101 retryUserInfoRequest: PropTypes.func.isRequired, 103 retryUserInfoRequest: PropTypes.func.isRequired,
@@ -115,6 +117,7 @@ export default @observer class AccountDashboard extends Component {
115 render() { 117 render() {
116 const { 118 const {
117 user, 119 user,
120 isProUser,
118 isLoading, 121 isLoading,
119 userInfoRequestFailed, 122 userInfoRequestFailed,
120 retryUserInfoRequest, 123 retryUserInfoRequest,
@@ -234,11 +237,13 @@ export default @observer class AccountDashboard extends Component {
234 </> 237 </>
235 )} 238 )}
236 <div className="manage-user-links"> 239 <div className="manage-user-links">
237 <Button 240 {!isProUser && (
238 label={intl.formatMessage(messages.upgradeAccountToPro)} 241 <Button
239 className="franz-form__button--primary" 242 label={intl.formatMessage(messages.upgradeAccountToPro)}
240 onClick={upgradeToPro} 243 className="franz-form__button--primary"
241 /> 244 onClick={upgradeToPro}
245 />
246 )}
242 <Button 247 <Button
243 label={intl.formatMessage(messages.manageSubscriptionButtonLabel)} 248 label={intl.formatMessage(messages.manageSubscriptionButtonLabel)}
244 className="franz-form__button--inverted" 249 className="franz-form__button--inverted"
@@ -290,3 +295,5 @@ export default @observer class AccountDashboard extends Component {
290 ); 295 );
291 } 296 }
292} 297}
298
299export default AccountDashboard;
diff --git a/src/components/settings/recipes/RecipesDashboard.js b/src/components/settings/recipes/RecipesDashboard.js
index 75e60b7ec..08988024a 100644
--- a/src/components/settings/recipes/RecipesDashboard.js
+++ b/src/components/settings/recipes/RecipesDashboard.js
@@ -218,7 +218,7 @@ export default @injectSheet(styles) @observer class RecipesDashboard extends Com
218 <> 218 <>
219 <H2> 219 <H2>
220 {intl.formatMessage(messages.headlineCustomRecipes)} 220 {intl.formatMessage(messages.headlineCustomRecipes)}
221 {isCommunityRecipesIncludedInCurrentPlan && ( 221 {!isCommunityRecipesIncludedInCurrentPlan && (
222 <ProBadge className={classes.proBadge} /> 222 <ProBadge className={classes.proBadge} />
223 )} 223 )}
224 </H2> 224 </H2>
@@ -247,7 +247,7 @@ export default @injectSheet(styles) @observer class RecipesDashboard extends Com
247 </> 247 </>
248 )} 248 )}
249 <PremiumFeatureContainer 249 <PremiumFeatureContainer
250 condition={(recipeFilter === 'dev' && communityRecipes.length > 0) && isCommunityRecipesIncludedInCurrentPlan} 250 condition={(recipeFilter === 'dev' && communityRecipes.length > 0) && !isCommunityRecipesIncludedInCurrentPlan}
251 > 251 >
252 {recipeFilter === 'dev' && communityRecipes.length > 0 && ( 252 {recipeFilter === 'dev' && communityRecipes.length > 0 && (
253 <H3>{intl.formatMessage(messages.headlineCommunityRecipes)}</H3> 253 <H3>{intl.formatMessage(messages.headlineCommunityRecipes)}</H3>
diff --git a/src/components/subscription/TrialForm.js b/src/components/subscription/TrialForm.js
index 9fe1c93b7..9ed548f16 100644
--- a/src/components/subscription/TrialForm.js
+++ b/src/components/subscription/TrialForm.js
@@ -41,7 +41,7 @@ const messages = defineMessages({
41 }, 41 },
42}); 42});
43 43
44const styles = () => ({ 44const styles = theme => ({
45 activateTrialButton: { 45 activateTrialButton: {
46 margin: [40, 0, 10], 46 margin: [40, 0, 10],
47 }, 47 },
@@ -49,6 +49,7 @@ const styles = () => ({
49 margin: [0, 0, 40], 49 margin: [0, 0, 40],
50 background: 'none', 50 background: 'none',
51 border: 'none', 51 border: 'none',
52 color: theme.colorText,
52 }, 53 },
53 keyTerms: { 54 keyTerms: {
54 marginTop: 20, 55 marginTop: 20,
diff --git a/src/components/ui/ActivateTrialButton/index.js b/src/components/ui/ActivateTrialButton/index.js
new file mode 100644
index 000000000..c3e5f4a6f
--- /dev/null
+++ b/src/components/ui/ActivateTrialButton/index.js
@@ -0,0 +1,115 @@
1import React, { Component } from 'react';
2import PropTypes from 'prop-types';
3import { inject, observer } from 'mobx-react';
4import { defineMessages, intlShape } from 'react-intl';
5import classnames from 'classnames';
6
7import { Button } from '@meetfranz/forms';
8import { gaEvent } from '../../../lib/analytics';
9
10import UserStore from '../../../stores/UserStore';
11
12const messages = defineMessages({
13 action: {
14 id: 'feature.delayApp.upgrade.action',
15 defaultMessage: '!!!Get a Franz Supporter License',
16 },
17 actionTrial: {
18 id: 'feature.delayApp.trial.action',
19 defaultMessage: '!!!Yes, I want the free 14 day trial of Franz Professional',
20 },
21 shortAction: {
22 id: 'feature.delayApp.upgrade.actionShort',
23 defaultMessage: '!!!Upgrade account',
24 },
25 shortActionTrial: {
26 id: 'feature.delayApp.trial.actionShort',
27 defaultMessage: '!!!Activate the free Franz Professional trial',
28 },
29});
30
31@inject('stores', 'actions') @observer
32class ActivateTrialButton extends Component {
33 static propTypes = {
34 // eslint-disable-next-line
35 classes: PropTypes.object.isRequired,
36 className: PropTypes.string,
37 short: PropTypes.bool,
38 gaEventInfo: PropTypes.shape({
39 category: PropTypes.string.isRequired,
40 event: PropTypes.string.isRequired,
41 label: PropTypes.string,
42 }),
43 };
44
45 static defaultProps = {
46 className: '',
47 short: false,
48 gaEventInfo: null,
49 }
50
51 static contextTypes = {
52 intl: intlShape,
53 };
54
55 handleCTAClick() {
56 const { actions, stores, gaEventInfo } = this.props;
57 const { hadSubscription } = stores.user.data;
58 const { defaultTrialPlan } = stores.features.features;
59
60 let label = '';
61 if (!hadSubscription) {
62 actions.user.activateTrial({ planId: defaultTrialPlan });
63
64 label = 'Start Trial';
65 } else {
66 actions.ui.openSettings({ path: 'user' });
67
68 label = 'Upgrade Account';
69 }
70
71 if (gaEventInfo) {
72 const { category, event } = gaEventInfo;
73 gaEvent(category, event, label);
74 }
75 }
76
77 render() {
78 const { stores, className, short } = this.props;
79 const { intl } = this.context;
80
81 const { hadSubscription } = stores.user.data;
82
83 let label;
84 if (hadSubscription) {
85 label = short ? messages.shortAction : messages.action;
86 } else {
87 label = short ? messages.shortActionTrial : messages.actionTrial;
88 }
89
90 return (
91 <Button
92 label={intl.formatMessage(label)}
93 className={classnames({
94 [className]: className,
95 })}
96 buttonType="inverted"
97 onClick={this.handleCTAClick.bind(this)}
98 busy={stores.user.activateTrialRequest.isExecuting}
99 />
100 );
101 }
102}
103
104export default ActivateTrialButton;
105
106ActivateTrialButton.wrappedComponent.propTypes = {
107 stores: PropTypes.shape({
108 user: PropTypes.instanceOf(UserStore).isRequired,
109 }).isRequired,
110 actions: PropTypes.shape({
111 ui: PropTypes.shape({
112 openSettings: PropTypes.func.isRequired,
113 }).isRequired,
114 }).isRequired,
115};
diff --git a/src/components/ui/FeatureItem.js b/src/components/ui/FeatureItem.js
index 53616f2eb..7c482c4d4 100644
--- a/src/components/ui/FeatureItem.js
+++ b/src/components/ui/FeatureItem.js
@@ -6,7 +6,7 @@ import { mdiCheckCircle } from '@mdi/js';
6 6
7const styles = theme => ({ 7const styles = theme => ({
8 featureItem: { 8 featureItem: {
9 borderBottom: [1, 'solid', theme.legacyStyles.themeGrayDark], 9 borderBottom: [1, 'solid', theme.defaultContentBorder],
10 padding: [8, 0], 10 padding: [8, 0],
11 display: 'flex', 11 display: 'flex',
12 alignItems: 'center', 12 alignItems: 'center',
diff --git a/src/components/ui/PremiumFeatureContainer/index.js b/src/components/ui/PremiumFeatureContainer/index.js
index 3c1e0fac3..8d2746e22 100644
--- a/src/components/ui/PremiumFeatureContainer/index.js
+++ b/src/components/ui/PremiumFeatureContainer/index.js
@@ -10,6 +10,7 @@ import UserStore from '../../../stores/UserStore';
10 10
11import styles from './styles'; 11import styles from './styles';
12import { gaEvent } from '../../../lib/analytics'; 12import { gaEvent } from '../../../lib/analytics';
13import { FeatureStore } from '../../../features/utils/FeatureStore';
13 14
14const messages = defineMessages({ 15const messages = defineMessages({
15 action: { 16 action: {
@@ -22,7 +23,10 @@ const messages = defineMessages({
22class PremiumFeatureContainer extends Component { 23class PremiumFeatureContainer extends Component {
23 static propTypes = { 24 static propTypes = {
24 classes: PropTypes.object.isRequired, 25 classes: PropTypes.object.isRequired,
25 condition: PropTypes.bool, 26 condition: PropTypes.oneOfType([
27 PropTypes.bool,
28 PropTypes.func,
29 ]),
26 gaEventInfo: PropTypes.shape({ 30 gaEventInfo: PropTypes.shape({
27 category: PropTypes.string.isRequired, 31 category: PropTypes.string.isRequired,
28 event: PropTypes.string.isRequired, 32 event: PropTypes.string.isRequired,
@@ -31,7 +35,7 @@ class PremiumFeatureContainer extends Component {
31 }; 35 };
32 36
33 static defaultProps = { 37 static defaultProps = {
34 condition: true, 38 condition: null,
35 gaEventInfo: null, 39 gaEventInfo: null,
36 }; 40 };
37 41
@@ -51,7 +55,18 @@ class PremiumFeatureContainer extends Component {
51 55
52 const { intl } = this.context; 56 const { intl } = this.context;
53 57
54 return !stores.user.data.isPremium && !!condition ? ( 58 let showWrapper = !!condition;
59
60 if (condition === null) {
61 showWrapper = !stores.user.data.isPremium;
62 } else if (typeof condition === 'function') {
63 showWrapper = condition({
64 isPremium: stores.user.data.isPremium,
65 features: stores.features.features,
66 });
67 }
68
69 return showWrapper ? (
55 <div className={classes.container}> 70 <div className={classes.container}>
56 <div className={classes.titleContainer}> 71 <div className={classes.titleContainer}>
57 <p className={classes.title}>Premium Feature</p> 72 <p className={classes.title}>Premium Feature</p>
@@ -81,6 +96,7 @@ PremiumFeatureContainer.wrappedComponent.propTypes = {
81 children: oneOrManyChildElements.isRequired, 96 children: oneOrManyChildElements.isRequired,
82 stores: PropTypes.shape({ 97 stores: PropTypes.shape({
83 user: PropTypes.instanceOf(UserStore).isRequired, 98 user: PropTypes.instanceOf(UserStore).isRequired,
99 features: PropTypes.instanceOf(FeatureStore).isRequired,
84 }).isRequired, 100 }).isRequired,
85 actions: PropTypes.shape({ 101 actions: PropTypes.shape({
86 ui: PropTypes.shape({ 102 ui: PropTypes.shape({