Skip to content
This repository was archived by the owner on Aug 11, 2021. It is now read-only.

Commit eef60fe

Browse files
committed
Plans descriptions, plans table, logos and titles dynamic
1 parent 6f0c987 commit eef60fe

File tree

4 files changed

+110
-84
lines changed

4 files changed

+110
-84
lines changed

containers/payments/PlansTable.js

Lines changed: 64 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,12 @@ const PlansTable = ({
2626
cycle = DEFAULT_CYCLE,
2727
updateCurrency,
2828
updateCycle,
29-
onSelect
29+
onSelect,
30+
expand = false
3031
}) => {
3132
const planName = getPlanName(subscription) || FREE;
3233
const { hasPaidVpn } = user;
33-
const { state, toggle } = useToggle();
34+
const { state, toggle } = useToggle(expand);
3435
const mySubscription = c('Title').t`My subscription`;
3536

3637
const getPrice = (planName) => {
@@ -310,54 +311,65 @@ const PlansTable = ({
310311
</td>
311312
</tr>
312313
) : null}
313-
<tr>
314-
<th scope="row" className="pm-simple-table-row-th alignleft bg-global-light">
315-
<span className="mr0-5">ProtonVPN</span>
316-
<Info title={c('Tooltip').t`ProtonVPN keeps your Internet traffic private`} />
317-
</th>
318-
<td className="aligncenter">
319-
<SmallButton className="pm-button--link" onClick={onSelect({ vpnplus: 1 })}>
320-
{hasPaidVpn ? c('Action').t`Edit VPN` : c('Action').t`Add VPN`}
321-
</SmallButton>
322-
</td>
323-
<td className="aligncenter">
324-
<SmallButton className="pm-button--link" onClick={onSelect({ plus: 1, vpnplus: 1 })}>
325-
{hasPaidVpn ? c('Action').t`Edit VPN` : c('Action').t`Add VPN`}
326-
</SmallButton>
327-
</td>
328-
<td className="aligncenter">
329-
<SmallButton className="pm-button--link" onClick={onSelect({ professional: 1, vpnplus: 1 })}>
330-
{hasPaidVpn ? c('Action').t`Edit VPN` : c('Action').t`Add VPN`}
331-
</SmallButton>
332-
</td>
333-
<td className="aligncenter">{c('Plan option').t`Included`}</td>
334-
</tr>
335-
<tr>
336-
<th scope="row" className="pm-simple-table-row-th alignleft bg-global-light">
337-
<SmallButton className="pm-button--link" onClick={toggle}>
338-
{state ? c('Action').t`Hide additional features` : c('Action').t`Compare all features`}
339-
</SmallButton>
340-
</th>
341-
<td className="aligncenter">
342-
<SmallButton className="pm-button--primary" onClick={onSelect()}>{c('Action')
343-
.t`Update`}</SmallButton>
344-
</td>
345-
<td className="aligncenter">
346-
<SmallButton className="pm-button--primary" onClick={onSelect({ plus: 1, vpnplus: 1 })}>{c(
347-
'Action'
348-
).t`Update`}</SmallButton>
349-
</td>
350-
<td className="aligncenter">
351-
<SmallButton
352-
className="pm-button--primary"
353-
onClick={onSelect({ professional: 1, vpnplus: 1 })}
354-
>{c('Action').t`Update`}</SmallButton>
355-
</td>
356-
<td className="aligncenter">
357-
<SmallButton className="pm-button--primary" onClick={onSelect({ visionary: 1 })}>{c('Action')
358-
.t`Update`}</SmallButton>
359-
</td>
360-
</tr>
314+
{onSelect && (
315+
<>
316+
<tr>
317+
<th scope="row" className="pm-simple-table-row-th alignleft bg-global-light">
318+
<span className="mr0-5">ProtonVPN</span>
319+
<Info title={c('Tooltip').t`ProtonVPN keeps your Internet traffic private`} />
320+
</th>
321+
<td className="aligncenter">
322+
<SmallButton className="pm-button--link" onClick={onSelect({ vpnplus: 1 })}>
323+
{hasPaidVpn ? c('Action').t`Edit VPN` : c('Action').t`Add VPN`}
324+
</SmallButton>
325+
</td>
326+
<td className="aligncenter">
327+
<SmallButton className="pm-button--link" onClick={onSelect({ plus: 1, vpnplus: 1 })}>
328+
{hasPaidVpn ? c('Action').t`Edit VPN` : c('Action').t`Add VPN`}
329+
</SmallButton>
330+
</td>
331+
<td className="aligncenter">
332+
<SmallButton
333+
className="pm-button--link"
334+
onClick={onSelect({ professional: 1, vpnplus: 1 })}
335+
>
336+
{hasPaidVpn ? c('Action').t`Edit VPN` : c('Action').t`Add VPN`}
337+
</SmallButton>
338+
</td>
339+
<td className="aligncenter">{c('Plan option').t`Included`}</td>
340+
</tr>
341+
<tr>
342+
<th scope="row" className="pm-simple-table-row-th alignleft bg-global-light">
343+
<SmallButton className="pm-button--link" onClick={toggle}>
344+
{state
345+
? c('Action').t`Hide additional features`
346+
: c('Action').t`Compare all features`}
347+
</SmallButton>
348+
</th>
349+
<td className="aligncenter">
350+
<SmallButton className="pm-button--primary" onClick={onSelect()}>{c('Action')
351+
.t`Update`}</SmallButton>
352+
</td>
353+
<td className="aligncenter">
354+
<SmallButton
355+
className="pm-button--primary"
356+
onClick={onSelect({ plus: 1, vpnplus: 1 })}
357+
>{c('Action').t`Update`}</SmallButton>
358+
</td>
359+
<td className="aligncenter">
360+
<SmallButton
361+
className="pm-button--primary"
362+
onClick={onSelect({ professional: 1, vpnplus: 1 })}
363+
>{c('Action').t`Update`}</SmallButton>
364+
</td>
365+
<td className="aligncenter">
366+
<SmallButton className="pm-button--primary" onClick={onSelect({ visionary: 1 })}>{c(
367+
'Action'
368+
).t`Update`}</SmallButton>
369+
</td>
370+
</tr>
371+
</>
372+
)}
361373
</tbody>
362374
</table>
363375
);
@@ -371,7 +383,8 @@ PlansTable.propTypes = {
371383
user: PropTypes.object,
372384
updateCurrency: PropTypes.func,
373385
updateCycle: PropTypes.func,
374-
onSelect: PropTypes.func
386+
onSelect: PropTypes.func,
387+
expand: PropTypes.bool
375388
};
376389

377390
export default PlansTable;

containers/signup/AccountStep/LoginPromptModal.js

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,17 @@ import PropTypes from 'prop-types';
33
import { FormModal, PrimaryButton, Alert } from 'react-components';
44
import { c } from 'ttag';
55
import { Link } from 'react-router-dom';
6+
import useConfig from '../../config/useConfig';
7+
import { CLIENT_TYPES } from 'proton-shared/lib/constants';
68

7-
// TODO: make it more generic (title, login url)
89
const LoginPromptModal = ({ email, ...rest }) => {
10+
const { CLIENT_TYPE } = useConfig();
11+
12+
const title = CLIENT_TYPE === CLIENT_TYPES.VPN ? 'ProtonVPN' : 'ProtonMail';
13+
914
return (
1015
<FormModal
11-
title={c('Title').t`ProtonVPN`}
16+
title={title}
1217
close={c('Action').t`Cancel`}
1318
submit={
1419
<Link to="/login">

containers/signup/SignupContainer.js

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
33
import { c } from 'ttag';
44
import { Button, Title, useLoading, TextLoader, VpnLogo, Href, FullLoader, SupportDropdown } from 'react-components';
55
import { checkCookie } from 'proton-shared/lib/helpers/cookies';
6-
import { CYCLE } from 'proton-shared/lib/constants';
6+
import { CYCLE, CLIENT_TYPES } from 'proton-shared/lib/constants';
77
import AccountStep from './AccountStep/AccountStep';
88
import PlanStep from './PlanStep/PlanStep';
99
import useSignup from './useSignup';
@@ -15,6 +15,7 @@ import PlanUpsell from './SelectedPlan/PlanUpsell';
1515
import useVerification from './VerificationStep/useVerification';
1616
import MobileRedirectionStep from './MobileRedirectionStep/MobileRedirectionStep';
1717
import useConfig from '../config/useConfig';
18+
import MailLogo from '../../components/logo/MailLogo';
1819

1920
const SignupState = {
2021
Plan: 'plan',
@@ -24,8 +25,7 @@ const SignupState = {
2425
MobileRedirection: 'mobile-redirection'
2526
};
2627

27-
// TODO: Flexible urls and plans for reuse between project
28-
const SignupContainer = ({ match, history, onLogin, stopRedirect, renderPlansTable }) => {
28+
const SignupContainer = ({ match, history, onLogin, stopRedirect, renderPlansTable, homepageUrl }) => {
2929
const { CLIENT_TYPE } = useConfig();
3030
const searchParams = new URLSearchParams(history.location.search);
3131
const preSelectedPlan = searchParams.get('plan');
@@ -154,13 +154,17 @@ const SignupContainer = ({ match, history, onLogin, stopRedirect, renderPlansTab
154154
(signupState && signupState !== SignupState.Plan ? (
155155
<Button onClick={() => history.goBack()}>{c('Action').t`Back`}</Button>
156156
) : (
157-
<Href className="pm-button" url="https://protonvpn.com" target="_self">{c('Action')
157+
<Href className="pm-button" url={homepageUrl} target="_self">{c('Action')
158158
.t`Homepage`}</Href>
159159
))}
160160
</div>
161161
<div className="onmobile-min-w100 onmobile-aligncenter onmobile-mt0-5">
162162
<Href url="https://protonvpn.com" target="_self">
163-
<VpnLogo className="fill-primary" />
163+
{CLIENT_TYPE === CLIENT_TYPES.VPN ? (
164+
<VpnLogo className="fill-primary" />
165+
) : (
166+
<MailLogo className="fill-primary" />
167+
)}
164168
</Href>
165169
</div>
166170
<div className="flex-item-fluid alignright plan-help-button">
@@ -217,6 +221,7 @@ const SignupContainer = ({ match, history, onLogin, stopRedirect, renderPlansTab
217221
};
218222

219223
SignupContainer.propTypes = {
224+
homepageUrl: PropTypes.string.isRequired,
220225
stopRedirect: PropTypes.func.isRequired,
221226
onLogin: PropTypes.func.isRequired,
222227
match: PropTypes.shape({

containers/signup/plans.tsx

Lines changed: 29 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ export const VPN_PLANS = [PLAN.FREE, PLAN.VPNBASIC, PLAN.VPNPLUS, PLAN.VISIONARY
3636
export const VPN_BEST_DEAL_PLANS = [PLAN.VPNBASIC, PLAN.VPNPLUS, PLAN.VISIONARY];
3737

3838
type MailPlans = PLAN.FREE | PLAN.PLUS | PLAN.VISIONARY | PLAN.PROFESSIONAL;
39-
export const MAIL_PLANS = [PLAN.FREE, PLAN.PLUS, PLAN.PROFESSIONAL, PLAN.VISIONARY];
39+
export const MAIL_PLANS = [PLAN.FREE, PLAN.PLUS, PLAN.VISIONARY, PLAN.PROFESSIONAL];
4040

4141
export const getPlusPlan = (clientType: CLIENT_TYPES) => (clientType === CLIENT_TYPES.VPN ? PLAN.VPNPLUS : PLAN.PLUS);
4242

@@ -145,7 +145,7 @@ const getMailPlanFeatures = (plan: MailPlans) =>
145145
({
146146
[PLAN.FREE]: {
147147
image: <div>FREE PLAN IMAGE</div>,
148-
description: c('Plan Description').t`Free plan description`,
148+
description: c('Plan Description').t`Basic account with limited features`,
149149
upsell: {
150150
planName: PLAN.PLUS,
151151
features: [
@@ -155,47 +155,51 @@ const getMailPlanFeatures = (plan: MailPlans) =>
155155
]
156156
},
157157
features: [
158-
c('Plan Feature').t`Feature 1`,
159-
c('Plan Feature').t`Feature 2`,
160-
c('Plan Feature').t`Feature 3`,
161-
c('Plan Feature').t`Feature 4`
158+
c('Plan Feature').t`500MB storage`,
159+
c('Plan Feature').t`150 messages per day`,
160+
c('Plan Feature').t`Limited Support`
162161
]
163162
},
164163
[PLAN.PLUS]: {
165164
image: <div>PLUS PLAN IMAGE</div>,
166165
isBest: true,
167-
description: c('Plan Description').t`Plus plan description`,
168-
additionalFeatures: c('Plan feature').t`All ${PLAN_NAMES[PLAN.FREE]} plan features`,
166+
description: c('Plan Description').t`Secure email with advanced features`,
169167
upsell: {
170-
planName: PLAN.PROFESSIONAL,
168+
planName: PLAN.VISIONARY,
171169
features: [
172170
c('Plan Feature').t`Upsell feature 1`,
173171
c('Plan Feature').t`Upsell feature 2`,
174-
c('Plan Feature').t`Upsell feature 3`
172+
c('Plan Feature').t`Upsell feature 3`,
173+
c('Plan Feature').t`Upsell feature 4`
175174
]
176175
},
177176
features: [
178-
c('Plan Feature').t`Feature 1`,
179-
c('Plan Feature').t`Feature 2`,
180-
c('Plan Feature').t`Feature 3`,
181-
c('Plan Feature').t`Feature 4`
177+
c('Plan Feature').t`5 GB storage`,
178+
c('Plan Feature').t`1000 messages per day`,
179+
c('Plan Feature').t`Labels, Custom Filters, and Folders`,
180+
c('Plan Feature').t`Send encrypted messages to external recipients`,
181+
c('Plan Feature').t`Use your own domain (e.g. john@smith.com)`,
182+
c('Plan Feature').t`Up to 5 email aliases`,
183+
c('Plan Feature').t`Priority Customer Support`
182184
]
183185
},
184-
[PLAN.PROFESSIONAL]: {
185-
image: <div>PROFESSIONAL PLAN IMAGE</div>,
186-
description: c('Plan Description').t`Professional plan description`,
186+
[PLAN.VISIONARY]: {
187+
image: <div>VISIONARY PLAN IMAGE</div>,
188+
description: c('Plan Description').t`Special accounts for our supporters`,
187189
additionalFeatures: c('Plan feature').t`All ${PLAN_NAMES[PLAN.PLUS]} plan features`,
188190
features: [
189-
c('Plan Feature').t`Feature 1`,
190-
c('Plan Feature').t`Feature 2`,
191-
c('Plan Feature').t`Feature 3`,
192-
c('Plan Feature').t`Feature 4`
191+
c('Plan Feature').t`20GB storage`,
192+
c('Plan Feature').t`No sending limits*`, // TODO: asterisk info
193+
c('Plan Feature').t`Support for up to 10 domains`,
194+
c('Plan Feature').t`Up to 50 email aliases`,
195+
c('Plan Feature').t`Multi-User Support (6 total)`,
196+
c('Plan Feature').t`Early access to new features`,
197+
c('Plan Feature').t`Includes access to ProtonVPN`
193198
]
194199
},
195-
[PLAN.VISIONARY]: {
196-
image: <div>VISIONARY PLAN IMAGE</div>,
197-
description: c('Plan Description').t`Visionary plan description`,
198-
additionalFeatures: c('Plan feature').t`All ${PLAN_NAMES[PLAN.PROFESSIONAL]} plan features`,
200+
[PLAN.PROFESSIONAL]: {
201+
image: <div>PROFESSIONAL PLAN IMAGE</div>,
202+
description: c('Plan Description').t`Encrypted Email for your Organization`,
199203
features: [
200204
c('Plan Feature').t`Feature 1`,
201205
c('Plan Feature').t`Feature 2`,
@@ -228,7 +232,6 @@ export const getPlan = (
228232
const plan = plans.find(({ Type, Name }: any) => Type === PLAN_TYPES.PLAN && Name === planName);
229233
const price = plan ? getPlanPrice(plan, cycle) : { monthly: 0, total: 0, totalMonthly: 0, saved: 0 };
230234

231-
// TODO: get Mail plan features
232235
const planFeatures =
233236
clientType === CLIENT_TYPES.VPN
234237
? getVPNPlanFeatures(planName as VPNPlans, plan ? plan.MaxVPN : 1, countries)

0 commit comments

Comments
 (0)