Ensure map marker clicks preserve search context
Fixes the back button just closing the sidebar and clearing the whole search after having seleted a result via map marker
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user