diff --git a/website/src/components/SearchPage/fields/DateRangeField.spec.tsx b/website/src/components/SearchPage/fields/DateRangeField.spec.tsx index e96f5f37ce..079bbbf065 100644 --- a/website/src/components/SearchPage/fields/DateRangeField.spec.tsx +++ b/website/src/components/SearchPage/fields/DateRangeField.spec.tsx @@ -158,6 +158,38 @@ describe('DateRangeField', () => { ); }); + it('does not snap back to strict when user toggles without having entered dates', async () => { + function Wrapper() { + const [values, _setValues] = useState({}); + + const setValues: SetSomeFieldValues = useCallback((...fieldValuesToSet) => { + _setValues((state) => { + const newState = { ...state }; + fieldValuesToSet.forEach(([k, v]) => { + // mirror the production behaviour of useSearchPageState: null/'' deletes + if (v === null || v === '') { + delete newState[k]; + } else { + newState[k] = v; + } + }); + return newState; + }); + }, []); + + return ; + } + + const user = userEvent.setup(); + render(); + + const strictCheckbox = screen.getByRole('checkbox'); + expect(strictCheckbox).toBeChecked(); + + await user.click(strictCheckbox); + expect(strictCheckbox).not.toBeChecked(); + }); + it('setting fieldValue to empty string clears date field', async () => { function Wrapper() { const [values, _setValues] = useState({ diff --git a/website/src/components/SearchPage/fields/DateRangeField.tsx b/website/src/components/SearchPage/fields/DateRangeField.tsx index 93b130dc77..a1729a1553 100644 --- a/website/src/components/SearchPage/fields/DateRangeField.tsx +++ b/website/src/components/SearchPage/fields/DateRangeField.tsx @@ -60,14 +60,17 @@ export const DateRangeField = ({ field, fieldValues, setSomeFieldValues }: DateR const [upperValue, setUpperValue] = useState(getFieldValue(upperField.name)); useEffect(() => { - setStrictMode( - isStrictMode( - lowerFromField.name in fieldValues, - lowerToField.name in fieldValues, - upperFromField.name in fieldValues, - upperToField.name in fieldValues, - ), - ); + const lowerFromDefined = lowerFromField.name in fieldValues; + const lowerToDefined = lowerToField.name in fieldValues; + const upperFromDefined = upperFromField.name in fieldValues; + const upperToDefined = upperToField.name in fieldValues; + // Only re-derive strictMode from fieldValues when at least one bound is actually defined. + // When the user toggles strictness without having entered any dates the other effect + // below clears all four fields, which would otherwise feed back into isStrictMode and + // collapse strictMode back to its default `true` — making the checkbox appear stuck on. + if (lowerFromDefined || lowerToDefined || upperFromDefined || upperToDefined) { + setStrictMode(isStrictMode(lowerFromDefined, lowerToDefined, upperFromDefined, upperToDefined)); + } setLowerValue(validateSingleValue(fieldValues[lowerField.name], lowerField.name)); setUpperValue(validateSingleValue(fieldValues[upperField.name], upperField.name)); }, [field, fieldValues]);