From 91a0fb20ef02dfa342cf26df3e047b2bd4370b9f Mon Sep 17 00:00:00 2001 From: Stefan Malzner Date: Tue, 15 Oct 2019 21:40:14 +0200 Subject: simplify plan selection --- src/components/auth/Pricing.js | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) (limited to 'src/components/auth') diff --git a/src/components/auth/Pricing.js b/src/components/auth/Pricing.js index cbeaaa5d9..40ce49814 100644 --- a/src/components/auth/Pricing.js +++ b/src/components/auth/Pricing.js @@ -18,7 +18,7 @@ const messages = defineMessages({ }, personalOffer: { id: 'pricing.trial.subheadline', - defaultMessage: '!!!Your personal welcome offer:', + defaultMessage: '!!!Here\'s a special welcome for you:', }, noStringsAttachedHeadline: { id: 'pricing.trial.terms.headline', @@ -38,7 +38,7 @@ const messages = defineMessages({ }, ctaAccept: { id: 'pricing.trial.cta.accept', - defaultMessage: '!!!Yes, upgrade my account to Franz Professional', + defaultMessage: '!!!Start my 14-day Franz Professional Trial ', }, ctaSkip: { id: 'pricing.trial.cta.skip', @@ -58,6 +58,7 @@ const styles = theme => ({ welcomeOffer: { textAlign: 'center', fontWeight: 'bold', + marginBottom: '6 !important', }, keyTerms: { textAlign: 'center', @@ -101,6 +102,7 @@ export default @observer @injectSheet(styles) class Signup extends Component { isLoadingRequiredData: PropTypes.bool.isRequired, isActivatingTrial: PropTypes.bool.isRequired, trialActivationError: PropTypes.bool.isRequired, + canSkipTrial: PropTypes.bool.isRequired, classes: PropTypes.object.isRequired, }; @@ -114,6 +116,7 @@ export default @observer @injectSheet(styles) class Signup extends Component { isLoadingRequiredData, isActivatingTrial, trialActivationError, + canSkipTrial, classes, } = this.props; const { intl } = this.context; @@ -138,7 +141,7 @@ export default @observer @injectSheet(styles) class Signup extends Component {

- Get the free 14 day Franz Professional trial and see your communication evolving. + For the next 14 days, we are going to give you the full Franz Professional experience so you can watch your communication evolve!

@@ -167,9 +170,11 @@ export default @observer @injectSheet(styles) class Signup extends Component { busy={isActivatingTrial} disabled={isLoadingRequiredData || isActivatingTrial} /> -

- {intl.formatMessage(messages.ctaSkip)} -

+ {canSkipTrial && ( +

+ {intl.formatMessage(messages.ctaSkip)} +

+ )}
-- cgit v1.2.3-70-g09d2 From ba578b8a6df8d31136fb170e78b70a71dad85e31 Mon Sep 17 00:00:00 2001 From: Stefan Malzner Date: Wed, 16 Oct 2019 10:22:00 +0200 Subject: polishing --- src/components/auth/Pricing.js | 15 +++ src/containers/auth/PricingScreen.js | 11 +++ src/features/planSelection/components/PlanItem.js | 50 +++++++--- .../planSelection/components/PlanSelection.js | 27 +++--- .../containers/PlanSelectionScreen.js | 14 --- src/features/planSelection/store.js | 3 + src/i18n/locales/defaultMessages.json | 102 +++++++++++++-------- src/i18n/locales/en-US.json | 4 +- src/i18n/messages/src/components/auth/Pricing.json | 29 ++++-- .../planSelection/components/PlanItem.json | 19 +++- 10 files changed, 184 insertions(+), 90 deletions(-) (limited to 'src/components/auth') diff --git a/src/components/auth/Pricing.js b/src/components/auth/Pricing.js index 40ce49814..67af04470 100644 --- a/src/components/auth/Pricing.js +++ b/src/components/auth/Pricing.js @@ -32,6 +32,10 @@ const messages = defineMessages({ id: 'pricing.trial.terms.automaticTrialEnd', defaultMessage: '!!!Your free trial ends automatically after 14 days', }, + trialWorth: { + id: 'pricing.trial.terms.trialWorth', + defaultMessage: '!!!Free trial (normally {currency}{price} per month)', + }, activationError: { id: 'pricing.trial.error', defaultMessage: '!!!Sorry, we could not activate your trial!', @@ -104,6 +108,8 @@ export default @observer @injectSheet(styles) class Signup extends Component { trialActivationError: PropTypes.bool.isRequired, canSkipTrial: PropTypes.bool.isRequired, classes: PropTypes.object.isRequired, + currency: PropTypes.string.isRequired, + price: PropTypes.number.isRequired, }; static contextTypes = { @@ -118,6 +124,8 @@ export default @observer @injectSheet(styles) class Signup extends Component { trialActivationError, canSkipTrial, classes, + currency, + price, } = this.props; const { intl } = this.context; @@ -156,6 +164,13 @@ export default @observer @injectSheet(styles) class Signup extends Component { {intl.formatMessage(messages.noStringsAttachedHeadline)}
    +
diff --git a/src/containers/auth/PricingScreen.js b/src/containers/auth/PricingScreen.js index 8e0ded16a..ff378bd8b 100644 --- a/src/containers/auth/PricingScreen.js +++ b/src/containers/auth/PricingScreen.js @@ -40,6 +40,15 @@ export default @inject('stores', 'actions') @observer class PricingScreen extend const { getUserInfoRequest, activateTrialRequest } = stores.user; const { featuresRequest, features } = stores.features; + const { pricingConfig } = features; + + let currency = '$'; + let price = '5.99'; + if (pricingConfig) { + ({ currency } = pricingConfig); + ({ price } = pricingConfig.plans.pro.yearly); + } + return ( ); } diff --git a/src/features/planSelection/components/PlanItem.js b/src/features/planSelection/components/PlanItem.js index a49cd40d3..ea04c8448 100644 --- a/src/features/planSelection/components/PlanItem.js +++ b/src/features/planSelection/components/PlanItem.js @@ -10,10 +10,6 @@ import { H2 } from '@meetfranz/ui'; import { Button } from '@meetfranz/forms'; import { mdiArrowRight } from '@mdi/js'; -// import { FeatureList } from '../ui/FeatureList'; -// import { PLANS, PAYMENT_INTERVAL } from '../../config'; -// import { i18nPlanName, i18nIntervalName } from '../../helpers/plan-helpers'; -// import { PLAN_INTERVAL_CONFIG_TYPE } from './types'; const messages = defineMessages({ perMonth: { @@ -24,6 +20,10 @@ const messages = defineMessages({ id: 'subscription.interval.perMonthPerUser', defaultMessage: '!!!per month & user', }, + bestValue: { + id: 'subscription.bestValue', + defaultMessage: '!!!Best value', + }, }); const styles = theme => ({ @@ -41,7 +41,6 @@ const styles = theme => ({ marginBottom: 20, fontSize: 30, color: theme.styleTypes.primary.contrast, - // fontWeight: 'bold', }, }, currency: { @@ -58,9 +57,6 @@ const styles = theme => ({ verticalAlign: 20, }, }, - interval: { - // paddingBottom: 40, - }, text: { marginBottom: 'auto', }, @@ -68,10 +64,6 @@ const styles = theme => ({ background: theme.styleTypes.primary.accent, color: theme.styleTypes.primary.contrast, margin: [40, 'auto', 0, 'auto'], - - // '&:active': { - // opacity: 0.7, - // }, }, divider: { width: 40, @@ -83,10 +75,10 @@ const styles = theme => ({ padding: 20, background: color(theme.styleTypes.primary.accent).darken(0.25).hex(), color: theme.styleTypes.primary.contrast, + position: 'relative', }, content: { padding: 20, - // border: [1, 'solid', 'red'], background: '#EFEFEF', }, simpleCTA: { @@ -97,6 +89,20 @@ const styles = theme => ({ fill: theme.styleTypes.primary.accent, }, }, + bestValue: { + background: theme.styleTypes.success.accent, + color: theme.styleTypes.success.contrast, + right: -66, + top: -40, + height: 'auto', + position: 'absolute', + transform: 'rotateZ(45deg)', + textAlign: 'center', + padding: [5, 50], + transformOrigin: 'left bottom', + fontSize: 12, + boxShadow: '0 2px 6px rgba(0,0,0,0.15)', + }, }); @@ -111,6 +117,8 @@ export default @observer @injectSheet(styles) class PlanItem extends Component { simpleCTA: PropTypes.bool, perUser: PropTypes.bool, classes: PropTypes.object.isRequired, + bestValue: PropTypes.bool, + className: PropTypes.string, children: PropTypes.element, }; @@ -118,6 +126,8 @@ export default @observer @injectSheet(styles) class PlanItem extends Component { simpleCTA: false, perUser: false, children: null, + bestValue: false, + className: '', } static contextTypes = { @@ -135,16 +145,26 @@ export default @observer @injectSheet(styles) class PlanItem extends Component { ctaLabel, simpleCTA, perUser, + bestValue, + className, children, } = this.props; const { intl } = this.context; const priceParts = `${price}`.split('.'); - // const intervalName = i18nIntervalName(PAYMENT_INTERVAL.MONTHLY, intl); return ( -
+
+ {bestValue && ( +
+ {intl.formatMessage(messages.bestValue)} +
+ )}

{name}

{text} diff --git a/src/features/planSelection/components/PlanSelection.js b/src/features/planSelection/components/PlanSelection.js index 9cd592083..1a45cf035 100644 --- a/src/features/planSelection/components/PlanSelection.js +++ b/src/features/planSelection/components/PlanSelection.js @@ -137,6 +137,9 @@ const styles = theme => ({ border: '1px solid red', overflow: 'scroll-x', }, + featuredPlan: { + transform: 'scale(1.05)', + }, }); @injectSheet(styles) @observer @@ -197,29 +200,31 @@ class PlanSelection extends Component { /> upgradeAccount(plans.personal.yearly.id)} + className={classes.featuredPlan} + perUser + bestValue > upgradeAccount(plans.personal.yearly.id)} - perUser > diff --git a/src/features/planSelection/containers/PlanSelectionScreen.js b/src/features/planSelection/containers/PlanSelectionScreen.js index 01b357861..dff9051d8 100644 --- a/src/features/planSelection/containers/PlanSelectionScreen.js +++ b/src/features/planSelection/containers/PlanSelectionScreen.js @@ -43,15 +43,12 @@ class PlanSelectionScreen extends Component { } upgradeAccount(planId) { - const { user, features } = this.props.stores; const { upgradeAccount, hideOverlay } = this.props.actions.planSelection; upgradeAccount({ planId, onCloseWindow: () => { hideOverlay(); - user.getUserInfoRequest.invalidate({ immediately: true }); - features.featuresRequest.invalidate({ immediately: true }); }, }); } @@ -68,17 +65,6 @@ class PlanSelectionScreen extends Component { const { activateTrial } = this.props.actions.user; const { upgradeAccount, downgradeAccount, hideOverlay } = this.props.actions.planSelection; - // const planConfig = [{ - // id: 'free', - // price: 0, - // }, { - // id: plans.personal.yearly.id, - // price: plans.personal.yearly.price, - // }, { - // id: plans.pro.yearly.id, - // price: plans.pro.yearly.price, - // }]; - return ( { + this.stores.user.getUserInfoRequest.invalidate({ immediately: true }); + this.stores.features.featuresRequest.invalidate({ immediately: true }); + onCloseWindow(); }); }; diff --git a/src/i18n/locales/defaultMessages.json b/src/i18n/locales/defaultMessages.json index 210ea001a..eafac1f87 100644 --- a/src/i18n/locales/defaultMessages.json +++ b/src/i18n/locales/defaultMessages.json @@ -482,55 +482,68 @@ } }, { - "defaultMessage": "!!!Sorry, we could not activate your trial!", + "defaultMessage": "!!!Free trial (normally {currency}{price} per month)", "end": { "column": 3, "line": 38 }, "file": "src/components/auth/Pricing.js", + "id": "pricing.trial.terms.trialWorth", + "start": { + "column": 14, + "line": 35 + } + }, + { + "defaultMessage": "!!!Sorry, we could not activate your trial!", + "end": { + "column": 3, + "line": 42 + }, + "file": "src/components/auth/Pricing.js", "id": "pricing.trial.error", "start": { "column": 19, - "line": 35 + "line": 39 } }, { "defaultMessage": "!!!Start my 14-day Franz Professional Trial", "end": { "column": 3, - "line": 42 + "line": 46 }, "file": "src/components/auth/Pricing.js", "id": "pricing.trial.cta.accept", "start": { "column": 13, - "line": 39 + "line": 43 } }, { "defaultMessage": "!!!Continue to Franz", "end": { "column": 3, - "line": 46 + "line": 50 }, "file": "src/components/auth/Pricing.js", "id": "pricing.trial.cta.skip", "start": { "column": 11, - "line": 43 + "line": 47 } }, { "defaultMessage": "!!!Franz Professional includes:", "end": { "column": 3, - "line": 50 + "line": 54 }, "file": "src/components/auth/Pricing.js", "id": "pricing.trial.features.headline", "start": { "column": 20, - "line": 47 + "line": 51 } } ], @@ -3923,6 +3936,19 @@ "column": 19, "line": 23 } + }, + { + "defaultMessage": "!!!Best value", + "end": { + "column": 3, + "line": 30 + }, + "file": "src/features/planSelection/components/PlanItem.js", + "id": "subscription.bestValue", + "start": { + "column": 13, + "line": 27 + } } ], "path": "src/features/planSelection/components/PlanItem.json" @@ -3933,143 +3959,143 @@ "defaultMessage": "!!!Welcome back, {name}", "end": { "column": 3, - "line": 19 + "line": 20 }, "file": "src/features/planSelection/components/PlanSelection.js", "id": "feature.planSelection.fullscreen.welcome", "start": { "column": 11, - "line": 16 + "line": 17 } }, { "defaultMessage": "!!!It's time to make a choice. Franz works best on our Personal and Professional plans. Please have a look and choose the best one for you.", "end": { "column": 3, - "line": 23 + "line": 24 }, "file": "src/features/planSelection/components/PlanSelection.js", "id": "feature.planSelection.fullscreen.subheadline", "start": { "column": 15, - "line": 20 + "line": 21 } }, { "defaultMessage": "!!!Basic functionality", "end": { "column": 3, - "line": 27 + "line": 28 }, "file": "src/features/planSelection/components/PlanSelection.js", "id": "feature.planSelection.free.text", "start": { "column": 12, - "line": 24 + "line": 25 } }, { "defaultMessage": "!!!More services, no waiting - ideal for personal use.", "end": { "column": 3, - "line": 31 + "line": 32 }, "file": "src/features/planSelection/components/PlanSelection.js", "id": "feature.planSelection.personal.text", "start": { "column": 16, - "line": 28 + "line": 29 } }, { "defaultMessage": "!!!Unlimited services and professional features for you - and your team.", "end": { "column": 3, - "line": 35 + "line": 36 }, "file": "src/features/planSelection/components/PlanSelection.js", "id": "feature.planSelection.pro.text", "start": { "column": 20, - "line": 32 + "line": 33 } }, { "defaultMessage": "!!!Stay on Free", "end": { "column": 3, - "line": 39 + "line": 40 }, "file": "src/features/planSelection/components/PlanSelection.js", "id": "feature.planSelection.cta.stayOnFree", "start": { "column": 17, - "line": 36 + "line": 37 } }, { "defaultMessage": "!!!Downgrade to Free", "end": { "column": 3, - "line": 43 + "line": 44 }, "file": "src/features/planSelection/components/PlanSelection.js", "id": "feature.planSelection.cta.ctaDowngradeFree", "start": { "column": 20, - "line": 40 + "line": 41 } }, { "defaultMessage": "!!!Start my free 14-days Trial", "end": { "column": 3, - "line": 47 + "line": 48 }, "file": "src/features/planSelection/components/PlanSelection.js", "id": "feature.planSelection.cta.trial", "start": { "column": 15, - "line": 44 + "line": 45 } }, { "defaultMessage": "!!!Choose Personal", "end": { "column": 3, - "line": 51 + "line": 52 }, "file": "src/features/planSelection/components/PlanSelection.js", "id": "feature.planSelection.cta.upgradePersonal", "start": { "column": 23, - "line": 48 + "line": 49 } }, { "defaultMessage": "!!!Choose Professional", "end": { "column": 3, - "line": 55 + "line": 56 }, "file": "src/features/planSelection/components/PlanSelection.js", "id": "feature.planSelection.cta.upgradePro", "start": { "column": 18, - "line": 52 + "line": 53 } }, { "defaultMessage": "!!!Complete comparison of all plans", "end": { "column": 3, - "line": 59 + "line": 60 }, "file": "src/features/planSelection/components/PlanSelection.js", "id": "feature.planSelection.fullFeatureList", "start": { "column": 19, - "line": 56 + "line": 57 } } ], @@ -4112,52 +4138,52 @@ "defaultMessage": "!!!Downgrade your Franz Plan", "end": { "column": 3, - "line": 19 + "line": 20 }, "file": "src/features/planSelection/containers/PlanSelectionScreen.js", "id": "feature.planSelection.fullscreen.dialog.title", "start": { "column": 15, - "line": 16 + "line": 17 } }, { "defaultMessage": "!!!You're about to downgrade to our Free account. Are you sure? Click here instead to get more services and functionality for just {currency}{price} a month.", "end": { "column": 3, - "line": 23 + "line": 24 }, "file": "src/features/planSelection/containers/PlanSelectionScreen.js", "id": "feature.planSelection.fullscreen.dialog.message", "start": { "column": 17, - "line": 20 + "line": 21 } }, { "defaultMessage": "!!!Downgrade to Free", "end": { "column": 3, - "line": 27 + "line": 28 }, "file": "src/features/planSelection/containers/PlanSelectionScreen.js", "id": "feature.planSelection.fullscreen.dialog.cta.downgrade", "start": { "column": 22, - "line": 24 + "line": 25 } }, { "defaultMessage": "!!!Choose Personal", "end": { "column": 3, - "line": 31 + "line": 32 }, "file": "src/features/planSelection/containers/PlanSelectionScreen.js", "id": "feature.planSelection.fullscreen.dialog.cta.upgrade", "start": { "column": 20, - "line": 28 + "line": 29 } } ], diff --git a/src/i18n/locales/en-US.json b/src/i18n/locales/en-US.json index f2fd7a52a..6977ec096 100644 --- a/src/i18n/locales/en-US.json +++ b/src/i18n/locales/en-US.json @@ -170,6 +170,7 @@ "pricing.trial.terms.automaticTrialEnd": "Your free trial ends automatically after 14 days", "pricing.trial.terms.headline": "No strings attached", "pricing.trial.terms.noCreditCard": "No credit card required", + "pricing.trial.terms.trialWorth": "Free trial (normally {currency}{price} per month)", "service.crashHandler.action": "Reload {name}", "service.crashHandler.autoReload": "Trying to automatically restore {name} in {seconds} seconds", "service.crashHandler.headline": "Oh no!", @@ -369,6 +370,7 @@ "signup.link.login": "Already have an account, sign in?", "signup.password.label": "Password", "signup.submit.label": "Create account", + "subscription.bestValue": "Best value", "subscription.cta.activateTrial": "Yes, start the free Franz Professional trial", "subscription.cta.allOptions": "See all options", "subscription.cta.choosePlan": "Choose your plan", @@ -413,4 +415,4 @@ "workspaceDrawer.workspaceFeatureInfo": "

Franz Workspaces let you focus on what’s important right now. Set up different sets of services and easily switch between them at any time.

You decide which services you need when and where, so we can help you stay on top of your game - or easily switch off from work whenever you want.

", "workspaceDrawer.workspacesSettingsTooltip": "Edit workspaces settings", "workspaces.switchingIndicator.switchingTo": "Switching to" -} \ 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 2d09c9ebb..3f0cf4e86 100644 --- a/src/i18n/messages/src/components/auth/Pricing.json +++ b/src/i18n/messages/src/components/auth/Pricing.json @@ -64,16 +64,29 @@ "column": 3 } }, + { + "id": "pricing.trial.terms.trialWorth", + "defaultMessage": "!!!Free trial (normally {currency}{price} per month)", + "file": "src/components/auth/Pricing.js", + "start": { + "line": 35, + "column": 14 + }, + "end": { + "line": 38, + "column": 3 + } + }, { "id": "pricing.trial.error", "defaultMessage": "!!!Sorry, we could not activate your trial!", "file": "src/components/auth/Pricing.js", "start": { - "line": 35, + "line": 39, "column": 19 }, "end": { - "line": 38, + "line": 42, "column": 3 } }, @@ -82,11 +95,11 @@ "defaultMessage": "!!!Start my 14-day Franz Professional Trial", "file": "src/components/auth/Pricing.js", "start": { - "line": 39, + "line": 43, "column": 13 }, "end": { - "line": 42, + "line": 46, "column": 3 } }, @@ -95,11 +108,11 @@ "defaultMessage": "!!!Continue to Franz", "file": "src/components/auth/Pricing.js", "start": { - "line": 43, + "line": 47, "column": 11 }, "end": { - "line": 46, + "line": 50, "column": 3 } }, @@ -108,11 +121,11 @@ "defaultMessage": "!!!Franz Professional includes:", "file": "src/components/auth/Pricing.js", "start": { - "line": 47, + "line": 51, "column": 20 }, "end": { - "line": 50, + "line": 54, "column": 3 } } diff --git a/src/i18n/messages/src/features/planSelection/components/PlanItem.json b/src/i18n/messages/src/features/planSelection/components/PlanItem.json index 839686390..5a94f32ee 100644 --- a/src/i18n/messages/src/features/planSelection/components/PlanItem.json +++ b/src/i18n/messages/src/features/planSelection/components/PlanItem.json @@ -4,11 +4,11 @@ "defaultMessage": "!!!per month", "file": "src/features/planSelection/components/PlanItem.js", "start": { - "line": 19, + "line": 15, "column": 12 }, "end": { - "line": 22, + "line": 18, "column": 3 } }, @@ -17,9 +17,22 @@ "defaultMessage": "!!!per month & user", "file": "src/features/planSelection/components/PlanItem.js", "start": { - "line": 23, + "line": 19, "column": 19 }, + "end": { + "line": 22, + "column": 3 + } + }, + { + "id": "subscription.bestValue", + "defaultMessage": "!!!Best value", + "file": "src/features/planSelection/components/PlanItem.js", + "start": { + "line": 23, + "column": 13 + }, "end": { "line": 26, "column": 3 -- cgit v1.2.3-70-g09d2 From b6276bd0cb88ce681bc35a6fc7b1ae0cf6ac56ea Mon Sep 17 00:00:00 2001 From: Stefan Malzner Date: Thu, 17 Oct 2019 14:12:36 +0200 Subject: optimize trial signup flow --- src/actions/user.js | 4 +- src/api/server/ServerApi.js | 2 +- src/components/auth/Pricing.js | 92 +++++++++++++++------ src/containers/auth/PricingScreen.js | 17 ++-- src/containers/auth/SignupScreen.js | 22 ++++- src/i18n/locales/defaultMessages.json | 94 +++++++++++++++++----- src/i18n/locales/en-US.json | 6 +- src/i18n/messages/src/components/auth/Pricing.json | 81 ++++++++++++++----- src/stores/FeaturesStore.js | 1 + src/stores/UserStore.js | 4 +- 10 files changed, 245 insertions(+), 78 deletions(-) (limited to 'src/components/auth') diff --git a/src/actions/user.js b/src/actions/user.js index 5d7d9a899..7061a367a 100644 --- a/src/actions/user.js +++ b/src/actions/user.js @@ -11,8 +11,10 @@ export default { lastname: PropTypes.string.isRequired, email: PropTypes.string.isRequired, password: PropTypes.string.isRequired, - accountType: PropTypes.string.isRequired, + accountType: PropTypes.string, company: PropTypes.string, + plan: PropTypes.string, + currency: PropTypes.string, }, retrievePassword: { email: PropTypes.string.isRequired, diff --git a/src/api/server/ServerApi.js b/src/api/server/ServerApi.js index f56c7b6e4..1f538368d 100644 --- a/src/api/server/ServerApi.js +++ b/src/api/server/ServerApi.js @@ -87,7 +87,7 @@ export default class ServerApi { } const trial = await request.json(); - debug('ServerApi::signup resolves', trial); + debug('ServerApi::activateTrial resolves', trial); return true; } diff --git a/src/components/auth/Pricing.js b/src/components/auth/Pricing.js index 67af04470..86b6a4263 100644 --- a/src/components/auth/Pricing.js +++ b/src/components/auth/Pricing.js @@ -13,12 +13,20 @@ import { FeatureList } from '../ui/FeatureList'; const messages = defineMessages({ headline: { - id: 'pricing.trial.headline', - defaultMessage: '!!!Franz Professional', + id: 'pricing.trial.headline.pro', + defaultMessage: '!!!Hi {name}, welcome to Franz', }, - personalOffer: { - id: 'pricing.trial.subheadline', - defaultMessage: '!!!Here\'s a special welcome for you:', + specialTreat: { + id: 'pricing.trial.intro.specialTreat', + defaultMessage: '!!!We have a special treat for you.', + }, + tryPro: { + id: 'pricing.trial.intro.tryPro', + defaultMessage: '!!!Enjoy the full Franz Professional experience completely free for 14 days.', + }, + happyMessaging: { + id: 'pricing.trial.intro.happyMessaging', + defaultMessage: '!!!Happy messaging,', }, noStringsAttachedHeadline: { id: 'pricing.trial.terms.headline', @@ -44,6 +52,10 @@ const messages = defineMessages({ id: 'pricing.trial.cta.accept', defaultMessage: '!!!Start my 14-day Franz Professional Trial ', }, + ctaStart: { + id: 'pricing.trial.cta.start', + defaultMessage: '!!!Start using Franz', + }, ctaSkip: { id: 'pricing.trial.cta.skip', defaultMessage: '!!!Continue to Franz', @@ -98,6 +110,34 @@ const styles = theme => ({ margin: [20, 0, 0], color: theme.styleTypes.danger.accent, }, + priceContainer: { + display: 'flex', + justifyContent: 'space-evenly', + margin: [10, 0, 15], + }, + price: { + '& sup': { + verticalAlign: 14, + fontSize: 20, + }, + }, + figure: { + fontSize: 40, + }, + regularPrice: { + position: 'relative', + + '&:before': { + content: '" "', + position: 'absolute', + width: '130%', + height: 1, + top: 14, + left: -12, + borderBottom: [3, 'solid', 'red'], + transform: 'rotateZ(-20deg)', + }, + }, }); export default @observer @injectSheet(styles) class Signup extends Component { @@ -129,6 +169,8 @@ export default @observer @injectSheet(styles) class Signup extends Component { } = this.props; const { intl } = this.context; + const [intPart, fractionPart] = (price).toString().split('.'); + return (
@@ -140,25 +182,39 @@ export default @observer @injectSheet(styles) class Signup extends Component { alt="" /> )} -

{intl.formatMessage(messages.personalOffer)}

-

{intl.formatMessage(messages.headline)}

+

{intl.formatMessage(messages.headline, { name: 'Stefan' })}

- We built Franz with a lot of effort, manpower and love, - to boost up your messaging experience. + {intl.formatMessage(messages.specialTreat)}

- For the next 14 days, we are going to give you the full Franz Professional experience so you can watch your communication evolve! + {intl.formatMessage(messages.tryPro)}

- Thanks for being a hero. + {intl.formatMessage(messages.happyMessaging)}

Stefan Malzner

+
+

+ + {currency} + {intPart} + + {fractionPart} +

+

+ + {currency} + 0 + + 00 +

+

{intl.formatMessage(messages.noStringsAttachedHeadline)} @@ -179,7 +235,7 @@ export default @observer @injectSheet(styles) class Signup extends Component {

{intl.formatMessage(messages.activationError)}

)}

- {/*
    - - - - - - - - - - -
*/}
diff --git a/src/containers/auth/PricingScreen.js b/src/containers/auth/PricingScreen.js index ff378bd8b..55811ed23 100644 --- a/src/containers/auth/PricingScreen.js +++ b/src/containers/auth/PricingScreen.js @@ -20,14 +20,19 @@ export default @inject('stores', 'actions') @observer class PricingScreen extend } = this.props; const { activateTrialRequest } = stores.user; - const { defaultTrialPlan } = stores.features.features; + const { defaultTrialPlan, canSkipTrial } = stores.features.anonymousFeatures; - actions.user.activateTrial({ planId: defaultTrialPlan }); - await activateTrialRequest._promise; - - if (!activateTrialRequest.isError) { + if (!canSkipTrial) { stores.router.push('/'); stores.user.hasCompletedSignup = true; + } else { + actions.user.activateTrial({ planId: defaultTrialPlan }); + await activateTrialRequest._promise; + + if (!activateTrialRequest.isError) { + stores.router.push('/'); + stores.user.hasCompletedSignup = true; + } } } @@ -43,7 +48,7 @@ export default @inject('stores', 'actions') @observer class PricingScreen extend const { pricingConfig } = features; let currency = '$'; - let price = '5.99'; + let price = 5.99; if (pricingConfig) { ({ currency } = pricingConfig); ({ price } = pricingConfig.plans.pro.yearly); diff --git a/src/containers/auth/SignupScreen.js b/src/containers/auth/SignupScreen.js index efc7ea4c1..f93498be2 100644 --- a/src/containers/auth/SignupScreen.js +++ b/src/containers/auth/SignupScreen.js @@ -4,6 +4,7 @@ import { inject, observer } from 'mobx-react'; import Signup from '../../components/auth/Signup'; import UserStore from '../../stores/UserStore'; +import FeaturesStore from '../../stores/FeaturesStore'; import { globalError as globalErrorPropType } from '../../prop-types'; @@ -12,11 +13,27 @@ export default @inject('stores', 'actions') @observer class SignupScreen extends error: globalErrorPropType.isRequired, }; + onSignup(values) { + const { actions, stores } = this.props; + + const { canSkipTrial, defaultTrialPlan, pricingConfig } = stores.features.anonymousFeatures; + + if (!canSkipTrial) { + Object.assign(values, { + plan: defaultTrialPlan, + currency: pricingConfig.currencyID, + }); + } + + actions.user.signup(values); + } + render() { - const { actions, stores, error } = this.props; + const { stores, error } = this.props; + return ( this.onSignup(values)} isSubmitting={stores.user.signupRequest.isExecuting} loginRoute={stores.user.loginRoute} error={error} @@ -33,5 +50,6 @@ SignupScreen.wrappedComponent.propTypes = { }).isRequired, stores: PropTypes.shape({ user: PropTypes.instanceOf(UserStore).isRequired, + features: PropTypes.instanceOf(FeaturesStore).isRequired, }).isRequired, }; diff --git a/src/i18n/locales/defaultMessages.json b/src/i18n/locales/defaultMessages.json index cd876c0ea..e46c69d67 100644 --- a/src/i18n/locales/defaultMessages.json +++ b/src/i18n/locales/defaultMessages.json @@ -417,133 +417,185 @@ { "descriptors": [ { - "defaultMessage": "!!!Franz Professional", + "defaultMessage": "!!!Hi {name}, welcome to Franz", "end": { "column": 3, "line": 18 }, "file": "src/components/auth/Pricing.js", - "id": "pricing.trial.headline", + "id": "pricing.trial.headline.pro", "start": { "column": 12, "line": 15 } }, { - "defaultMessage": "!!!Here's a special welcome for you:", + "defaultMessage": "!!!We have a special treat for you.", "end": { "column": 3, "line": 22 }, "file": "src/components/auth/Pricing.js", + "id": "pricing.trial.intro.specialTreat", + "start": { + "column": 16, + "line": 19 + } + }, + { + "defaultMessage": "!!!Try out the full Franz Professional experience completely free for 14 days.", + "end": { + "column": 3, + "line": 26 + }, + "file": "src/components/auth/Pricing.js", + "id": "pricing.trial.intro.tryPro", + "start": { + "column": 10, + "line": 23 + } + }, + { + "defaultMessage": "!!!Happy messaging,", + "end": { + "column": 3, + "line": 30 + }, + "file": "src/components/auth/Pricing.js", + "id": "pricing.trial.intro.happyMessaging", + "start": { + "column": 18, + "line": 27 + } + }, + { + "defaultMessage": "!!!Here's a special welcome for you:", + "end": { + "column": 3, + "line": 34 + }, + "file": "src/components/auth/Pricing.js", "id": "pricing.trial.subheadline", "start": { "column": 17, - "line": 19 + "line": 31 } }, { "defaultMessage": "!!!No strings attached", "end": { "column": 3, - "line": 26 + "line": 38 }, "file": "src/components/auth/Pricing.js", "id": "pricing.trial.terms.headline", "start": { "column": 29, - "line": 23 + "line": 35 } }, { "defaultMessage": "!!!No credit card required", "end": { "column": 3, - "line": 30 + "line": 42 }, "file": "src/components/auth/Pricing.js", "id": "pricing.trial.terms.noCreditCard", "start": { "column": 16, - "line": 27 + "line": 39 } }, { "defaultMessage": "!!!Your free trial ends automatically after 14 days", "end": { "column": 3, - "line": 34 + "line": 46 }, "file": "src/components/auth/Pricing.js", "id": "pricing.trial.terms.automaticTrialEnd", "start": { "column": 21, - "line": 31 + "line": 43 } }, { "defaultMessage": "!!!Free trial (normally {currency}{price} per month)", "end": { "column": 3, - "line": 38 + "line": 50 }, "file": "src/components/auth/Pricing.js", "id": "pricing.trial.terms.trialWorth", "start": { "column": 14, - "line": 35 + "line": 47 } }, { "defaultMessage": "!!!Sorry, we could not activate your trial!", "end": { "column": 3, - "line": 42 + "line": 54 }, "file": "src/components/auth/Pricing.js", "id": "pricing.trial.error", "start": { "column": 19, - "line": 39 + "line": 51 } }, { "defaultMessage": "!!!Start my 14-day Franz Professional Trial", "end": { "column": 3, - "line": 46 + "line": 58 }, "file": "src/components/auth/Pricing.js", "id": "pricing.trial.cta.accept", "start": { "column": 13, - "line": 43 + "line": 55 + } + }, + { + "defaultMessage": "!!!Start using Franz", + "end": { + "column": 3, + "line": 62 + }, + "file": "src/components/auth/Pricing.js", + "id": "pricing.trial.cta.start", + "start": { + "column": 12, + "line": 59 } }, { "defaultMessage": "!!!Continue to Franz", "end": { "column": 3, - "line": 50 + "line": 66 }, "file": "src/components/auth/Pricing.js", "id": "pricing.trial.cta.skip", "start": { "column": 11, - "line": 47 + "line": 63 } }, { "defaultMessage": "!!!Franz Professional includes:", "end": { "column": 3, - "line": 54 + "line": 70 }, "file": "src/components/auth/Pricing.js", "id": "pricing.trial.features.headline", "start": { "column": 20, - "line": 51 + "line": 67 } } ], @@ -3956,7 +4008,7 @@ { "descriptors": [ { - "defaultMessage": "!!!Welcome back, {name}", + "defaultMessage": "!!!Are you ready to choose, {name}", "end": { "column": 3, "line": 20 diff --git a/src/i18n/locales/en-US.json b/src/i18n/locales/en-US.json index 8af42554b..6b0aebb13 100644 --- a/src/i18n/locales/en-US.json +++ b/src/i18n/locales/en-US.json @@ -170,9 +170,13 @@ "pricing.plan.pro-yearly": "Professional Yearly", "pricing.trial.cta.accept": "Start my 14-day Franz Professional Trial ", "pricing.trial.cta.skip": "Continue to Franz", + "pricing.trial.cta.start": "Start using Franz", "pricing.trial.error": "Sorry, we could not activate your trial!", "pricing.trial.features.headline": "Franz Professional includes:", - "pricing.trial.headline": "Franz Professional", + "pricing.trial.headline.pro": "Hi {name}, welcome to Franz", + "pricing.trial.intro.happyMessaging": "Happy messaging,", + "pricing.trial.intro.specialTreat": "We have a special treat for you.", + "pricing.trial.intro.tryPro": "Enjoy the full Franz Professional experience completely free for 14 days.", "pricing.trial.subheadline": "Here's a special welcome for you:", "pricing.trial.terms.automaticTrialEnd": "Your free trial ends automatically after 14 days", "pricing.trial.terms.headline": "No strings attached", diff --git a/src/i18n/messages/src/components/auth/Pricing.json b/src/i18n/messages/src/components/auth/Pricing.json index 3f0cf4e86..6db39148c 100644 --- a/src/i18n/messages/src/components/auth/Pricing.json +++ b/src/i18n/messages/src/components/auth/Pricing.json @@ -1,7 +1,7 @@ [ { - "id": "pricing.trial.headline", - "defaultMessage": "!!!Franz Professional", + "id": "pricing.trial.headline.pro", + "defaultMessage": "!!!Hi {name}, welcome to Franz", "file": "src/components/auth/Pricing.js", "start": { "line": 15, @@ -13,28 +13,54 @@ } }, { - "id": "pricing.trial.subheadline", - "defaultMessage": "!!!Here's a special welcome for you:", + "id": "pricing.trial.intro.specialTreat", + "defaultMessage": "!!!We have a special treat for you.", "file": "src/components/auth/Pricing.js", "start": { "line": 19, - "column": 17 + "column": 16 }, "end": { "line": 22, "column": 3 } }, + { + "id": "pricing.trial.intro.tryPro", + "defaultMessage": "!!!Enjoy the full Franz Professional experience completely free for 14 days.", + "file": "src/components/auth/Pricing.js", + "start": { + "line": 23, + "column": 10 + }, + "end": { + "line": 26, + "column": 3 + } + }, + { + "id": "pricing.trial.intro.happyMessaging", + "defaultMessage": "!!!Happy messaging,", + "file": "src/components/auth/Pricing.js", + "start": { + "line": 27, + "column": 18 + }, + "end": { + "line": 30, + "column": 3 + } + }, { "id": "pricing.trial.terms.headline", "defaultMessage": "!!!No strings attached", "file": "src/components/auth/Pricing.js", "start": { - "line": 23, + "line": 31, "column": 29 }, "end": { - "line": 26, + "line": 34, "column": 3 } }, @@ -43,11 +69,11 @@ "defaultMessage": "!!!No credit card required", "file": "src/components/auth/Pricing.js", "start": { - "line": 27, + "line": 35, "column": 16 }, "end": { - "line": 30, + "line": 38, "column": 3 } }, @@ -56,11 +82,11 @@ "defaultMessage": "!!!Your free trial ends automatically after 14 days", "file": "src/components/auth/Pricing.js", "start": { - "line": 31, + "line": 39, "column": 21 }, "end": { - "line": 34, + "line": 42, "column": 3 } }, @@ -69,11 +95,11 @@ "defaultMessage": "!!!Free trial (normally {currency}{price} per month)", "file": "src/components/auth/Pricing.js", "start": { - "line": 35, + "line": 43, "column": 14 }, "end": { - "line": 38, + "line": 46, "column": 3 } }, @@ -82,11 +108,11 @@ "defaultMessage": "!!!Sorry, we could not activate your trial!", "file": "src/components/auth/Pricing.js", "start": { - "line": 39, + "line": 47, "column": 19 }, "end": { - "line": 42, + "line": 50, "column": 3 } }, @@ -95,11 +121,24 @@ "defaultMessage": "!!!Start my 14-day Franz Professional Trial", "file": "src/components/auth/Pricing.js", "start": { - "line": 43, + "line": 51, "column": 13 }, "end": { - "line": 46, + "line": 54, + "column": 3 + } + }, + { + "id": "pricing.trial.cta.start", + "defaultMessage": "!!!Start using Franz", + "file": "src/components/auth/Pricing.js", + "start": { + "line": 55, + "column": 12 + }, + "end": { + "line": 58, "column": 3 } }, @@ -108,11 +147,11 @@ "defaultMessage": "!!!Continue to Franz", "file": "src/components/auth/Pricing.js", "start": { - "line": 47, + "line": 59, "column": 11 }, "end": { - "line": 50, + "line": 62, "column": 3 } }, @@ -121,11 +160,11 @@ "defaultMessage": "!!!Franz Professional includes:", "file": "src/components/auth/Pricing.js", "start": { - "line": 51, + "line": 63, "column": 20 }, "end": { - "line": 54, + "line": 66, "column": 3 } } diff --git a/src/stores/FeaturesStore.js b/src/stores/FeaturesStore.js index 5d379fd3e..adbd401b4 100644 --- a/src/stores/FeaturesStore.js +++ b/src/stores/FeaturesStore.js @@ -67,6 +67,7 @@ export default class FeaturesStore extends Store { if (this.stores.user.isLoggedIn) { this.featuresRequest.invalidate({ immediately: true }); } else { + this.defaultFeaturesRequest.execute(); this.defaultFeaturesRequest.invalidate({ immediately: true }); } } diff --git a/src/stores/UserStore.js b/src/stores/UserStore.js index 735e8f886..297ea1121 100644 --- a/src/stores/UserStore.js +++ b/src/stores/UserStore.js @@ -205,7 +205,7 @@ export default class UserStore extends Store { } @action async _signup({ - firstname, lastname, email, password, accountType, company, + firstname, lastname, email, password, accountType, company, plan, currency, }) { const authToken = await this.signupRequest.execute({ firstname, @@ -215,6 +215,8 @@ export default class UserStore extends Store { accountType, company, locale: this.stores.app.locale, + plan, + currency, }); this.hasCompletedSignup = false; -- cgit v1.2.3-70-g09d2 From 71b9e05d45bac8a592b859dbb707fe4ac8ff4ffd Mon Sep 17 00:00:00 2001 From: Stefan Malzner Date: Fri, 18 Oct 2019 14:30:29 +0200 Subject: Fix name in pricing screen --- src/components/auth/Pricing.js | 4 +++- src/containers/auth/PricingScreen.js | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) (limited to 'src/components/auth') diff --git a/src/components/auth/Pricing.js b/src/components/auth/Pricing.js index 86b6a4263..53ae046a0 100644 --- a/src/components/auth/Pricing.js +++ b/src/components/auth/Pricing.js @@ -150,6 +150,7 @@ export default @observer @injectSheet(styles) class Signup extends Component { classes: PropTypes.object.isRequired, currency: PropTypes.string.isRequired, price: PropTypes.number.isRequired, + name: PropTypes.string.isRequired, }; static contextTypes = { @@ -166,6 +167,7 @@ export default @observer @injectSheet(styles) class Signup extends Component { classes, currency, price, + name, } = this.props; const { intl } = this.context; @@ -182,7 +184,7 @@ export default @observer @injectSheet(styles) class Signup extends Component { alt="" /> )} -

{intl.formatMessage(messages.headline, { name: 'Stefan' })}

+

{intl.formatMessage(messages.headline, { name })}

{intl.formatMessage(messages.specialTreat)} diff --git a/src/containers/auth/PricingScreen.js b/src/containers/auth/PricingScreen.js index 55811ed23..21c859c12 100644 --- a/src/containers/auth/PricingScreen.js +++ b/src/containers/auth/PricingScreen.js @@ -42,7 +42,7 @@ export default @inject('stores', 'actions') @observer class PricingScreen extend stores, } = this.props; - const { getUserInfoRequest, activateTrialRequest } = stores.user; + const { getUserInfoRequest, activateTrialRequest, data } = stores.user; const { featuresRequest, features } = stores.features; const { pricingConfig } = features; @@ -64,6 +64,7 @@ export default @inject('stores', 'actions') @observer class PricingScreen extend error={error} currency={currency} price={price} + name={data.firstname} /> ); } -- cgit v1.2.3-70-g09d2