f2c0bff9df
no issue
refs dac5cca899
- added cleanup of the `message` event handler added to `window` when the component is destroyed
- added a guard to the event handler method to abort early if a message is received whilst the component is being destroyed
- updated Billing Service and `<GHBillingIframe>` to not use `@classic` decorator
137 lines
4.2 KiB
JavaScript
137 lines
4.2 KiB
JavaScript
import Service, {inject as service} from '@ember/service';
|
|
import {inject} from 'ghost-admin/decorators/inject';
|
|
import {tracked} from '@glimmer/tracking';
|
|
|
|
export default class BillingService extends Service {
|
|
@service ghostPaths;
|
|
@service router;
|
|
@service store;
|
|
|
|
@inject config;
|
|
|
|
billingRouteRoot = '#/pro';
|
|
|
|
@tracked billingWindowOpen = false;
|
|
@tracked subscription = null;
|
|
@tracked previousRoute = null;
|
|
@tracked action = null;
|
|
@tracked ownerUser = null;
|
|
|
|
constructor() {
|
|
super(...arguments);
|
|
|
|
if (this.config.hostSettings?.billing?.url) {
|
|
window.addEventListener('message', (event) => {
|
|
if (event && event.data && event.data.route) {
|
|
this.handleRouteChangeInIframe(event.data.route);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
handleRouteChangeInIframe(destinationRoute) {
|
|
if (this.billingWindowOpen) {
|
|
let billingRoute = this.billingRouteRoot;
|
|
|
|
if (destinationRoute !== '/') {
|
|
billingRoute += destinationRoute;
|
|
}
|
|
|
|
if (window.location.hash !== billingRoute) {
|
|
window.history.replaceState(window.history.state, '', billingRoute);
|
|
}
|
|
}
|
|
}
|
|
|
|
getIframeURL() {
|
|
// initiate getting owner user in the background
|
|
this.getOwnerUser();
|
|
|
|
let url = this.config.hostSettings?.billing?.url;
|
|
|
|
if (window.location.hash && window.location.hash.includes(this.billingRouteRoot)) {
|
|
let destinationRoute = window.location.hash.replace(this.billingRouteRoot, '');
|
|
|
|
if (destinationRoute) {
|
|
url += destinationRoute;
|
|
}
|
|
}
|
|
|
|
return url;
|
|
}
|
|
|
|
async getOwnerUser() {
|
|
if (!this.ownerUser) {
|
|
// Try to receive the owner user from the store
|
|
let user = this.store.peekAll('user').findBy('isOwnerOnly', true);
|
|
|
|
if (!user) {
|
|
// load it when it's not there yet
|
|
await this.store.findAll('user', {reload: true});
|
|
user = this.store.peekAll('user').findBy('isOwnerOnly', true);
|
|
}
|
|
this.ownerUser = user;
|
|
}
|
|
return this.ownerUser;
|
|
}
|
|
|
|
// Sends a route update to a child route in the BMA, because we can't control
|
|
// navigating to it otherwise
|
|
sendRouteUpdate() {
|
|
const action = this.action;
|
|
|
|
if (action) {
|
|
if (action === 'checkout') {
|
|
this.getBillingIframe().contentWindow.postMessage({
|
|
query: 'routeUpdate',
|
|
response: this.checkoutRoute
|
|
}, '*');
|
|
}
|
|
|
|
this.action = null;
|
|
}
|
|
}
|
|
|
|
// Controls billing window modal visibility and sync of the URL visible in browser
|
|
// and the URL opened on the iframe. It is responsible to non user triggered iframe opening,
|
|
// for example: by entering "/pro" route in the URL or using history navigation (back and forward)
|
|
toggleProWindow(value) {
|
|
if (this.billingWindowOpen && value && !this.action) {
|
|
// don't attempt to open again
|
|
return;
|
|
}
|
|
|
|
this.sendRouteUpdate();
|
|
|
|
this.billingWindowOpen = value;
|
|
}
|
|
|
|
// Controls navigation to billing window modal which is triggered from the application UI.
|
|
// For example: pressing "View Billing" link in navigation menu. It's main side effect is
|
|
// remembering the route from which the action has been triggered - "previousRoute" so it
|
|
// could be reused when closing billing window
|
|
openBillingWindow(currentRoute, childRoute) {
|
|
// initiate getting owner user in the background
|
|
this.getOwnerUser();
|
|
|
|
if (this.billingWindowOpen) {
|
|
// don't attempt to open again
|
|
return;
|
|
}
|
|
|
|
this.previousRoute = currentRoute;
|
|
|
|
// Ensures correct "getIframeURL" calculation when syncing iframe location
|
|
// in toggleProWindow
|
|
window.location.hash = childRoute || '/pro';
|
|
|
|
this.sendRouteUpdate();
|
|
|
|
this.router.transitionTo(childRoute || '/pro');
|
|
}
|
|
|
|
getBillingIframe() {
|
|
return document.getElementById('billing-frame');
|
|
}
|
|
}
|