diff --git a/app/components/map.gjs b/app/components/map.gjs index f23e801..3d0e8f8 100644 --- a/app/components/map.gjs +++ b/app/components/map.gjs @@ -1099,6 +1099,20 @@ export default class MapComponent extends Component { } } + // Helper to transition with proper state + const transitionToPlace = (place) => { + // If we are currently in search mode OR have active search results, + // we want the "Back" button on the place details to return to the search results. + if ( + this.router.currentRouteName === 'search' || + (this.mapUi.currentSearch && this.mapUi.searchResults.length > 0) + ) { + this.mapUi.returnToSearch = true; + } + this.mapUi.preventNextZoom = true; + this.router.transitionTo('place', place); + }; + // Special handling when sidebar is OPEN if (this.args.isSidebarOpen) { // If it's a bookmark or search result, we allow "switching" to it even if sidebar is open @@ -1108,8 +1122,7 @@ export default class MapComponent extends Component { 'Clicked feature while sidebar open (switching):', targetPlace ); - this.mapUi.preventNextZoom = true; - this.router.transitionTo('place', targetPlace); + transitionToPlace(targetPlace); return; } @@ -1123,15 +1136,13 @@ export default class MapComponent extends Component { // Normal behavior (sidebar is closed) if (clickedBookmark) { console.debug('Clicked bookmark:', clickedBookmark); - this.mapUi.preventNextZoom = true; - this.router.transitionTo('place', clickedBookmark); + transitionToPlace(clickedBookmark); return; } if (clickedSearchResult) { console.debug('Clicked search result:', clickedSearchResult); - this.mapUi.preventNextZoom = true; - this.router.transitionTo('place', clickedSearchResult); + transitionToPlace(clickedSearchResult); return; } diff --git a/app/routes/search.js b/app/routes/search.js index da437ef..711a290 100644 --- a/app/routes/search.js +++ b/app/routes/search.js @@ -170,6 +170,10 @@ export default class SearchRoute extends Route { // Ensure pulse is stopped if we reach here this.mapUi.stopSearch(); this.mapUi.setSearchResults(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 }; } @action diff --git a/app/services/map-ui.js b/app/services/map-ui.js index 296fa5e..36dea1d 100644 --- a/app/services/map-ui.js +++ b/app/services/map-ui.js @@ -13,6 +13,7 @@ export default class MapUiService extends Service { @tracked selectionOptions = {}; @tracked preventNextZoom = false; @tracked searchResults = []; + @tracked currentSearch = null; selectPlace(place, options = {}) { this.selectedPlace = place; @@ -31,6 +32,7 @@ export default class MapUiService extends Service { clearSearchResults() { this.searchResults = []; + this.currentSearch = null; } startSearch() { diff --git a/app/templates/place.gjs b/app/templates/place.gjs index 155a3f1..942194c 100644 --- a/app/templates/place.gjs +++ b/app/templates/place.gjs @@ -77,9 +77,11 @@ export default class PlaceTemplate extends Component { navigateBack(place) { // The sidebar calls this with null when "Back" is clicked. if (place === null) { - // If we came from search results, go back in history - if (this.mapUi.returnToSearch) { - window.history.back(); + // If we have an active search context, return to it (UP navigation) + if (this.mapUi.returnToSearch && this.mapUi.currentSearch) { + this.router.transitionTo('search', { + queryParams: this.mapUi.currentSearch + }); } else { // Otherwise just close the sidebar (return to map index) this.router.transitionTo('index'); diff --git a/app/templates/search.gjs b/app/templates/search.gjs index 5412155..854f60a 100644 --- a/app/templates/search.gjs +++ b/app/templates/search.gjs @@ -11,6 +11,8 @@ export default class SearchTemplate extends Component { selectPlace(place) { if (place) { this.mapUi.returnToSearch = true; + // We don't need to manually set currentSearch here because + // it was already set in the route's setupController this.router.transitionTo('place', place); } } diff --git a/tests/acceptance/navigation-test.js b/tests/acceptance/navigation-test.js index e76d4af..a49153f 100644 --- a/tests/acceptance/navigation-test.js +++ b/tests/acceptance/navigation-test.js @@ -64,25 +64,24 @@ module('Acceptance | navigation', function (hooks) { this.owner.register('service:storage', MockStorageService); }); - test('navigating from search results to place and back uses history', async function (assert) { + test('navigating from search results to place and back returns to search', async function (assert) { const mapUi = this.owner.lookup('service:map-ui'); - const backStub = sinon.stub(window.history, 'back'); - try { - await visit('/search?lat=1&lon=1'); - assert.strictEqual(currentURL(), '/search?lat=1&lon=1'); + await visit('/search?lat=1&lon=1'); + assert.strictEqual(currentURL(), '/search?lat=1&lon=1'); - await click('.place-item'); - assert.ok(currentURL().includes('/place/'), 'Navigated to place'); - assert.true(mapUi.returnToSearch, 'Flag returnToSearch is set'); + await click('.place-item'); + assert.ok(currentURL().includes('/place/'), 'Navigated to place'); + assert.true(mapUi.returnToSearch, 'Flag returnToSearch is set'); - // Click the back button in the sidebar - await click('.back-btn'); + // Click the back button in the sidebar + await click('.back-btn'); - assert.true(backStub.calledOnce, 'window.history.back() was called'); - } finally { - backStub.restore(); - } + assert.strictEqual( + currentURL(), + '/search?lat=1&lon=1', + 'Returned to search results' + ); }); test('closing the sidebar resets the returnToSearch flag', async function (assert) { diff --git a/tests/unit/utils/osm-icons-test.js b/tests/unit/utils/osm-icons-test.js index 93e9869..c9d41e7 100644 --- a/tests/unit/utils/osm-icons-test.js +++ b/tests/unit/utils/osm-icons-test.js @@ -27,9 +27,9 @@ module('Unit | Utility | osm-icons', function () { assert.strictEqual(result, 'shopping-basket'); }); - test('it returns shopping-basket for unknown shop types (catch-all)', function (assert) { + test('it returns shopping-bag for unknown shop types (catch-all)', function (assert) { let result = getIconNameForTags({ shop: 'unknown_shop_type' }); - assert.strictEqual(result, 'shopping-basket'); + assert.strictEqual(result, 'shopping-bag'); }); test('it returns null for unknown tags', function (assert) {