mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-02-17 23:44:39 -05:00
Added new Signin/Signup/MagicLink pages
Added new pages for different UI flows - Sign-in Page: Allow member to signin with magic link - Signup Page: Allow member to signup with name + email, also allow choosing plan in checkout - Signed-in Page: Default account page if member is signed in - Magic Link Page: Info page which shows magic link is sent to inbox
This commit is contained in:
parent
582bc46176
commit
3cbe8d6f0c
4 changed files with 660 additions and 0 deletions
31
ghost/portal/src/components/MagicLinkPage.js
Normal file
31
ghost/portal/src/components/MagicLinkPage.js
Normal file
|
@ -0,0 +1,31 @@
|
|||
const React = require('react');
|
||||
|
||||
export default class MagicLinkPage extends React.Component {
|
||||
renderFormHeader() {
|
||||
return (
|
||||
<div style={{display: 'flex', flexDirection: 'column', alignItems: 'center', marginBottom: '12px'}}>
|
||||
<div style={{fontSize: '18px', fontWeight: 'bold'}}> Check your Inbox! </div>
|
||||
<div> We just sent you a login link, check your Inbox! </div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
renderLoginMessage() {
|
||||
return (
|
||||
<div style={{display: 'flex', justifyContent: 'center'}}>
|
||||
<div style={{color: '#3db0ef', fontWeight: 'bold', cursor: 'pointer'}} onClick={() => this.props.switchPage('signin')}> Back to Log in </div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div style={{display: 'flex', flexDirection: 'column', color: '#313131'}}>
|
||||
<div style={{paddingLeft: '16px', paddingRight: '16px', paddingTop: '12px'}}>
|
||||
{this.renderFormHeader()}
|
||||
{this.renderLoginMessage()}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
163
ghost/portal/src/components/SignedInPage.js
Normal file
163
ghost/portal/src/components/SignedInPage.js
Normal file
|
@ -0,0 +1,163 @@
|
|||
const React = require('react');
|
||||
const PropTypes = require('prop-types');
|
||||
|
||||
export default class SignedInPage 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
|
||||
}).isRequired,
|
||||
onAction: PropTypes.func
|
||||
};
|
||||
|
||||
handleSignout(e) {
|
||||
e.preventDefault();
|
||||
this.props.onAction('signout');
|
||||
}
|
||||
|
||||
handlePlanCheckout(e) {
|
||||
e.preventDefault();
|
||||
const plan = e.target.name;
|
||||
const email = this.getMemberEmail();
|
||||
this.props.onAction('checkoutPlan', {email, plan});
|
||||
}
|
||||
|
||||
getMemberEmail() {
|
||||
return this.props.data.member.email;
|
||||
}
|
||||
|
||||
renderPlanSelectButton({name}) {
|
||||
const buttonStyle = {
|
||||
display: 'inline-block',
|
||||
height: '38px',
|
||||
border: '0',
|
||||
fontSize: '14px',
|
||||
fontWeight: '300',
|
||||
textAlign: 'center',
|
||||
textDecoration: 'none',
|
||||
whiteSpace: 'nowrap',
|
||||
borderRadius: '5px',
|
||||
cursor: 'pointer',
|
||||
transition: '.4s ease',
|
||||
color: '#fff',
|
||||
backgroundColor: '#3eb0ef',
|
||||
boxShadow: 'none',
|
||||
userSelect: 'none',
|
||||
width: '90px',
|
||||
marginBottom: '12px'
|
||||
};
|
||||
|
||||
return (
|
||||
<button name={name} onClick={(e) => {
|
||||
this.handlePlanCheckout(e);
|
||||
}} style={buttonStyle}>
|
||||
Choose
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
renderPlanBox({position, id, type, price, currency, name}) {
|
||||
const boxStyle = (position) => {
|
||||
const style = {
|
||||
padding: '12px 24px',
|
||||
flexBasis: '100%'
|
||||
};
|
||||
if (position !== 'last') {
|
||||
style.borderRight = '1px solid black';
|
||||
}
|
||||
return style;
|
||||
};
|
||||
|
||||
const nameStyle = {
|
||||
fontSize: '14px',
|
||||
fontWeight: 'bold',
|
||||
display: 'flex',
|
||||
justifyContent: 'center'
|
||||
};
|
||||
|
||||
const priceStyle = {
|
||||
fontSize: '12px',
|
||||
fontWeight: 'bold',
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
marginBottom: '9px'
|
||||
};
|
||||
const checkboxStyle = {
|
||||
display: 'flex',
|
||||
justifyContent: 'center'
|
||||
};
|
||||
|
||||
return (
|
||||
<div style={boxStyle(position)}>
|
||||
<div style={nameStyle}> {name} </div>
|
||||
<div style={priceStyle}>
|
||||
<strong style={{fontSize: '14px'}}> {currency} {price} </strong>
|
||||
<span> {` / ${type}`}</span>
|
||||
</div>
|
||||
<div style={checkboxStyle}> {this.renderPlanSelectButton({name})} </div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
renderPlans() {
|
||||
const containerStyle = {
|
||||
display: 'flex',
|
||||
border: '1px solid black',
|
||||
marginBottom: '12px'
|
||||
};
|
||||
const siteTitle = this.props.data.site && this.props.data.site.title;
|
||||
const plans = this.props.data.member && this.props.data.member.plans;
|
||||
return (
|
||||
<div style={{padding: '12px 12px'}}>
|
||||
<div style={{marginBottom: '12px', fontSize: '14px'}}>
|
||||
{`Hey there! You are subscribed to free updates from ${siteTitle}, but don't have a paid subscription to unlock full access`}
|
||||
</div>
|
||||
<div style={{fontWeight: 'bold', marginBottom: '9px'}}> Choose a Plan </div>
|
||||
<div style={containerStyle}>
|
||||
{this.renderPlanBox({position: 'first', type: 'month', price: plans.monthly, currency: plans.currencySymbol, name: 'Monthly'})}
|
||||
{this.renderPlanBox({position: 'last', type: 'year', price: plans.yearly, currency: plans.currencySymbol, name: 'Yearly'})}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
renderSignedInHeader() {
|
||||
const memberEmail = this.getMemberEmail();
|
||||
|
||||
return (
|
||||
<>
|
||||
<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>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
renderLogoutButton() {
|
||||
return (
|
||||
<div style={{paddingLeft: '16px', paddingRight: '16px', paddingTop: '12px', borderTop: '1px solid #EFEFEF', cursor: 'pointer'}}>
|
||||
<div onClick={(e) => {
|
||||
this.handleSignout(e);
|
||||
}} style={{fontWeight: 'bold'}}> Logout </div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div style={{display: 'flex', flexDirection: 'column', color: '#313131'}}>
|
||||
{this.renderSignedInHeader()}
|
||||
{this.renderPlans()}
|
||||
{this.renderLogoutButton()}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
158
ghost/portal/src/components/SigninPage.js
Normal file
158
ghost/portal/src/components/SigninPage.js
Normal file
|
@ -0,0 +1,158 @@
|
|||
const React = require('react');
|
||||
const PropTypes = require('prop-types');
|
||||
|
||||
export default class SigninPage extends React.Component {
|
||||
static propTypes = {
|
||||
data: PropTypes.shape({
|
||||
site: PropTypes.shape({
|
||||
title: PropTypes.string,
|
||||
description: PropTypes.string
|
||||
}).isRequired
|
||||
}).isRequired,
|
||||
onAction: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
email: ''
|
||||
};
|
||||
}
|
||||
|
||||
handleSignin(e) {
|
||||
e.preventDefault();
|
||||
const email = this.state.email;
|
||||
|
||||
this.props.onAction('signin', {email});
|
||||
}
|
||||
|
||||
handleInput(e, field) {
|
||||
this.setState({
|
||||
[field]: e.target.value,
|
||||
showSuccess: false,
|
||||
isLoading: false
|
||||
});
|
||||
}
|
||||
|
||||
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',
|
||||
width: '100%',
|
||||
marginBottom: '12px'
|
||||
};
|
||||
const isRunning = this.props.action && this.props.action.name === 'signin' && this.props.action.isRunning;
|
||||
const label = this.state.isLoading ? 'Sending' : 'Continue';
|
||||
const disabled = isRunning ? true : false;
|
||||
if (disabled) {
|
||||
buttonStyle.backgroundColor = 'grey';
|
||||
}
|
||||
|
||||
return (
|
||||
<button onClick={(e) => {
|
||||
this.handleSignin(e);
|
||||
}} style={buttonStyle} disabled={disabled}>
|
||||
{label}
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
renderInputField(fieldName) {
|
||||
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 fields = {
|
||||
name: {
|
||||
type: 'text',
|
||||
value: this.state.name,
|
||||
placeholder: 'Name...'
|
||||
},
|
||||
email: {
|
||||
type: 'email',
|
||||
value: this.state.email,
|
||||
placeholder: 'Email...'
|
||||
}
|
||||
};
|
||||
const field = fields[fieldName];
|
||||
return (
|
||||
<input
|
||||
type={field.type}
|
||||
placeholder={field.placeholder}
|
||||
value={field.value}
|
||||
onChange={(e) => {
|
||||
this.handleInput(e, fieldName);
|
||||
}}
|
||||
style={inputStyle}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
renderSignupMessage() {
|
||||
return (
|
||||
<div style={{display: 'flex'}}>
|
||||
<div style={{marginRight: '6px'}}> Not a member ? </div>
|
||||
<div style={{color: '#3db0ef', fontWeight: 'bold', cursor: 'pointer'}} onClick={() => this.props.switchPage('signup')}> Signup </div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
renderForm() {
|
||||
return (
|
||||
<div style={{display: 'flex', flexDirection: 'column', alignItems: 'center', marginBottom: '12px'}}>
|
||||
{this.renderInputField('email')}
|
||||
{this.renderSubmitButton()}
|
||||
{this.renderSignupMessage()}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
renderFormHeader() {
|
||||
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', alignItems: 'center', marginBottom: '12px'}}>
|
||||
<div style={{fontSize: '18px', fontWeight: 'bold'}}> Signin to {siteTitle}</div>
|
||||
<div> {siteDescription} </div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div style={{display: 'flex', flexDirection: 'column', color: '#313131'}}>
|
||||
<div style={{paddingLeft: '16px', paddingRight: '16px', paddingTop: '12px'}}>
|
||||
{this.renderFormHeader()}
|
||||
{this.renderForm()}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
308
ghost/portal/src/components/SignupPage.js
Normal file
308
ghost/portal/src/components/SignupPage.js
Normal file
|
@ -0,0 +1,308 @@
|
|||
const React = require('react');
|
||||
const PropTypes = require('prop-types');
|
||||
|
||||
export default class SignupPage extends React.Component {
|
||||
static propTypes = {
|
||||
data: PropTypes.shape({
|
||||
site: PropTypes.shape({
|
||||
title: PropTypes.string,
|
||||
description: PropTypes.string
|
||||
}).isRequired
|
||||
}).isRequired,
|
||||
onAction: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
name: '',
|
||||
email: '',
|
||||
plan: 'Free',
|
||||
isLoading: false,
|
||||
showSuccess: false
|
||||
};
|
||||
}
|
||||
|
||||
handleSignin(e) {
|
||||
e.preventDefault();
|
||||
const email = this.state.email;
|
||||
const name = this.state.name;
|
||||
const plan = this.state.plan;
|
||||
this.props.onAction('signup', {name, email, plan});
|
||||
this.setState({
|
||||
isLoading: true,
|
||||
showSuccess: false
|
||||
});
|
||||
setTimeout(() => {
|
||||
this.setState({
|
||||
isLoading: false,
|
||||
showSuccess: true
|
||||
});
|
||||
}, 3000);
|
||||
}
|
||||
|
||||
handleInput(e, field) {
|
||||
this.setState({
|
||||
[field]: e.target.value,
|
||||
showSuccess: false,
|
||||
isLoading: false
|
||||
});
|
||||
}
|
||||
|
||||
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',
|
||||
width: '100%',
|
||||
marginBottom: '12px'
|
||||
};
|
||||
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>
|
||||
);
|
||||
}
|
||||
|
||||
renderPlanBox({position, id, type, price, currency, name}) {
|
||||
const boxStyle = (position) => {
|
||||
const style = {
|
||||
padding: '12px 24px',
|
||||
flexBasis: '100%'
|
||||
};
|
||||
if (position !== 'last') {
|
||||
style.borderRight = '1px solid black';
|
||||
}
|
||||
return style;
|
||||
};
|
||||
|
||||
const nameStyle = {
|
||||
fontSize: '14px',
|
||||
fontWeight: 'bold',
|
||||
display: 'flex',
|
||||
justifyContent: 'center'
|
||||
};
|
||||
|
||||
const priceStyle = {
|
||||
fontSize: '12px',
|
||||
fontWeight: 'bold',
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
marginBottom: '9px'
|
||||
};
|
||||
const checkboxStyle = {
|
||||
display: 'flex',
|
||||
justifyContent: 'center'
|
||||
};
|
||||
const isChecked = this.state.plan === name;
|
||||
if (name === 'Free') {
|
||||
return (
|
||||
<div style={boxStyle(position)}>
|
||||
<div style={nameStyle}> {name} </div>
|
||||
<div style={priceStyle}>
|
||||
<strong style={{fontSize: '14px'}}> {price} </strong>
|
||||
</div>
|
||||
<div style={checkboxStyle}> {this.renderCheckbox({name, isChecked})} </div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<div style={boxStyle(position)}>
|
||||
<div style={nameStyle}> {name} </div>
|
||||
<div style={priceStyle}>
|
||||
<strong style={{fontSize: '14px'}}> {currency} {price} </strong>
|
||||
<span> {` / ${type}`}</span>
|
||||
</div>
|
||||
<div style={checkboxStyle}> {this.renderCheckbox({name, isChecked})} </div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
renderPlanBoxOld({position, id, type, price, name}) {
|
||||
const boxStyle = (position) => {
|
||||
const style = {
|
||||
padding: '12px 24px',
|
||||
flexBasis: '100%'
|
||||
};
|
||||
if (position !== 'last') {
|
||||
style.borderRight = '1px solid black';
|
||||
}
|
||||
return style;
|
||||
};
|
||||
|
||||
const nameStyle = {
|
||||
fontSize: '14px',
|
||||
fontWeight: 'bold',
|
||||
display: 'flex',
|
||||
justifyContent: 'center'
|
||||
};
|
||||
|
||||
const priceStyle = {
|
||||
fontSize: '12px',
|
||||
fontWeight: 'bold',
|
||||
display: 'flex',
|
||||
justifyContent: 'center'
|
||||
};
|
||||
const checkboxStyle = {
|
||||
display: 'flex',
|
||||
justifyContent: 'center'
|
||||
};
|
||||
|
||||
const isChecked = (this.state.plan === name);
|
||||
return (
|
||||
<div style={boxStyle(position)}>
|
||||
<div style={nameStyle}> {type} </div>
|
||||
<div style={priceStyle}> {price} </div>
|
||||
<div style={checkboxStyle}> {this.renderCheckbox({name, isChecked})} </div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
handleSelectPlan(e) {
|
||||
const plan = e.target.name;
|
||||
this.setState({
|
||||
plan
|
||||
});
|
||||
}
|
||||
|
||||
renderCheckbox({name, isChecked = false}) {
|
||||
const style = {
|
||||
width: '20px',
|
||||
height: '20px',
|
||||
border: 'solid 1px #cccccc'
|
||||
};
|
||||
return (
|
||||
<input
|
||||
name={name}
|
||||
type="checkbox"
|
||||
style={style}
|
||||
checked={isChecked}
|
||||
onChange = {e => this.handleSelectPlan(e)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
renderPlans() {
|
||||
const containerStyle = {
|
||||
display: 'flex',
|
||||
border: '1px solid black',
|
||||
borderRadius: '6px',
|
||||
marginBottom: '12px'
|
||||
};
|
||||
const plans = this.props.data.site && this.props.data.site.plans;
|
||||
return (
|
||||
<div style={{width: '100%'}}>
|
||||
<div style={{fontWeight: 'bold', marginBottom: '9px'}}> Choose a Plan </div>
|
||||
<div style={containerStyle}>
|
||||
{this.renderPlanBox({position: 'first', type: 'free', price: 'Decide later', name: 'Free'})}
|
||||
{this.renderPlanBox({position: 'middle', type: 'month', price: plans.monthly, currency: plans.currencySymbol, name: 'Monthly'})}
|
||||
{this.renderPlanBox({position: 'last', type: 'year', price: plans.yearly, currency: plans.currencySymbol, name: 'Yearly'})}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
renderInputField(fieldName) {
|
||||
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 fields = {
|
||||
name: {
|
||||
type: 'text',
|
||||
value: this.state.name,
|
||||
placeholder: 'Name...'
|
||||
},
|
||||
email: {
|
||||
type: 'email',
|
||||
value: this.state.email,
|
||||
placeholder: 'Email...'
|
||||
}
|
||||
};
|
||||
const field = fields[fieldName];
|
||||
return (
|
||||
<input
|
||||
type={field.type}
|
||||
placeholder={field.placeholder}
|
||||
value={field.value}
|
||||
onChange={(e) => {
|
||||
this.handleInput(e, fieldName);
|
||||
}}
|
||||
style={inputStyle}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
renderLoginMessage() {
|
||||
return (
|
||||
<div style={{display: 'flex'}}>
|
||||
<div style={{marginRight: '6px'}}> Already a member ? </div>
|
||||
<div style={{color: '#3db0ef', fontWeight: 'bold', cursor: 'pointer'}} onClick={() => this.props.switchPage('signin')}> Log in </div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
renderForm() {
|
||||
return (
|
||||
<div style={{display: 'flex', flexDirection: 'column', alignItems: 'center', marginBottom: '12px'}}>
|
||||
{this.renderInputField('name')}
|
||||
{this.renderInputField('email')}
|
||||
{this.renderPlans()}
|
||||
{this.renderSubmitButton()}
|
||||
{this.renderLoginMessage()}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
renderFormHeader() {
|
||||
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', alignItems: 'center', marginBottom: '12px'}}>
|
||||
<div style={{fontSize: '18px', fontWeight: 'bold'}}> Signup to {siteTitle}</div>
|
||||
<div> {siteDescription} </div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div style={{display: 'flex', flexDirection: 'column', color: '#313131'}}>
|
||||
<div style={{paddingLeft: '16px', paddingRight: '16px', paddingTop: '12px'}}>
|
||||
{this.renderFormHeader()}
|
||||
{this.renderForm()}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue