feat(lookup): read QRZ's island reference and fill the IOTA award
QRZ's XML carries <iota>EU-048</iota> for an operator on an island, and OpsLog read past it. Wired end to end: the provider, the lookup cache (a column, like web and zip before it), and the entry's award references. It matters more here than the same field would for another award. There is no live "who is on an island right now" feed anywhere — POTA has one and that is what OpsLog matches spots against; SOTA has one behind conditions; IOTA publishes only static lists. So the callbook record is the practical source, and it is known BEFORE the contact is logged, which is when a reference is useful. The reference goes in as an IOTA award reference, exactly as one picked by hand, so the existing path carries it to the qso.iota column on save. Two limits, both deliberate. A reference the operator typed or picked WINS: a callbook entry can be years out of date, and the operator in front of the radio has just been told where the station is. And the value must look like an IOTA reference — two letters, a hyphen, three digits — because writing anything else into the award makes a reference no list contains, which counts for nothing and has to be found by hand later.
This commit is contained in:
+13
-1
@@ -56,7 +56,7 @@ import {
|
||||
QSLViaRepairStatus, RepairQSLVia, DismissQSLViaRepair,
|
||||
} from '../wailsjs/go/main/App';
|
||||
import { Combobox } from '@/components/ui/combobox';
|
||||
import { applyAwardRefs, parseAwardRefs as parseManualRefs, spotRefList } from '@/lib/awardRefs';
|
||||
import { applyAwardRefs, parseAwardRefs as parseManualRefs, spotRefList , withIOTARef } from '@/lib/awardRefs';
|
||||
import { EventsOn, BrowserOpenURL, WindowMinimise, WindowToggleMaximise, WindowIsMaximised, Quit } from '../wailsjs/runtime/runtime';
|
||||
import type { adif as adifModels, lookup as lookupModels, cat as catModels } from '../wailsjs/go/models';
|
||||
import type { QSOForm, WorkedBeforeView, StationSettingsForm, ListsSettingsForm, ModePresetForm } from '@/types';
|
||||
@@ -3867,6 +3867,18 @@ export default function App() {
|
||||
email: d.email || last.email || '',
|
||||
web: d.web || last.web || '',
|
||||
qsl_via: d.qsl_via || last.qsl_via || '',
|
||||
// An island reference from the callbook becomes an IOTA award reference
|
||||
// on the entry, exactly like one picked by hand.
|
||||
//
|
||||
// QRZ carries <iota> for an operator on an island and OpsLog read past
|
||||
// it. That matters more for IOTA than it would for another award:
|
||||
// unlike POTA there is no live "who is on an island right now" feed
|
||||
// anywhere, so the callbook record is the practical source — and it is
|
||||
// known BEFORE the contact is logged, which is when it is useful.
|
||||
//
|
||||
// Only when the operator has not set one already: a reference typed or
|
||||
// picked by hand outranks a callbook that may be years out of date.
|
||||
award_refs: withIOTARef(d.award_refs ?? '', String((r as any)?.iota ?? '')),
|
||||
};
|
||||
});
|
||||
if (adoptLastGrid || last.grid || last.lat) setMapZoomSignal((n) => n + 1);
|
||||
|
||||
@@ -192,3 +192,27 @@ export function spotRefList(byCode: Record<string, string>, fieldOf: Record<stri
|
||||
}
|
||||
return out.sort((a, b) => a.length - b.length || a.localeCompare(b));
|
||||
}
|
||||
|
||||
// withIOTARef adds an island reference from the callbook to an entry's award
|
||||
// references, unless the operator has already set one.
|
||||
//
|
||||
// QRZ sends <iota> for an operator on an island and OpsLog used to read past it.
|
||||
// It matters more here than it would for another award: unlike POTA there is no
|
||||
// live "who is on an island right now" feed anywhere, so the callbook record is
|
||||
// the practical source — and it is known before the contact is logged, which is
|
||||
// when it is useful.
|
||||
//
|
||||
// A reference the operator typed or picked wins. A callbook entry can be years
|
||||
// old, and the operator in front of the radio has just been told where the
|
||||
// station is.
|
||||
export function withIOTARef(awardRefs: string, iota: string): string {
|
||||
const ref = (iota || '').trim().toUpperCase();
|
||||
// EU-048: two letters, a hyphen, three digits. Anything else is not an IOTA
|
||||
// reference, and writing it into the award would make a reference that no
|
||||
// list contains — which counts for nothing and has to be found by hand later.
|
||||
if (!/^[A-Z]{2}-\d{3}$/.test(ref)) return awardRefs;
|
||||
const byCode = parseAwardRefs(awardRefs);
|
||||
if ((byCode['IOTA'] ?? '').trim() !== '') return awardRefs; // already set: leave it
|
||||
const sep = awardRefs.trim() === '' ? '' : ';';
|
||||
return awardRefs + sep + 'IOTA@' + ref;
|
||||
}
|
||||
|
||||
@@ -1444,6 +1444,7 @@ export namespace lookup {
|
||||
email?: string;
|
||||
qsl_via?: string;
|
||||
web?: string;
|
||||
iota?: string;
|
||||
zip?: string;
|
||||
image_url?: string;
|
||||
source: string;
|
||||
@@ -1473,6 +1474,7 @@ export namespace lookup {
|
||||
this.email = source["email"];
|
||||
this.qsl_via = source["qsl_via"];
|
||||
this.web = source["web"];
|
||||
this.iota = source["iota"];
|
||||
this.zip = source["zip"];
|
||||
this.image_url = source["image_url"];
|
||||
this.source = source["source"];
|
||||
@@ -4546,6 +4548,7 @@ export namespace qso {
|
||||
my_vucc_grids?: string;
|
||||
extras?: Record<string, string>;
|
||||
award_refs?: string;
|
||||
sync_uid?: string;
|
||||
// Go type: time
|
||||
created_at: any;
|
||||
// Go type: time
|
||||
@@ -4687,6 +4690,7 @@ export namespace qso {
|
||||
this.my_vucc_grids = source["my_vucc_grids"];
|
||||
this.extras = source["extras"];
|
||||
this.award_refs = source["award_refs"];
|
||||
this.sync_uid = source["sync_uid"];
|
||||
this.created_at = this.convertValues(source["created_at"], null);
|
||||
this.updated_at = this.convertValues(source["updated_at"], null);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user