Added handling allowing members to edit their billing info (#11571)

no issue

- This functionality allows member to update their billing information, like credit card information.
- Adds handler to update Stripe billing when element with `data-members-edit-billing` attribute is present on the page. Additional `data-members-success` and `data-members-cancel` attributes could be used to control the redirects on billing update success or failure. They work in the same fission as for 'members-plan' (https://ghost.org/docs/members/checkout-buttons/#redirects)
This commit is contained in:
Naz 2020-02-26 12:42:41 +08:00 committed by GitHub
parent 2b9e494dfc
commit 3af621ea9a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 82 additions and 5 deletions

View File

@ -119,6 +119,75 @@ Array.prototype.forEach.call(document.querySelectorAll('[data-members-plan]'), f
el.addEventListener('click', clickHandler);
});
Array.prototype.forEach.call(document.querySelectorAll('[data-members-edit-billing]'), function (el) {
var errorEl = el.querySelector('[data-members-error]');
var membersSuccess = el.dataset.membersSuccess;
var membersCancel = el.dataset.membersCancel;
var successUrl;
var cancelUrl;
if (membersSuccess) {
successUrl = (new URL(membersSuccess, window.location.href)).href;
}
if (membersCancel) {
cancelUrl = (new URL(membersCancel, window.location.href)).href;
}
function clickHandler(event) {
el.removeEventListener('click', clickHandler);
event.preventDefault();
if (errorEl) {
errorEl.innerText = '';
}
el.classList.add('loading');
fetch('{{blog-url}}/members/ssr', {
credentials: 'same-origin'
}).then(function (res) {
if (!res.ok) {
return null;
}
return res.text();
}).then(function (identity) {
return fetch('{{admin-url}}/api/canary/members/create-stripe-setup-session/', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
identity: identity,
successUrl: successUrl,
cancelUrl: cancelUrl
})
}).then(function (res) {
if (!res.ok) {
throw new Error('Could not create stripe checkout session');
}
return res.json();
});
}).then(function (result) {
var stripe = Stripe(result.publicKey);
return stripe.redirectToCheckout({
sessionId: result.sessionId
});
}).then(function (result) {
if (result.error) {
throw new Error(result.error.message);
}
}).catch(function (err) {
console.error(err);
el.addEventListener('click', clickHandler);
el.classList.remove('loading');
if (errorEl) {
errorEl.innerText = err.message;
}
el.classList.add('error');
});
}
el.addEventListener('click', clickHandler);
});
Array.prototype.forEach.call(document.querySelectorAll('[data-members-signout]'), function (el) {
function clickHandler(event) {
el.removeEventListener('click', clickHandler);

View File

@ -61,11 +61,18 @@ function getStripePaymentConfig() {
const checkoutCancelUrl = new URL(siteUrl);
checkoutCancelUrl.searchParams.set('stripe', 'cancel');
const billingSuccessUrl = new URL(siteUrl);
billingSuccessUrl.searchParams.set('stripe', 'billing-update-success');
const billingCancelUrl = new URL(siteUrl);
billingCancelUrl.searchParams.set('stripe', 'billing-update-cancel');
return {
publicKey: stripePaymentProcessor.config.public_token,
secretKey: stripePaymentProcessor.config.secret_token,
checkoutSuccessUrl: checkoutSuccessUrl.href,
checkoutCancelUrl: checkoutCancelUrl.href,
billingSuccessUrl: billingSuccessUrl.href,
billingCancelUrl: billingCancelUrl.href,
webhookHandlerUrl: webhookHandlerUrl.href,
product: stripePaymentProcessor.config.product,
plans: stripePaymentProcessor.config.plans,

View File

@ -27,6 +27,7 @@ module.exports = function setupMembersApiApp() {
// NOTE: this is wrapped in a function to ensure we always go via the getter
apiApp.post('/send-magic-link', (req, res, next) => membersService.api.middleware.sendMagicLink(req, res, next));
apiApp.post('/create-stripe-checkout-session', (req, res, next) => membersService.api.middleware.createCheckoutSession(req, res, next));
apiApp.post('/create-stripe-setup-session', (req, res, next) => membersService.api.middleware.createCheckoutSetupSession(req, res, next));
apiApp.put('/subscriptions/:id', (req, res, next) => membersService.api.middleware.updateSubscription(req, res, next));
// API error handling

View File

@ -42,7 +42,7 @@
"@nexes/nql": "0.3.0",
"@sentry/node": "5.12.4",
"@tryghost/helpers": "1.1.22",
"@tryghost/members-api": "0.15.1",
"@tryghost/members-api": "0.16.0",
"@tryghost/members-ssr": "0.7.4",
"@tryghost/social-urls": "0.1.5",
"@tryghost/string": "^0.1.3",

View File

@ -330,10 +330,10 @@
jsonwebtoken "^8.5.1"
lodash "^4.17.15"
"@tryghost/members-api@0.15.1":
version "0.15.1"
resolved "https://registry.yarnpkg.com/@tryghost/members-api/-/members-api-0.15.1.tgz#65ea2722e200127a6f6604debbb77fa6c0c96dfd"
integrity sha512-Nlt7ZmZGHKJamrzu7hbS9OlSFifH3w7XKr7IYwWYaAMhkJpHTqCCMBJ7tuyiC6c5YgwGt9AT51+JsFvum29hnA==
"@tryghost/members-api@0.16.0":
version "0.16.0"
resolved "https://registry.yarnpkg.com/@tryghost/members-api/-/members-api-0.16.0.tgz#429870aa5a35783f6e56bde00c9bae037b0c6a92"
integrity sha512-up51hixehvEDPyj1dP9gLdZtCr12rGLB/0yMPTxiBx2DN40Y0k3qvNBc8YdXmE9zuXTRUCgOMJV3BTZywYOW7g==
dependencies:
"@tryghost/magic-link" "^0.4.1"
bluebird "^3.5.4"