import React, { createContext, useContext, useState, useEffect, useCallback, } from "react"; import { SiteStatusContextProps, SiteStatusProviderProps, } from "@app/models/components"; import { getSiteStatus } from "@app/services/api"; const SiteStatusContext = createContext( {} as SiteStatusContextProps ); type PatchedFetch = typeof fetch & { __sfsyncSiteStatusPatched?: boolean }; /** * Patches window.fetch (once per fetch reference) so that any 403 coming * back from a plugin REST call - other than /site-status itself, to avoid a * refresh loop - triggers an immediate site-status refresh (see WP-4534). */ const installSiteStatusInterceptor = (refresh: () => void) => { if (typeof window.fetch !== "function") { return; } const currentFetch = window.fetch as PatchedFetch; if (currentFetch.__sfsyncSiteStatusPatched) { return; } const originalFetch = currentFetch; const patchedFetch: PatchedFetch = async (...args) => { const response = await originalFetch(...args); const input = args[0]; const url = typeof input === "string" ? input : input instanceof Request ? input.url : String(input); const isPluginRequest = url.startsWith(sfsyncRestAPI.baseURL); const isSiteStatusRequest = url.includes("/sfsync/v1/site-status"); if (response.status === 403 && isPluginRequest && !isSiteStatusRequest) { refresh(); } return response; }; patchedFetch.__sfsyncSiteStatusPatched = true; window.fetch = patchedFetch; }; export const SiteStatusProvider: React.FC = ({ children, }) => { const [isDisabled, setIsDisabled] = useState( sfsyncData.is_disabled ?? false ); const [disabledSince, setDisabledSince] = useState( sfsyncData.disabled_since ?? null ); const refreshSiteStatus = useCallback(async () => { const result = await getSiteStatus(); if (result?.error) { return; } setIsDisabled(!!result.disabled); setDisabledSince(result.since ?? null); }, []); useEffect(() => { installSiteStatusInterceptor(refreshSiteStatus); }, [refreshSiteStatus]); useEffect(() => { refreshSiteStatus(); // eslint-disable-next-line react-hooks/exhaustive-deps }, []); return ( {children} ); }; export const useSiteStatus = () => { return useContext(SiteStatusContext); };