From 83461b07486da3ba977b341483889075adbe964e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A2u=20Cao?= Date: Fri, 16 Jan 2026 12:08:56 +0700 Subject: [PATCH] Fix sidebar content switching --- app/components/map.gjs | 78 ++++++++++++++++------------- app/components/places-sidebar.gjs | 83 ++++++++++++------------------- app/templates/application.gjs | 8 ++- 3 files changed, 81 insertions(+), 88 deletions(-) diff --git a/app/components/map.gjs b/app/components/map.gjs index 2b743dd..3450b2b 100644 --- a/app/components/map.gjs +++ b/app/components/map.gjs @@ -74,8 +74,9 @@ export default class MapComponent extends Component { this.loadBookmarks(); }); - this.storage.places.on('change', (event) => { - // Ideally we would only update the changed one, but refreshing all is safer for now + // Listen to changes in the /places/ scope + this.storage.rs.scope('/places/').on('change', (event) => { + console.log('RemoteStorage change detected:', event); this.loadBookmarks(); }); }); @@ -106,49 +107,56 @@ export default class MapComponent extends Component { } handleMapClick = async (event) => { - // 0. Handle closing sidebar if open and clicked on empty map area + // Check if user clicked on a rendered feature (POI or Bookmark) FIRST + const features = this.mapInstance.getFeaturesAtPixel(event.pixel); + let clickedBookmark = null; + let selectedFeatureName = null; + let selectedFeatureType = null; + + if (features && features.length > 0) { + const bookmarkFeature = features.find(f => f.get('isBookmark')); + if (bookmarkFeature) { + clickedBookmark = bookmarkFeature.get('originalPlace'); + } + // Also get visual props for standard map click logic later + const props = features[0].getProperties(); + if (props.name) { + selectedFeatureName = props.name; + selectedFeatureType = props.class || props.subclass; + } + } + + // Special handling when sidebar is OPEN if (this.args.isSidebarOpen) { - // We can just trigger the outside click and return. - // However, if the user clicked on a feature, maybe they want to switch selection? - // The requirement says "when clicking on the map while the sidebar is open, it should close the sidebar instead of executing the normal map click logic" - // This implies strict closing behavior. + // If it's a bookmark, we allow "switching" to it even if sidebar is open + if (clickedBookmark) { + console.log("Clicked bookmark while sidebar open (switching):", clickedBookmark); + if (this.args.onPlacesFound) { + this.args.onPlacesFound([], clickedBookmark); + } + return; + } + + // Otherwise (empty map or non-bookmark feature), close the sidebar if (this.args.onOutsideClick) { this.args.onOutsideClick(); } return; } + // Normal behavior (sidebar is closed) + if (clickedBookmark) { + console.log("Clicked bookmark:", clickedBookmark); + if (this.args.onPlacesFound) { + this.args.onPlacesFound([], clickedBookmark); + } + return; + } + const coords = toLonLat(event.coordinate); const [lon, lat] = coords; - // 1. Check if user clicked on a rendered feature (POI or Bookmark) - const features = this.mapInstance.getFeaturesAtPixel(event.pixel); - let selectedFeatureName = null; - let selectedFeatureType = null; - let clickedBookmark = null; - - if (features && features.length > 0) { - // Prioritize bookmarks if clicked - const bookmarkFeature = features.find(f => f.get('isBookmark')); - if (bookmarkFeature) { - clickedBookmark = bookmarkFeature.get('originalPlace'); - console.log("Clicked bookmark:", clickedBookmark); - - // Notify parent to show bookmark details - if (this.args.onPlacesFound) { - // We pass it as a "selectedPlace" but with an empty list of nearby items since it's a specific bookmark - this.args.onPlacesFound([], clickedBookmark); - } - return; // Stop processing to avoid fetching OSM data for a known bookmark - } - - const props = features[0].getProperties(); - if (props.name) { - selectedFeatureName = props.name; - selectedFeatureType = props.class || props.subclass; // e.g., 'cafe' - console.log(`Clicked visual feature: "${selectedFeatureName}" (${selectedFeatureType})`); - } - } + // ... continue with normal OSM fetch logic ... // 2. Fetch authoritative data via Overpass try { diff --git a/app/components/places-sidebar.gjs b/app/components/places-sidebar.gjs index f25ff1a..e4ca2b7 100644 --- a/app/components/places-sidebar.gjs +++ b/app/components/places-sidebar.gjs @@ -8,31 +8,26 @@ import or from 'ember-truth-helpers/helpers/or'; export default class PlacesSidebar extends Component { @service storage; - @tracked selectedPlace = null; - constructor() { - super(...arguments); - // If a specific place was passed in (pre-selected by map), show it immediately - if (this.args.initialPlace) { - this.selectedPlace = this.args.initialPlace; + @action + selectPlace(place) { + if (this.args.onSelect) { + this.args.onSelect(place); } } - @action - selectPlace(place) { - this.selectedPlace = place; - } - @action clearSelection() { - this.selectedPlace = null; - // If we were initialized with a single place (direct click), - // going "back" might mean closing or showing the list if available. - // Logic: if we have a list (@places), go back to list. - // If we only had one place (@initialPlace) and no list, maybe close? - // For now, assuming @places is always passed if we want a list fallback. + // Going "back" clears the specific selection but keeps the sidebar open (showing list) + if (this.args.onSelect) { + this.args.onSelect(null); + } + + // Fallback logic: if no list available, close sidebar if (!this.args.places || this.args.places.length === 0) { - this.args.onClose(); + if (this.args.onClose) { + this.args.onClose(); + } } } @@ -44,16 +39,11 @@ export default class PlacesSidebar extends Component { // It's a saved bookmark -> Delete it if (confirm(`Delete "${place.title}"?`)) { try { - // We need geohash to delete. - // Existing bookmarks have it. - // If for some reason it's missing (shouldn't happen for saved items), we can't delete easily. if (place.id && place.geohash) { await this.storage.places.remove(place.id, place.geohash); console.log('Place deleted:', place.title); - // Close sidebar after delete since the item is gone from "Saved" context - // Or we could revert to "Save" state if we had the original POI data, - // but usually we just close or show "Nearby". + // Close sidebar after delete if (this.args.onClose) { this.args.onClose(); } @@ -67,8 +57,6 @@ export default class PlacesSidebar extends Component { } } else { // It's a fresh POI -> Save it - - // Map Overpass POI to our Place schema const placeData = { title: place.tags.name || place.tags['name:en'] || 'Untitled Place', lat: place.lat, @@ -76,23 +64,15 @@ export default class PlacesSidebar extends Component { tags: [], url: place.tags.website, osmId: String(place.id), - // We rely on the module to generate ID and Geohash }; try { const savedPlace = await this.storage.places.store(placeData); console.log('Place saved:', placeData.title); - // Update the selected place in the UI to be the saved bookmark - // (so the button turns to "Saved") - // We can update the local tracked property if we are viewing a single item - // or let the parent update. - // Ideally, we switch `this.selectedPlace` to the `savedPlace` returned by the store. - this.selectedPlace = savedPlace; - - // Notify parent if needed (map will auto-update via events) - if (this.args.onBookmarkSaved) { - this.args.onBookmarkSaved(); + // Update selection to the new saved place object + if (this.args.onSelect) { + this.args.onSelect(savedPlace); } } catch (error) { console.error('Failed to save place:', error); @@ -104,7 +84,7 @@ export default class PlacesSidebar extends Component {