import { useState, ReactNode, useMemo } from 'react'; import { Settings, X, Palette, RefreshCw, Maximize2, Minimize2, Eye, EyeOff, Bell, Volume2, VolumeX, ListFilter, Hash, Zap, MapPin, Clock, BarChart3, TrendingUp, AlertTriangle, Globe, Rss } from 'lucide-react'; import { cn } from '@/lib/utils'; import { Button } from '@/components/ui/button'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '@/components/ui/select'; import { Switch } from '@/components/ui/switch'; import { Slider } from '@/components/ui/slider'; import { Input } from '@/components/ui/input'; import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'; import { useWidgetSettings, generateWidgetId, WidgetConfig } from '@/hooks/useWidgetSettings'; // Re-export WidgetConfig for backwards compatibility export type { WidgetConfig }; // Widget-specific settings export interface NewsWidgetSettings { itemCount: number; showSeverityBadge: boolean; sources: string[]; autoScroll: boolean; } export interface AlertWidgetSettings { showCritical: boolean; showWarning: boolean; showInfo: boolean; soundEnabled: boolean; maxAlerts: number; } export interface MetricsWidgetSettings { showChange: boolean; compactMode: boolean; animateValues: boolean; decimalPlaces: number; } export interface MapWidgetSettings { animationSpeed: 'slow' | 'normal' | 'fast'; showLabels: boolean; hotspotSize: 'small' | 'medium' | 'large'; pulseEffect: boolean; } export interface RadarWidgetSettings { scanSpeed: number; showGrid: boolean; threatHighlight: boolean; radarStyle: 'classic' | 'modern'; } export interface EventWidgetSettings { maxEvents: number; showTimestamps: boolean; filterByType: string[]; highlightNew: boolean; } export interface StatisticsWidgetSettings { showPercentage: boolean; barStyle: 'filled' | 'gradient' | 'striped'; sortBy: 'value' | 'name'; animateBars: boolean; } export interface GlobalWidgetSettings { showTrend: boolean; sortByThreats: boolean; highlightTop: boolean; regionStyle: 'list' | 'compact'; } export type WidgetSpecificSettings = | NewsWidgetSettings | AlertWidgetSettings | MetricsWidgetSettings | MapWidgetSettings | RadarWidgetSettings | EventWidgetSettings | StatisticsWidgetSettings | GlobalWidgetSettings | Record; interface ConfigurableWidgetProps { name: string; icon: ReactNode; widgetType?: string; children: ((config: WidgetConfig, settings: any) => ReactNode) | ReactNode; defaultConfig?: Partial; className?: string; } const colorOptions = [ { value: 'primary', label: 'Cyan', class: 'bg-primary' }, { value: 'accent', label: 'Teal', class: 'bg-accent' }, { value: 'destructive', label: 'Red', class: 'bg-destructive' }, { value: 'orange', label: 'Orange', class: 'bg-orange-400' }, ]; const defaultBaseConfig: WidgetConfig = { refreshRate: 30, accentColor: 'primary', showHeader: true, expanded: false, opacity: 100, }; // Default settings for each widget type const getDefaultSettings = (widgetType?: string): WidgetSpecificSettings => { switch (widgetType) { case 'news': return { itemCount: 4, showSeverityBadge: true, sources: ['all'], autoScroll: false }; case 'alerts': return { showCritical: true, showWarning: true, showInfo: true, soundEnabled: false, maxAlerts: 5 }; case 'metrics': return { showChange: true, compactMode: false, animateValues: true, decimalPlaces: 0 }; case 'threatmap': case 'map': return { animationSpeed: 'normal', showLabels: true, hotspotSize: 'medium', pulseEffect: true }; case 'radar': return { scanSpeed: 3, showGrid: true, threatHighlight: true, radarStyle: 'classic' }; case 'events': return { maxEvents: 5, showTimestamps: true, filterByType: ['all'], highlightNew: true }; case 'statistics': return { showPercentage: true, barStyle: 'filled', sortBy: 'value', animateBars: true }; case 'global': return { showTrend: true, sortByThreats: true, highlightTop: true, regionStyle: 'list' }; default: return {}; } }; const ConfigurableWidget = ({ name, icon, widgetType, children, defaultConfig, className }: ConfigurableWidgetProps) => { const [showConfig, setShowConfig] = useState(false); const [activeTab, setActiveTab] = useState('general'); // Generate stable widget ID for localStorage const widgetId = useMemo(() => generateWidgetId(name, widgetType), [name, widgetType]); // Memoize default values const mergedDefaultConfig = useMemo(() => ({ ...defaultBaseConfig, ...defaultConfig, }), [defaultConfig]); const defaultSettings = useMemo(() => getDefaultSettings(widgetType), [widgetType]); // Use persistent settings hook const { config, settings, setConfig, setSettings, resetToDefaults } = useWidgetSettings({ widgetId, defaultConfig: mergedDefaultConfig, defaultSettings, }); const updateConfig = (key: keyof WidgetConfig, value: any) => { setConfig({ [key]: value }); }; const updateSettings = (key: string, value: any) => { setSettings({ [key]: value }); }; const accentColorClass = { primary: 'text-primary border-primary/50', accent: 'text-accent border-accent/50', destructive: 'text-destructive border-destructive/50', orange: 'text-orange-400 border-orange-400/50', }[config.accentColor]; const accentBgClass = { primary: 'bg-primary/20', accent: 'bg-accent/20', destructive: 'bg-destructive/20', orange: 'bg-orange-400/20', }[config.accentColor]; // Widget-specific settings panels const renderWidgetSpecificSettings = () => { switch (widgetType) { case 'news': const newsSettings = settings as NewsWidgetSettings; return (
updateSettings('itemCount', v)} min={2} max={10} step={1} className="w-full" /> {newsSettings.itemCount} items
updateSettings('showSeverityBadge', v)} />
updateSettings('autoScroll', v)} />
); case 'alerts': const alertSettings = settings as AlertWidgetSettings; return (
Critical updateSettings('showCritical', v)} />
Warning updateSettings('showWarning', v)} />
Info updateSettings('showInfo', v)} />
updateSettings('soundEnabled', v)} />
updateSettings('maxAlerts', v)} min={3} max={15} step={1} className="w-full" /> {alertSettings.maxAlerts} alerts
); case 'metrics': const metricsSettings = settings as MetricsWidgetSettings; return (
updateSettings('showChange', v)} />
updateSettings('compactMode', v)} />
updateSettings('animateValues', v)} />
); case 'threatmap': case 'map': const mapSettings = settings as MapWidgetSettings; return (
updateSettings('showLabels', v)} />
updateSettings('pulseEffect', v)} />
); case 'radar': const radarSettings = settings as RadarWidgetSettings; return (
updateSettings('scanSpeed', v)} min={1} max={10} step={1} className="w-full" />
updateSettings('showGrid', v)} />
updateSettings('threatHighlight', v)} />
); case 'statistics': const statsSettings = settings as StatisticsWidgetSettings; return (
updateSettings('showPercentage', v)} />
updateSettings('animateBars', v)} />
); case 'global': const globalSettings = settings as GlobalWidgetSettings; return (
updateSettings('showTrend', v)} />
updateSettings('sortByThreats', v)} />
updateSettings('highlightTop', v)} />
); default: return (

Ingen specifikke indstillinger for denne widget type.

); } }; return (
{/* Header */} {config.showHeader && (
{name}
{config.refreshRate}s
)} {/* Config Panel with Tabs */} {showConfig && (
Widget Settings
Generelt Widget {/* Accent Color */}
{colorOptions.map((color) => (
{/* Refresh Rate */}
{/* Opacity */}
updateConfig('opacity', v)} min={40} max={100} step={10} className="w-full" />
{/* Show Header Toggle */}
updateConfig('showHeader', v)} />
{renderWidgetSpecificSettings()}
)} {/* Widget Content */}
{typeof children === 'function' ? children(config, settings) : children}
{/* Corner accents */}
); }; export default ConfigurableWidget;