/** * DXClusterPanel Component * Displays DX cluster spots with filtering controls */ import React from 'react'; import { getBandColor } from '../utils/callsign.js'; export const DXClusterPanel = ({ data, loading, totalSpots, filters, onOpenFilters, onHoverSpot, hoveredSpot }) => { const getActiveFilterCount = () => { let count = 0; if (filters?.cqZones?.length) count++; if (filters?.ituZones?.length) count++; if (filters?.continents?.length) count++; if (filters?.bands?.length) count++; if (filters?.modes?.length) count++; if (filters?.watchlist?.length) count++; if (filters?.excludeList?.length) count++; if (filters?.callsign) count++; if (filters?.watchlistOnly) count++; return count; }; const filterCount = getActiveFilterCount(); return (
{/* Header with filter button */}
📻 DX CLUSTER {data.length}/{totalSpots || 0}
{/* Spots list */} {loading ? (
) : data.length === 0 ? (
{filterCount > 0 ? 'No spots match filters' : 'No spots available'}
) : (
{data.slice(0, 15).map((spot, i) => { const freq = parseFloat(spot.freq); const color = getBandColor(freq / 1000); // Convert kHz to MHz for color const isHovered = hoveredSpot?.call === spot.call && Math.abs(parseFloat(hoveredSpot?.freq) - freq) < 1; return (
onHoverSpot?.(spot)} onMouseLeave={() => onHoverSpot?.(null)} style={{ display: 'grid', gridTemplateColumns: '70px 1fr auto', gap: '8px', padding: '6px 8px', borderRadius: '4px', marginBottom: '2px', background: isHovered ? 'rgba(68, 136, 255, 0.2)' : (i % 2 === 0 ? 'rgba(255,255,255,0.02)' : 'transparent'), cursor: 'pointer', transition: 'background 0.15s' }} >
{(freq / 1000).toFixed(3)}
{spot.call}
{spot.time || ''}
); })}
)}
); }; export default DXClusterPanel;