feat(cluster): a SOTA column, and a spot click that credits the summit
The SOTA feeds put the summit in the spot's own text, so there is nothing to poll: a regex on the comment gives the reference, and clicking the spot writes SOTA@<ref> into the award references the way a park already wrote POTA@<ref>. The regex is narrow on purpose — association/region-NNN, anchored — because POTA (US-4475), WWFF (DLFF-0001) and portable callsigns (DL/SP9DPM/P) share that field and none of them is a summit. Pinned by a table test. Off by default: the reference is only there on the summit feeds, and an empty column for every operator who does not chase them is worse than a checkbox.
This commit is contained in:
+15
-11
@@ -3275,7 +3275,7 @@ export default function App() {
|
||||
function handleSpotSelect(s: any) {
|
||||
if (!s?.dx_call?.trim()) return;
|
||||
onCallsignInput(s.dx_call, { force: true });
|
||||
applySpotPOTA((s as any).pota_ref);
|
||||
applySpotRefs((s as any).pota_ref, (s as any).sota_ref);
|
||||
}
|
||||
|
||||
function handleSpotClick(s: any) {
|
||||
@@ -3300,7 +3300,7 @@ export default function App() {
|
||||
FlexZoomForSpot(m ?? '', s.freq_hz ?? 0).catch(() => {});
|
||||
if (m) applyModeFromSpot(m);
|
||||
onCallsignInput(s.dx_call, { force: true });
|
||||
applySpotPOTA((s as any).pota_ref);
|
||||
applySpotRefs((s as any).pota_ref, (s as any).sota_ref);
|
||||
if (s.dx_call?.trim()) restartRecordingForNewTarget(s.dx_call);
|
||||
}
|
||||
|
||||
@@ -3761,14 +3761,14 @@ export default function App() {
|
||||
restartRecordingForNewTarget(call);
|
||||
// The park, like a click in the band map: the radio reports only a
|
||||
// callsign, so the backend looks it up again before sending the event.
|
||||
applySpotPOTA(String(p?.pota_ref ?? ''));
|
||||
applySpotRefs(String(p?.pota_ref ?? ''), String(p?.sota_ref ?? ''));
|
||||
});
|
||||
// Clicking a spot on the ExpertSDR (TCI) panorama fills the call, like Flex.
|
||||
const unsubTciSpot = EventsOn('tci:spot_clicked', (p: any) => {
|
||||
const call = String(p?.call ?? '');
|
||||
if (!applyUdpCall(call, true)) return;
|
||||
restartRecordingForNewTarget(call);
|
||||
applySpotPOTA(String(p?.pota_ref ?? ''));
|
||||
applySpotRefs(String(p?.pota_ref ?? ''), String(p?.sota_ref ?? ''));
|
||||
});
|
||||
const unsubBulk = EventsOn('bulkupdate:progress', (p: any) => {
|
||||
const total = Number(p?.total ?? 0);
|
||||
@@ -4796,13 +4796,17 @@ export default function App() {
|
||||
}
|
||||
wbTimerRef.current = window.setTimeout(() => runWorkedBefore(call), 150);
|
||||
}
|
||||
// applySpotPOTA sets the QSO's POTA award reference(s) from a clicked spot's
|
||||
// park ref ("US-4164" or n-fer "US-1,US-2"). Empty ref clears it (fresh
|
||||
// target). Routed to the pota_ref column at save via applyAwardRefs.
|
||||
function applySpotPOTA(potaRef?: string) {
|
||||
const refs = String(potaRef || '')
|
||||
.split(/[,;]/).map((x) => x.trim().toUpperCase()).filter(Boolean);
|
||||
setDetails((d) => ({ ...d, award_refs: refs.map((r) => `POTA@${r}`).join(';') }));
|
||||
// Award references carried by the spot itself: the park a station is
|
||||
// activating, the summit it is on, or both. Written into award_refs the same
|
||||
// way for each, so logging the contact credits it without retyping a
|
||||
// reference that was on screen.
|
||||
function applySpotRefs(potaRef?: string, sotaRef?: string) {
|
||||
const split = (v?: string) => String(v || '').split(/[,;]/).map((x) => x.trim().toUpperCase()).filter(Boolean);
|
||||
const refs = [
|
||||
...split(potaRef).map((r) => `POTA@${r}`),
|
||||
...split(sotaRef).map((r) => `SOTA@${r}`),
|
||||
];
|
||||
setDetails((d) => ({ ...d, award_refs: refs.join(';') }));
|
||||
}
|
||||
function onCallsignInput(v: string, opts?: { force?: boolean }) {
|
||||
// Programmatic call-sets (force: spot click, UDP, external app) count as
|
||||
|
||||
Reference in New Issue
Block a user