mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-02-10 23:18:42 -05:00
✨ 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:
parent
2b9e494dfc
commit
3af621ea9a
5 changed files with 82 additions and 5 deletions
|
@ -119,6 +119,75 @@ Array.prototype.forEach.call(document.querySelectorAll('[data-members-plan]'), f
|
||||||
el.addEventListener('click', clickHandler);
|
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) {
|
Array.prototype.forEach.call(document.querySelectorAll('[data-members-signout]'), function (el) {
|
||||||
function clickHandler(event) {
|
function clickHandler(event) {
|
||||||
el.removeEventListener('click', clickHandler);
|
el.removeEventListener('click', clickHandler);
|
||||||
|
|
|
@ -61,11 +61,18 @@ function getStripePaymentConfig() {
|
||||||
const checkoutCancelUrl = new URL(siteUrl);
|
const checkoutCancelUrl = new URL(siteUrl);
|
||||||
checkoutCancelUrl.searchParams.set('stripe', 'cancel');
|
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 {
|
return {
|
||||||
publicKey: stripePaymentProcessor.config.public_token,
|
publicKey: stripePaymentProcessor.config.public_token,
|
||||||
secretKey: stripePaymentProcessor.config.secret_token,
|
secretKey: stripePaymentProcessor.config.secret_token,
|
||||||
checkoutSuccessUrl: checkoutSuccessUrl.href,
|
checkoutSuccessUrl: checkoutSuccessUrl.href,
|
||||||
checkoutCancelUrl: checkoutCancelUrl.href,
|
checkoutCancelUrl: checkoutCancelUrl.href,
|
||||||
|
billingSuccessUrl: billingSuccessUrl.href,
|
||||||
|
billingCancelUrl: billingCancelUrl.href,
|
||||||
webhookHandlerUrl: webhookHandlerUrl.href,
|
webhookHandlerUrl: webhookHandlerUrl.href,
|
||||||
product: stripePaymentProcessor.config.product,
|
product: stripePaymentProcessor.config.product,
|
||||||
plans: stripePaymentProcessor.config.plans,
|
plans: stripePaymentProcessor.config.plans,
|
||||||
|
|
|
@ -27,6 +27,7 @@ module.exports = function setupMembersApiApp() {
|
||||||
// NOTE: this is wrapped in a function to ensure we always go via the getter
|
// 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('/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-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));
|
apiApp.put('/subscriptions/:id', (req, res, next) => membersService.api.middleware.updateSubscription(req, res, next));
|
||||||
|
|
||||||
// API error handling
|
// API error handling
|
||||||
|
|
|
@ -42,7 +42,7 @@
|
||||||
"@nexes/nql": "0.3.0",
|
"@nexes/nql": "0.3.0",
|
||||||
"@sentry/node": "5.12.4",
|
"@sentry/node": "5.12.4",
|
||||||
"@tryghost/helpers": "1.1.22",
|
"@tryghost/helpers": "1.1.22",
|
||||||
"@tryghost/members-api": "0.15.1",
|
"@tryghost/members-api": "0.16.0",
|
||||||
"@tryghost/members-ssr": "0.7.4",
|
"@tryghost/members-ssr": "0.7.4",
|
||||||
"@tryghost/social-urls": "0.1.5",
|
"@tryghost/social-urls": "0.1.5",
|
||||||
"@tryghost/string": "^0.1.3",
|
"@tryghost/string": "^0.1.3",
|
||||||
|
|
|
@ -330,10 +330,10 @@
|
||||||
jsonwebtoken "^8.5.1"
|
jsonwebtoken "^8.5.1"
|
||||||
lodash "^4.17.15"
|
lodash "^4.17.15"
|
||||||
|
|
||||||
"@tryghost/members-api@0.15.1":
|
"@tryghost/members-api@0.16.0":
|
||||||
version "0.15.1"
|
version "0.16.0"
|
||||||
resolved "https://registry.yarnpkg.com/@tryghost/members-api/-/members-api-0.15.1.tgz#65ea2722e200127a6f6604debbb77fa6c0c96dfd"
|
resolved "https://registry.yarnpkg.com/@tryghost/members-api/-/members-api-0.16.0.tgz#429870aa5a35783f6e56bde00c9bae037b0c6a92"
|
||||||
integrity sha512-Nlt7ZmZGHKJamrzu7hbS9OlSFifH3w7XKr7IYwWYaAMhkJpHTqCCMBJ7tuyiC6c5YgwGt9AT51+JsFvum29hnA==
|
integrity sha512-up51hixehvEDPyj1dP9gLdZtCr12rGLB/0yMPTxiBx2DN40Y0k3qvNBc8YdXmE9zuXTRUCgOMJV3BTZywYOW7g==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@tryghost/magic-link" "^0.4.1"
|
"@tryghost/magic-link" "^0.4.1"
|
||||||
bluebird "^3.5.4"
|
bluebird "^3.5.4"
|
||||||
|
|
Loading…
Add table
Reference in a new issue