diff --git a/ghost/portal/src/components/ParentContainer.js b/ghost/portal/src/components/ParentContainer.js index 5c62d764d2..9b5a374c85 100644 --- a/ghost/portal/src/components/ParentContainer.js +++ b/ghost/portal/src/components/ParentContainer.js @@ -2,7 +2,8 @@ import TriggerButton from './TriggerButton'; import PopupMenu from './PopupMenu'; import PopupModal from './PopupModal'; import * as Fixtures from '../test/fixtures/data'; -const setupMembersApi = require('../utils/api'); +import Api from '../utils/api'; + const React = require('react'); const PropTypes = require('prop-types'); 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 const {adminUrl} = this.props.data; const siteUrl = window.location.origin; - this.MembersAPI = setupMembersApi({siteUrl, adminUrl}); + this.MembersAPI = Api({siteUrl, adminUrl}); 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); this.setState({ site, @@ -114,7 +115,7 @@ export default class ParentContainer extends React.Component { showPopup: false }); } else if (action === 'signout') { - await this.MembersAPI.signout(); + await this.MembersAPI.member.signout(); this.setState({ action: { @@ -126,7 +127,7 @@ export default class ParentContainer extends React.Component { } if (action === 'signin') { - await this.MembersAPI.sendMagicLink(data); + await this.MembersAPI.member.sendMagicLink(data); this.setState({ 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 checkoutCancelUrl = (new URL('/account/?stripe=billing-update-cancel', window.location.href)).href; const {plan} = data; - await this.MembersAPI.checkoutPlan({ + await this.MembersAPI.member.checkoutPlan({ plan, checkoutSuccessUrl, checkoutCancelUrl diff --git a/ghost/portal/src/utils/api.js b/ghost/portal/src/utils/api.js index 8190858f29..6bb881c1f2 100644 --- a/ghost/portal/src/utils/api.js +++ b/ghost/portal/src/utils/api.js @@ -1,94 +1,120 @@ -function createSignoutApi(siteUrl) { - return function () { - return fetch(`${siteUrl}/members/ssr`, { - method: 'DELETE' - }).then(function (res) { - if (res.ok) { - window.location.reload(); - return 'Success'; - } else { - console.log('Failed to signout!', res); - } - }); - }; -} +function MembersAPI({adminUrl}) { + const ghostPath = 'ghost'; + const ssrPath = 'members/ssr'; + const version = 'v3'; -function createSendMagicLinkApi(adminUrl) { - 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'; - } - }); - }; -} + const siteUrl = window.location.origin; -function createMemberIdentityApi(siteUrl) { - return function () { - return fetch(`${siteUrl}/members/ssr`, { - credentials: 'same-origin' - }).then(function (res) { - if (!res.ok) { - return null; - } - return res.text(); - }); - }; -} + function endpointFor({type, resource}) { + if (type === 'members') { + return `${adminUrl}/${ghostPath}/api/${version}/members/${resource}/`; + } else if (type === 'admin') { + return `${adminUrl}/${ghostPath}/api/${version}/admin/${resource}/`; + } else if (type === 'ssr') { + return resource ? `${siteUrl}/${ssrPath}/${resource}/` : `${siteUrl}/${ssrPath}/`; + } + } -function createMemberSessionDataApi(siteUrl) { - return function () { - return fetch(`${siteUrl}/members/ssr/member`, { - credentials: 'same-origin' - }).then(function (res) { - if (!res.ok) { - return null; - } - return res.json(); - }); - }; -} + function makeRequest({url, method, headers = {}, credentials, body}) { + const options = { + method, + headers, + credentials, + body + }; + return fetch(url, options); + } + const api = {}; -function createSiteDataApi(adminUrl) { - return function () { - return fetch(`${adminUrl}/api/canary/admin/site/`, { - method: 'GET', - headers: { - 'Content-Type': 'application/json' - } - }).then(function (res) { - if (res.ok) { + api.site = { + read() { + const url = endpointFor({type: 'admin', resource: 'site'}); + return makeRequest({ + url, + method: 'GET', + headers: { + 'Content-Type': 'application/json' + } + }).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(); - } else { - return 'Failed to fetch site data'; - } - }); - }; -} + }); + }, -function createCheckoutPlanApi(siteUrl, adminUrl) { - return function ({plan, checkoutCancelUrl, checkoutSuccessUrl}) { - return fetch(`${siteUrl}/members/ssr`, { - credentials: 'same-origin' - }).then(function (res) { - if (!res.ok) { - return null; - } - return res.text(); - }).then(function (identity) { - return fetch(`${adminUrl}/api/canary/members/create-stripe-checkout-session/`, { + sendMagicLink({email, emailType, labels}) { + const url = endpointFor({type: 'members', resource: 'send-magic-link'}); + return makeRequest({ + url, + 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'; + } + }); + }, + + 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', headers: { 'Content-Type': 'application/json' @@ -104,32 +130,22 @@ function createCheckoutPlanApi(siteUrl, adminUrl) { throw new Error('Could not create stripe checkout session'); } 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 */ -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; +export default MembersAPI;