fix(awards): live detection only saw the address, never the QTH

The award editor's Test tab matched DK2FJ on its OR rule "qth / exact"
and reported the two Aachen DOKs as ambiguous. The F3 panel, on the same
contact, showed nothing — it builds its own QSO for ComputeQSOAwardRefs
and that object carried address, state, county, zones and continent only.
Any award keyed on the town could not fire there, so live detection was
silently blind to a whole class of awards and the operator only saw them
after logging.

It now passes the entry-strip text as well: QTH, name, country, comment,
note and grid.
This commit is contained in:
2026-08-01 01:15:05 +02:00
parent ae21ddb9d7
commit c21d6cc23a
3 changed files with 29 additions and 8 deletions
+5
View File
@@ -5313,6 +5313,11 @@ export default function App() {
prefix={prefix}
operatorGrid={station.my_grid}
remoteGrid={grid}
qth={qth}
name={name}
country={country}
comment={comment}
note={note}
details={details}
onChange={updateDetails}
wb={wb}
+20 -6
View File
@@ -53,6 +53,14 @@ interface Props {
prefix: string;
operatorGrid: string; // station.my_grid — origin for bearing/distance
remoteGrid: string; // entry-strip Grid value — destination
// Entry-strip text fields. Live award detection matches on these too — a DARC
// DOK keys off QTH, not the address — and sending only the address meant such
// an award stayed silent until the QSO was logged.
qth?: string;
name?: string;
country?: string;
comment?: string;
note?: string;
details: DetailsState;
onChange: (patch: Partial<DetailsState>) => void;
// Stats (F1) tab content: the worked-before matrix + optional QRZ image.
@@ -123,16 +131,20 @@ function Field({ label, span = 1, children }: { label: string; span?: 1 | 2 | 3
);
}
export function DetailsPanel({ callsign, prefix, operatorGrid, remoteGrid, details, onChange, wb, wbBusy, band, mode, bands, tab, onTab, keyerActive }: Props) {
export function DetailsPanel({ callsign, prefix, operatorGrid, remoteGrid, qth, name, country, comment, note, details, onChange, wb, wbBusy, band, mode, bands, tab, onTab, keyerActive }: Props) {
const { t } = useI18n();
const [internalOpen, setInternalOpen] = useState<TabName>('stats');
const open = tab ?? internalOpen; // controlled when `tab` is provided
// Live award detection: run the SAME engine used at log time over the current
// contact (callsign + looked-up address/state/zones) so award references the
// QSO will earn — e.g. WAPC matching "Beijing" inside the address — are
// surfaced and auto-added the moment you enter a call or click a spot, instead
// of only appearing after logging. Pickable matches are merged into award_refs
// contact callsign, the looked-up address/state/zones AND the entry-strip
// text (QTH, name, country, comment, note, grid). Sending only the address was
// a silent hole: a DARC DOK matches on QTH, so "Aachen" produced nothing here
// while the award editor's Test tab, which passes the whole QSO, matched it.
// References the QSO will earn — WAPC matching "Beijing" inside the address,
// a DOK matching the town — are surfaced and auto-added the moment you enter a
// call or click a spot, instead of only appearing after logging. Pickable
// matches are merged into award_refs
// (idempotent; award_refs is NOT a dependency, so removing one by hand sticks).
const [detected, setDetected] = useState<Array<{ code: string; ref: string; name?: string; pickable?: boolean; ambiguous?: boolean }>>([]);
useEffect(() => {
@@ -142,6 +154,8 @@ export function DetailsPanel({ callsign, prefix, operatorGrid, remoteGrid, detai
const q: any = {
callsign, band, mode,
address: details.address ?? '', state: details.state ?? '', cnty: details.cnty ?? '',
qth: qth ?? '', name: name ?? '', country: country ?? '',
comment: comment ?? '', notes: note ?? '', grid: remoteGrid ?? '',
cont: details.cont ?? '', dxcc: details.dxcc, cqz: details.cqz, ituz: details.ituz,
qso_date: new Date().toISOString(),
};
@@ -162,7 +176,7 @@ export function DetailsPanel({ callsign, prefix, operatorGrid, remoteGrid, detai
}, 400);
return () => window.clearTimeout(t);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [open, callsign, details.address, details.state, details.cnty, details.dxcc, details.cqz, details.ituz, band, mode]);
}, [open, callsign, details.address, details.state, details.cnty, details.dxcc, details.cqz, details.ituz, qth, name, country, comment, note, remoteGrid, band, mode]);
// Bearing/distance from operator's home grid to the remote station.
// Recomputed only when either grid actually changes.
const path = useMemo(() => {