diff --git a/frontend/src/components/AwardEditor.tsx b/frontend/src/components/AwardEditor.tsx index 4cdad24..a7a44ef 100644 --- a/frontend/src/components/AwardEditor.tsx +++ b/frontend/src/components/AwardEditor.tsx @@ -97,6 +97,13 @@ function Chips({ all, value, onToggle }: { all: string[]; value: string[]; onTog ); } +// Awards use a far-future date as "no end" (RDA carries 9999-12-31). Printing it +// back at the operator reads like a real deadline, so show it as open-ended. +function openEnded(d?: string): string { + if (!d) return '—'; + return /^9\d{3}-/.test(d) ? '—' : d; +} + function Field2({ label, children }: { label: string; children: React.ReactNode }) { return (
{(awardValidFrom || awardValidTo) - ? t('awed.refValidHintAward', { from: awardValidFrom || '—', to: awardValidTo || '—' }) + ? t('awed.refValidHintAward', { from: openEnded(awardValidFrom), to: openEnded(awardValidTo) }) : t('awed.refValidHint')}
diff --git a/internal/award/refvalidity_test.go b/internal/award/refvalidity_test.go index ae6dcdc..7178cfe 100644 --- a/internal/award/refvalidity_test.go +++ b/internal/award/refvalidity_test.go @@ -76,3 +76,34 @@ func TestExpiredRefStopsCountingForLaterQSOs(t *testing.T) { t.Errorf("a reference with no window is unaffected: got %v", got) } } + +// The claim that an empty per-reference window "inherits the award's" has to be +// a fact about the code, not a comment. Compute and MatchQSO both gate on +// inScope, which enforces the award's own dates — so a reference with no window +// of its own is already bounded by them, and duplicating the check per reference +// would only create a second place for the same dates to disagree. +func TestEmptyRefWindowInheritsTheAward(t *testing.T) { + d := Def{ + Code: "RDA", Name: "Russian District Award", Valid: true, + Type: TypeQSOFields, Field: "note", MatchBy: "code", + Confirm: []string{"lotw"}, + ValidFrom: "1991-06-12", // the award itself starts here + } + metas := []RefMeta{{Code: "KL-04", Name: "Kostomuksha", Valid: true}} // no window of its own + + q := func(on string) *qso.QSO { + return &qso.QSO{Callsign: "RA1ABC", Band: "20m", Notes: "KL-04", QSODate: day(on)} + } + if got := MatchQSO(d, metas, q("1991-06-11")); len(got) != 0 { + t.Errorf("a QSO before the AWARD's start counted for a reference with no window of its own: %v", got) + } + if got := MatchQSO(d, metas, q("1991-06-12")); len(got) != 1 { + t.Errorf("a QSO on the award's first day must count: %v", got) + } + + // And a reference window NARROWER than the award's still applies on top. + metas[0].ValidTo = "2025-08-31" + if got := MatchQSO(d, metas, q("2025-09-01")); len(got) != 0 { + t.Errorf("the reference's own end date was ignored: %v", got) + } +}