diff --git a/client/src/components/Header/index.js b/client/src/components/Header/index.js index 5f045e794f..098c6e93bb 100644 --- a/client/src/components/Header/index.js +++ b/client/src/components/Header/index.js @@ -1,6 +1,7 @@ import React from 'react'; import Helmet from 'react-helmet'; +import stripeObserver from './stripeIframesFix'; import UniversalNav from './components/UniversalNav'; import './header.css'; @@ -19,6 +20,10 @@ export class Header extends React.Component { componentDidMount() { document.addEventListener('click', this.handleClickOutside); + + // Remove stacking Stripe iframes with each navigation + // after visiting /donate + stripeObserver(); } componentWillUnmount() { diff --git a/client/src/components/Header/stripeIframesFix.js b/client/src/components/Header/stripeIframesFix.js new file mode 100644 index 0000000000..2fa62d5b6f --- /dev/null +++ b/client/src/components/Header/stripeIframesFix.js @@ -0,0 +1,30 @@ +const stripeObserver = () => { + const config = { attributes: false, childList: true, subtree: false }; + + const filterNodes = nl => + Array.from(nl) + .filter(b => b.nodeName === 'IFRAME') + .filter(b => /__privateStripeController/.test(b.name)); + + const mutationCallback = a => { + const controllerAdded = a.reduce( + (acc, curr) => + curr.type === 'childList' + ? [...acc, ...filterNodes(curr.addedNodes)] + : acc, + [] + )[0]; + if (controllerAdded) { + const allControllers = filterNodes(document.body.childNodes); + allControllers.forEach(controller => { + if (controller.name !== controllerAdded.name) { + controller.remove(); + } + }); + } + }; + + return new MutationObserver(mutationCallback).observe(document.body, config); +}; + +export default stripeObserver; diff --git a/client/src/pages/donate.js b/client/src/pages/donate.js index 2127e189d6..9427478e26 100644 --- a/client/src/pages/donate.js +++ b/client/src/pages/donate.js @@ -48,6 +48,7 @@ export class DonatePage extends Component { this.handleStripeLoad = this.handleStripeLoad.bind(this); this.toggleOtherOptions = this.toggleOtherOptions.bind(this); } + componentDidMount() { if (window.Stripe) { this.handleStripeLoad();