/** * PSKReporter Panel * Shows where your digital mode signals are being received */ import React, { useState } from 'react'; import { usePSKReporter } from '../hooks/usePSKReporter.js'; const PSKReporterPanel = ({ callsign, onShowOnMap }) => { const [timeWindow, setTimeWindow] = useState(15); // minutes const [activeTab, setActiveTab] = useState('tx'); // 'tx' or 'rx' const { txReports, txCount, rxReports, rxCount, stats, loading, lastUpdate, refresh } = usePSKReporter(callsign, { minutes: timeWindow, direction: 'both', enabled: callsign && callsign !== 'N0CALL' }); const formatTime = (timestamp) => { const date = new Date(timestamp); return date.toLocaleTimeString('en-US', { hour: '2-digit', minute: '2-digit', hour12: false }) + 'z'; }; const formatAge = (minutes) => { if (minutes < 1) return 'now'; if (minutes === 1) return '1m ago'; return `${minutes}m ago`; }; const getSnrColor = (snr) => { if (snr === null || snr === undefined) return 'var(--text-muted)'; if (snr >= 0) return '#4ade80'; // Green - excellent if (snr >= -10) return '#fbbf24'; // Yellow - good if (snr >= -15) return '#f97316'; // Orange - fair return '#ef4444'; // Red - weak }; const reports = activeTab === 'tx' ? txReports : rxReports; const count = activeTab === 'tx' ? txCount : rxCount; if (!callsign || callsign === 'N0CALL') { return (
📡

PSKReporter

Set your callsign in Settings to see PSKReporter data

); } return (
📡

PSKReporter

{/* Tabs */}
{loading && reports.length === 0 ? (
Loading...
) : reports.length === 0 ? (
No {activeTab === 'tx' ? 'reception reports' : 'stations heard'} in the last {timeWindow} minutes
) : ( <> {/* Summary stats for TX */} {activeTab === 'tx' && txCount > 0 && (
{txCount} stations hearing you {stats.txBands.length > 0 && ( Bands: {stats.txBands.join(', ')} )} {stats.txModes.length > 0 && ( Modes: {stats.txModes.slice(0, 3).join(', ')} )}
)} {/* Reports list */}
{reports.slice(0, 25).map((report, idx) => (
onShowOnMap && report.lat && report.lon && onShowOnMap(report)} style={{ display: 'grid', gridTemplateColumns: '1fr auto auto auto', gap: '8px', padding: '6px 8px', background: 'var(--bg-tertiary)', borderRadius: '4px', fontSize: '0.75rem', cursor: report.lat && report.lon ? 'pointer' : 'default', alignItems: 'center' }} >
{activeTab === 'tx' ? report.receiver : report.sender} {(activeTab === 'tx' ? report.receiverGrid : report.senderGrid) && ( {activeTab === 'tx' ? report.receiverGrid : report.senderGrid} )}
{report.freqMHz} {report.band}
{report.mode}
{report.snr !== null && ( {report.snr > 0 ? '+' : ''}{report.snr}dB )} {formatAge(report.age)}
))}
{reports.length > 25 && (
Showing 25 of {reports.length} reports
)} )}
{/* Footer with last update */} {lastUpdate && (
Updated: {lastUpdate.toLocaleTimeString()}
)}
); }; export default PSKReporterPanel; export { PSKReporterPanel };