mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-02-17 23:44:39 -05:00
Refactored Parent pages to use pages
Refactors Parent and Popup-menu pages to load different pages as per UI flows and pass necessary data and actions down to UI components.
This commit is contained in:
parent
3cbe8d6f0c
commit
f727fdd1ed
2 changed files with 174 additions and 201 deletions
|
@ -5,7 +5,7 @@ const React = require('react');
|
||||||
const PropTypes = require('prop-types');
|
const PropTypes = require('prop-types');
|
||||||
export default class ParentContainer extends React.Component {
|
export default class ParentContainer extends React.Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
name: PropTypes.string
|
data: PropTypes.object.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
|
@ -19,12 +19,25 @@ export default class ParentContainer extends React.Component {
|
||||||
// Setup custom trigger button handling
|
// Setup custom trigger button handling
|
||||||
this.customTriggerButton = document.querySelector('[data-members-trigger-button]');
|
this.customTriggerButton = document.querySelector('[data-members-trigger-button]');
|
||||||
this.setupCustomTriggerButton(this.customTriggerButton);
|
this.setupCustomTriggerButton(this.customTriggerButton);
|
||||||
|
const page = this.isMemberLoggedIn() ? 'signedin' : 'signin';
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
showPopup: false
|
page,
|
||||||
|
showPopup: false,
|
||||||
|
action: null
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isMemberLoggedIn() {
|
||||||
|
return !!this.props.data.member;
|
||||||
|
}
|
||||||
|
|
||||||
|
switchPage(page) {
|
||||||
|
this.setState({
|
||||||
|
page
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
setupCustomTriggerButton(customTriggerButton) {
|
setupCustomTriggerButton(customTriggerButton) {
|
||||||
if (customTriggerButton) {
|
if (customTriggerButton) {
|
||||||
const clickHandler = (event) => {
|
const clickHandler = (event) => {
|
||||||
|
@ -40,12 +53,66 @@ export default class ParentContainer extends React.Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onSignout() {
|
resetAction() {
|
||||||
this.MembersAPI.signout();
|
this.setState({
|
||||||
|
action: null
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
onSignin(data) {
|
async onAction(action, data) {
|
||||||
this.MembersAPI.sendMagicLink(data);
|
this.setState({
|
||||||
|
action: {
|
||||||
|
name: action,
|
||||||
|
isRunning: true,
|
||||||
|
isSuccess: false,
|
||||||
|
error: null
|
||||||
|
}
|
||||||
|
});
|
||||||
|
try {
|
||||||
|
if (action === 'signout') {
|
||||||
|
await this.MembersAPI.signout();
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
action: {
|
||||||
|
name: action,
|
||||||
|
isRunning: false,
|
||||||
|
isSuccess: true
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (action === 'signin') {
|
||||||
|
await this.MembersAPI.sendMagicLink(data);
|
||||||
|
this.setState({
|
||||||
|
action: {
|
||||||
|
name: action,
|
||||||
|
isRunning: false,
|
||||||
|
isSuccess: true
|
||||||
|
},
|
||||||
|
page: 'magiclink'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (action === 'checkoutPlan') {
|
||||||
|
const checkoutSuccessUrl = (new URL('/account/?stripe=billing-update-success', window.location.href)).href;
|
||||||
|
const checkoutCancelUrl = (new URL('/account/?stripe=billing-update-cancel', window.location.href)).href;
|
||||||
|
console.log('Checkout URLs', checkoutSuccessUrl, checkoutCancelUrl);
|
||||||
|
const {plan} = data;
|
||||||
|
await this.MembersAPI.checkoutPlan({
|
||||||
|
plan,
|
||||||
|
checkoutSuccessUrl,
|
||||||
|
checkoutCancelUrl
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
this.setState({
|
||||||
|
action: {
|
||||||
|
name: action,
|
||||||
|
isRunning: false,
|
||||||
|
error: e
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onTriggerToggle() {
|
onTriggerToggle() {
|
||||||
|
@ -59,10 +126,11 @@ export default class ParentContainer extends React.Component {
|
||||||
if (this.state.showPopup) {
|
if (this.state.showPopup) {
|
||||||
return (
|
return (
|
||||||
<PopupMenuComponent
|
<PopupMenuComponent
|
||||||
name={this.props.name}
|
|
||||||
data={this.props.data}
|
data={this.props.data}
|
||||||
onSignout={e => this.onSignout()}
|
action={this.state.action}
|
||||||
onSignin={data => this.onSignin(data)}
|
page={this.state.page}
|
||||||
|
switchPage={page => this.switchPage(page)}
|
||||||
|
onAction={(action, data) => this.onAction(action, data)}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,177 +1,59 @@
|
||||||
import FrameComponent from './FrameComponent';
|
import FrameComponent from './FrameComponent';
|
||||||
|
import SignupPage from './SignupPage';
|
||||||
|
import SigninPage from './SigninPage';
|
||||||
|
import SignedInPage from './SignedInPage';
|
||||||
|
import MagicLinkPage from './MagicLinkPage';
|
||||||
const React = require('react');
|
const React = require('react');
|
||||||
const PropTypes = require('prop-types');
|
const PropTypes = require('prop-types');
|
||||||
|
|
||||||
export default class PopupMenuComponent extends React.Component {
|
const Styles = {
|
||||||
static propTypes = {
|
frame: {
|
||||||
name: PropTypes.string
|
common: {
|
||||||
};
|
zIndex: '2147483000',
|
||||||
|
position: 'fixed',
|
||||||
constructor(props) {
|
bottom: '100px',
|
||||||
super(props);
|
right: '20px',
|
||||||
this.state = {
|
width: '350px',
|
||||||
inputVal: '',
|
minHeight: '350px',
|
||||||
isLoading: false,
|
maxHeight: '410px',
|
||||||
showSuccess: false
|
boxShadow: 'rgba(0, 0, 0, 0.16) 0px 5px 40px',
|
||||||
};
|
opacity: '1',
|
||||||
|
height: 'calc(100% - 120px)',
|
||||||
|
borderRadius: '8px',
|
||||||
|
overflow: 'hidden',
|
||||||
|
backgroundColor: 'white'
|
||||||
|
},
|
||||||
|
signin: {
|
||||||
|
width: '400px',
|
||||||
|
minHeight: '200px',
|
||||||
|
maxHeight: '240px'
|
||||||
|
},
|
||||||
|
signup: {
|
||||||
|
width: '450px',
|
||||||
|
minHeight: '400px',
|
||||||
|
maxHeight: '460px'
|
||||||
|
},
|
||||||
|
signedin: {
|
||||||
|
width: '380px',
|
||||||
|
minHeight: '350px',
|
||||||
|
maxHeight: '410px'
|
||||||
|
},
|
||||||
|
magiclink: {
|
||||||
|
width: '400px',
|
||||||
|
minHeight: '130px',
|
||||||
|
maxHeight: '130px'
|
||||||
}
|
}
|
||||||
|
},
|
||||||
handleSignout(e) {
|
popup: {
|
||||||
e.preventDefault();
|
parent: {
|
||||||
this.props.onSignout();
|
|
||||||
}
|
|
||||||
|
|
||||||
handleSignin(e) {
|
|
||||||
e.preventDefault();
|
|
||||||
const email = this.state.inputVal;
|
|
||||||
this.props.onSignin({email});
|
|
||||||
this.setState({
|
|
||||||
isLoading: true,
|
|
||||||
showSuccess: false
|
|
||||||
});
|
|
||||||
setTimeout(() => {
|
|
||||||
this.setState({
|
|
||||||
isLoading: false,
|
|
||||||
showSuccess: true
|
|
||||||
});
|
|
||||||
}, 3000);
|
|
||||||
}
|
|
||||||
|
|
||||||
handleInput(e) {
|
|
||||||
this.setState({
|
|
||||||
inputVal: e.target.value,
|
|
||||||
showSuccess: false,
|
|
||||||
isLoading: false
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
isMemberLoggedIn() {
|
|
||||||
return !!this.props.data.member;
|
|
||||||
}
|
|
||||||
|
|
||||||
getMemberEmail() {
|
|
||||||
if (this.isMemberLoggedIn()) {
|
|
||||||
return this.props.data.member.email;
|
|
||||||
}
|
|
||||||
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
|
|
||||||
renderSignedOutContent() {
|
|
||||||
const inputStyle = {
|
|
||||||
display: 'block',
|
|
||||||
padding: '0 .6em',
|
|
||||||
width: '100%',
|
|
||||||
height: '44px',
|
|
||||||
outline: '0',
|
|
||||||
border: '1px solid #c5d2d9',
|
|
||||||
color: 'inherit',
|
|
||||||
textDecoration: 'none',
|
|
||||||
background: '#fff',
|
|
||||||
borderRadius: '5px',
|
|
||||||
fontSize: '14px',
|
|
||||||
marginBottom: '12px'
|
|
||||||
};
|
|
||||||
|
|
||||||
const siteTitle = (this.props.data.site && this.props.data.site.title) || 'Site Title';
|
|
||||||
const siteDescription = (this.props.data.site && this.props.data.site.description) || 'Site Description';
|
|
||||||
return (
|
|
||||||
<div style={{display: 'flex', flexDirection: 'column', color: '#313131'}}>
|
|
||||||
<div style={{paddingLeft: '16px', paddingRight: '16px', paddingTop: '12px', cursor: 'pointer'}}>
|
|
||||||
<div style={{display: 'flex', flexDirection: 'column', alignItems: 'center', marginBottom: '12px'}}>
|
|
||||||
<div style={{fontSize: '18px', fontWeight: 'bold'}}> Signup/Signin to {siteTitle}</div>
|
|
||||||
<div>{siteDescription} </div>
|
|
||||||
</div>
|
|
||||||
<div style={{display: 'flex', flexDirection: 'column', alignItems: 'center', marginBottom: '12px'}}>
|
|
||||||
<input
|
|
||||||
type="email"
|
|
||||||
placeholder="Type your email..."
|
|
||||||
value={this.state.inputVal}
|
|
||||||
onChange={(e) => {
|
|
||||||
this.handleInput(e);
|
|
||||||
}}
|
|
||||||
style={inputStyle}
|
|
||||||
/>
|
|
||||||
{this.renderSubmitButton()}
|
|
||||||
{this.renderSuccessMessage()}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
renderSuccessMessage() {
|
|
||||||
if (!this.state.isLoading && this.state.showSuccess) {
|
|
||||||
return (
|
|
||||||
<div> Please check your email for magic link! </div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
renderSubmitButton() {
|
|
||||||
const buttonStyle = {
|
|
||||||
display: 'inline-block',
|
|
||||||
padding: '0 1.8rem',
|
|
||||||
height: '44px',
|
|
||||||
border: '0',
|
|
||||||
fontSize: '1.5rem',
|
|
||||||
lineHeight: '42px',
|
|
||||||
fontWeight: '600',
|
|
||||||
textAlign: 'center',
|
|
||||||
textDecoration: 'none',
|
|
||||||
whiteSpace: 'nowrap',
|
|
||||||
borderRadius: '5px',
|
|
||||||
cursor: 'pointer',
|
|
||||||
transition: '.4s ease',
|
|
||||||
color: '#fff',
|
|
||||||
backgroundColor: '#3eb0ef',
|
|
||||||
boxShadow: 'none',
|
|
||||||
userSelect: 'none'
|
|
||||||
};
|
|
||||||
const label = this.state.isLoading ? 'Sending' : 'Continue';
|
|
||||||
const disabled = this.state.isLoading ? true : false;
|
|
||||||
return (
|
|
||||||
<button onClick={(e) => {
|
|
||||||
this.handleSignin(e);
|
|
||||||
}} style={buttonStyle} disabled={disabled}>
|
|
||||||
{label}
|
|
||||||
</button>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
renderSignedinContent() {
|
|
||||||
const memberEmail = (this.props.data.member && this.props.data.member.email) || 'test@test.com';
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div style={{display: 'flex', flexDirection: 'column', color: '#313131'}}>
|
|
||||||
<div style={{paddingLeft: '16px', paddingRight: '16px', color: '#A6A6A6', fontSize: '1.2rem', lineHeight: '1.0em'}}>
|
|
||||||
Signed in as
|
|
||||||
</div>
|
|
||||||
<div style={{paddingLeft: '16px', paddingRight: '16px', paddingBottom: '9px'}}>
|
|
||||||
{memberEmail}
|
|
||||||
</div>
|
|
||||||
<div style={{paddingLeft: '16px', paddingRight: '16px', paddingTop: '12px', borderTop: '1px solid #EFEFEF', cursor: 'pointer'}}>
|
|
||||||
<div onClick={(e) => {
|
|
||||||
this.handleSignout(e);
|
|
||||||
}}> Logout </div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
renderPopupContent() {
|
|
||||||
const launcherStyle = {
|
|
||||||
width: '100%',
|
width: '100%',
|
||||||
height: '100%',
|
height: '100%',
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
letterSpacing: '0',
|
letterSpacing: '0',
|
||||||
textRendering: 'optimizeLegibility',
|
textRendering: 'optimizeLegibility',
|
||||||
fontSize: '1.5rem'
|
fontSize: '1.5rem'
|
||||||
};
|
},
|
||||||
|
container: {
|
||||||
const buttonStyle = {
|
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
justifyContent: 'flex-start',
|
justifyContent: 'flex-start',
|
||||||
|
@ -184,47 +66,70 @@ export default class PopupMenuComponent extends React.Component {
|
||||||
paddingTop: '18px',
|
paddingTop: '18px',
|
||||||
paddingBottom: '18px',
|
paddingBottom: '18px',
|
||||||
textAlign: 'left'
|
textAlign: 'left'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const Pages = {
|
||||||
|
signin: SigninPage,
|
||||||
|
signup: SignupPage,
|
||||||
|
signedin: SignedInPage,
|
||||||
|
magiclink: MagicLinkPage
|
||||||
|
};
|
||||||
|
|
||||||
|
export default class PopupMenuComponent extends React.Component {
|
||||||
|
static propTypes = {
|
||||||
|
data: PropTypes.shape({
|
||||||
|
site: PropTypes.shape({
|
||||||
|
title: PropTypes.string,
|
||||||
|
description: PropTypes.string
|
||||||
|
}).isRequired,
|
||||||
|
member: PropTypes.shape({
|
||||||
|
email: PropTypes.string
|
||||||
|
})
|
||||||
|
}).isRequired,
|
||||||
|
action: PropTypes.object,
|
||||||
|
page: PropTypes.string.isRequired,
|
||||||
|
onAction: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
|
renderCurrentPage(page) {
|
||||||
|
const PageComponent = Pages[page];
|
||||||
return (
|
return (
|
||||||
<div style={launcherStyle}>
|
<PageComponent
|
||||||
<div style={buttonStyle}>
|
data={this.props.data}
|
||||||
{this.isMemberLoggedIn() ? this.renderSignedinContent() : this.renderSignedOutContent()}
|
action={this.props.action}
|
||||||
|
onAction={(action, data) => this.props.onAction(action, data)}
|
||||||
|
switchPage={page => this.props.switchPage(page)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderPopupContent() {
|
||||||
|
return (
|
||||||
|
<div style={Styles.popup.parent}>
|
||||||
|
<div style={Styles.popup.container}>
|
||||||
|
{this.renderCurrentPage(this.props.page)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
renderFrameContainer() {
|
||||||
let hoverStyle = {
|
const page = this.props.page;
|
||||||
zIndex: '2147483000',
|
const frameStyle = {
|
||||||
position: 'fixed',
|
...Styles.frame.common,
|
||||||
bottom: '100px',
|
...Styles.frame[page]
|
||||||
right: '20px',
|
|
||||||
width: '250px',
|
|
||||||
minHeight: '50px',
|
|
||||||
maxHeight: '116px',
|
|
||||||
boxShadow: 'rgba(0, 0, 0, 0.16) 0px 5px 40px',
|
|
||||||
opacity: '1',
|
|
||||||
height: 'calc(100% - 120px)',
|
|
||||||
borderRadius: '8px',
|
|
||||||
overflow: 'hidden',
|
|
||||||
backgroundColor: 'white'
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!this.isMemberLoggedIn()) {
|
|
||||||
hoverStyle = {
|
|
||||||
...hoverStyle,
|
|
||||||
width: '450px',
|
|
||||||
minHeight: '200px',
|
|
||||||
maxHeight: '220px'
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FrameComponent style={hoverStyle}>
|
<FrameComponent style={frameStyle}>
|
||||||
{this.renderPopupContent()}
|
{this.renderPopupContent()}
|
||||||
</FrameComponent>
|
</FrameComponent>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return this.renderFrameContainer();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue