fix: bug correction on Awards columns persistence after relaunch
This commit is contained in:
@@ -262,6 +262,30 @@ export function RecentQSOsGrid({ rows, selectAllSignal, onRowDoubleClicked, onRo
|
||||
// auto-save during that window. Set in the memo (runs at render, before the
|
||||
// column events) and cleared by the re-apply effect below.
|
||||
const restoringRef = useRef(true);
|
||||
|
||||
// Award-column visibility is stored as an explicit set of award CODES, NOT via
|
||||
// AG Grid's column-state round-trip. Those columns load asynchronously and
|
||||
// race the state restore, and AG Grid preserves an existing column's visibility
|
||||
// across a columnDefs rebuild instead of re-reading `hide` — which is exactly
|
||||
// why previously-shown award columns kept vanishing on reopen. A dedicated set
|
||||
// is deterministic: it drives `hide` directly and is re-enforced below.
|
||||
const AWARD_SHOWN_KEY = 'hamlog.awardColsShown';
|
||||
const [awardShown, setAwardShown] = useState<Set<string>>(() => new Set((loadLocal(AWARD_SHOWN_KEY) ?? []).map((s) => String(s).toUpperCase())));
|
||||
useEffect(() => {
|
||||
// Fresh machine: hydrate the set from the portable DB copy, then seed the cache.
|
||||
if (loadLocal(AWARD_SHOWN_KEY)) return;
|
||||
loadRemote(AWARD_SHOWN_KEY).then((remote) => {
|
||||
if (remote && remote.length) {
|
||||
seedLocal(AWARD_SHOWN_KEY, remote);
|
||||
setAwardShown(new Set(remote.map((s: any) => String(s).toUpperCase())));
|
||||
}
|
||||
});
|
||||
}, []);
|
||||
const persistAwardShown = useCallback((next: Set<string>) => {
|
||||
setAwardShown(next);
|
||||
saveState(AWARD_SHOWN_KEY, [...next]);
|
||||
}, []);
|
||||
|
||||
const columnDefs = useMemo<ColDef<QSOForm>[]>(() => {
|
||||
restoringRef.current = true;
|
||||
const base = COL_CATALOG.map((c) => {
|
||||
@@ -274,16 +298,26 @@ export function RecentQSOsGrid({ rows, selectAllSignal, onRowDoubleClicked, onRo
|
||||
headerTooltip: t('rqg.awardTip', { name: a.name }),
|
||||
width: 110,
|
||||
cellClass: 'text-[11px]',
|
||||
// Hidden by DEFAULT (award columns are opt-in). Without this, AG Grid shows
|
||||
// them whenever the saved column state doesn't cover them — a newly-added
|
||||
// award, an empty cache, or a rebuild that runs before the saved state is
|
||||
// re-applied — which is why "all award columns" kept reappearing. The user's
|
||||
// saved state (a column they explicitly showed) still overrides this.
|
||||
hide: true,
|
||||
// Visibility comes from the persisted award-code set, so a column the user
|
||||
// showed reappears on reopen and one they didn't stays hidden.
|
||||
hide: !awardShown.has(a.code.toUpperCase()),
|
||||
valueGetter: (p) => (p.data as any)?.award_refs?.[a.code.toUpperCase()] ?? '',
|
||||
}));
|
||||
return [...base, ...awards];
|
||||
}, [awardCols, COL_CATALOG, t]);
|
||||
}, [awardCols, COL_CATALOG, t, awardShown]);
|
||||
|
||||
// Enforce award-column visibility via the API after the columns (re)appear —
|
||||
// colDef.hide alone isn't honoured by AG Grid for a column that already exists,
|
||||
// so we set it explicitly whenever the award set or the loaded columns change.
|
||||
useEffect(() => {
|
||||
const api = gridRef.current?.api;
|
||||
if (!api || !awardCols?.length) return;
|
||||
for (const a of awardCols) {
|
||||
const want = awardShown.has(a.code.toUpperCase());
|
||||
const col = api.getColumn(`award_${a.code}`);
|
||||
if (col && col.isVisible() !== want) api.setColumnsVisible([`award_${a.code}`], want);
|
||||
}
|
||||
}, [awardCols, awardShown]);
|
||||
|
||||
const defaultColDef = useMemo<ColDef>(() => ({
|
||||
sortable: true,
|
||||
@@ -342,10 +376,22 @@ export function RecentQSOsGrid({ rows, selectAllSignal, onRowDoubleClicked, onRo
|
||||
// state for "which columns are visible" — AG Grid's column state is the
|
||||
// source of truth, and saveColumnState persists it.
|
||||
function isColVisible(colId: string): boolean {
|
||||
// Award columns: the persisted set is the source of truth (see awardShown).
|
||||
if (colId.startsWith('award_')) return awardShown.has(colId.slice('award_'.length).toUpperCase());
|
||||
const col = gridRef.current?.api?.getColumn(colId);
|
||||
return col ? col.isVisible() : !!COL_CATALOG.find((c) => c.colId === colId)?.defaultVisible;
|
||||
}
|
||||
function setColVisible(colId: string, visible: boolean) {
|
||||
// Award columns are driven by the persisted code set — update it and let the
|
||||
// enforce effect apply visibility. This is what makes them stick across reopen.
|
||||
if (colId.startsWith('award_')) {
|
||||
const code = colId.slice('award_'.length).toUpperCase();
|
||||
const next = new Set(awardShown);
|
||||
if (visible) next.add(code); else next.delete(code);
|
||||
persistAwardShown(next);
|
||||
gridRef.current?.api?.setColumnsVisible([colId], visible);
|
||||
return;
|
||||
}
|
||||
const api = gridRef.current?.api;
|
||||
if (!api) return;
|
||||
api.setColumnsVisible([colId], visible);
|
||||
@@ -373,6 +419,9 @@ export function RecentQSOsGrid({ rows, selectAllSignal, onRowDoubleClicked, onRo
|
||||
api.setColumnsVisible(visible, true);
|
||||
api.setColumnsVisible(hidden, false);
|
||||
saveColumnState();
|
||||
// Award columns are opt-in: reset hides them all.
|
||||
persistAwardShown(new Set());
|
||||
(awardCols ?? []).forEach((a) => api.setColumnsVisible([`award_${a.code}`], false));
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -469,8 +518,8 @@ export function RecentQSOsGrid({ rows, selectAllSignal, onRowDoubleClicked, onRo
|
||||
<div className="flex items-center justify-between mb-2 pb-1.5 border-b border-border/60">
|
||||
<span className="text-[11px] font-semibold uppercase tracking-wider text-muted-foreground">{t('rqg.grpAwards')}</span>
|
||||
<div className="flex gap-0.5">
|
||||
<button className="text-[10px] text-primary hover:underline px-1" onClick={() => { awardCols.forEach((a) => setColVisible(`award_${a.code}`, true)); }}>{t('rqg.all')}</button>
|
||||
<button className="text-[10px] text-muted-foreground hover:underline px-1" onClick={() => { awardCols.forEach((a) => setColVisible(`award_${a.code}`, false)); }}>{t('rqg.none')}</button>
|
||||
<button className="text-[10px] text-primary hover:underline px-1" onClick={() => { persistAwardShown(new Set(awardCols.map((a) => a.code.toUpperCase()))); awardCols.forEach((a) => gridRef.current?.api?.setColumnsVisible([`award_${a.code}`], true)); }}>{t('rqg.all')}</button>
|
||||
<button className="text-[10px] text-muted-foreground hover:underline px-1" onClick={() => { persistAwardShown(new Set()); awardCols.forEach((a) => gridRef.current?.api?.setColumnsVisible([`award_${a.code}`], false)); }}>{t('rqg.none')}</button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col gap-1">
|
||||
|
||||
Reference in New Issue
Block a user