Clear search with no results when closing drawer #106

Merged
raucao merged 1 commits from chore/clear_empty_search into master 2026-09-17 21:05:07 +00:00
6 changed files with 109 additions and 7 deletions
+12
View File
@@ -176,6 +176,18 @@ export default class SearchController extends Controller {
return saved || p;
});
// A search with results is a restorable context (e.g. for "up" navigation
// from place details). Empty searches are intentionally not restorable, so
// they don't reopen an invisible "no results" drawer later on.
if (pois.length > 0) {
this.mapUi.currentSearch = {
q: params.q,
category: params.category,
lat: params.lat,
lon: params.lon,
};
}
const targetName = params.selected || params.q;
if (targetName && pois.length > 0) {
-4
View File
@@ -24,10 +24,6 @@ export default class SearchRoute extends Route {
// Trigger the background task to fetch results
controller.fetchResultsTask.perform(model);
// Store current search params to allow "Up" navigation from place details
const { q, category, lat, lon } = this.paramsFor('search');
this.mapUi.currentSearch = { q, category, lat, lon };
}
resetController(controller, isExiting) {
+3
View File
@@ -72,6 +72,9 @@ export default class ApplicationComponent extends Component {
} else {
this.router.transitionTo('index');
}
} else if (name === 'search' && this.mapUi.searchResults.length === 0) {
// An empty search has no markers worth keeping, so clear the route
this.router.replaceWith('index');
}
}
}
+8 -2
View File
@@ -18,14 +18,20 @@ export default class SearchTemplate extends Component {
this.mapUi.showSidebar();
this.mapUi.preventNextZoom = true;
// We don't need to manually set currentSearch here because
// it was already set in the route's setupController
// it was already set in the search controller
this.router.transitionTo('place', place);
}
}
@action
close() {
this.mapUi.hideSidebar();
// With no results there is nothing to keep around (no map markers), so
// dismissing the drawer clears the search route entirely.
if (this.mapUi.searchResults.length === 0) {
this.router.replaceWith('index');
} else {
this.mapUi.hideSidebar();
}
}
<template>
+43
View File
@@ -129,4 +129,47 @@ module('Acceptance | navigation', function (hooks) {
backStub.restore();
}
});
test('an empty search is not restored when navigating back from a place', async function (assert) {
const mapUi = this.owner.lookup('service:map-ui');
// Nearby search that yields no results, but with a fetchable place
this.owner.register(
'service:osm',
class extends Service {
async getNearbyPois() {
return [];
}
async fetchOsmObject(id, type) {
return {
osmId: id,
osmType: type,
lat: 1,
lon: 1,
osmTags: { name: 'Test Place', amenity: 'cafe' },
title: 'Test Place',
};
}
}
);
await visit('/search?lat=1&lon=1');
assert.strictEqual(
mapUi.currentSearch,
null,
'Empty search is not restorable'
);
// Simulate opening a place while the (empty) search route is active
mapUi.returnToSearch = true;
await visit('/place/osm:node:123');
await click('.back-btn');
assert.strictEqual(
currentURL(),
'/',
'Back navigation does not reopen the empty search'
);
});
});
+43 -1
View File
@@ -1,5 +1,5 @@
import { module, test } from 'qunit';
import { visit, currentURL } from '@ember/test-helpers';
import { visit, currentURL, click } from '@ember/test-helpers';
import { setupApplicationTest } from 'marco/tests/helpers';
import Service from '@ember/service';
@@ -342,4 +342,46 @@ module('Acceptance | search', function (hooks) {
.dom('.search-input')
.hasValue('', 'Search input is cleared on transitioning to index');
});
test('closing the drawer clears the search route when there are no results', async function (assert) {
class MockPhotonService extends Service {
async search() {
return [];
}
}
this.owner.register('service:photon', MockPhotonService);
class MockStorageService extends Service {
savedPlaces = [];
findPlaceById() {
return null;
}
isPlaceSaved() {
return false;
}
rs = { on: () => {} };
placesInView = [];
loadPlacesInBounds() {
return Promise.resolve();
}
}
this.owner.register('service:storage', MockStorageService);
const mapUi = this.owner.lookup('service:map-ui');
await visit('/search?q=nowhere');
assert.dom('.empty-state').hasText('No results found.');
assert.strictEqual(
mapUi.currentSearch,
null,
'An empty search is not kept as a restorable search context'
);
await click('.close-btn');
assert.dom('.sidebar').doesNotExist('Sidebar should be closed');
assert.strictEqual(currentURL(), '/', 'Search route is cleared');
assert.strictEqual(mapUi.searchResults.length, 0, 'Results are cleared');
});
});