/** * SettingsPanel Component * Full settings modal matching production version */ import React, { useState, useEffect } from 'react'; import { calculateGridSquare } from '../utils/geo.js'; export const SettingsPanel = ({ isOpen, onClose, config, onSave }) => { const [callsign, setCallsign] = useState(config?.callsign || ''); const [gridSquare, setGridSquare] = useState(''); const [lat, setLat] = useState(config?.location?.lat || 0); const [lon, setLon] = useState(config?.location?.lon || 0); const [theme, setTheme] = useState(config?.theme || 'dark'); const [layout, setLayout] = useState(config?.layout || 'modern'); const [dxClusterSource, setDxClusterSource] = useState(config?.dxClusterSource || 'dxspider-proxy'); useEffect(() => { if (config) { setCallsign(config.callsign || ''); setLat(config.location?.lat || 0); setLon(config.location?.lon || 0); setTheme(config.theme || 'dark'); setLayout(config.layout || 'modern'); setDxClusterSource(config.dxClusterSource || 'dxspider-proxy'); // Calculate grid from coordinates if (config.location?.lat && config.location?.lon) { setGridSquare(calculateGridSquare(config.location.lat, config.location.lon)); } } }, [config, isOpen]); // Update lat/lon when grid square changes const handleGridChange = (grid) => { setGridSquare(grid.toUpperCase()); // Parse grid square to lat/lon if valid (6 char) if (grid.length >= 4) { const parsed = parseGridSquare(grid); if (parsed) { setLat(parsed.lat); setLon(parsed.lon); } } }; // Parse grid square to coordinates const parseGridSquare = (grid) => { grid = grid.toUpperCase(); if (grid.length < 4) return null; const lon1 = (grid.charCodeAt(0) - 65) * 20 - 180; const lat1 = (grid.charCodeAt(1) - 65) * 10 - 90; const lon2 = parseInt(grid[2]) * 2; const lat2 = parseInt(grid[3]) * 1; let lon = lon1 + lon2 + 1; let lat = lat1 + lat2 + 0.5; if (grid.length >= 6) { const lon3 = (grid.charCodeAt(4) - 65) * (2/24); const lat3 = (grid.charCodeAt(5) - 65) * (1/24); lon = lon1 + lon2 + lon3 + (1/24); lat = lat1 + lat2 + lat3 + (1/48); } return { lat, lon }; }; // Update grid when lat/lon changes useEffect(() => { if (lat && lon) { setGridSquare(calculateGridSquare(lat, lon)); } }, [lat, lon]); const handleUseLocation = () => { if (navigator.geolocation) { navigator.geolocation.getCurrentPosition( (position) => { setLat(position.coords.latitude); setLon(position.coords.longitude); }, (error) => { console.error('Geolocation error:', error); alert('Unable to get location. Please enter manually.'); } ); } else { alert('Geolocation not supported by your browser.'); } }; const handleSave = () => { onSave({ ...config, callsign: callsign.toUpperCase(), location: { lat: parseFloat(lat), lon: parseFloat(lon) }, theme, layout, dxClusterSource }); onClose(); }; if (!isOpen) return null; const themeDescriptions = { dark: '→ Modern dark theme (default)', light: '→ Light theme for daytime use', legacy: '→ Green terminal CRT style', classic: '→ 90s Windows retro style' }; const layoutDescriptions = { modern: '→ Modern responsive grid layout', classic: '→ Classic HamClock-style layout' }; return (