mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-02-03 23:00:14 -05:00
Updated signup flow to handle invalid payments
no issue
This commit is contained in:
parent
371a0698a6
commit
618f7e35cc
2 changed files with 139 additions and 1 deletions
|
@ -11,6 +11,7 @@ import ResetPasswordPage from '../pages/ResetPasswordPage';
|
||||||
import StripeSubscribePage from '../pages/StripeSubscribePage';
|
import StripeSubscribePage from '../pages/StripeSubscribePage';
|
||||||
import { IconClose } from '../components/icons';
|
import { IconClose } from '../components/icons';
|
||||||
import StripeUpgradePage from '../pages/StripeUpgradePage';
|
import StripeUpgradePage from '../pages/StripeUpgradePage';
|
||||||
|
import StripeSubscribePaymentPage from '../pages/StripeSubscribePaymentPage';
|
||||||
|
|
||||||
export default class Modal extends Component {
|
export default class Modal extends Component {
|
||||||
constructor(props, context) {
|
constructor(props, context) {
|
||||||
|
@ -57,6 +58,7 @@ export default class Modal extends Component {
|
||||||
window.location.hash = 'signup-complete';
|
window.location.hash = 'signup-complete';
|
||||||
}, (error) => {
|
}, (error) => {
|
||||||
this.setState({ error: "Unable to confirm payment", showSpinner: false });
|
this.setState({ error: "Unable to confirm payment", showSpinner: false });
|
||||||
|
window.location.hash = data.coupon ? `signup-payment?coupon=${data.coupon}` : "signup-payment";
|
||||||
});
|
});
|
||||||
}, (error) => {
|
}, (error) => {
|
||||||
this.setState({ error: "Unable to signup", showSpinner: false });
|
this.setState({ error: "Unable to signup", showSpinner: false });
|
||||||
|
@ -70,6 +72,20 @@ export default class Modal extends Component {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
renderSignupPaymentPage({error, stripeConfig, members, signup, closeModal, siteConfig, showSpinner}) {
|
||||||
|
|
||||||
|
const createSubscription = (data) => {
|
||||||
|
this.setState({showSpinner: true});
|
||||||
|
return members.createSubscription(data).then((success) => {
|
||||||
|
this.setState({showSpinner: false});
|
||||||
|
window.location.hash = 'signup-complete';
|
||||||
|
}, (error) => {
|
||||||
|
this.setState({ error: "Unable to confirm payment", showSpinner: false });
|
||||||
|
});
|
||||||
|
};
|
||||||
|
return <StripeSubscribePaymentPage stripeConfig={stripeConfig} error={error} hash="signup-payment" handleSubmit={createSubscription} handleClose={closeModal} siteConfig={siteConfig} showSpinner={showSpinner} />
|
||||||
|
}
|
||||||
|
|
||||||
renderUpgradePage(props, state) {
|
renderUpgradePage(props, state) {
|
||||||
const { error, paymentConfig } = state;
|
const { error, paymentConfig } = state;
|
||||||
const { members } = this.context;
|
const { members } = this.context;
|
||||||
|
@ -79,7 +95,6 @@ export default class Modal extends Component {
|
||||||
);
|
);
|
||||||
const stripeConfig = paymentConfig && paymentConfig.find(({adapter}) => adapter === 'stripe');
|
const stripeConfig = paymentConfig && paymentConfig.find(({adapter}) => adapter === 'stripe');
|
||||||
return <StripeUpgradePage stripeConfig={stripeConfig} error={error} hash="upgrade" handleSubmit={createSubscription} handleClose={closeModal}/>
|
return <StripeUpgradePage stripeConfig={stripeConfig} error={error} hash="upgrade" handleSubmit={createSubscription} handleClose={closeModal}/>
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
render(props, state) {
|
render(props, state) {
|
||||||
|
@ -132,6 +147,7 @@ export default class Modal extends Component {
|
||||||
<SigninPage error={error} hash="" handleSubmit={signup} showLoggedIn={showLoggedIn} />
|
<SigninPage error={error} hash="" handleSubmit={signup} showLoggedIn={showLoggedIn} />
|
||||||
<SigninPage error={error} hash="signin" handleSubmit={signin} showLoggedIn={showLoggedIn} />
|
<SigninPage error={error} hash="signin" handleSubmit={signin} showLoggedIn={showLoggedIn} />
|
||||||
{this.renderSignupPage({ error, stripeConfig, members, signup, closeModal, siteConfig, showSpinner})}
|
{this.renderSignupPage({ error, stripeConfig, members, signup, closeModal, siteConfig, showSpinner})}
|
||||||
|
{this.renderSignupPaymentPage({ error, stripeConfig, members, signup, closeModal, siteConfig, showSpinner})}
|
||||||
{this.renderUpgradePage(props, state)}
|
{this.renderUpgradePage(props, state)}
|
||||||
<SignupCompletePage error={ error } hash="signup-complete" handleSubmit={ closeModal } siteConfig={ siteConfig } />
|
<SignupCompletePage error={ error } hash="signup-complete" handleSubmit={ closeModal } siteConfig={ siteConfig } />
|
||||||
<RequestPasswordResetPage error={error} hash="request-password-reset" handleSubmit={requestReset} />
|
<RequestPasswordResetPage error={error} hash="request-password-reset" handleSubmit={requestReset} />
|
||||||
|
|
|
@ -0,0 +1,122 @@
|
||||||
|
import { Elements, StripeProvider, injectStripe } from 'react-stripe-elements';
|
||||||
|
import { Component } from 'react';
|
||||||
|
import FormHeader from '../components/FormHeader';
|
||||||
|
import FormSubmit from '../components/FormSubmit';
|
||||||
|
import CouponInput from '../components/CouponInput';
|
||||||
|
import CheckoutForm from '../components/CheckoutForm';
|
||||||
|
import Form from '../components/Form';
|
||||||
|
|
||||||
|
const getCouponData = frameLocation => {
|
||||||
|
const params = new URLSearchParams(frameLocation.query);
|
||||||
|
const coupon = params.get('coupon') || '';
|
||||||
|
return { coupon };
|
||||||
|
};
|
||||||
|
|
||||||
|
class PaymentForm extends Component {
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
}
|
||||||
|
|
||||||
|
handleSubmit = ({ name, email, password, plan, coupon }) => {
|
||||||
|
// Within the context of `Elements`, this call to createToken knows which Element to
|
||||||
|
// tokenize, since there's only one in this group.
|
||||||
|
plan = this.props.selectedPlan ? this.props.selectedPlan.name : "";
|
||||||
|
this.props.stripe.createToken({ name: name }).then(({ token }) => {
|
||||||
|
this.props.handleSubmit({
|
||||||
|
adapter: 'stripe',
|
||||||
|
plan: plan,
|
||||||
|
stripeToken: token.id,
|
||||||
|
name, email, password, coupon
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
render({frameLocation}) {
|
||||||
|
let label = this.props.showSpinner ? "Confirming payment..." : "Confirm payment";
|
||||||
|
const { coupon } = getCouponData(frameLocation);
|
||||||
|
return (
|
||||||
|
<Form includeData={getCouponData(frameLocation)} onSubmit={(data) => this.handleSubmit(data)}>
|
||||||
|
{ coupon ? <CouponInput disabled={true} bindTo="coupon" /> : '' }
|
||||||
|
<CheckoutForm />
|
||||||
|
|
||||||
|
<FormSubmit label={label} />
|
||||||
|
</Form>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const PaymentFormWrapped = injectStripe(PaymentForm);
|
||||||
|
|
||||||
|
export default class StripeSubscriptionPage extends Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.plans = props.stripeConfig.config.plans || [];
|
||||||
|
this.state = {
|
||||||
|
selectedPlan: this.plans[0] ? this.plans[0] : ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
renderPlan({ currency, amount, id, interval, name }) {
|
||||||
|
const selectedPlanId = this.state.selectedPlan ? this.state.selectedPlan.id : "";
|
||||||
|
const dollarAmount = (amount / 100);
|
||||||
|
return (
|
||||||
|
<label for={ id }>
|
||||||
|
<div className={ (selectedPlanId === id ? "gm-plan selected" : "gm-plan") }>
|
||||||
|
<input type="radio" id={ id } name="radio-group" value={ id } defaultChecked={ id === selectedPlanId } />
|
||||||
|
<span className="gm-amount">{ `$${dollarAmount}` }</span>
|
||||||
|
<span className="gm-interval"><span className="gm-currency">{ `${currency}` }</span> { `${interval}` }</span>
|
||||||
|
</div>
|
||||||
|
</label>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
changePlan(e) {
|
||||||
|
const plan = this.plans.find(plan => plan.id === e.target.value);
|
||||||
|
this.setState({
|
||||||
|
selectedPlan: plan
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
renderPlans(plans) {
|
||||||
|
return (
|
||||||
|
<div className="mt3" onChange={(e) => this.changePlan(e)}>
|
||||||
|
{
|
||||||
|
plans.map((plan) => this.renderPlan(plan))
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderPlansSection() {
|
||||||
|
return (
|
||||||
|
<div className="gm-plans-container">
|
||||||
|
<h2 className="gm-form-section">Billing period</h2>
|
||||||
|
{this.renderPlans(this.plans)}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
render({ error, handleSubmit, stripeConfig, frameLocation, showSpinner }) {
|
||||||
|
const publicKey = stripeConfig.config.publicKey || '';
|
||||||
|
return (
|
||||||
|
<div class="gm-upgrade-page">
|
||||||
|
<div className="gm-modal-form gm-subscribe-form">
|
||||||
|
<FormHeader title="Complete payment" error={error} errorText="Unable to confirm payment" />
|
||||||
|
<div> We were unable to process your payment, please try again or use different card details.</div>
|
||||||
|
<div className="flex flex-column justfiy-stretch mt7">
|
||||||
|
{ this.renderPlansSection() }
|
||||||
|
<div className="mt4 nb3">
|
||||||
|
<h2 className="gm-form-section">Card details</h2>
|
||||||
|
</div>
|
||||||
|
<StripeProvider apiKey={publicKey}>
|
||||||
|
<Elements>
|
||||||
|
<PaymentFormWrapped handleSubmit={handleSubmit} publicKey={publicKey} selectedPlan={this.state.selectedPlan} frameLocation={frameLocation} showSpinner={showSpinner} />
|
||||||
|
</Elements>
|
||||||
|
</StripeProvider>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
};
|
Loading…
Add table
Reference in a new issue