From 355a5a841ca28d5001936e89bbd4c0b75c658ac0 Mon Sep 17 00:00:00 2001 From: Tudor Date: Thu, 1 Oct 2026 17:52:59 +0100 Subject: [PATCH] feat(search): offer a quarter-mile distance Adds "Within 0.25 miles" to the Distance control; 0.5 stays the default. The radius shown in the results heading and drawn on the map was rounded to one decimal place, which would have turned 0.25 into 0.3. It now keeps two, and the list heading says "1 mile" rather than "1.0 miles". Co-Authored-By: Claude Opus 5.5 --- .../__tests__/components/FilterBarRadius.test.tsx | 10 ++++++++++ .../__tests__/components/ResultsMapView.test.tsx | 13 ++++++++++++- nextjs-app/components/FilterBar.tsx | 1 + nextjs-app/components/HomeView.tsx | 7 ++++--- 4 files changed, 27 insertions(+), 4 deletions(-) diff --git a/nextjs-app/__tests__/components/FilterBarRadius.test.tsx b/nextjs-app/__tests__/components/FilterBarRadius.test.tsx index d6d200e..5bcf04b 100644 --- a/nextjs-app/__tests__/components/FilterBarRadius.test.tsx +++ b/nextjs-app/__tests__/components/FilterBarRadius.test.tsx @@ -39,3 +39,13 @@ describe('FilterBar default distance', () => { expect(screen.getByRole('combobox', { name: 'Distance' })).toHaveValue('3'); }); }); + +describe('FilterBar distance options', () => { + it('offers a quarter mile without making it the default', () => { + searchParams = new URLSearchParams('postcode=SW196AR'); + render(); + const distance = screen.getByRole('combobox', { name: 'Distance' }); + expect([...(distance as HTMLSelectElement).options].map(o => o.value)).toEqual(['0.25', '0.5', '1', '3', '5']); + expect(distance).toHaveValue('0.5'); + }); +}); diff --git a/nextjs-app/__tests__/components/ResultsMapView.test.tsx b/nextjs-app/__tests__/components/ResultsMapView.test.tsx index 2178630..61b6ee0 100644 --- a/nextjs-app/__tests__/components/ResultsMapView.test.tsx +++ b/nextjs-app/__tests__/components/ResultsMapView.test.tsx @@ -180,5 +180,16 @@ it('lets a keyboard pick a pin from the list, with a real button', async () => { it('keeps the postcode in the heading in list view, where there is room', async () => { await renderMap(); fireEvent.click(screen.getByRole('button', { name: 'List' })); - expect(screen.getByRole('heading', { name: '3 schools within 1.0 miles of SW196AR' })).toBeInTheDocument(); + expect(screen.getByRole('heading', { name: '3 schools within 1 mile of SW196AR' })).toBeInTheDocument(); +}); + +it('draws and names a quarter-mile search as 0.25, not rounded to 0.3', async () => { + params = new URLSearchParams('postcode=SW196AR&radius=0.25'); + const quarter = { ...results(), location_info: { postcode: 'SW196AR', radius: 0.25 * 1.60934, coordinates: [51.42, -0.21] } } as SchoolsResponse; + render(); + await act(async () => {}); + expect(screen.getByTestId('map')).toHaveAttribute('data-radius', '0.25'); + expect(screen.getByRole('heading', { name: '3 schools within 0.25 miles' })).toBeInTheDocument(); + fireEvent.click(screen.getByRole('button', { name: 'List' })); + expect(screen.getByRole('heading', { name: '3 schools within 0.25 miles of SW196AR' })).toBeInTheDocument(); }); diff --git a/nextjs-app/components/FilterBar.tsx b/nextjs-app/components/FilterBar.tsx index ebab6e9..25fde82 100644 --- a/nextjs-app/components/FilterBar.tsx +++ b/nextjs-app/components/FilterBar.tsx @@ -481,6 +481,7 @@ export function FilterBar({ aria-label="Distance" disabled={isPending} > + diff --git a/nextjs-app/components/HomeView.tsx b/nextjs-app/components/HomeView.tsx index f14c019..3ea0b4f 100644 --- a/nextjs-app/components/HomeView.tsx +++ b/nextjs-app/components/HomeView.tsx @@ -461,8 +461,9 @@ export function HomeView({ initialSchools, filters, totalSchools, howItWorks, ed // open card); only the list beside it is sorted. const mapResultSchools = mapSchools.length > 0 ? mapSchools : initialSchools.schools; const mapListSchools = sortSchools(mapResultSchools); + // Two places, so a 0.25-mile search is not drawn or labelled as 0.3. const radiusMiles = initialSchools.location_info - ? Number((initialSchools.location_info.radius / 1.60934).toFixed(1)) + ? Number((initialSchools.location_info.radius / 1.60934).toFixed(2)) : undefined; // Empty-results sentinel: track when a search returns nothing. @@ -596,8 +597,8 @@ export function HomeView({ initialSchools, filters, totalSchools, howItWorks, ed drops the postcode, which the search box just above already shows. */} {isMapView && radiusMiles != null ? `${schoolCount} within ${radiusMiles} mile${radiusMiles === 1 ? '' : 's'}` - : isLocationSearch && initialSchools.location_info - ? `${schoolCount} within ${(initialSchools.location_info.radius / 1.60934).toFixed(1)} miles of ${initialSchools.location_info.postcode}` + : isLocationSearch && radiusMiles != null && initialSchools.location_info + ? `${schoolCount} within ${radiusMiles} mile${radiusMiles === 1 ? '' : 's'} of ${initialSchools.location_info.postcode}` : `${schoolCount} found` }