import { useState, useEffect } from 'react' import { useQuery } from '@tanstack/react-query' import { devicesApi } from '../api' import type { WidgetType, WidgetConfig } from '../hooks' import { createDefaultWidgetTitle } from '../utils/formatters' interface AddWidgetModalProps { isOpen: boolean onClose: () => void onAdd: (widget: WidgetConfig) => void } export default function AddWidgetModal({ isOpen, onClose, onAdd }: AddWidgetModalProps) { const [step, setStep] = useState(1) const [widgetType, setWidgetType] = useState('stat') const [title, setTitle] = useState('') const [selectedDevices, setSelectedDevices] = useState([]) const [selectedMetrics, setSelectedMetrics] = useState([]) const [timeframeHours, setTimeframeHours] = useState(24) const [widgetWidth, setWidgetWidth] = useState(1) const [widgetHeight, setWidgetHeight] = useState(2) const [city, setCity] = useState('Skopje') // Fetch devices const { data: devicesData } = useQuery({ queryKey: ['devices'], queryFn: async () => { const response = await devicesApi.getAll() return response.data }, }) // Fetch metrics for selected device(s) const { data: deviceMetricsData } = useQuery({ queryKey: ['device-metrics', selectedDevices[0]], queryFn: async () => { if (selectedDevices.length === 0) return [] const response = await devicesApi.getMetrics(selectedDevices[0]) return response.data.metrics }, enabled: selectedDevices.length > 0, }) const devices = devicesData?.results || [] const availableMetrics = deviceMetricsData || [] // Reset form when modal opens useEffect(() => { if (isOpen) { setStep(1) setWidgetType('stat') setTitle('') setSelectedDevices([]) setSelectedMetrics([]) setTimeframeHours(24) setWidgetWidth(1) setWidgetHeight(2) } }, [isOpen]) // Reset metrics when device changes useEffect(() => { setSelectedMetrics([]) }, [selectedDevices]) const handleSubmit = () => { // Weather and air-quality widgets don't need device/metric validation if (widgetType !== 'weather' && widgetType !== 'air-quality') { if (selectedDevices.length === 0 || selectedMetrics.length === 0) { alert('Please select at least one device and one metric') return } } // Create title let defaultTitle = '' if (widgetType === 'weather') { defaultTitle = `Weather - ${city}` } else if (widgetType === 'air-quality') { defaultTitle = `Air Quality - ${city}` } else { const selectedDevice = devices.find(d => d.id === selectedDevices[0]) defaultTitle = createDefaultWidgetTitle(widgetType, selectedDevice?.name, selectedMetrics) } const newWidget: WidgetConfig = { id: `widget-${Date.now()}`, type: widgetType, title: title || defaultTitle, deviceIds: widgetType === 'weather' || widgetType === 'air-quality' ? [] : selectedDevices, metricIds: widgetType === 'weather' || widgetType === 'air-quality' ? [] : selectedMetrics, timeframe: { hours: timeframeHours, }, visualization: { showLegend: true, showGrid: true, height: widgetType === 'line-chart' ? 300 : undefined, city: widgetType === 'weather' || widgetType === 'air-quality' ? city : undefined, }, position: { x: 0, y: 0, w: widgetWidth, h: widgetHeight, }, } onAdd(newWidget) onClose() } const toggleDevice = (deviceId: string) => { // Only allow single device selection for better UX setSelectedDevices([deviceId]) } const toggleMetric = (metric: string) => { // Stat and gauge widgets only allow one metric const singleMetricWidgets = ['stat', 'gauge'] const maxMetrics = singleMetricWidgets.includes(widgetType) ? 1 : 5 setSelectedMetrics((prev) => { if (prev.includes(metric)) { return prev.filter((m) => m !== metric) } // If adding would exceed max, replace last or prevent if (prev.length >= maxMetrics) { if (maxMetrics === 1) { return [metric] // Replace for single-metric widgets } return prev // Don't add more for multi-metric widgets } return [...prev, metric] }) } if (!isOpen) return null return (

Add Widget

{/* Progress steps */}
  • = 1 ? 'step-primary' : ''}`}>Type
  • = 2 ? 'step-primary' : ''}`}>Data Source
  • = 3 ? 'step-primary' : ''}`}>Configure
{/* Step 1: Widget Type */} {step === 1 && (
)} {/* Step 2: Data Source */} {step === 2 && widgetType !== 'weather' && widgetType !== 'air-quality' && (
{devices.length === 0 ? (
No devices found
) : ( devices.map((device) => ( )) )}
{selectedDevices.length === 0 ? (
Please select a device first
) : ( <> {(['stat', 'gauge'].includes(widgetType)) && (
This widget type supports only one metric
)}
{availableMetrics.length === 0 ? (
No metrics found for this device
) : ( availableMetrics.map((metric) => ( )) )}
)}
)} {/* Step 3: Configure */} {step === 3 && (
{/* City input for weather and air-quality widgets */} {(widgetType === 'weather' || widgetType === 'air-quality') ? ( <>
setCity(e.target.value)} />
setTitle(e.target.value)} />
) : ( // Original configuration for sensor-based widgets <>
setTitle(e.target.value)} />
)}
Widget Summary
Type: {widgetType}
Device: {devices.find(d => d.id === selectedDevices[0])?.name}
Metrics: {selectedMetrics.join(', ')}
Size: {widgetWidth} × {widgetHeight}
)}
) }