mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-12-01 05:50:35 +03:00
Added offers static data
This commit is contained in:
parent
e34cf74735
commit
fabb4ebc16
@ -19,7 +19,7 @@ const DEV_MODE_DATA = {
|
||||
showPopup: true,
|
||||
site: Fixtures.site,
|
||||
member: Fixtures.member.free,
|
||||
page: 'offer'
|
||||
page: 'signup'
|
||||
};
|
||||
|
||||
function SentryErrorBoundary({site, children}) {
|
||||
|
@ -17,6 +17,7 @@ import {AvatarStyles} from './common/MemberGravatar';
|
||||
import {MagicLinkStyles} from './pages/MagicLinkPage';
|
||||
import {LinkPageStyles} from './pages/LinkPage';
|
||||
import {PopupNotificationStyles} from './common/PopupNotification';
|
||||
import {OfferPageStyles} from './pages/OfferPage';
|
||||
|
||||
// Global styles
|
||||
const FrameStyles = `
|
||||
@ -332,13 +333,13 @@ const FrameStyles = `
|
||||
position: relative;
|
||||
overflow-y: scroll;
|
||||
padding: 24px 32px 32px;
|
||||
max-height: 680px;
|
||||
max-height: calc(100vh - 20vmin);
|
||||
}
|
||||
|
||||
.gh-portal-content.with-footer {
|
||||
overflow-y: scroll;
|
||||
padding-bottom: 0;
|
||||
max-height: calc(680px - 72px);
|
||||
max-height: calc(100vh - 20vmin - 132px);
|
||||
}
|
||||
|
||||
/* Hide scrollbar for Chrome, Safari and Opera */
|
||||
@ -892,6 +893,7 @@ export function getFrameStyles({site}) {
|
||||
MagicLinkStyles +
|
||||
LinkPageStyles +
|
||||
SignupPageStyles +
|
||||
OfferPageStyles +
|
||||
PopupNotificationStyles +
|
||||
MobileStyles +
|
||||
MultipleProductsGlobalStyles;
|
||||
|
@ -137,13 +137,16 @@ class PopupContent extends React.Component {
|
||||
|
||||
const portalPlans = getSitePrices({site, pageQuery});
|
||||
|
||||
if (page === 'signup' || page === 'signin') {
|
||||
if (page === 'signup' || page === 'signin' || page === 'offer') {
|
||||
if (!isInviteOnlySite({site, pageQuery}) && portalPlans.length === 3 && (page === 'signup' || page === 'signin')) {
|
||||
popupWidthStyle = ' gh-portal-container-wide';
|
||||
}
|
||||
if (portalPlans.length <= 1 || !isStripeConfigured) {
|
||||
popupWidthStyle = 'gh-portal-container-narrow';
|
||||
}
|
||||
if (page === 'offer') {
|
||||
popupWidthStyle = ' gh-portal-container-wide';
|
||||
}
|
||||
}
|
||||
let cookieBannerText = '';
|
||||
let pageClass = page;
|
||||
|
@ -1,14 +1,338 @@
|
||||
import ActionButton from '../common/ActionButton';
|
||||
import {offer} from '../../utils/fixtures';
|
||||
import AppContext from '../../AppContext';
|
||||
import {ReactComponent as CheckmarkIcon} from '../../images/icons/checkmark.svg';
|
||||
import CloseButton from '../common/CloseButton';
|
||||
import InputForm from '../common/InputForm';
|
||||
const React = require('react');
|
||||
|
||||
export const OfferPageStyles = `
|
||||
.gh-portal-offer {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
.gh-portal-offer h4 {
|
||||
color: var(--grey0);
|
||||
margin: 0 0 7px;
|
||||
}
|
||||
|
||||
.gh-portal-offer p {
|
||||
color: var(--grey3);
|
||||
font-size: 1.25rem;
|
||||
font-weight: 400;
|
||||
margin: 0 0 6px;
|
||||
}
|
||||
|
||||
.gh-portal-offer-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.gh-portal-plans-container.offer {
|
||||
justify-content: space-between;
|
||||
border-color: var(--grey12);
|
||||
border-top: none;
|
||||
border-top-left-radius: 0;
|
||||
border-top-right-radius: 0;
|
||||
padding: 12px 16px;
|
||||
font-size: 1.3rem;
|
||||
}
|
||||
|
||||
.gh-portal-offer-bar {
|
||||
position: relative;
|
||||
padding: 12px 16px;
|
||||
}
|
||||
|
||||
.gh-portal-offer-bar::before {
|
||||
border-radius: 5px 5px 0 0;
|
||||
position: absolute;
|
||||
display: block;
|
||||
content: "";
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
background-color: var(--brandcolor);
|
||||
opacity: 0.1;
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
.gh-portal-offer-tag {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 0;
|
||||
background: var(--brandcolor);
|
||||
color: #fff;
|
||||
padding: 4px 8px 4px 12px;
|
||||
font-weight: 500;
|
||||
font-size: 1.2rem;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.5px;
|
||||
border-radius: 999px 0 0 999px;
|
||||
}
|
||||
|
||||
.gh-portal-offer-details .gh-portal-plan-name,
|
||||
.gh-portal-offer-details p {
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.gh-portal-offer-price {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-end;
|
||||
padding-left: 20px;
|
||||
}
|
||||
|
||||
.gh-portal-offer-price .old {
|
||||
text-decoration: line-through;
|
||||
color: var(--grey8);
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.gh-portal-offer-price .new {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
margin-top: 6px;
|
||||
}
|
||||
|
||||
.gh-portal-offer-price .new .currency {
|
||||
font-weight: 500;
|
||||
line-height: 1.3;
|
||||
font-size: 1.5rem;
|
||||
margin-right: 1px;
|
||||
}
|
||||
|
||||
.gh-portal-offer-price .new .value {
|
||||
font-size: 2.4rem;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.gh-portal-offer-details p {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.gh-portal-offer-details .footnote {
|
||||
color: var(--grey7);
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.gh-portal-offer .gh-portal-product-benefit {
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
`;
|
||||
|
||||
export default class OfferPage extends React.Component {
|
||||
render() {
|
||||
static contextType = AppContext;
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
name: '',
|
||||
email: '',
|
||||
plan: 'free'
|
||||
};
|
||||
}
|
||||
|
||||
getInputFields({state, fieldNames}) {
|
||||
const {portal_name: portalName} = this.context.site;
|
||||
|
||||
const errors = state.errors || {};
|
||||
const fields = [
|
||||
{
|
||||
type: 'email',
|
||||
value: state.email,
|
||||
placeholder: 'jamie@example.com',
|
||||
label: 'Email',
|
||||
name: 'email',
|
||||
required: true,
|
||||
tabindex: 2,
|
||||
errorMessage: errors.email || ''
|
||||
}
|
||||
];
|
||||
|
||||
/** Show Name field if portal option is set*/
|
||||
if (portalName) {
|
||||
fields.unshift({
|
||||
type: 'text',
|
||||
value: state.name,
|
||||
placeholder: 'Jamie Larson',
|
||||
label: 'Name',
|
||||
name: 'name',
|
||||
required: true,
|
||||
tabindex: 1,
|
||||
errorMessage: errors.name || ''
|
||||
});
|
||||
}
|
||||
fields[0].autoFocus = true;
|
||||
if (fieldNames && fieldNames.length > 0) {
|
||||
return fields.filter((f) => {
|
||||
return fieldNames.includes(f.name);
|
||||
});
|
||||
}
|
||||
return fields;
|
||||
}
|
||||
|
||||
onKeyDown(e) {
|
||||
// Handles submit on Enter press
|
||||
if (e.keyCode === 13){
|
||||
this.handleSignup(e);
|
||||
}
|
||||
}
|
||||
|
||||
handleSignup(e) {
|
||||
return;
|
||||
}
|
||||
|
||||
handleInputChange(e, field) {
|
||||
const fieldName = field.name;
|
||||
const value = e.target.value;
|
||||
this.setState({
|
||||
[fieldName]: value
|
||||
});
|
||||
}
|
||||
|
||||
renderSiteLogo() {
|
||||
const {site} = this.context;
|
||||
|
||||
const siteLogo = site.icon;
|
||||
|
||||
const logoStyle = {};
|
||||
|
||||
if (siteLogo) {
|
||||
logoStyle.backgroundImage = `url(${siteLogo})`;
|
||||
return (
|
||||
<img className='gh-portal-signup-logo' src={siteLogo} alt={site.title} />
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
renderFormHeader() {
|
||||
const {site} = this.context;
|
||||
const siteTitle = site.title || '';
|
||||
return (
|
||||
<div className='gh-portal-content'>
|
||||
<div style={{paddingLeft: '16px', paddingRight: '16px', paddingTop: '12px'}}>
|
||||
Offer - {offer.name}
|
||||
<header className='gh-portal-signup-header'>
|
||||
{this.renderSiteLogo()}
|
||||
<h2 className="gh-portal-main-title">{siteTitle}</h2>
|
||||
</header>
|
||||
);
|
||||
}
|
||||
|
||||
renderForm() {
|
||||
const fields = this.getInputFields({state: this.state});
|
||||
|
||||
return (
|
||||
<section>
|
||||
<div className='gh-portal-section'>
|
||||
<InputForm
|
||||
fields={fields}
|
||||
onChange={(e, field) => this.handleInputChange(e, field)}
|
||||
onKeyDown={e => this.onKeyDown(e)}
|
||||
/>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
renderSubmitButton() {
|
||||
const {action, brandColor} = this.context;
|
||||
let label = 'Continue';
|
||||
|
||||
let isRunning = false;
|
||||
if (action === 'signup:running') {
|
||||
label = 'Sending...';
|
||||
isRunning = true;
|
||||
}
|
||||
let retry = false;
|
||||
if (action === 'signup:failed') {
|
||||
label = 'Retry';
|
||||
retry = true;
|
||||
}
|
||||
|
||||
const disabled = (action === 'signup:running') ? true : false;
|
||||
return (
|
||||
<ActionButton
|
||||
style={{width: '100%'}}
|
||||
retry={retry}
|
||||
onClick={e => this.handleSignup(e)}
|
||||
disabled={disabled}
|
||||
brandColor={brandColor}
|
||||
label={label}
|
||||
isRunning={isRunning}
|
||||
tabIndex='3'
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
renderLoginMessage() {
|
||||
const {brandColor, onAction} = this.context;
|
||||
return (
|
||||
<div className='gh-portal-signup-message'>
|
||||
<div>Already a member?</div>
|
||||
<button
|
||||
className='gh-portal-btn gh-portal-btn-link'
|
||||
style={{color: brandColor}}
|
||||
onClick={() => onAction('switchPage', {page: 'signin'})}
|
||||
>
|
||||
<span>Sign in</span>
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<>
|
||||
<div className='gh-portal-content gh-portal-offer'>
|
||||
<CloseButton />
|
||||
{this.renderFormHeader()}
|
||||
{this.renderForm()}
|
||||
|
||||
<div className="gh-portal-offer-container">
|
||||
<div className="gh-portal-offer-bar">
|
||||
<h4 className="gh-portal-plan-name">Holiday special!</h4>
|
||||
<h5 className="gh-portal-offer-tag">20% off</h5>
|
||||
<p>Limited time offer! Sign up now with a massive discount and get full access to Ball is Life.</p>
|
||||
</div>
|
||||
<div className="gh-portal-plans-container offer">
|
||||
<div className="gh-portal-offer-details">
|
||||
<h4 className="gh-portal-plan-name">{offer.name} - {(offer.cadence === 'month' ? 'Monthly' : 'Yearly')}</h4>
|
||||
<p>The bestest tier you can get with Ball is Life. Subscribe to this if you want it all.</p>
|
||||
<div className="gh-portal-product-benefits">
|
||||
<div className="gh-portal-product-benefit">
|
||||
<CheckmarkIcon className='gh-portal-benefit-checkmark' />
|
||||
<span className="gh-portal-product-benefit">Limited early adopter pricing</span>
|
||||
</div>
|
||||
<div className="gh-portal-product-benefit">
|
||||
<CheckmarkIcon className='gh-portal-benefit-checkmark' />
|
||||
<span className="gh-portal-product-benefit">Latest gear reviews</span>
|
||||
</div>
|
||||
<div className="gh-portal-product-benefit">
|
||||
<CheckmarkIcon className='gh-portal-benefit-checkmark' />
|
||||
<span className="gh-portal-product-benefit">Weekly email newsletter</span>
|
||||
</div>
|
||||
<div className="gh-portal-product-benefit">
|
||||
<CheckmarkIcon className='gh-portal-benefit-checkmark' />
|
||||
<span className="gh-portal-product-benefit">Listen to my podcast</span>
|
||||
</div>
|
||||
</div>
|
||||
<p className="footnote">20% off for first year. Renews at $75/year</p>
|
||||
</div>
|
||||
<div className="gh-portal-offer-price">
|
||||
<div className="old">$75</div>
|
||||
<div className="new">
|
||||
<span className="currency">$</span>
|
||||
<span className="value">60</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<footer className='gh-portal-signup-footer'>
|
||||
{this.renderSubmitButton()}
|
||||
{this.renderLoginMessage()}
|
||||
</footer>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user