saleor-dashboard/src/apps/components/AppDetailsSettingsPage/useAppConfigLoader.ts
Dominik Żegleń c8d7edfeab
Fix app configuration frame embedding (#1172)
* Fix app configuration frame embedding

* Tidy up code
2021-06-21 12:55:47 +02:00

75 lines
2.1 KiB
TypeScript

import { AppFragment } from "@saleor/fragments/types/AppFragment";
import { useEffect, useRef } from "react";
import urlJoin from "url-join";
export type UseAppConfigLoaderCallbacks = Record<
"onLoad" | "onError",
() => void
>;
function fixRelativeScriptSrc(origin: string) {
return (node: HTMLScriptElement) => {
// Using node.getAttribute beacuse node.src returns absolute path
const src = node.getAttribute("src");
if (src?.startsWith("/")) {
node.src = urlJoin(origin, src);
}
};
}
async function fetchAndSetContent(
frameContainer: HTMLDivElement,
data: AppFragment,
backendHostname: string,
{ onError, onLoad }: UseAppConfigLoaderCallbacks
) {
if (!frameContainer?.innerHTML && data?.configurationUrl) {
try {
const response = await fetch(data?.configurationUrl, {
headers: {
"x-saleor-domain": backendHostname,
"x-saleor-token": data.accessToken
},
method: "GET"
});
const url = new URL(response.url);
const text = await response.text();
const content = new DOMParser().parseFromString(text, "text/html");
const frame = document.createElement("iframe");
frame.src = "about:blank";
frame.id = "extension-app";
frameContainer.innerHTML = "";
frameContainer.appendChild(frame);
const frameContent = frame.contentWindow.document;
const documentElement = content.documentElement;
const scriptNodes = documentElement.querySelectorAll("script");
scriptNodes.forEach(fixRelativeScriptSrc(url.origin));
frameContent.write(content.documentElement.innerHTML);
frameContent.close();
frame.contentWindow.onload = onLoad;
} catch (error) {
console.error(error);
onError();
}
}
}
function useAppConfigLoader(
data: AppFragment,
backendHost: string,
callbacks: UseAppConfigLoaderCallbacks
) {
const frameContainer = useRef<HTMLDivElement>(null);
useEffect(() => {
fetchAndSetContent(frameContainer.current, data, backendHost, callbacks);
}, [data]);
return frameContainer;
}
export default useAppConfigLoader;