fix(editor): a corrected frequency corrects its band
Band and frequency have to agree — the log, every award and every upload are read on the BAND — and an operator fixing a wrong frequency is not also expecting to fix the band by hand. That is exactly how a QSO ends up filed on 20m at 7 MHz. Both sides follow, TX and RX. Only when the number lands in a known allocation, because half a frequency is typed on the way to all of it and a band must never be blanked by that. bandForMHz moves out of App.tsx into lib/bandplan, where the two callers can share one answer instead of drifting.
This commit is contained in:
@@ -22,6 +22,7 @@ import { Combobox } from '@/components/ui/combobox';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { flagURL } from '@/lib/flags';
|
||||
import { useI18n } from '@/lib/i18n';
|
||||
import { bandForMHz } from '@/lib/bandplan';
|
||||
import { titleCase, sentenceCase } from '@/lib/textCase';
|
||||
import type { QSOForm } from '@/types';
|
||||
|
||||
@@ -312,6 +313,19 @@ export function QSOEditModal({ qso, onSave, onDelete, onClose, countries = [], b
|
||||
const splitHz = (hz?: number) => hz
|
||||
? { khz: String(Math.floor(hz / 1000)), hz: String(hz % 1000).padStart(3, '0') }
|
||||
: { khz: '', hz: '' };
|
||||
// Correcting a frequency corrects its band. The pair has to agree — the log,
|
||||
// every award and every upload are read on the BAND — and an operator fixing
|
||||
// a wrong frequency is not also expecting to fix the band by hand, which is
|
||||
// exactly how a QSO ends up filed on 20m at 7 MHz.
|
||||
//
|
||||
// Only when the number lands in a known allocation: half a frequency is typed
|
||||
// on the way to all of it, and a band must never be blanked by that.
|
||||
const syncBand = (khz: string, hz: string, field: 'band' | 'band_rx') => {
|
||||
if (!khz.trim()) return;
|
||||
const b = bandForMHz((parseInt(khz, 10) * 1000 + (parseInt(hz, 10) || 0)) / 1_000_000);
|
||||
if (b) set(field, b as any);
|
||||
};
|
||||
|
||||
const f0 = splitHz(draft.freq_hz);
|
||||
const fr0 = splitHz(draft.freq_rx_hz);
|
||||
const [freqKHz, setFreqKHz] = useState(f0.khz);
|
||||
@@ -634,13 +648,13 @@ export function QSOEditModal({ qso, onSave, onDelete, onClose, countries = [], b
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<Label className="w-20 shrink-0">{t('qedit.txFreq')}</Label>
|
||||
<Input value={freqKHz} onChange={(e) => setFreqKHz(e.target.value.replace(/\D/g, ''))} className="font-mono w-24" placeholder="kHz" />
|
||||
<Input value={freqHz} onChange={(e) => setFreqHz(e.target.value.replace(/\D/g, ''))} maxLength={3} className="font-mono w-16" placeholder="Hz" />
|
||||
<Input value={freqKHz} onChange={(e) => { const v = e.target.value.replace(/\D/g, ''); setFreqKHz(v); syncBand(v, freqHz, 'band'); }} className="font-mono w-24" placeholder="kHz" />
|
||||
<Input value={freqHz} onChange={(e) => { const v = e.target.value.replace(/\D/g, ''); setFreqHz(v); syncBand(freqKHz, v, 'band'); }} maxLength={3} className="font-mono w-16" placeholder="Hz" />
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<Label className="w-20 shrink-0">{t('qedit.rxFreq')}</Label>
|
||||
<Input value={freqRxKHz} onChange={(e) => setFreqRxKHz(e.target.value.replace(/\D/g, ''))} className="font-mono w-24" placeholder="kHz" />
|
||||
<Input value={freqRxHz} onChange={(e) => setFreqRxHz(e.target.value.replace(/\D/g, ''))} maxLength={3} className="font-mono w-16" placeholder="Hz" />
|
||||
<Input value={freqRxKHz} onChange={(e) => { const v = e.target.value.replace(/\D/g, ''); setFreqRxKHz(v); syncBand(v, freqRxHz, 'band_rx'); }} className="font-mono w-24" placeholder="kHz" />
|
||||
<Input value={freqRxHz} onChange={(e) => { const v = e.target.value.replace(/\D/g, ''); setFreqRxHz(v); syncBand(freqRxKHz, v, 'band_rx'); }} maxLength={3} className="font-mono w-16" placeholder="Hz" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user