From 76559f2895012803aed3256ce521b9cfff2f63b8 Mon Sep 17 00:00:00 2001 From: Stefan Malzner Date: Mon, 5 Aug 2019 13:24:35 +0200 Subject: WIP: add option to activate trial --- src/api/server/ServerApi.js | 2 - src/components/TrialActivationInfoBar.js | 94 +++++++ src/components/layout/AppLayout.js | 37 ++- src/components/services/content/Services.js | 61 ++--- .../settings/account/AccountDashboard.js | 134 ++++++---- .../settings/settings/EditSettingsForm.js | 2 - src/containers/layout/AppLayoutContainer.js | 2 + src/features/delayApp/Component.js | 43 +++- src/features/delayApp/index.js | 2 +- src/i18n/locales/defaultMessages.json | 284 ++++++++++++++++++--- src/i18n/locales/en-US.json | 29 ++- .../src/components/TrialActivationInfoBar.json | 15 ++ .../messages/src/components/layout/AppLayout.json | 12 +- .../messages/src/features/delayApp/Component.json | 40 ++- src/models/User.js | 14 +- src/stores/UserStore.js | 21 ++ src/styles/recipes.scss | 1 + 17 files changed, 630 insertions(+), 163 deletions(-) create mode 100644 src/components/TrialActivationInfoBar.js create mode 100644 src/i18n/messages/src/components/TrialActivationInfoBar.json (limited to 'src') diff --git a/src/api/server/ServerApi.js b/src/api/server/ServerApi.js index f2568d597..f56c7b6e4 100644 --- a/src/api/server/ServerApi.js +++ b/src/api/server/ServerApi.js @@ -87,8 +87,6 @@ export default class ServerApi { } const trial = await request.json(); - console.log(trial); - debug('ServerApi::signup resolves', trial); return true; } 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 @@ +import React, { Component } from 'react'; +import PropTypes from 'prop-types'; +import { defineMessages, intlShape } from 'react-intl'; +import ms from 'ms'; +import injectSheet from 'react-jss'; +import classnames from 'classnames'; + +import InfoBar from './ui/InfoBar'; + +const messages = defineMessages({ + message: { + id: 'infobar.trialActivated', + defaultMessage: '!!!Your trial was successfully activated. Happy messaging!', + }, +}); + +const styles = { + notification: { + height: 'auto', + position: 'absolute', + top: -50, + transition: 'top 0.3s', + zIndex: 300, + width: 'calc(100% - 300px)', + }, + show: { + top: 0, + }, +}; + +@injectSheet(styles) +class TrialActivationInfoBar extends Component { + static propTypes = { + // eslint-disable-next-line + classes: PropTypes.object.isRequired, + }; + + static contextTypes = { + intl: intlShape, + }; + + state = { + showing: false, + removed: false, + } + + componentDidMount() { + setTimeout(() => { + this.setState({ + showing: true, + }); + }, 0); + + setTimeout(() => { + this.setState({ + showing: false, + }); + }, ms('6s')); + + setTimeout(() => { + this.setState({ + removed: true, + }); + }, ms('7s')); + } + + render() { + const { classes } = this.props; + const { showing, removed } = this.state; + const { intl } = this.context; + + if (removed) return null; + + return ( +
+ + + {intl.formatMessage(messages.message)} + +
+ ); + } +} + +export default TrialActivationInfoBar; diff --git a/src/components/layout/AppLayout.js b/src/components/layout/AppLayout.js index ebb9849ea..1976f5a50 100644 --- a/src/components/layout/AppLayout.js +++ b/src/components/layout/AppLayout.js @@ -17,6 +17,7 @@ import { isWindows } from '../../environment'; import WorkspaceSwitchingIndicator from '../../features/workspaces/components/WorkspaceSwitchingIndicator'; import { workspaceStore } from '../../features/workspaces'; import AppUpdateInfoBar from '../AppUpdateInfoBar'; +import TrialActivationInfoBar from '../TrialActivationInfoBar'; function createMarkup(HTMLString) { return { __html: HTMLString }; @@ -57,7 +58,6 @@ class AppLayout extends Component { services: PropTypes.element.isRequired, children: PropTypes.element, news: MobxPropTypes.arrayOrObservableArray.isRequired, - // isOnline: PropTypes.bool.isRequired, showServicesUpdatedInfoBar: PropTypes.bool.isRequired, appUpdateIsDownloaded: PropTypes.bool.isRequired, nextAppReleaseVersion: PropTypes.string, @@ -69,6 +69,7 @@ class AppLayout extends Component { retryRequiredRequests: PropTypes.func.isRequired, areRequiredRequestsLoading: PropTypes.bool.isRequired, isDelayAppScreenVisible: PropTypes.bool.isRequired, + hasActivatedTrial: PropTypes.bool.isRequired, }; static defaultProps = { @@ -88,7 +89,6 @@ class AppLayout extends Component { sidebar, services, children, - // isOnline, news, showServicesUpdatedInfoBar, appUpdateIsDownloaded, @@ -101,6 +101,7 @@ class AppLayout extends Component { retryRequiredRequests, areRequiredRequestsLoading, isDelayAppScreenVisible, + hasActivatedTrial, } = this.props; const { intl } = this.context; @@ -125,26 +126,20 @@ class AppLayout extends Component { ))} - {/* {!isOnline && ( - - - {intl.formatMessage(globalMessages.notConnectedToTheInternet)} - - )} */} + {hasActivatedTrial && ( + + )} {!areRequiredRequestsSuccessful && showRequiredRequestsError && ( - - - {intl.formatMessage(messages.requiredRequestsFailed)} - + + + {intl.formatMessage(messages.requiredRequestsFailed)} + )} {showServicesUpdatedInfoBar && ( + {(userHasCompletedSignup || hasActivatedTrial) && ( +
+ +
+ )} {services.length === 0 && ( - <> - {userHasCompletedSignup && ( -
- -
- )} - -
- -

{intl.formatMessage(messages.welcome)}

- - - {intl.formatMessage(messages.getStarted)} - - -
-
- + +
+ +

{intl.formatMessage(messages.welcome)}

+ + + {intl.formatMessage(messages.getStarted)} + + +
+
)} {services.map(service => ( + <> {!isLoading && ( -
-
-
- -
-
-

- {`${user.firstname} ${user.lastname}`} - {user.isPremium && ( - <> - {' '} - - {intl.formatMessage(messages.accountTypePremium)} - - )} -

- {user.organization && `${user.organization}, `} - {user.email} - {user.isPremium && ( -
-
+ +

+ {user.organization && `${user.organization}, `} + {user.email} +

+ {user.isPremium && ( +
+
+ )} +
+ {!user.isPremium && ( +
- {!user.isPremium && ( -
- + {user.isSubscriptionOwner && ( +
+
+

+ Your license: {user.team.plan} +

+ {user.team.isTrial && ( + <> +

+ Trial ends in 14 days +

+ + )} + {user.isPremium && ( +
+
+ )} +
+
+ )} + )} {!user.isPremium && ( @@ -227,7 +261,7 @@ export default @observer class AccountDashboard extends Component { )} - + )} diff --git a/src/components/settings/settings/EditSettingsForm.js b/src/components/settings/settings/EditSettingsForm.js index 6d0811b1b..3f9e0a6bc 100644 --- a/src/components/settings/settings/EditSettingsForm.js +++ b/src/components/settings/settings/EditSettingsForm.js @@ -143,8 +143,6 @@ export default @observer class EditSettingsForm extends Component { updateButtonLabelMessage = messages.buttonSearchForUpdate; } - console.log('isSpellcheckerIncludedInCurrentPlan', isSpellcheckerIncludedInCurrentPlan); - return (
diff --git a/src/containers/layout/AppLayoutContainer.js b/src/containers/layout/AppLayoutContainer.js index b4e32cffa..a14a98554 100644 --- a/src/containers/layout/AppLayoutContainer.js +++ b/src/containers/layout/AppLayoutContainer.js @@ -128,6 +128,7 @@ export default @inject('stores', 'actions') @observer class AppLayoutContainer e openSettings={openSettings} update={updateService} userHasCompletedSignup={user.hasCompletedSignup} + hasActivatedTrial={user.hasActivatedTrial} /> ); @@ -152,6 +153,7 @@ export default @inject('stores', 'actions') @observer class AppLayoutContainer e retryRequiredRequests={retryRequiredRequests} areRequiredRequestsLoading={requests.areRequiredRequestsLoading} isDelayAppScreenVisible={delayAppState.isDelayAppScreenVisible} + hasActivatedTrial={user.hasActivatedTrial} > {React.Children.count(children) > 0 ? children : null} 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'; import { defineMessages, intlShape } from 'react-intl'; import injectSheet from 'react-jss'; +import { Button } from '@meetfranz/forms'; import { gaEvent } from '../../lib/analytics'; -import Button from '../../components/ui/Button'; +// import Button from '../../components/ui/Button'; import { config } from '.'; import styles from './styles'; +import UserStore from '../../stores/UserStore'; const messages = defineMessages({ headline: { id: 'feature.delayApp.headline', defaultMessage: '!!!Please purchase license to skip waiting', }, + headlineTrial: { + id: 'feature.delayApp.trial.headline', + defaultMessage: '!!!Get the free Franz Professional 14 day trial and skip the line', + }, action: { - id: 'feature.delayApp.action', + id: 'feature.delayApp.upgrade.action', defaultMessage: '!!!Get a Franz Supporter License', }, + actionTrial: { + id: 'feature.delayApp.trial.action', + defaultMessage: '!!!Yes, I want the free 14 day trial of Franz Professional', + }, text: { id: 'feature.delayApp.text', defaultMessage: '!!!Franz will continue in {seconds} seconds.', }, }); -export default @inject('actions') @injectSheet(styles) @observer class DelayApp extends Component { +export default @inject('stores', 'actions') @injectSheet(styles) @observer class DelayApp extends Component { static propTypes = { // eslint-disable-next-line classes: PropTypes.object.isRequired, @@ -62,25 +72,37 @@ export default @inject('actions') @injectSheet(styles) @observer class DelayApp } handleCTAClick() { - const { actions } = this.props; + const { actions, stores } = this.props; + const { hadSubscription } = stores.user.data; + const { defaultTrialPlan } = stores.features.features; + + if (!hadSubscription) { + console.log('directly activate trial'); + actions.user.activateTrial({ planId: defaultTrialPlan }); - actions.ui.openSettings({ path: 'user' }); + gaEvent('DelayApp', 'subscribe_click', 'Delay App Feature'); + } else { + actions.ui.openSettings({ path: 'user' }); - gaEvent('DelayApp', 'subscribe_click', 'Delay App Feature'); + gaEvent('DelayApp', 'subscribe_click', 'Delay App Feature'); + } } render() { - const { classes } = this.props; + const { classes, stores } = this.props; const { intl } = this.context; + const { hadSubscription } = stores.user.data; + return (
-

{intl.formatMessage(messages.headline)}

+

{intl.formatMessage(hadSubscription ? messages.headline : messages.headlineTrial)}