diff --git a/src/features/filters/components/filters-aside/filters-aside.client.test.tsx b/src/features/filters/components/filters-aside/filters-aside.client.test.tsx
index fa943b7d..5af63cf4 100644
--- a/src/features/filters/components/filters-aside/filters-aside.client.test.tsx
+++ b/src/features/filters/components/filters-aside/filters-aside.client.test.tsx
@@ -62,6 +62,27 @@ afterEach(() => {
});
describe('main filter panel', () => {
+ it('opens continent search without applying Africa or navigating before a choice', async () => {
+ Element.prototype.scrollIntoView = vi.fn();
+ const user = userEvent.setup();
+ const continents: FilterConfigSchema = {
+ ...configs[0],
+ kind: 'SEARCH',
+ label: 'Continent',
+ paramKey: 'continents',
+ options: [
+ { label: 'Africa', value: 'africa' },
+ { label: 'Europe', value: 'europe' },
+ ],
+ };
+ render();
+ await user.click(screen.getByRole('button', { name: 'Continent' }));
+ const search = screen.getByPlaceholderText('Search continent...');
+ await user.type(search, 'Europe');
+ expect(search).toHaveValue('Europe');
+ expect(setParam).not.toHaveBeenCalled();
+ });
+
it('offers previously hidden filters directly and applies the chosen option without selecting a default first', async () => {
const user = userEvent.setup();
render();
diff --git a/src/features/filters/server/dtos/dto-to-filter-config.test.ts b/src/features/filters/server/dtos/dto-to-filter-config.test.ts
index d29fb1b6..25f6bd9e 100644
--- a/src/features/filters/server/dtos/dto-to-filter-config.test.ts
+++ b/src/features/filters/server/dtos/dto-to-filter-config.test.ts
@@ -25,7 +25,7 @@ const locationConfig = (position: number, label: string, paramKey: string) => ({
});
describe('dtoToFilterConfig location facets', () => {
- it('keeps each geographic dimension distinct and suggested', () => {
+ it('keeps each geographic dimension searchable even with only two options', () => {
const result = dtoToFilterConfig({
countries: locationConfig(1, 'Country', 'countries'),
regions: locationConfig(2, 'Region', 'regions'),
@@ -64,6 +64,7 @@ describe('dtoToFilterConfig location facets', () => {
]),
);
for (const config of result) {
+ expect(config.kind).toBe('SEARCH');
if (!('options' in config)) continue;
for (const option of config.options) {
expect(option.value).toMatch(/^[a-z0-9]+(?:-[a-z0-9]+)*$/);
diff --git a/src/features/filters/server/dtos/dto-to-filter-config.ts b/src/features/filters/server/dtos/dto-to-filter-config.ts
index 209e5bb3..fc435250 100644
--- a/src/features/filters/server/dtos/dto-to-filter-config.ts
+++ b/src/features/filters/server/dtos/dto-to-filter-config.ts
@@ -101,6 +101,15 @@ const SUGGESTED_RANGE_PARAM_KEYS = new Set([
'maxActiveLeads',
]);
+// Geography controls stay searchable even when only a few places are available.
+const SEARCHABLE_LOCATION_PARAM_KEYS = new Set([
+ PARAM_KEYS.CITIES,
+ PARAM_KEYS.REGIONS,
+ PARAM_KEYS.COUNTRIES,
+ PARAM_KEYS.CONTINENTS,
+ PARAM_KEYS.TIMEZONES,
+]);
+
const RADIO_FILTER_OPTION_THRESHOLD = 6;
const CHECKBOX_FILTER_OPTION_THRESHOLD = 6;
const SELECT_OPTION_THRESHOLD = 2;
@@ -317,7 +326,11 @@ const handleMultiSelect = (
const normalizedDto = withRequiredRemoteWorkModes(dto);
// Get rid of issues where options look borked
+ const searchableLocation = SEARCHABLE_LOCATION_PARAM_KEYS.has(
+ normalizedDto.paramKey,
+ );
const minimumOptions =
+ searchableLocation ||
normalizedDto.paramKey === PARAM_KEYS.COLLABORATION_HOURS
? 1
: SELECT_OPTION_THRESHOLD;
@@ -325,6 +338,7 @@ const handleMultiSelect = (
if (hasNoOptions) return null;
const isCheckbox =
+ !searchableLocation &&
normalizedDto.options.length <= CHECKBOX_FILTER_OPTION_THRESHOLD;
const baseFilter = isCheckbox
? dtoToCheckboxFilterConfig(normalizedDto)