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');
|
||||
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)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue