/**
* 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
{/* 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 };