Updated price list

This commit is contained in:
Peter Zimon 2021-04-23 14:33:26 +02:00 committed by Rishabh Garg
parent 725ec2e09a
commit cdb9e0e02c
5 changed files with 464 additions and 69 deletions

View File

@ -11,7 +11,7 @@ import {AccountHomePageStyles} from './pages/AccountHomePage';
import {AccountPlanPageStyles} from './pages/AccountPlanPage';
import {InputFieldStyles} from './common/InputField';
import {SignupPageStyles} from './pages/SignupPage';
import {PlanSectionStyles} from './common/PlansSection';
import {PlanSectionStyles} from './common/ProductsSection';
import {AvatarStyles} from './common/MemberGravatar';
import {MagicLinkStyles} from './pages/MagicLinkPage';
import {LinkPageStyles} from './pages/LinkPage';
@ -229,7 +229,7 @@ const FrameStyles = `
.gh-portal-popup-wrapper {
position: relative;
padding: 15vmin 0 0;
padding: 10vmin 0 0;
height: 100%;
}
@ -421,6 +421,7 @@ const FrameStyles = `
text-transform: uppercase;
letter-spacing: 0.2px;
line-height: 1.7em;
margin-bottom: 4px;
}
.gh-portal-list + .gh-portal-list-header {
@ -471,6 +472,18 @@ const FrameStyles = `
color: var(--grey6);
}
.gh-portal-right-arrow {
line-height: 1;
color: var(--grey8);
}
.gh-portal-right-arrow svg {
width: 17px;
height: 17px;
margin-top: 1px;
margin-right: -6px;
}
.gh-portal-expire-warning {
text-align: center;
color: var(--red);
@ -680,76 +693,55 @@ const MobileStyles = `
}
.gh-portal-plan-section {
flex-direction: row;
grid-template-columns: 32px auto auto;
grid-template-rows: auto auto;
justify-items: start;
min-height: 60px;
border-right: none;
border-bottom: 1px solid var(--grey10);
}
.gh-portal-plan-checkbox {
grid-column: 1 / 2;
grid-row: 1 / 3;
margin: 0 12px;
}
.gh-portal-plan-pricelabel {
grid-column: 3 / 4;
grid-row: 1 / 3;
justify-self: end;
margin: 0 4px 0 12px;
}
.gh-portal-plan-name {
text-transform: none;
font-size: 1.4rem;
letter-spacing: 0.2px;
margin: 0;
}
.gh-portal-plan-featurewrapper {
margin: 0;
padding: 0;
border: none;
align-items: flex-start;
}
.gh-portal-plan-feature {
text-align: left;
}
.gh-portal-plan-section:last-of-type {
border-bottom: none;
}
.gh-portal-plan-checkbox {
order: 1;
margin-left: 12px;
.gh-portal-plan-section:first-of-type::before {
border-radius: 5px 5px 0 0;
}
.gh-portal-plan-name {
position: absolute;
left: 40px;
top: 12px;
padding: 0;
margin: 0;
text-transform: none;
font-size: 1.4rem;
letter-spacing: 0.2px;
}
.gh-portal-plan-featurewrapper {
position: absolute;
left: 40px;
top: 32px;
padding: 0;
margin: 0;
width: unset;
text-align: left;
border-top: none;
font-weight: 400;
letter-spacing: 0.2px;
}
.gh-portal-plan-pricelabel {
right: 20px;
top: 12px;
position: absolute;
}
.gh-portal-plan-section:first-of-type.checked::before {
border-top-left-radius: 5px;
border-top-right-radius: 5px;
border-bottom-left-radius: 0;
}
.gh-portal-plan-section:last-of-type.checked::before {
border-bottom-left-radius: 5px;
border-bottom-right-radius: 5px;
border-top-right-radius: 0;
}
.gh-portal-plans-container.hide-checkbox .gh-portal-plan-name,
.gh-portal-plans-container.hide-checkbox .gh-portal-plan-featurewrapper,
.gh-portal-content.signup.singleplan .gh-portal-plan-name,
.gh-portal-content.signup.singleplan .gh-portal-plan-featurewrapper {
left: 12px;
}
.gh-portal-plans-container.hide-checkbox .gh-portal-plan-featurewrapper {
flex-direction: row;
}
.gh-portal-plans-container.hide-checkbox .gh-portal-plan-featurewrapper .gh-portal-plan-current {
margin: 0 0 0 12px;
.gh-portal-plan-section:last-of-type::before {
border-radius: 0 0 5px 5px;
}
.gh-portal-input {

View File

@ -0,0 +1,391 @@
import React from 'react';
import {isCookiesDisabled, formatNumber} from '../../utils/helpers';
export const PlanSectionStyles = `
.gh-portal-plans-container {
display: flex;
align-items: stretch;
border: 1px solid var(--grey10);
border-radius: 5px;
}
.gh-portal-plan-section {
flex: 1;
position: relative;
display: grid;
align-items: center;
justify-items: center;
font-size: 1.4rem;
line-height: 1.35em;
border-right: 1px solid var(--grey10);
padding: 16px 10px;
cursor: pointer;
user-select: none;
}
.gh-portal-plans-container.disabled .gh-portal-plan-section {
cursor: auto;
}
.gh-portal-plan-section.checked::before {
position: absolute;
display: block;
top: -1px;
right: -1px;
bottom: -1px;
left: -1px;
content: "";
z-index: 999;
border: 2px solid var(--brandcolor);
pointer-events: none;
}
.gh-portal-plan-section:first-of-type::before {
border-top-left-radius: 5px;
border-bottom-left-radius: 5px;
}
.gh-portal-plan-section:last-of-type::before {
border-top-right-radius: 5px;
border-bottom-right-radius: 5px;
}
.gh-portal-plan-section:last-of-type {
border-right: none;
}
.gh-portal-plans-container.disabled .gh-portal-plan-section.checked::before {
opacity: 0.3;
}
.gh-portal-plan-pricelabel {
display: flex;
margin-top: 8px;
}
.gh-portal-plan-name {
font-size: 1.2rem;
font-weight: 500;
letter-spacing: 0.5px;
text-transform: uppercase;
margin-top: 8px;
}
.gh-portal-plan-currency {
position: relative;
bottom: 2px;
font-size: 1.4rem;
font-weight: 500;
letter-spacing: 0.4px;
}
.gh-portal-plan-currency-code {
margin-right: 2px;
font-size: 1.15rem;
}
.gh-portal-plan-price {
font-size: 2.2rem;
font-weight: 500;
letter-spacing: 0.1px;
}
.gh-portal-plan-type {
color: var(--grey7);
}
.gh-portal-plan-featurewrapper {
display: flex;
flex-direction: column;
align-items: center;
border-top: 1px solid var(--grey12);
margin-top: 12px;
padding-top: 12px;
width: 100%;
}
.gh-portal-plan-feature {
font-size: 1.25rem;
font-weight: 500;
line-height: 1.25em;
text-align: center;
letter-spacing: 0.2px;
}
.gh-portal-plan-checkbox {
position: relative;
display: block;
font-size: 22px;
height: 18px;
cursor: pointer;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.gh-portal-plans-container.disabled .gh-portal-plan-checkbox {
cursor: auto;
}
.gh-portal-plan-checkbox input {
position: absolute;
height: 0;
width: 0;
opacity: 0;
cursor: pointer;
}
.gh-portal-plan-checkbox .checkmark {
position: absolute;
top: 0;
left: -9px;
background-color: var(--grey12);
border-radius: 999px;
height: 18px;
width: 18px;
}
.gh-portal-plan-checkbox input:checked ~ .checkmark {
background-color: var(--brandcolor);
}
.gh-portal-plan-checkbox .checkmark::after {
position: absolute;
display: none;
content: "";
}
.gh-portal-plan-checkbox input:checked ~ .checkmark:after {
display: block;
}
.gh-portal-plan-checkbox .checkmark:after {
left: 6.5px;
top: 2.5px;
width: 5px;
height: 11px;
border: solid var(--white);
border-width: 0 2px 2px 0;
-webkit-transform: rotate(45deg);
-ms-transform: rotate(45deg);
transform: rotate(45deg);
}
.gh-portal-plans-container.disabled .gh-portal-plan-checkbox input:checked ~ .checkmark {
opacity: 0.3;
}
.gh-portal-content.signup.singleplan .gh-portal-plan-section {
cursor: auto;
}
.gh-portal-content.signup.singleplan .gh-portal-plan-checkbox,
.gh-portal-content.signup.singleplan .gh-portal-plan-section.checked::before {
display: none;
}
.gh-portal-content.signup.singleplan .gh-portal-plan-name {
margin-top: 0;
}
.gh-portal-plan-section:not(.checked)::before {
position: absolute;
display: block;
top: -1px;
right: -1px;
bottom: -1px;
left: -1px;
content: "";
z-index: 999;
border: 1px solid var(--brandcolor);
pointer-events: none;
opacity: 0;
transition: all 0.2s ease-in-out;
}
.gh-portal-plans-container.disabled .gh-portal-plan-section:not(.checked):hover::before {
opacity: 0;
}
.gh-portal-plans-container.hide-checkbox .gh-portal-plan-checkbox {
display: none;
}
.gh-portal-plans-container.hide-checkbox .gh-portal-plan-section {
padding-top: 12px;
padding-bottom: 20px;
}
.gh-portal-plan-current {
display: block;
font-size: 1.25rem;
letter-spacing: 0.2px;
line-height: 1.25em;
color: var(--brandcolor);
margin: 4px 0 -2px;
}
.gh-portal-plans-container.vertical {
flex-direction: column;
}
.gh-portal-plans-container.vertical .gh-portal-plan-section {
grid-template-columns: 32px auto auto;
grid-template-rows: auto auto;
justify-items: start;
min-height: 60px;
border-right: none;
border-bottom: 1px solid var(--grey10);
}
.gh-portal-plans-container.vertical .gh-portal-plan-checkbox {
grid-column: 1 / 2;
grid-row: 1 / 3;
margin: 0 12px;
}
.gh-portal-plans-container.vertical .gh-portal-plan-pricelabel {
grid-column: 3 / 4;
grid-row: 1 / 3;
justify-self: end;
margin: 0 4px 0 12px;
}
.gh-portal-plans-container.vertical .gh-portal-plan-name {
text-transform: none;
font-size: 1.4rem;
letter-spacing: 0.2px;
margin: 0;
}
.gh-portal-plans-container.vertical .gh-portal-plan-featurewrapper {
margin: 0;
padding: 0;
border: none;
align-items: flex-start;
}
.gh-portal-plans-container.vertical .gh-portal-plan-feature {
text-align: left;
}
.gh-portal-plans-container.vertical .gh-portal-plan-section:last-of-type {
border-bottom: none;
}
.gh-portal-plans-container.vertical .gh-portal-plan-section:first-of-type::before {
border-radius: 5px 5px 0 0;
}
.gh-portal-plans-container.vertical .gh-portal-plan-section:last-of-type::before {
border-radius: 0 0 5px 5px;
}
`;
function Checkbox({name, onPlanSelect, isChecked, disabled}) {
if (isCookiesDisabled()) {
disabled = true;
}
return (
<div className='gh-portal-plan-checkbox'>
<input
name={name}
key={name}
type="checkbox"
checked={isChecked}
aria-label={name}
onChange={e => onPlanSelect(e, name)}
disabled={disabled}
/>
<span className='checkmark'></span>
</div>
);
}
function PriceLabel({currencySymbol, price}) {
const isSymbol = currencySymbol.length !== 3;
const currencyClass = isSymbol ? 'gh-portal-plan-currency gh-portal-plan-currency-symbol' : 'gh-portal-plan-currency gh-portal-plan-currency-code';
return (
<div className='gh-portal-plan-pricelabel'>
<span className={currencyClass}>{currencySymbol}</span>
<span className='gh-portal-plan-price'>{formatNumber(price)}</span>
</div>
);
}
function PlanOptions({plans, selectedPlan, onPlanSelect, changePlan}) {
const hasMonthlyPlan = plans.some(({name}) => {
return name === 'Monthly';
});
return plans.map(({name, currency_symbol: currencySymbol, price, discount}, i) => {
const isChecked = selectedPlan === name;
const classes = (isChecked ? 'gh-portal-plan-section checked' : 'gh-portal-plan-section');
const planDetails = {};
let displayName = '';
switch (name) {
case 'Free':
planDetails.feature = 'Free preview';
break;
case 'Monthly':
case 'Complimentary':
planDetails.feature = 'Full access';
break;
case 'Yearly':
displayName = 'Annually';
planDetails.feature = ((hasMonthlyPlan && discount > 0) ? (discount + '% discount') : 'Full access');
break;
// TODO: mock!
case 'Custom':
displayName = 'Custom';
planDetails.feature = ((hasMonthlyPlan && discount > 0) ? (discount + '% discount') : 'Full access');
break;
default:
break;
}
return (
<div className={classes} key={name} onClick={e => onPlanSelect(e, name)}>
<Checkbox name={name} isChecked={isChecked} onPlanSelect={onPlanSelect} />
<h4 className='gh-portal-plan-name'>{displayName || name}</h4>
<PriceLabel name={name} currencySymbol={currencySymbol} price={price} />
<div className='gh-portal-plan-featurewrapper'>
<div className='gh-portal-plan-feature'>
{planDetails.feature}
</div>
{(changePlan && selectedPlan === name ? <span className='gh-portal-plan-current'>Current plan</span> : '')}
</div>
</div>
);
});
}
function PlanLabel({showLabel}) {
if (!showLabel) {
return null;
}
return (
<label className='gh-portal-input-label'>Plan</label>
);
}
function PlansSection({plans, showLabel = true, type, selectedPlan, onPlanSelect, changePlan = false, style}) {
if (!plans || plans.length === 0 || (plans.length === 1 && plans[0].type === 'free')) {
return null;
}
const cookiesDisabled = isCookiesDisabled();
if (cookiesDisabled) {
onPlanSelect = (e, name) => {};
}
return (
<section>
<PlanLabel showLabel={showLabel} />
<div className={'gh-portal-plans-container' + (changePlan ? ' hide-checkbox' : '') + (cookiesDisabled ? ' disabled' : '') + (plans.length > 3 ? ' vertical' : '')}>
<PlanOptions plans={plans} onPlanSelect={onPlanSelect} selectedPlan={selectedPlan} changePlan={changePlan} />
</div>
</section>
);
}
export default PlansSection;

View File

@ -99,13 +99,6 @@ export const AccountHomePageStyles = `
margin-right: 12px;
border-radius: 2px;
}
.gh-portal-right-arrow svg {
width: 17px;
height: 17px;
margin-top: 1px;
margin-right: -6px;
}
`;
const UserAvatar = ({avatar, brandColor}) => {

View File

@ -2,6 +2,7 @@ import ActionButton from '../common/ActionButton';
import CloseButton from '../common/CloseButton';
import AppContext from '../../AppContext';
import PlansSection from '../common/PlansSection';
import ProductsSection from '../common/ProductsSection';
import InputForm from '../common/InputForm';
import {ValidateInputForm} from '../../utils/form';
import CalculateDiscount from '../../utils/discount';
@ -283,6 +284,15 @@ class SignupPage extends React.Component {
currency_symbol: plans.currency_symbol,
name: 'Yearly',
discount
},
// TODO: mock!
{
type: 'custom',
price: plans.yearly,
currency_symbol: plans.currency_symbol,
name: 'Custom',
discount
}
];
@ -384,7 +394,7 @@ class SignupPage extends React.Component {
const plansData = getSitePlans({site, pageQuery});
return (
<>
<PlansSection
<ProductsSection
plans={plansData}
selectedPlan={this.state.plan}
onPlanSelect={(e, name) => this.handleSelectPlan(e, name)}

View File

@ -137,6 +137,15 @@ export function getSitePlans({site = {}, includeFree = true, pageQuery} = {}) {
currency_symbol: getCurrencySymbol(plans.currency),
name: 'Yearly',
discount
},
// TODO: mock!
{
type: 'custom',
price: plans.yearly,
currency_symbol: getCurrencySymbol(plans.currency),
name: 'Custom',
discount
}
];