Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
6d7bea411a
|
|||
|
7b01bb1118
|
@@ -31,70 +31,46 @@ export default class PlacesSidebar extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
get geoLink() {
|
|
||||||
if (!this.args.selectedPlace) return '#';
|
|
||||||
const p = this.args.selectedPlace;
|
|
||||||
// geo:lat,lon?q=lat,lon(Label)
|
|
||||||
const label = encodeURIComponent(
|
|
||||||
p.title ||
|
|
||||||
p.tags?.name ||
|
|
||||||
p.tags?.['name:en'] ||
|
|
||||||
'Location'
|
|
||||||
);
|
|
||||||
return `geo:${p.lat},${p.lon}?q=${p.lat},${p.lon}(${label})`;
|
|
||||||
}
|
|
||||||
|
|
||||||
get visibleGeoLink() {
|
|
||||||
if (!this.args.selectedPlace) return '';
|
|
||||||
const p = this.args.selectedPlace;
|
|
||||||
return `geo:${p.lat},${p.lon}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
@action
|
@action
|
||||||
async toggleSave(place) {
|
async toggleSave(place) {
|
||||||
if (!place) return;
|
if (!place) return;
|
||||||
|
|
||||||
if (place.createdAt) {
|
if (place.createdAt) {
|
||||||
// It's a saved bookmark -> Delete it
|
|
||||||
if (confirm(`Delete "${place.title}"?`)) {
|
if (confirm(`Delete "${place.title}"?`)) {
|
||||||
try {
|
try {
|
||||||
if (place.id && place.geohash) {
|
await this.storage.removePlace(place);
|
||||||
await this.storage.places.remove(place.id, place.geohash);
|
console.log('Place deleted:', place.title);
|
||||||
console.log('Place deleted:', place.title);
|
|
||||||
|
|
||||||
// Notify parent to refresh map bookmarks
|
// Notify parent to refresh map bookmarks
|
||||||
if (this.args.onBookmarkChange) {
|
if (this.args.onBookmarkChange) {
|
||||||
this.args.onBookmarkChange();
|
this.args.onBookmarkChange();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update selection to the new saved place object
|
// Update selection to the new saved place object
|
||||||
// This updates the local UI state immediately without a route refresh
|
// This updates the local UI state immediately without a route refresh
|
||||||
if (this.args.onUpdate) {
|
if (this.args.onUpdate) {
|
||||||
// When deleting, we revert to a "fresh" object or just close.
|
// When deleting, we revert to a "fresh" object or just close.
|
||||||
// Since we close the sidebar below, we might not strictly need to update local state,
|
// Since we close the sidebar below, we might not strictly need to update local state,
|
||||||
// but it's good practice.
|
// but it's good practice.
|
||||||
// Reconstruct the "original" place without ID/Geohash/CreatedAt
|
// Reconstruct the "original" place without ID/Geohash/CreatedAt
|
||||||
const freshPlace = {
|
const freshPlace = {
|
||||||
...place,
|
...place,
|
||||||
id: undefined,
|
id: undefined,
|
||||||
geohash: undefined,
|
geohash: undefined,
|
||||||
createdAt: undefined
|
createdAt: undefined
|
||||||
};
|
};
|
||||||
this.args.onUpdate(freshPlace);
|
this.args.onUpdate(freshPlace);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Also fire onSelect if it exists (for list view)
|
// Also fire onSelect if it exists (for list view)
|
||||||
if (this.args.onSelect) {
|
if (this.args.onSelect) {
|
||||||
// Similar logic for select if needed, but we usually close.
|
// Similar logic for select if needed, but we usually close.
|
||||||
this.args.onSelect(null);
|
this.args.onSelect(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close sidebar after delete
|
// Close sidebar after delete
|
||||||
if (this.args.onClose) {
|
if (this.args.onClose) {
|
||||||
this.args.onClose();
|
this.args.onClose();
|
||||||
}
|
|
||||||
} else {
|
|
||||||
alert('Cannot delete: Missing ID or Geohash');
|
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('Failed to delete:', e);
|
console.error('Failed to delete:', e);
|
||||||
@@ -115,7 +91,7 @@ export default class PlacesSidebar extends Component {
|
|||||||
};
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const savedPlace = await this.storage.places.store(placeData);
|
const savedPlace = await this.storage.storePlace(placeData);
|
||||||
console.log('Place saved:', placeData.title);
|
console.log('Place saved:', placeData.title);
|
||||||
|
|
||||||
// Notify parent to refresh map bookmarks
|
// Notify parent to refresh map bookmarks
|
||||||
|
|||||||
@@ -9,17 +9,14 @@ export default class PlaceRoute extends Route {
|
|||||||
async model(params) {
|
async model(params) {
|
||||||
const id = params.place_id;
|
const id = params.place_id;
|
||||||
|
|
||||||
// Check for explicit OSM prefixes
|
|
||||||
if (id.startsWith('osm:node:') || id.startsWith('osm:way:')) {
|
if (id.startsWith('osm:node:') || id.startsWith('osm:way:')) {
|
||||||
const [, type, osmId] = id.split(':');
|
const [, type, osmId] = id.split(':');
|
||||||
console.log(`Fetching explicit OSM ${type}:`, osmId);
|
console.log(`Fetching explicit OSM ${type}:`, osmId);
|
||||||
return this.loadOsmPlace(osmId, type);
|
return this.loadOsmPlace(osmId, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait for storage sync before checking bookmarks
|
|
||||||
await this.waitForSync();
|
await this.waitForSync();
|
||||||
|
|
||||||
// 1. Try to find in local bookmarks
|
|
||||||
let bookmark = this.storage.findPlaceById(id);
|
let bookmark = this.storage.findPlaceById(id);
|
||||||
|
|
||||||
if (bookmark) {
|
if (bookmark) {
|
||||||
@@ -27,9 +24,8 @@ export default class PlaceRoute extends Route {
|
|||||||
return bookmark;
|
return bookmark;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. Fallback: Fetch from OSM (assuming generic ID or old format)
|
console.warn('Not in bookmarks:', id);
|
||||||
console.log('Not in bookmarks, fetching from OSM:', id);
|
return null;
|
||||||
return this.loadOsmPlace(id);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async waitForSync() {
|
async waitForSync() {
|
||||||
|
|||||||
@@ -178,12 +178,26 @@ export default class StorageService extends Service {
|
|||||||
}
|
}
|
||||||
|
|
||||||
findPlaceById(id) {
|
findPlaceById(id) {
|
||||||
// Search by internal ID first
|
if (!id) return undefined;
|
||||||
let place = this.savedPlaces.find((p) => p.id === id);
|
const strId = String(id);
|
||||||
|
|
||||||
|
// Search by internal ID first (loose comparison via string cast)
|
||||||
|
let place = this.savedPlaces.find((p) => p.id && String(p.id) === strId);
|
||||||
if (place) return place;
|
if (place) return place;
|
||||||
|
|
||||||
// Then search by OSM ID
|
// Then search by OSM ID
|
||||||
place = this.savedPlaces.find((p) => p.osmId === id);
|
place = this.savedPlaces.find((p) => p.osmId && String(p.osmId) === strId);
|
||||||
return place;
|
return place;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async storePlace(placeData) {
|
||||||
|
const savedPlace = await this.places.store(placeData);
|
||||||
|
this.savedPlaces = [...this.savedPlaces, savedPlace];
|
||||||
|
return savedPlace;
|
||||||
|
}
|
||||||
|
|
||||||
|
async removePlace(place) {
|
||||||
|
await this.places.remove(place.id, place.geohash);
|
||||||
|
this.savedPlaces = this.savedPlaces.filter(p => p.id !== place.id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,20 +23,37 @@ export default class PlaceTemplate extends Component {
|
|||||||
// Let's use a modifier or just sync it.
|
// Let's use a modifier or just sync it.
|
||||||
|
|
||||||
get place() {
|
get place() {
|
||||||
// If we have a manually updated place (from save), use it.
|
// 1. Resolve the ID from the model (OSM ID or internal ID)
|
||||||
// Otherwise use the route model.
|
|
||||||
// We need to ensure we reset `localPlace` when navigating to a NEW place.
|
|
||||||
// Comparing IDs is a safe bet.
|
|
||||||
|
|
||||||
const model = this.args.model;
|
const model = this.args.model;
|
||||||
if (
|
const id = model.osmId || model.id;
|
||||||
this.localPlace &&
|
|
||||||
(this.localPlace.id === model.id || this.localPlace.osmId === model.osmId)
|
// 2. Check the storage service for a LIVE version of this bookmark
|
||||||
) {
|
// This is the most critical fix: Storage is the source of truth.
|
||||||
// If the local place is "richer" (has createdAt), prefer it.
|
// Since `this.storage.savedPlaces` is @tracked, this getter will re-compute
|
||||||
if (this.localPlace.createdAt && !model.createdAt) return this.localPlace;
|
// whenever a bookmark is added or removed.
|
||||||
// If we deleted it (local has no createdAt, model might?) - wait, if we delete, we close sidebar.
|
const saved = this.storage.findPlaceById(id);
|
||||||
|
if (saved) {
|
||||||
|
return saved;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 3. If not saved, check our local "optimistic" state (from handleUpdate)
|
||||||
|
// This handles the "unsaved" state immediately after deletion before any other sync
|
||||||
|
if (this.localPlace && (this.localPlace.osmId === id || this.localPlace.id === id)) {
|
||||||
|
return this.localPlace;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. Fallback to the route model (which might be the stale "saved" object from when the route loaded)
|
||||||
|
// If the model *has* a createdAt but we didn't find it in step 2 (storage),
|
||||||
|
// it means it was deleted. We must return a sanitized version.
|
||||||
|
if (model.createdAt) {
|
||||||
|
return {
|
||||||
|
...model,
|
||||||
|
id: undefined,
|
||||||
|
createdAt: undefined,
|
||||||
|
geohash: undefined
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
return model;
|
return model;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "marco",
|
"name": "marco",
|
||||||
"version": "1.4.0",
|
"version": "1.4.1",
|
||||||
"private": true,
|
"private": true,
|
||||||
"description": "Small description for marco goes here",
|
"description": "Small description for marco goes here",
|
||||||
"repository": "",
|
"repository": "",
|
||||||
|
|||||||
2
release/assets/main-DXDcwTAg.js
Normal file
2
release/assets/main-DXDcwTAg.js
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -6,7 +6,7 @@
|
|||||||
<meta name="description" content="">
|
<meta name="description" content="">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
|
||||||
<script type="module" crossorigin src="/assets/main-IB7GaxzK.js"></script>
|
<script type="module" crossorigin src="/assets/main-DXDcwTAg.js"></script>
|
||||||
<link rel="stylesheet" crossorigin href="/assets/main-B-vHK2y6.css">
|
<link rel="stylesheet" crossorigin href="/assets/main-B-vHK2y6.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|||||||
Reference in New Issue
Block a user