fix(chase): the unconfirmed flag survives the next QSO
Reported as 'South Africa shows NEW BAND although I have worked 15m'. The verdict was right — his hunt counts only LoTW and paper QSL, and no 15m contact is confirmed by either — but the badge drew SOLID, saying 'never worked here' about a band with four contacts in the log. Proved with his own data: the confirmed ledger holds 10/12/17/20/30/40/80 and not 15, the all-QSO ledger holds 15m FT8 four times, and the backend sets UnconfStatus correctly for exactly that case (new test, end to end through ClusterSpotStatuses). The flag died in the frontend. FOUR hand-written copies of the same backend-result mapping, and they had drifted: the two that RE-fetch — after a QSO is logged, and when a pane becomes visible — rebuilt each entry without the unconf_* flags, so the first refresh after any contact turned every dimmed badge solid for good. None of the four ever copied grid_state either, so a known-but-unconfirmed square never dimmed at all. One mapper now, used by all four.
This commit is contained in:
+39
-50
@@ -2098,7 +2098,41 @@ export default function App() {
|
||||
// worked_slot must be carried explicitly like every other field: this map is
|
||||
// assembled field by field, so a backend flag that nobody copies here simply
|
||||
// never reaches the panels — silently, since the extra key is just dropped.
|
||||
const [spotStatus, setSpotStatus] = useState<Record<string, { status: string; country?: string; continent?: string; worked_call?: boolean; worked_slot?: boolean; new_county?: boolean; county?: string; state?: string; lotw?: boolean; spotter_continent?: string; grid?: string; new_grid?: boolean; new_state?: boolean; new_pota?: boolean; unconf_status?: boolean; unconf_pfx?: boolean; unconf_cty?: boolean; unconf_state?: boolean; new_pfx?: boolean; pfx?: string }>>({});
|
||||
// spotStatusEntry maps ONE backend verdict onto the entry the panels read.
|
||||
//
|
||||
// There were four of these, written by hand at each call site, and they had
|
||||
// drifted apart: the two that RE-fetch — after a QSO is logged, and when a
|
||||
// pane becomes visible — rebuilt every entry without the unconfirmed flags.
|
||||
// So a badge drawn correctly as "worked, QSL missing" turned solid at the
|
||||
// next refresh and stayed that way, which is how South Africa came to read
|
||||
// NEW BAND on a band with four contacts in the log. grid_state was never
|
||||
// copied by any of them, so a known-but-unconfirmed square never dimmed at
|
||||
// all. One function now, so a field added to the backend cannot reach three
|
||||
// callers and miss the fourth.
|
||||
const spotStatusEntry = (r: any) => ({
|
||||
status: r.status ?? '',
|
||||
country: r.country,
|
||||
continent: r.continent,
|
||||
worked_call: !!r.worked_call,
|
||||
worked_slot: !!r.worked_slot,
|
||||
new_county: !!r.new_county,
|
||||
lotw: !!r.lotw,
|
||||
spotter_continent: r.spotter_continent,
|
||||
grid: r.grid,
|
||||
grid_state: r.grid_state,
|
||||
new_grid: !!r.new_grid,
|
||||
county: r.county,
|
||||
state: r.state,
|
||||
new_state: !!r.new_state,
|
||||
new_pota: !!r.new_pota,
|
||||
new_pfx: !!r.new_pfx,
|
||||
pfx: r.pfx,
|
||||
unconf_status: !!r.unconf_status,
|
||||
unconf_pfx: !!r.unconf_pfx,
|
||||
unconf_cty: !!r.unconf_cty,
|
||||
unconf_state: !!r.unconf_state,
|
||||
});
|
||||
const [spotStatus, setSpotStatus] = useState<Record<string, { status: string; country?: string; continent?: string; worked_call?: boolean; worked_slot?: boolean; new_county?: boolean; county?: string; state?: string; lotw?: boolean; spotter_continent?: string; grid?: string; grid_state?: string; new_grid?: boolean; new_state?: boolean; new_pota?: boolean; unconf_status?: boolean; unconf_pfx?: boolean; unconf_cty?: boolean; unconf_state?: boolean; new_pfx?: boolean; pfx?: string }>>({});
|
||||
// Live mirror of spotStatus so the incoming-spot buffer can tell which slots
|
||||
// still need resolving without re-subscribing the cluster:spot listener.
|
||||
const spotStatusRef = useRef(spotStatus);
|
||||
@@ -2171,11 +2205,7 @@ export default function App() {
|
||||
const next = { ...prev };
|
||||
for (const r of res) {
|
||||
const k = `${r.call}|${r.band ?? ''}|${(r.mode ?? '').toUpperCase()}`;
|
||||
next[k] = {
|
||||
status: r.status ?? '', country: r.country, continent: (r as any).continent,
|
||||
worked_call: !!(r as any).worked_call, worked_slot: !!(r as any).worked_slot, new_county: !!(r as any).new_county, lotw: !!(r as any).lotw, spotter_continent: (r as any).spotter_continent, grid: (r as any).grid, new_grid: !!(r as any).new_grid, county: (r as any).county, state: (r as any).state,
|
||||
new_pota: !!(r as any).new_pota, new_pfx: !!(r as any).new_pfx, pfx: (r as any).pfx,
|
||||
};
|
||||
next[k] = spotStatusEntry(r);
|
||||
}
|
||||
return next;
|
||||
});
|
||||
@@ -3654,22 +3684,7 @@ export default function App() {
|
||||
const next = { ...prev };
|
||||
for (const r of res) {
|
||||
const k = `${r.call}|${r.band ?? ''}|${(r.mode ?? '').toUpperCase()}`;
|
||||
next[k] = {
|
||||
status: r.status ?? '',
|
||||
country: r.country,
|
||||
continent: (r as any).continent,
|
||||
worked_call: !!(r as any).worked_call,
|
||||
worked_slot: !!(r as any).worked_slot,
|
||||
new_county: !!(r as any).new_county, lotw: !!(r as any).lotw, spotter_continent: (r as any).spotter_continent, grid: (r as any).grid, new_grid: !!(r as any).new_grid, county: (r as any).county, state: (r as any).state,
|
||||
new_state: !!(r as any).new_state,
|
||||
unconf_status: !!(r as any).unconf_status,
|
||||
unconf_pfx: !!(r as any).unconf_pfx,
|
||||
unconf_cty: !!(r as any).unconf_cty,
|
||||
unconf_state: !!(r as any).unconf_state,
|
||||
new_pota: !!(r as any).new_pota,
|
||||
new_pfx: !!(r as any).new_pfx,
|
||||
pfx: (r as any).pfx,
|
||||
};
|
||||
next[k] = spotStatusEntry(r);
|
||||
}
|
||||
return next;
|
||||
});
|
||||
@@ -3763,23 +3778,7 @@ export default function App() {
|
||||
const next = { ...prev };
|
||||
for (const r of res) {
|
||||
const k = `${r.call}|${r.band ?? ''}|${(r.mode ?? '').toUpperCase()}`;
|
||||
next[k] = {
|
||||
status: r.status ?? '',
|
||||
country: r.country,
|
||||
continent: (r as any).continent,
|
||||
worked_call: !!(r as any).worked_call,
|
||||
worked_slot: !!(r as any).worked_slot,
|
||||
new_county: !!(r as any).new_county, lotw: !!(r as any).lotw,
|
||||
grid: (r as any).grid, new_grid: !!(r as any).new_grid,
|
||||
county: (r as any).county, state: (r as any).state,
|
||||
new_state: !!(r as any).new_state,
|
||||
unconf_status: !!(r as any).unconf_status,
|
||||
unconf_pfx: !!(r as any).unconf_pfx,
|
||||
unconf_cty: !!(r as any).unconf_cty,
|
||||
unconf_state: !!(r as any).unconf_state,
|
||||
new_pota: !!(r as any).new_pota,
|
||||
new_pfx: !!(r as any).new_pfx, pfx: (r as any).pfx,
|
||||
};
|
||||
next[k] = spotStatusEntry(r);
|
||||
}
|
||||
return next;
|
||||
});
|
||||
@@ -4277,17 +4276,7 @@ export default function App() {
|
||||
const next = { ...prev };
|
||||
for (const r of res) {
|
||||
const k = `${r.call}|${r.band ?? ''}|${(r.mode ?? '').toUpperCase()}`;
|
||||
next[k] = {
|
||||
status: r.status ?? '',
|
||||
country: r.country,
|
||||
continent: (r as any).continent,
|
||||
worked_call: !!(r as any).worked_call,
|
||||
worked_slot: !!(r as any).worked_slot,
|
||||
new_county: !!(r as any).new_county, lotw: !!(r as any).lotw, spotter_continent: (r as any).spotter_continent, grid: (r as any).grid, new_grid: !!(r as any).new_grid, county: (r as any).county, state: (r as any).state,
|
||||
new_pota: !!(r as any).new_pota,
|
||||
new_pfx: !!(r as any).new_pfx,
|
||||
pfx: (r as any).pfx,
|
||||
};
|
||||
next[k] = spotStatusEntry(r);
|
||||
}
|
||||
return next;
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user