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'); 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)}
/> />
); );
} }

View file

@ -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();
}
} }