fix(search): offer every filter option, not only those in the results
PR Checks / Frontend Typecheck + Tests (pull_request) Successful in 1m17s
PR Checks / Backend Smoke (pull_request) Successful in 9s
PR Checks / Build Backend (no push) (pull_request) Successful in 19s
PR Checks / Build Frontend (no push) (pull_request) Successful in 1m22s
PR Checks / Build Pipeline (no push) (pull_request) Successful in 11s
PR Checks / AI Code Review (Claude) (pull_request) Successful in 15s
PR Checks / Frontend Typecheck + Tests (pull_request) Successful in 1m17s
PR Checks / Backend Smoke (pull_request) Successful in 9s
PR Checks / Build Backend (no push) (pull_request) Successful in 19s
PR Checks / Build Frontend (no push) (pull_request) Successful in 1m22s
PR Checks / Build Pipeline (no push) (pull_request) Successful in 11s
PR Checks / AI Code Review (Claude) (pull_request) Successful in 15s
School type, gender and admissions took their options from the result set, which the filter had already narrowed: choose "Girls" and only "Girls" was offered, so switching to "Boys" meant clearing first. They now offer the full lists from /api/filters, as phase already did. Local authority stays scoped to the results, so a postcode search offers the councils nearby rather than all 153. Whether gender, sixth form and admissions show was also decided by the results (any secondary school in them). It is now decided by the phase alone: hidden for Primary, Nursery and Middle deemed primary, shown otherwise. Choosing one of those phases clears the three filters, which would otherwise stay applied with no control showing. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
eb13ab0b5e
commit
0cc4f52816
4 files changed
+168
-16
No files matched your search
@@ -66,6 +66,14 @@ const FILTER_KEYS = [
|
||||
] as const;
|
||||
type FilterKey = (typeof FILTER_KEYS)[number];
|
||||
|
||||
/** Filters that only mean something for schools teaching beyond primary. */
|
||||
const SECONDARY_ONLY_KEYS = ["gender", "has_sixth_form", "admissions_policy"] as const;
|
||||
|
||||
/** Phases with no secondary-age pupils, for which those filters are hidden. */
|
||||
const PRIMARY_PHASES = new Set(["primary", "nursery", "middle deemed primary"]);
|
||||
|
||||
const hasSecondaryFilters = (phase: string) => !PRIMARY_PHASES.has(phase.toLowerCase());
|
||||
|
||||
function SlidersIcon() {
|
||||
return (
|
||||
<svg
|
||||
@@ -326,7 +334,13 @@ export function FilterBar({
|
||||
};
|
||||
|
||||
const handleFilterChange = (key: string, value: string) => {
|
||||
updateURL({ [key]: value });
|
||||
// A primary phase hides the secondary-only filters, so it clears them
|
||||
// too: left applied, they would empty the list with no control showing.
|
||||
const cleared =
|
||||
key === "phase" && !hasSecondaryFilters(value)
|
||||
? Object.fromEntries(SECONDARY_ONLY_KEYS.map((k) => [k, ""]))
|
||||
: {};
|
||||
updateURL({ ...cleared, [key]: value });
|
||||
};
|
||||
|
||||
// Every filter at once, keeping the search and its distance: what "Clear
|
||||
@@ -353,20 +367,24 @@ export function FilterBar({
|
||||
currentAdmissionsPolicy ||
|
||||
currentHasSixthForm;
|
||||
|
||||
// Use result-scoped filter values when available, fall back to global
|
||||
/*
|
||||
* A filter's options come from the full lists, not from the results: the
|
||||
* results have already been narrowed by that filter, so scoping to them
|
||||
* would leave only the chosen value on offer, and switching (Girls to Boys,
|
||||
* one school type to another) would need clearing first.
|
||||
*
|
||||
* Local authority is the exception, scoped to the results so a postcode
|
||||
* search offers the councils nearby rather than all of England's.
|
||||
*/
|
||||
const laOptions =
|
||||
resultFilters?.local_authorities ?? filters.local_authorities;
|
||||
const typeOptions = resultFilters?.school_types ?? filters.school_types;
|
||||
// Phase is the exception: always the full list. The result set has already
|
||||
// been narrowed by the phase filter, so scoping to it would leave only the
|
||||
// chosen phase on offer and switching phase would need "Any phase" first.
|
||||
const typeOptions = filters.school_types;
|
||||
const phaseOptions = filters.phases ?? [];
|
||||
const genderOptions = resultFilters?.genders ?? filters.genders ?? [];
|
||||
const admissionsPolicyOptions =
|
||||
resultFilters?.admissions_policies ?? filters.admissions_policies ?? [];
|
||||
const genderOptions = filters.genders ?? [];
|
||||
const admissionsPolicyOptions = filters.admissions_policies ?? [];
|
||||
|
||||
const isSecondaryMode =
|
||||
currentPhase === "secondary" || genderOptions.length > 0;
|
||||
// Set by the phase chosen, never by what the results happen to contain.
|
||||
const isSecondaryMode = hasSecondaryFilters(currentPhase);
|
||||
|
||||
// A select that is narrowing the results carries a sage tint; the class is
|
||||
// only ever additive, so the control's behaviour is untouched.
|
||||
@@ -409,11 +427,8 @@ export function FilterBar({
|
||||
// rest are the names themselves.
|
||||
const named: Partial<Record<FilterKey, string[]>> = {
|
||||
phase: phaseOptions,
|
||||
gender: [...genderOptions, ...(filters.genders ?? [])],
|
||||
admissions_policy: [
|
||||
...admissionsPolicyOptions,
|
||||
...(filters.admissions_policies ?? []),
|
||||
],
|
||||
gender: genderOptions,
|
||||
admissions_policy: admissionsPolicyOptions,
|
||||
};
|
||||
return (named[key] ?? []).find((o) => o.toLowerCase() === value.toLowerCase()) ?? value;
|
||||
};
|
||||
|
||||
Reference in new issue
Block a user