Refactored API setup and admin url initialization

refs https://github.com/TryGhost/members.js/issues/6

- Refactored API util to be more consistent with existing API SDKs
- Updated init method to expect admin url same as other SDKs
This commit is contained in:
Rish 2020-04-23 17:54:21 +05:30
parent c58f29f1a9
commit c1a5c67e37
2 changed files with 133 additions and 116 deletions

View File

@ -2,7 +2,8 @@ import TriggerButton from './TriggerButton';
import PopupMenu from './PopupMenu'; import PopupMenu from './PopupMenu';
import PopupModal from './PopupModal'; import PopupModal from './PopupModal';
import * as Fixtures from '../test/fixtures/data'; import * as Fixtures from '../test/fixtures/data';
const setupMembersApi = require('../utils/api'); import Api from '../utils/api';
const React = require('react'); const React = require('react');
const PropTypes = require('prop-types'); const PropTypes = require('prop-types');
export default class ParentContainer extends React.Component { export default class ParentContainer extends React.Component {
@ -39,9 +40,9 @@ export default class ParentContainer extends React.Component {
// Setup Members API with site/admin URLs // Setup Members API with site/admin URLs
const {adminUrl} = this.props.data; const {adminUrl} = this.props.data;
const siteUrl = window.location.origin; const siteUrl = window.location.origin;
this.MembersAPI = setupMembersApi({siteUrl, adminUrl}); this.MembersAPI = Api({siteUrl, adminUrl});
try { try {
const [{site}, member] = await Promise.all([this.MembersAPI.getSiteData(), this.MembersAPI.getMemberData()]); const [{site}, member] = await Promise.all([this.MembersAPI.site.read(), this.MembersAPI.member.sessionData()]);
console.log('Initialized Members.js with', site, member); console.log('Initialized Members.js with', site, member);
this.setState({ this.setState({
site, site,
@ -114,7 +115,7 @@ export default class ParentContainer extends React.Component {
showPopup: false showPopup: false
}); });
} else if (action === 'signout') { } else if (action === 'signout') {
await this.MembersAPI.signout(); await this.MembersAPI.member.signout();
this.setState({ this.setState({
action: { action: {
@ -126,7 +127,7 @@ export default class ParentContainer extends React.Component {
} }
if (action === 'signin') { if (action === 'signin') {
await this.MembersAPI.sendMagicLink(data); await this.MembersAPI.member.sendMagicLink(data);
this.setState({ this.setState({
action: { action: {
name: action, name: action,
@ -141,7 +142,7 @@ export default class ParentContainer extends React.Component {
const checkoutSuccessUrl = (new URL('/account/?stripe=billing-update-success', window.location.href)).href; 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; const checkoutCancelUrl = (new URL('/account/?stripe=billing-update-cancel', window.location.href)).href;
const {plan} = data; const {plan} = data;
await this.MembersAPI.checkoutPlan({ await this.MembersAPI.member.checkoutPlan({
plan, plan,
checkoutSuccessUrl, checkoutSuccessUrl,
checkoutCancelUrl checkoutCancelUrl

View File

@ -1,94 +1,120 @@
function createSignoutApi(siteUrl) { function MembersAPI({adminUrl}) {
return function () { const ghostPath = 'ghost';
return fetch(`${siteUrl}/members/ssr`, { const ssrPath = 'members/ssr';
method: 'DELETE' const version = 'v3';
}).then(function (res) {
if (res.ok) {
window.location.reload();
return 'Success';
} else {
console.log('Failed to signout!', res);
}
});
};
}
function createSendMagicLinkApi(adminUrl) { const siteUrl = window.location.origin;
return function ({email, emailType = 'signup', labels = []}) {
return fetch(`${adminUrl}/api/canary/members/send-magic-link/`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
email,
emailType,
labels
})
}).then(function (res) {
if (res.ok) {
return 'Success';
} else {
return 'Failed to send magic link';
}
});
};
}
function createMemberIdentityApi(siteUrl) { function endpointFor({type, resource}) {
return function () { if (type === 'members') {
return fetch(`${siteUrl}/members/ssr`, { return `${adminUrl}/${ghostPath}/api/${version}/members/${resource}/`;
credentials: 'same-origin' } else if (type === 'admin') {
}).then(function (res) { return `${adminUrl}/${ghostPath}/api/${version}/admin/${resource}/`;
if (!res.ok) { } else if (type === 'ssr') {
return null; return resource ? `${siteUrl}/${ssrPath}/${resource}/` : `${siteUrl}/${ssrPath}/`;
} }
return res.text(); }
});
};
}
function createMemberSessionDataApi(siteUrl) { function makeRequest({url, method, headers = {}, credentials, body}) {
return function () { const options = {
return fetch(`${siteUrl}/members/ssr/member`, { method,
credentials: 'same-origin' headers,
}).then(function (res) { credentials,
if (!res.ok) { body
return null; };
} return fetch(url, options);
return res.json(); }
}); const api = {};
};
}
function createSiteDataApi(adminUrl) { api.site = {
return function () { read() {
return fetch(`${adminUrl}/api/canary/admin/site/`, { const url = endpointFor({type: 'admin', resource: 'site'});
method: 'GET', return makeRequest({
headers: { url,
'Content-Type': 'application/json' method: 'GET',
} headers: {
}).then(function (res) { 'Content-Type': 'application/json'
if (res.ok) { }
}).then(function (res) {
if (res.ok) {
return res.json();
} else {
return 'Failed to fetch site data';
}
});
}
};
api.member = {
identity() {
const url = endpointFor({type: 'ssr'});
return makeRequest({
url,
credentials: 'same-origin'
}).then(function (res) {
if (!res.ok) {
return null;
}
return res.text();
});
},
sessionData() {
const url = endpointFor({type: 'ssr', resource: 'member'});
return makeRequest({
url,
credentials: 'same-origin'
}).then(function (res) {
if (!res.ok) {
return null;
}
return res.json(); return res.json();
} else { });
return 'Failed to fetch site data'; },
}
});
};
}
function createCheckoutPlanApi(siteUrl, adminUrl) { sendMagicLink({email, emailType, labels}) {
return function ({plan, checkoutCancelUrl, checkoutSuccessUrl}) { const url = endpointFor({type: 'members', resource: 'send-magic-link'});
return fetch(`${siteUrl}/members/ssr`, { return makeRequest({
credentials: 'same-origin' url,
}).then(function (res) { method: 'POST',
if (!res.ok) { headers: {
return null; 'Content-Type': 'application/json'
} },
return res.text(); body: JSON.stringify({
}).then(function (identity) { email,
return fetch(`${adminUrl}/api/canary/members/create-stripe-checkout-session/`, { emailType,
labels
})
}).then(function (res) {
if (res.ok) {
return 'Success';
} else {
return 'Failed to send magic link';
}
});
},
signout() {
const url = endpointFor({type: 'ssr'});
return makeRequest({
url,
method: 'DELETE'
}).then(function (res) {
if (res.ok) {
window.location.reload();
return 'Success';
} else {
console.log('Failed to signout!', res);
}
});
},
async checkoutPlan({plan, checkoutCancelUrl, checkoutSuccessUrl}) {
const identity = await api.member.identity();
const url = endpointFor({type: 'members', resource: 'create-stripe-checkout-session'});
return makeRequest({
url,
method: 'POST', method: 'POST',
headers: { headers: {
'Content-Type': 'application/json' 'Content-Type': 'application/json'
@ -104,32 +130,22 @@ function createCheckoutPlanApi(siteUrl, adminUrl) {
throw new Error('Could not create stripe checkout session'); throw new Error('Could not create stripe checkout session');
} }
return res.json(); return res.json();
}).then(function (result) {
var stripe = window.Stripe(result.publicKey);
return stripe.redirectToCheckout({
sessionId: result.sessionId
});
}).then(function (result) {
if (result.error) {
throw new Error(result.error.message);
}
}).catch(function (err) {
throw err;
}); });
}).then(function (result) { }
var stripe = window.Stripe(result.publicKey);
return stripe.redirectToCheckout({
sessionId: result.sessionId
});
}).then(function (result) {
if (result.error) {
throw new Error(result.error.message);
}
}).catch(function (err) {
throw err;
});
}; };
return api;
} }
/** siteUrl and adminUrl are being passed by theme */ export default MembersAPI;
function setupMembersApi({siteUrl, adminUrl}) {
return {
sendMagicLink: createSendMagicLinkApi(adminUrl),
signout: createSignoutApi(siteUrl),
checkoutPlan: createCheckoutPlanApi(siteUrl, adminUrl),
getMemberIdentity: createMemberIdentityApi(siteUrl),
getMemberData: createMemberSessionDataApi(siteUrl),
getSiteData: createSiteDataApi(adminUrl)
};
}
module.exports = setupMembersApi;