dograh/ui/src/context/AppConfigContext.tsx
2026-06-26 17:04:01 +05:30

100 lines
3.3 KiB
TypeScript

'use client';
import { createContext, ReactNode, useCallback, useContext, useEffect, useState } from 'react';
type BackendStatus = 'reachable' | 'unreachable';
interface AppConfig {
uiVersion: string;
apiVersion: string;
deploymentMode: string;
authProvider: string;
turnEnabled: boolean;
forceTurnRelay: boolean;
// Public URL when the deployment is reached through a Cloudflare tunnel
// (host has no public IP); null for a directly-reachable deployment.
tunnelUrl: string | null;
backendStatus: BackendStatus;
backendUrl: string;
backendMessage: string | null;
}
interface AppConfigContextType {
config: AppConfig | null;
loading: boolean;
refresh: () => Promise<void>;
}
const defaultConfig: AppConfig = {
uiVersion: 'dev',
apiVersion: 'unavailable',
deploymentMode: 'oss',
authProvider: 'local',
turnEnabled: false,
forceTurnRelay: false,
tunnelUrl: null,
backendStatus: 'unreachable',
backendUrl: process.env.NEXT_PUBLIC_BACKEND_URL || 'unknown',
backendMessage: process.env.NEXT_PUBLIC_BACKEND_URL
? `Unable to verify backend health at ${process.env.NEXT_PUBLIC_BACKEND_URL}.`
: 'Unable to verify backend health.',
};
const AppConfigContext = createContext<AppConfigContextType>({
config: null,
loading: true,
refresh: async () => { },
});
export function AppConfigProvider({ children }: { children: ReactNode }) {
const [config, setConfig] = useState<AppConfig | null>(null);
const [loading, setLoading] = useState(true);
const loadConfig = useCallback(async () => {
setLoading(true);
try {
const response = await fetch('/api/config/version', { cache: 'no-store' });
const data = await response.json();
const backend = data.backend && typeof data.backend === 'object' ? data.backend : {};
const backendStatus: BackendStatus = backend.status === 'reachable' ? 'reachable' : 'unreachable';
const backendUrl = typeof backend.url === 'string' && backend.url.length > 0
? backend.url
: defaultConfig.backendUrl;
setConfig({
uiVersion: data.ui || 'dev',
apiVersion: data.api || 'unknown',
deploymentMode: data.deploymentMode || 'oss',
authProvider: data.authProvider || 'local',
turnEnabled: Boolean(data.turnEnabled),
forceTurnRelay: Boolean(data.forceTurnRelay),
tunnelUrl: typeof data.tunnelUrl === 'string' ? data.tunnelUrl : null,
backendStatus,
backendUrl,
backendMessage: typeof backend.message === 'string' && backend.message.length > 0
? backend.message
: backendStatus === 'reachable'
? null
: `Backend is not reachable at ${backendUrl}.`,
});
} catch {
setConfig(defaultConfig);
} finally {
setLoading(false);
}
}, []);
useEffect(() => {
loadConfig();
}, [loadConfig]);
return (
<AppConfigContext.Provider value={{ config, loading, refresh: loadConfig }}>
{children}
</AppConfigContext.Provider>
);
}
export function useAppConfig() {
return useContext(AppConfigContext);
}