import Component from '@glimmer/component'; import { service } from '@ember/service'; import { tracked } from '@glimmer/tracking'; import { action } from '@ember/object'; import { on } from '@ember/modifier'; import { fn } from '@ember/helper'; import { debounce } from '@ember/runloop'; import Icon from '#components/icon'; export default class SearchBoxComponent extends Component { @service photon; @service router; @service mapUi; @service map; // Assuming we might need map context, but mostly we use router @tracked query = ''; @tracked results = []; @tracked isFocused = false; @tracked isLoading = false; get showPopover() { return this.isFocused && this.results.length > 0; } @action handleInput(event) { this.query = event.target.value; if (this.query.length < 2) { this.results = []; return; } debounce(this, this.performSearch, 300); } async performSearch() { if (this.query.length < 2) return; this.isLoading = true; try { // Use map center if available for location bias let lat, lon; if (this.mapUi.currentCenter) { ({ lat, lon } = this.mapUi.currentCenter); } const results = await this.photon.search(this.query, lat, lon); this.results = results; } catch (e) { console.error('Search failed', e); this.results = []; } finally { this.isLoading = false; } } @action handleFocus() { this.isFocused = true; if (this.query.length >= 2 && this.results.length === 0) { this.performSearch(); } } @action handleBlur() { // Delay hiding so clicks on results can register setTimeout(() => { this.isFocused = false; }, 200); } @action handleSubmit(event) { event.preventDefault(); if (!this.query) return; let queryParams = { q: this.query, selected: null }; if (this.mapUi.currentCenter) { const { lat, lon } = this.mapUi.currentCenter; queryParams.lat = parseFloat(lat).toFixed(4); queryParams.lon = parseFloat(lon).toFixed(4); } this.router.transitionTo('search', { queryParams }); this.isFocused = false; } @action selectResult(place) { this.query = place.title; this.results = []; // Hide popover // If it has an OSM ID, go to place details if (place.osmId) { // Format: osm:node:123 // place.osmType is already normalized to 'node', 'way', or 'relation' by PhotonService const id = `osm:${place.osmType}:${place.osmId}`; this.router.transitionTo('place', id); } else { // Just a location (e.g. from Photon without OSM ID, though unlikely for Photon) // Or we can treat it as a search query this.router.transitionTo('search', { queryParams: { q: place.title, lat: place.lat, lon: place.lon, selected: null, }, }); } } @action clear() { this.query = ''; this.results = []; this.router.transitionTo('index'); // Or stay on current page? // Usually clear just clears the input. } }