mirror of
https://github.com/arsvendg/Stirling-PDF.git
synced 2026-07-16 11:23:10 +02:00
# Description of Changes When I added Prettier formatting in #6052, my aim was to use just the default settings in Prettier. Turns out, Prettier looks _really hard_ for any config files if it's not explicitly given one, which means that if a developer has some sort of Prettier config file lying around on their system, Prettier might find it and use it. Also, Prettier changes its defaults based on stuff in `.editorconfig` without any good way of disabling that behaviour explicitly in its config file. To solve both of these issues, I've introduced a `.prettierrc` file which sets Prettier's defaults explicitly, and then reformatted all our code _again_ in Prettier's actual default settings. This should achieve the aim of #6052 and remove the possibility for it breaking on different dev computers.
151 lines
4.2 KiB
TypeScript
151 lines
4.2 KiB
TypeScript
import React, {
|
|
createContext,
|
|
useContext,
|
|
useState,
|
|
useCallback,
|
|
useEffect,
|
|
useMemo,
|
|
useRef,
|
|
ReactNode,
|
|
} from "react";
|
|
import { useLocation } from "react-router-dom";
|
|
import licenseService, { LicenseInfo } from "@app/services/licenseService";
|
|
import { useAppConfig } from "@app/contexts/AppConfigContext";
|
|
import { getSimulatedLicenseInfo } from "@app/testing/serverExperienceSimulations";
|
|
|
|
interface LicenseContextValue {
|
|
licenseInfo: LicenseInfo | null;
|
|
loading: boolean;
|
|
error: string | null;
|
|
refetchLicense: () => Promise<void>;
|
|
}
|
|
|
|
const LicenseContext = createContext<LicenseContextValue | undefined>(
|
|
undefined,
|
|
);
|
|
|
|
interface LicenseProviderProps {
|
|
children: ReactNode;
|
|
}
|
|
|
|
export const LicenseProvider: React.FC<LicenseProviderProps> = ({
|
|
children,
|
|
}) => {
|
|
const { config } = useAppConfig();
|
|
const location = useLocation();
|
|
const configRef = useRef(config);
|
|
const [licenseInfo, setLicenseInfo] = useState<LicenseInfo | null>(null);
|
|
const [loading, setLoading] = useState<boolean>(true);
|
|
const [error, setError] = useState<string | null>(null);
|
|
|
|
// Keep ref updated with latest config
|
|
useEffect(() => {
|
|
configRef.current = config;
|
|
}, [config]);
|
|
|
|
const refetchLicense = useCallback(async () => {
|
|
// Wait for config to load if it's not available yet
|
|
let currentConfig = configRef.current;
|
|
if (!currentConfig) {
|
|
console.log("[LicenseContext] Config not loaded yet, waiting...");
|
|
// OPTIMIZATION: Reduced from 5s to 1s - config should load quickly
|
|
const maxWait = 1000;
|
|
const startTime = Date.now();
|
|
while (!configRef.current && Date.now() - startTime < maxWait) {
|
|
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
currentConfig = configRef.current;
|
|
}
|
|
|
|
if (!currentConfig) {
|
|
console.error("[LicenseContext] Config failed to load after waiting");
|
|
setLoading(false);
|
|
return;
|
|
}
|
|
}
|
|
|
|
// Only fetch license info if user is an admin
|
|
if (!currentConfig.isAdmin) {
|
|
console.log(
|
|
"[LicenseContext] User is not an admin, skipping license fetch",
|
|
);
|
|
setLoading(false);
|
|
return;
|
|
}
|
|
|
|
console.log("[LicenseContext] Fetching license info");
|
|
|
|
try {
|
|
const testInfo = getSimulatedLicenseInfo();
|
|
if (testInfo) {
|
|
setLicenseInfo(testInfo);
|
|
setLoading(false);
|
|
setError(null);
|
|
return;
|
|
}
|
|
|
|
setLoading(true);
|
|
setError(null);
|
|
const info = await licenseService.getLicenseInfo();
|
|
setLicenseInfo(info);
|
|
} catch (err) {
|
|
const errorMessage =
|
|
err instanceof Error ? err.message : "Failed to fetch license info";
|
|
console.error("Error fetching license info:", errorMessage);
|
|
setError(errorMessage);
|
|
setLicenseInfo(null);
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
}, []);
|
|
|
|
// Fetch license info when config changes (only if user is admin)
|
|
useEffect(() => {
|
|
// CRITICAL FIX: Skip license fetch on auth routes to prevent race conditions
|
|
// during SAML/OAuth callback processing. License isn't needed until user
|
|
// is authenticated and navigates to main app.
|
|
const isAuthRoute =
|
|
location.pathname === "/login" ||
|
|
location.pathname === "/signup" ||
|
|
location.pathname === "/auth/callback" ||
|
|
location.pathname.startsWith("/invite/");
|
|
|
|
if (isAuthRoute) {
|
|
console.log("[LicenseContext] On auth route, skipping license fetch");
|
|
setLoading(false);
|
|
return;
|
|
}
|
|
|
|
if (config) {
|
|
refetchLicense();
|
|
}
|
|
}, [config, refetchLicense, location.pathname]);
|
|
|
|
const contextValue: LicenseContextValue = useMemo(
|
|
() => ({
|
|
licenseInfo,
|
|
loading,
|
|
error,
|
|
refetchLicense,
|
|
}),
|
|
[licenseInfo, loading, error, refetchLicense],
|
|
);
|
|
|
|
return (
|
|
<LicenseContext.Provider value={contextValue}>
|
|
{children}
|
|
</LicenseContext.Provider>
|
|
);
|
|
};
|
|
|
|
export const useOptionalLicense = (): LicenseContextValue | undefined => {
|
|
return useContext(LicenseContext);
|
|
};
|
|
|
|
export const useLicense = (): LicenseContextValue => {
|
|
const context = useContext(LicenseContext);
|
|
if (!context) {
|
|
throw new Error("useLicense must be used within LicenseProvider");
|
|
}
|
|
return context;
|
|
};
|