/** * Plugin context provider. * Fetches enabled plugins and their settings from the API on mount. * Exposes helpers to check plugin state and a refresh method for admin pages. */ 'use client' import { createContext, useCallback, useEffect, useMemo, useState } from 'react' import type { ReactNode } from 'react' import type { Plugin } from '@/lib/api/types' import { getPlugins } from '@/lib/api/client' import { useAuth } from '@/hooks/use-auth' import { loadBundledPlugins } from '@/lib/plugins/loader' export interface PluginContextValue { /** List of all plugins (enabled and disabled) */ plugins: Plugin[] /** Check whether a plugin with the given name is enabled */ isPluginEnabled: (name: string) => boolean /** Get the settings for a plugin by name, or null if not found */ getPluginSettings: (name: string) => Record | null /** Whether the plugin list is still loading */ isLoading: boolean /** Re-fetch the plugin list (call after admin changes) */ refreshPlugins: () => Promise } export const PluginContext = createContext(null) interface PluginProviderProps { children: ReactNode } export function PluginProvider({ children }: PluginProviderProps) { const { getAccessToken, isLoading: authLoading } = useAuth() const [plugins, setPlugins] = useState([]) const [isLoading, setIsLoading] = useState(true) const fetchPlugins = useCallback(async () => { const token = getAccessToken() if (!token) { // Unauthenticated: no plugin data available from API setPlugins([]) setIsLoading(false) return } try { const response = await getPlugins(token) const enabledNames = response.plugins.filter((p) => p.enabled).map((p) => p.name) await loadBundledPlugins(enabledNames) setPlugins(response.plugins) } catch { // On error, keep existing plugins (or empty on first load) setPlugins((prev) => prev) } finally { setIsLoading(false) } }, [getAccessToken]) const refreshPlugins = useCallback(async () => { setIsLoading(true) await fetchPlugins() }, [fetchPlugins]) useEffect(() => { if (authLoading) return void fetchPlugins() }, [authLoading, fetchPlugins]) const isPluginEnabled = useCallback( (name: string): boolean => { const plugin = plugins.find((p) => p.name === name) return plugin?.enabled ?? false }, [plugins] ) const getPluginSettings = useCallback( (name: string): Record | null => { const plugin = plugins.find((p) => p.name === name) if (!plugin) return null return { ...plugin.settings } }, [plugins] ) const value = useMemo( () => ({ plugins, isPluginEnabled, getPluginSettings, isLoading, refreshPlugins, }), [plugins, isPluginEnabled, getPluginSettings, isLoading, refreshPlugins] ) return {children} }