Barazo default frontend
barazo.forum
1/**
2 * Plugin context provider.
3 * Fetches enabled plugins and their settings from the API on mount.
4 * Exposes helpers to check plugin state and a refresh method for admin pages.
5 */
6
7'use client'
8
9import { createContext, useCallback, useEffect, useMemo, useState } from 'react'
10import type { ReactNode } from 'react'
11import type { Plugin } from '@/lib/api/types'
12import { getPlugins } from '@/lib/api/client'
13import { useAuth } from '@/hooks/use-auth'
14import { loadBundledPlugins } from '@/lib/plugins/loader'
15
16export interface PluginContextValue {
17 /** List of all plugins (enabled and disabled) */
18 plugins: Plugin[]
19 /** Check whether a plugin with the given name is enabled */
20 isPluginEnabled: (name: string) => boolean
21 /** Get the settings for a plugin by name, or null if not found */
22 getPluginSettings: (name: string) => Record<string, unknown> | null
23 /** Whether the plugin list is still loading */
24 isLoading: boolean
25 /** Re-fetch the plugin list (call after admin changes) */
26 refreshPlugins: () => Promise<void>
27}
28
29export const PluginContext = createContext<PluginContextValue | null>(null)
30
31interface PluginProviderProps {
32 children: ReactNode
33}
34
35export function PluginProvider({ children }: PluginProviderProps) {
36 const { getAccessToken, isLoading: authLoading } = useAuth()
37 const [plugins, setPlugins] = useState<Plugin[]>([])
38 const [isLoading, setIsLoading] = useState(true)
39
40 const fetchPlugins = useCallback(async () => {
41 const token = getAccessToken()
42 if (!token) {
43 // Unauthenticated: no plugin data available from API
44 setPlugins([])
45 setIsLoading(false)
46 return
47 }
48
49 try {
50 const response = await getPlugins(token)
51 const enabledNames = response.plugins.filter((p) => p.enabled).map((p) => p.name)
52 await loadBundledPlugins(enabledNames)
53 setPlugins(response.plugins)
54 } catch {
55 // On error, keep existing plugins (or empty on first load)
56 setPlugins((prev) => prev)
57 } finally {
58 setIsLoading(false)
59 }
60 }, [getAccessToken])
61
62 const refreshPlugins = useCallback(async () => {
63 setIsLoading(true)
64 await fetchPlugins()
65 }, [fetchPlugins])
66
67 useEffect(() => {
68 if (authLoading) return
69 void fetchPlugins()
70 }, [authLoading, fetchPlugins])
71
72 const isPluginEnabled = useCallback(
73 (name: string): boolean => {
74 const plugin = plugins.find((p) => p.name === name)
75 return plugin?.enabled ?? false
76 },
77 [plugins]
78 )
79
80 const getPluginSettings = useCallback(
81 (name: string): Record<string, unknown> | null => {
82 const plugin = plugins.find((p) => p.name === name)
83 if (!plugin) return null
84 return { ...plugin.settings }
85 },
86 [plugins]
87 )
88
89 const value = useMemo<PluginContextValue>(
90 () => ({
91 plugins,
92 isPluginEnabled,
93 getPluginSettings,
94 isLoading,
95 refreshPlugins,
96 }),
97 [plugins, isPluginEnabled, getPluginSettings, isLoading, refreshPlugins]
98 )
99
100 return <PluginContext.Provider value={value}>{children}</PluginContext.Provider>
101}