Spaces:
Paused
Paused
| import { createContext, useContext, useState, useCallback, ReactNode } from 'react'; | |
| // Types for widget communication | |
| export interface WidgetFilter { | |
| severity?: 'all' | 'critical' | 'high' | 'medium' | 'low'; | |
| region?: string; | |
| timeRange?: '1h' | '6h' | '24h' | '7d' | '30d'; | |
| searchQuery?: string; | |
| } | |
| export interface WidgetEvent { | |
| type: string; | |
| sourceWidgetId: string; | |
| payload: any; | |
| timestamp: number; | |
| } | |
| export interface SharedData { | |
| selectedThreat?: { id: string; name: string; severity: string }; | |
| selectedRegion?: string; | |
| highlightedIP?: string; | |
| activeAlert?: { id: string; type: string; message: string }; | |
| } | |
| interface WidgetContextType { | |
| // Global filters | |
| filters: WidgetFilter; | |
| setFilters: (filters: Partial<WidgetFilter>) => void; | |
| resetFilters: () => void; | |
| // Shared data between widgets | |
| sharedData: SharedData; | |
| updateSharedData: (data: Partial<SharedData>) => void; | |
| // Event system for widget communication | |
| publishEvent: (event: Omit<WidgetEvent, 'timestamp'>) => void; | |
| subscribeToEvents: (callback: (event: WidgetEvent) => void) => () => void; | |
| // Recent events for debugging/display | |
| recentEvents: WidgetEvent[]; | |
| } | |
| const defaultFilters: WidgetFilter = { | |
| severity: 'all', | |
| region: undefined, | |
| timeRange: '24h', | |
| searchQuery: '', | |
| }; | |
| const WidgetContext = createContext<WidgetContextType | null>(null); | |
| export const WidgetProvider = ({ children }: { children: ReactNode }) => { | |
| const [filters, setFiltersState] = useState<WidgetFilter>(defaultFilters); | |
| const [sharedData, setSharedData] = useState<SharedData>({}); | |
| const [recentEvents, setRecentEvents] = useState<WidgetEvent[]>([]); | |
| const [subscribers, setSubscribers] = useState<Set<(event: WidgetEvent) => void>>(new Set()); | |
| const setFilters = useCallback((newFilters: Partial<WidgetFilter>) => { | |
| setFiltersState(prev => ({ ...prev, ...newFilters })); | |
| }, []); | |
| const resetFilters = useCallback(() => { | |
| setFiltersState(defaultFilters); | |
| }, []); | |
| const updateSharedData = useCallback((data: Partial<SharedData>) => { | |
| setSharedData(prev => ({ ...prev, ...data })); | |
| }, []); | |
| const publishEvent = useCallback((event: Omit<WidgetEvent, 'timestamp'>) => { | |
| const fullEvent: WidgetEvent = { | |
| ...event, | |
| timestamp: Date.now(), | |
| }; | |
| // Add to recent events (keep last 50) | |
| setRecentEvents(prev => [fullEvent, ...prev.slice(0, 49)]); | |
| // Notify all subscribers | |
| subscribers.forEach(callback => callback(fullEvent)); | |
| console.log('[WidgetContext] Event published:', fullEvent); | |
| }, [subscribers]); | |
| const subscribeToEvents = useCallback((callback: (event: WidgetEvent) => void) => { | |
| setSubscribers(prev => new Set(prev).add(callback)); | |
| // Return unsubscribe function | |
| return () => { | |
| setSubscribers(prev => { | |
| const newSet = new Set(prev); | |
| newSet.delete(callback); | |
| return newSet; | |
| }); | |
| }; | |
| }, []); | |
| return ( | |
| <WidgetContext.Provider value={{ | |
| filters, | |
| setFilters, | |
| resetFilters, | |
| sharedData, | |
| updateSharedData, | |
| publishEvent, | |
| subscribeToEvents, | |
| recentEvents, | |
| }}> | |
| {children} | |
| </WidgetContext.Provider> | |
| ); | |
| }; | |
| export const useWidgetContext = () => { | |
| const context = useContext(WidgetContext); | |
| if (!context) { | |
| throw new Error('useWidgetContext must be used within a WidgetProvider'); | |
| } | |
| return context; | |
| }; | |
| // Custom hook for widgets to easily communicate | |
| export const useWidgetCommunication = (widgetId: string) => { | |
| const context = useWidgetContext(); | |
| const publish = useCallback((type: string, payload: any) => { | |
| context.publishEvent({ | |
| type, | |
| sourceWidgetId: widgetId, | |
| payload, | |
| }); | |
| }, [context, widgetId]); | |
| const selectThreat = useCallback((threat: { id: string; name: string; severity: string }) => { | |
| context.updateSharedData({ selectedThreat: threat }); | |
| publish('threat_selected', threat); | |
| }, [context, publish]); | |
| const selectRegion = useCallback((region: string) => { | |
| context.updateSharedData({ selectedRegion: region }); | |
| context.setFilters({ region }); | |
| publish('region_selected', { region }); | |
| }, [context, publish]); | |
| const highlightIP = useCallback((ip: string) => { | |
| context.updateSharedData({ highlightedIP: ip }); | |
| publish('ip_highlighted', { ip }); | |
| }, [context, publish]); | |
| const selectAlert = useCallback((alert: { id: string; type: string; message: string }) => { | |
| context.updateSharedData({ activeAlert: alert }); | |
| publish('alert_selected', alert); | |
| }, [context, publish]); | |
| return { | |
| ...context, | |
| publish, | |
| selectThreat, | |
| selectRegion, | |
| highlightIP, | |
| selectAlert, | |
| }; | |
| }; | |