0
Fork 0
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:
Rish 2020-04-14 12:34:42 +05:30
parent 3cbe8d6f0c
commit f727fdd1ed
2 changed files with 174 additions and 201 deletions

View file

@ -5,7 +5,7 @@ const React = require('react');
const PropTypes = require('prop-types');
export default class ParentContainer extends React.Component {
static propTypes = {
name: PropTypes.string
data: PropTypes.object.isRequired
};
constructor(props) {
@ -19,12 +19,25 @@ export default class ParentContainer extends React.Component {
// Setup custom trigger button handling
this.customTriggerButton = document.querySelector('[data-members-trigger-button]');
this.setupCustomTriggerButton(this.customTriggerButton);
const page = this.isMemberLoggedIn() ? 'signedin' : 'signin';
this.state = {
showPopup: false
page,
showPopup: false,
action: null
};
}
isMemberLoggedIn() {
return !!this.props.data.member;
}
switchPage(page) {
this.setState({
page
});
}
setupCustomTriggerButton(customTriggerButton) {
if (customTriggerButton) {
const clickHandler = (event) => {
@ -40,12 +53,66 @@ export default class ParentContainer extends React.Component {
}
}
onSignout() {
this.MembersAPI.signout();
resetAction() {
this.setState({
action: null
});
}
onSignin(data) {
this.MembersAPI.sendMagicLink(data);
async onAction(action, 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() {
@ -59,10 +126,11 @@ export default class ParentContainer extends React.Component {
if (this.state.showPopup) {
return (
<PopupMenuComponent
name={this.props.name}
data={this.props.data}
onSignout={e => this.onSignout()}
onSignin={data => this.onSignin(data)}
action={this.state.action}
page={this.state.page}
switchPage={page => this.switchPage(page)}
onAction={(action, data) => this.onAction(action, data)}
/>
);
}

View file

@ -1,177 +1,59 @@
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 PropTypes = require('prop-types');
export default class PopupMenuComponent extends React.Component {
static propTypes = {
name: PropTypes.string
};
constructor(props) {
super(props);
this.state = {
inputVal: '',
isLoading: false,
showSuccess: false
};
}
handleSignout(e) {
e.preventDefault();
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;
const Styles = {
frame: {
common: {
zIndex: '2147483000',
position: 'fixed',
bottom: '100px',
right: '20px',
width: '350px',
minHeight: '350px',
maxHeight: '410px',
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'
}
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 = {
},
popup: {
parent: {
width: '100%',
height: '100%',
position: 'absolute',
letterSpacing: '0',
textRendering: 'optimizeLegibility',
fontSize: '1.5rem'
};
const buttonStyle = {
},
container: {
display: 'flex',
flexDirection: 'column',
justifyContent: 'flex-start',
@ -184,47 +66,70 @@ export default class PopupMenuComponent extends React.Component {
paddingTop: '18px',
paddingBottom: '18px',
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 (
<div style={launcherStyle}>
<div style={buttonStyle}>
{this.isMemberLoggedIn() ? this.renderSignedinContent() : this.renderSignedOutContent()}
<PageComponent
data={this.props.data}
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>
);
}
render() {
let hoverStyle = {
zIndex: '2147483000',
position: 'fixed',
bottom: '100px',
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'
renderFrameContainer() {
const page = this.props.page;
const frameStyle = {
...Styles.frame.common,
...Styles.frame[page]
};
if (!this.isMemberLoggedIn()) {
hoverStyle = {
...hoverStyle,
width: '450px',
minHeight: '200px',
maxHeight: '220px'
};
}
return (
<FrameComponent style={hoverStyle}>
<FrameComponent style={frameStyle}>
{this.renderPopupContent()}
</FrameComponent>
);
}
render() {
return this.renderFrameContainer();
}
}