diff --git a/package.json b/package.json index ce54b023..38007a78 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "version": "0.0.1", "scripts": { "ng": "ng", - "start": "ng serve", + "start": "npx ng serve --proxy-config proxy.conf.json", "build": "ng build", "test": "ng test", "lint": "ng lint", @@ -62,4 +62,4 @@ "tslint": "~6.1.0", "typescript": "~4.1.6" } -} +} \ No newline at end of file diff --git a/proxy.conf.json b/proxy.conf.json new file mode 100644 index 00000000..bd20e145 --- /dev/null +++ b/proxy.conf.json @@ -0,0 +1,10 @@ +{ + "/api": { + "target": "https://api.testing.opensensemap.org", + "secure": true, + "changeOrigin": true, + "pathRewrite": { + "^/api": "" + } + } +} \ No newline at end of file diff --git a/src/app/@types/Location.ts b/src/app/@types/Location.ts new file mode 100644 index 00000000..2517905f --- /dev/null +++ b/src/app/@types/Location.ts @@ -0,0 +1,5 @@ +export interface Location { + timestamp: string; + coordinats: number[]; + type: string; +} \ No newline at end of file diff --git a/src/app/@types/LocationIq.ts b/src/app/@types/LocationIq.ts new file mode 100644 index 00000000..4c54c44c --- /dev/null +++ b/src/app/@types/LocationIq.ts @@ -0,0 +1,71 @@ +/** + * Location IQ Search Request Interface + * + * @export + * @interface LocationIqSearchRequest + */ +export interface LocationIqSearchRequest { + q?: string; + street?: string; + city?: string; + county?: string; + state?: string; + country?: string; + postalcode?: string; + viewbox?: string; + bounded?: string; + addressdetails?: boolean; + limit?: string; + acceptLanguage?: string; + countrycodes?: string; + namedetails?: string; + dedupe?: string; + polygon_geojson?: string; + polygon_kml?: string; + polygon_svg?: string; + polygon_text?: string; + extratags?: string; + excludePlaceIds?: string; + normalizecity?: string; +} + +/** + * * Location IQ Search Result Interface + * + * @export + * @interface LocationIqSearchResult + */ +export interface LocationIqSearchResult { + place_id?: string; + licence?: string; + osm_type?: string; + osm_id?: string; + boundingbox?: any[]; + lat?: number; + lon?: number; + display_name?: string; + class?: string; + type?: string; + importance?: string; + icon?: string; + address?: string; + extratags?: string; + namedetails?: string; + geojson?: string; + geokml?: string; + svg?: string; + geotext?: string; +} + +/** + * * Location IQ Search Response Interface + * + * @export + * @interface LocationIqSearchResponse + */ +export interface LocationIqSearchResponse { + status: number; + total?: number; + error?: string; + results?: LocationIqSearchResponse[] +} \ No newline at end of file diff --git a/src/app/@types/SearchResult.ts b/src/app/@types/SearchResult.ts new file mode 100644 index 00000000..afd3b02a --- /dev/null +++ b/src/app/@types/SearchResult.ts @@ -0,0 +1,7 @@ +import { Location } from "./Location"; + +export interface SearchResult { + _id: string; + name: string; + currentLocation: Location; +} \ No newline at end of file diff --git a/src/app/models/ui/state/ui.service.ts b/src/app/models/ui/state/ui.service.ts index 38c49937..0bf76a2e 100644 --- a/src/app/models/ui/state/ui.service.ts +++ b/src/app/models/ui/state/ui.service.ts @@ -5,6 +5,7 @@ import { ColorHelper } from '@swimlane/ngx-charts'; import { HttpClient, HttpParams } from '@angular/common/http'; import { first, tap } from 'rxjs/operators'; import { environment } from './../../../../environments/environment'; +import { SearchResult } from 'src/app/@types/SearchResult'; @Injectable({ providedIn: 'root' }) @@ -16,30 +17,35 @@ export class UiService { constructor( - private uiStore: UiStore, + private uiStore: UiStore, private http: HttpClient) { } fetchStats() { - return this.http.get(`${environment.api_url}/stats`).pipe(tap(stats => { - this.uiStore.update(state => ({ ...state , stats: { totalBoxes: stats[0], totalMeasurements: stats[1]} })) + this.uiStore.update(state => ({ ...state, stats: { totalBoxes: stats[0], totalMeasurements: stats[1] } })) })); } - - - fetchGeocodeResults(searchstring){ + fetchGeocodeResults(searchstring) { const params = new HttpParams() .set('format', "json") .set('key', this.LOCATIONIQ_TOKEN) .set('addressdetails', "1") .set('limit', "4") .set('q', searchstring) - - return this.http.get("//locationiq.org/v1/search.php", {params: params}).pipe(first()).pipe(tap((res:any) => { - this.uiStore.update(state => ({ ...state , locationAutocompleteResults: res })) + return this.http.get("//locationiq.org/v1/search.php", { params: params }).pipe(first()).pipe(tap((res: any) => { + this.uiStore.update(state => ({ ...state, locationAutocompleteResults: res })) + })); + } + + fetchDevices(searchstring) { + const params = new HttpParams() + .set('name', searchstring) + + return this.http.get(`${environment.api_url}/boxes`, { params: params }).pipe(tap((results: SearchResult[]) => { + this.setSearchResults(results); })); } @@ -47,11 +53,11 @@ export class UiService { this.uiStore.update(ui); } - updateColors(colors: ColorHelper){ - this.uiStore.update({colors: colors}); + updateColors(colors: ColorHelper) { + this.uiStore.update({ colors: colors }); } - setActiveSensorTypes(types){ + setActiveSensorTypes(types) { this.uiStore.setActiveSensorTypes(types); } @@ -59,7 +65,7 @@ export class UiService { this.uiStore.updateSelectedPheno(pheno); } - setLayers(layers){ + setLayers(layers) { this.uiStore.setLayers(layers); } @@ -85,129 +91,159 @@ export class UiService { updateEndDateChart(date) { this.uiStore.updateEndDateChart(date); } - setSelectedDate(date){ + setSelectedDate(date) { this.uiStore.updateSelectedDate(date); } - updateActiveTimeMode(mode){ - this.uiStore.update( state => ({ ...state , activeTimeMode: mode })); + updateActiveTimeMode(mode) { + this.uiStore.update(state => ({ ...state, activeTimeMode: mode })); } - setLanguage(lang){ + setLanguage(lang) { this.uiStore.setLanguage(lang); } - setTheme(theme){ + setTheme(theme) { this.uiStore.setTheme(theme); } - updateBaseLayer(layer){ + updateBaseLayer(layer) { console.log("UPDATING BASE LAYER") this.uiStore.updateBaseLayer(layer); } - - toggleFilterVisible(){ - this.uiStore.update( state => ({ ...state , fitlerVisible: !state.fitlerVisible })); + + toggleFilterVisible() { + this.uiStore.update(state => ({ ...state, fitlerVisible: !state.fitlerVisible })); } - setFilterVisible(filter){ - this.uiStore.update( state => ({ ...state , fitlerVisible: filter })); + setFilterVisible(filter) { + this.uiStore.update(state => ({ ...state, fitlerVisible: filter })); } - setSearchTerm(searchTerm){ - this.uiStore.update( state => ({ ...state , searchTerm: searchTerm })); + setSearchTerm(searchTerm) { + this.uiStore.update(state => ({ ...state, searchTerm: searchTerm })); } - setSearchResults(results){ - this.uiStore.update( state => ({ ...state , searchResults: results })); + setSearchResults(results) { + this.uiStore.update(state => ({ ...state, searchResults: results })); } - setClustering(clustering){ - this.uiStore.update( state => ( - {...state, baseLayer: + setClustering(clustering) { + this.uiStore.update(state => ( + { + ...state, baseLayer: + { + ...state.baseLayer, + layout: + { + ...state.baseLayer.layout, + visibility: clustering ? 'none' : 'visible' + } + } + })); + this.uiStore.update(state => ( + { + ...state, clusterLayers: [ + { + ...state.clusterLayers[0], layout: + { + ...state.baseLayer.layout, + visibility: clustering && !state.selectedDate ? 'visible' : 'none' + } + }, + { + ...state.clusterLayers[1], layout: + { + ...state.baseLayer.layout, + visibility: clustering && !state.selectedDate ? 'visible' : 'none' + } + } + + ] + })); + + this.uiStore.update(state => ({ ...state, clustering: clustering })); + } + toggleClustering() { + this.uiStore.update(state => ( + { + ...state, baseLayer: + { + ...state.baseLayer, + layout: + { + ...state.baseLayer.layout, + visibility: state.clustering ? 'none' : 'visible' + } + } + })); + + + this.uiStore.update(state => ( + { + ...state, clusterLayers: [ { - ...state.baseLayer, - layout: - {...state.baseLayer.layout, - visibility: clustering ? 'none' : 'visible'}}})); - this.uiStore.update( state => ( - {...state, clusterLayers: [ - {...state.clusterLayers[0], layout: - {...state.baseLayer.layout, - visibility: clustering && !state.selectedDate ? 'visible' : 'none'}}, - {...state.clusterLayers[1], layout: - {...state.baseLayer.layout, - visibility: clustering && !state.selectedDate ? 'visible' : 'none'}} - - ]} )); - - this.uiStore.update( state => ({ ...state , clustering: clustering })); - } - toggleClustering(){ - this.uiStore.update( state => ( - {...state, baseLayer: + ...state.clusterLayers[0], layout: + { + ...state.baseLayer.layout, + visibility: !state.clustering && !state.selectedDate ? 'visible' : 'none' + } + }, { - ...state.baseLayer, - layout: - {...state.baseLayer.layout, - visibility: state.clustering ? 'none' : 'visible'}}})); - - - this.uiStore.update( state => ( - {...state, clusterLayers: [ - {...state.clusterLayers[0], layout: - {...state.baseLayer.layout, - visibility: !state.clustering && !state.selectedDate ? 'visible' : 'none'}}, - {...state.clusterLayers[1], layout: - {...state.baseLayer.layout, - visibility: !state.clustering && !state.selectedDate ? 'visible' : 'none'}} - - ]} + ...state.clusterLayers[1], layout: + { + ...state.baseLayer.layout, + visibility: !state.clustering && !state.selectedDate ? 'visible' : 'none' + } + } + + ] + } )); - this.uiStore.update( state => ({ ...state , clustering: !state.clustering })); + this.uiStore.update(state => ({ ...state, clustering: !state.clustering })); } - toggleCircles(){ - this.uiStore.update( state => ({ ...state , circles: !state.circles })); + toggleCircles() { + this.uiStore.update(state => ({ ...state, circles: !state.circles })); } - toggleNumbers(){ - this.uiStore.update( state => ({ ...state , numbers: !state.numbers })); + toggleNumbers() { + this.uiStore.update(state => ({ ...state, numbers: !state.numbers })); } - setNumbers(numbers){ - this.uiStore.update( state => ({ ...state , numbers: numbers })); + setNumbers(numbers) { + this.uiStore.update(state => ({ ...state, numbers: numbers })); } - setCluster(cluster){ - if(!cluster){ + setCluster(cluster) { + if (!cluster) { this.clusterTimeout = setTimeout(() => { - this.uiStore.update( state => ({ ...state , cluster: cluster })); - },250) + this.uiStore.update(state => ({ ...state, cluster: cluster })); + }, 250) } else { clearTimeout(this.clusterTimeout); - this.uiStore.update( state => ({ ...state , cluster: cluster })); + this.uiStore.update(state => ({ ...state, cluster: cluster })); } } - setInfoPheno(infoPheno){ - this.uiStore.update( state => ({ ...state, infoPheno: infoPheno})); + setInfoPheno(infoPheno) { + this.uiStore.update(state => ({ ...state, infoPheno: infoPheno })); } - setFilters(filters){ - this.uiStore.update( state => ({...state, filters: filters})) + setFilters(filters) { + this.uiStore.update(state => ({ ...state, filters: filters })) } - setReloadMapData(mapData){ - this.uiStore.update( state => ({...state, reloadMapData: mapData})) + setReloadMapData(mapData) { + this.uiStore.update(state => ({ ...state, reloadMapData: mapData })) } - setMapLoading(mapLoading){ - this.uiStore.update( state => ({ ...state , mapLoading: mapLoading })); + setMapLoading(mapLoading) { + this.uiStore.update(state => ({ ...state, mapLoading: mapLoading })); } - setShowDateModal(showDateModal){ - this.uiStore.update( state => ({ ...state , showDateModal: showDateModal })); + setShowDateModal(showDateModal) { + this.uiStore.update(state => ({ ...state, showDateModal: showDateModal })); } - updateLegend(steps){ + updateLegend(steps) { this.uiStore.updateLegend(steps); } - setFilterIds(ids){ - this.uiStore.update( state => ({ ...state, filters: {...state.filters, ids: ids}})) + setFilterIds(ids) { + this.uiStore.update(state => ({ ...state, filters: { ...state.filters, ids: ids } })) } - setActiveTab(tab){ - this.uiStore.update( state => ({ ...state, activeTab: tab})) + setActiveTab(tab) { + this.uiStore.update(state => ({ ...state, activeTab: tab })) } - setChartLoading(loading){ - this.uiStore.update( state => ({ ...state, chartLoading: loading})) + setChartLoading(loading) { + this.uiStore.update(state => ({ ...state, chartLoading: loading })) } } diff --git a/src/app/models/ui/state/ui.store.ts b/src/app/models/ui/state/ui.store.ts index 279502a1..befecb15 100644 --- a/src/app/models/ui/state/ui.store.ts +++ b/src/app/models/ui/state/ui.store.ts @@ -5,6 +5,7 @@ import { ColorHelper } from '@swimlane/ngx-charts'; import { clusterLayerSolo, clusterLayer } from './layers'; import { Filter } from '../../filter/filter.model'; import { state } from '@angular/animations'; +import { SearchResult } from "../../../@types/SearchResult"; // Should contain all variables to describe the state of the ui export interface UiState { @@ -23,8 +24,9 @@ export interface UiState { clusterLayers: any, fitlerVisible: boolean, searchTerm: string, - searchResults: any[], + searchResults: SearchResult[], locationAutocompleteResults: any[], + autoCompleteResults: any[], clustering: boolean, cluster: any, numbers: boolean, @@ -51,11 +53,11 @@ export function createInitialState(): UiState { selectedDate: null, language: 'de-DE', theme: 'light', - baseLayer: { + baseLayer: { 'id': 'base-layer', 'type': 'circle', 'source': 'boxes', - 'filter': ["!=", null, [ "get", "Temperatur", ["object", ["get", "live", ["object", ["get", "sensors"]]]]]], + 'filter': ["!=", null, ["get", "Temperatur", ["object", ["get", "live", ["object", ["get", "sensors"]]]]]], 'paint': { 'circle-radius': { 'base': 2, @@ -64,7 +66,7 @@ export function createInitialState(): UiState { 'circle-color': [ 'interpolate', ['linear'], - [ "get", "Temperatur", ["object", ["get", "live", ["object", ["get", "sensors"]]]]], + ["get", "Temperatur", ["object", ["get", "live", ["object", ["get", "sensors"]]]]], -5, '#9900cc', 0, '#0000ff', 10, '#0099ff', @@ -72,9 +74,9 @@ export function createInitialState(): UiState { 30, '#ff0000' ] }, - 'layout' : { + 'layout': { visibility: 'none' - } + } }, layers: [{ 'id': 'base-layer', @@ -82,28 +84,29 @@ export function createInitialState(): UiState { 'source': 'boxes', 'filter': ["!=", 'old', ["get", "state"]], 'paint': { - 'circle-radius': { - 'base': 2, - 'stops': [[1,6], [22, 3000]] - }, - 'circle-stroke-width': 1, - 'circle-stroke-color': '#383838', - - // 'circle-blur': 0.8, - 'circle-color': [ - 'match', - ['get', 'state'], - 'active', '#4EAF47', - 'old', '#eb5933', + 'circle-radius': { + 'base': 2, + 'stops': [[1, 6], [22, 3000]] + }, + 'circle-stroke-width': 1, + 'circle-stroke-color': '#383838', + + // 'circle-blur': 0.8, + 'circle-color': [ + 'match', + ['get', 'state'], + 'active', '#4EAF47', + 'old', '#eb5933', /* other */ '#ccc200' ] - } + } }], clusterLayers: [clusterLayer, clusterLayerSolo], fitlerVisible: true, searchTerm: "", searchResults: [], locationAutocompleteResults: [], + autoCompleteResults: [], clustering: false, cluster: null, numbers: true, @@ -136,42 +139,42 @@ export class UiStore extends Store { super(createInitialState()); } - setActiveSensorTypes(types){ - this.update( state => ({...state, activeSensorTypes: types})); + setActiveSensorTypes(types) { + this.update(state => ({ ...state, activeSensorTypes: types })); } // updates the selected Pheno (this is so complicated because all Layers have to be changed if the selected Phenomenon changes) updateSelectedPheno(pheno) { console.log("updateSelectedPheno") - this.update( state => { - let circleColorCluster:any = + this.update(state => { + let circleColorCluster: any = ['match', ['get', 'model'], 'custom', '#fbb03b', /* other */ '#ccc']; - let circleColorSolo:any = + let circleColorSolo: any = ['match', ['get', 'model'], 'custom', '#fbb03b', /* other */ '#ccc']; - if(pheno && pheno.title != 'ALL'){ + if (pheno && pheno.title != 'ALL') { //DEEP CLONE because immutable, apparently this is the most efficient way to do it - circleColorCluster =JSON.parse(JSON.stringify(pheno.layer.paint['circle-color'])); + circleColorCluster = JSON.parse(JSON.stringify(pheno.layer.paint['circle-color'])); circleColorCluster[2] = JSON.parse(JSON.stringify(state.clusterLayers[0].paint['circle-color']))[2]; circleColorCluster[2][1][1] = pheno.title; - + circleColorSolo = JSON.parse(JSON.stringify(pheno.layer.paint['circle-color'])); circleColorSolo[2] = JSON.parse(JSON.stringify(state.clusterLayers[1].paint['circle-color']))[2]; circleColorSolo[2][1] = pheno.title; } - if(pheno.title != 'ALL'){ + if (pheno.title != 'ALL') { return { - ...state, - selectedPheno: pheno, + ...state, + selectedPheno: pheno, baseLayer: { ...state.baseLayer, filter: pheno.layer.filter, @@ -196,11 +199,11 @@ export class UiStore extends Store { 'circle-color': circleColorCluster, // 'circle-stroke-width': 1 } - },{ + }, { ...state.clusterLayers[1], - filter: [ + filter: [ 'all', - ["!=", null, [ "get", pheno.title, ["object", ["get", "live", ["object", ["get", "sensors"]]]]]], + ["!=", null, ["get", pheno.title, ["object", ["get", "live", ["object", ["get", "sensors"]]]]]], ['!', ['has', 'point_count']] ], paint: { @@ -209,7 +212,8 @@ export class UiStore extends Store { // 'circle-stroke-width': 1 } } - ]} + ] + } } else { return { ...state, @@ -220,45 +224,45 @@ export class UiStore extends Store { }); } - setLayers(layers){ - this.update( state => ( { ...state , layers: layers })); + setLayers(layers) { + this.update(state => ({ ...state, layers: layers })); } - updateDateStamp(date: Date){ - this.update( stae => ({...state, dateStamp: date})); + updateDateStamp(date: Date) { + this.update(stae => ({ ...state, dateStamp: date })); } updateDateRange(dateRange: Array) { - this.update( state => ({ ...state ,dateRange: dateRange}) ); + this.update(state => ({ ...state, dateRange: dateRange })); } updateStartDate(startDate: Date) { - this.update( state => ({ ...state ,dateRange: [startDate, state.dateRange[1] ? state.dateRange[1] : null]} ) ); + this.update(state => ({ ...state, dateRange: [startDate, state.dateRange[1] ? state.dateRange[1] : null] })); } updateEndDate(endDate: Date) { - this.update( state => ({ ...state ,dateRange: [state.dateRange[0] ? state.dateRange[0] : null , endDate]}) ); + this.update(state => ({ ...state, dateRange: [state.dateRange[0] ? state.dateRange[0] : null, endDate] })); } updateDateRangeChart(dateRange: Array) { - this.update( state => ({ ...state ,dateRangeChart: dateRange}) ); + this.update(state => ({ ...state, dateRangeChart: dateRange })); } updateStartDateChart(startDate: Date) { - this.update( state => ({ ...state ,dateRangeChart: [startDate, state.dateRangeChart[1] ? state.dateRangeChart[1] : null]} ) ); + this.update(state => ({ ...state, dateRangeChart: [startDate, state.dateRangeChart[1] ? state.dateRangeChart[1] : null] })); } updateEndDateChart(endDate: Date) { - this.update( state => ({ ...state ,dateRangeChart: [state.dateRangeChart[0] ? state.dateRangeChart[0] : null , endDate]}) ); + this.update(state => ({ ...state, dateRangeChart: [state.dateRangeChart[0] ? state.dateRangeChart[0] : null, endDate] })); } - updateSelectedDate(date){ - this.update( state => ({ ...state , selectedDate: date })); + updateSelectedDate(date) { + this.update(state => ({ ...state, selectedDate: date })); } - setLanguage(lang){ - this.update( state => ({ ...state , language: lang })); + setLanguage(lang) { + this.update(state => ({ ...state, language: lang })); } - setTheme(theme){ - this.update( state => ({ ...state , theme: theme })); + setTheme(theme) { + this.update(state => ({ ...state, theme: theme })); } - updateBaseLayer(layer){ + updateBaseLayer(layer) { console.log("updateBaseLayer") - this.update( state => ( { + this.update(state => ({ baseLayer: { ...state.baseLayer, filter: layer.filter ? layer.filter : state.baseLayer.filter, @@ -273,14 +277,14 @@ export class UiStore extends Store { })) } - updateLegend(steps){ + updateLegend(steps) { let newPheno = { ...this.getValue().selectedPheno, layer: { ...this.getValue().selectedPheno.layer, paint: { ...this.getValue().selectedPheno.layer.paint, - 'circle-color': this.getValue().selectedPheno.layer.paint['circle-color'].slice(0,3).concat(steps) + 'circle-color': this.getValue().selectedPheno.layer.paint['circle-color'].slice(0, 3).concat(steps) } } } @@ -289,5 +293,3 @@ export class UiStore extends Store { } } - - diff --git a/src/app/modules/core/filter/filter-container/filter-container.component.html b/src/app/modules/core/filter/filter-container/filter-container.component.html index fbe78da5..40ba1513 100644 --- a/src/app/modules/core/filter/filter-container/filter-container.component.html +++ b/src/app/modules/core/filter/filter-container/filter-container.component.html @@ -7,17 +7,17 @@ (unfocused)="leave()" (focused)="enter()" [resultsActive]="resultsActive" - [autoCompleteResults]="autoCompleteResults$ | async" + [searchResults]="searchResults$ | async" [locationAutocompleteResults]="locationAutocompleteResults$ | async" > - - + - -
diff --git a/src/app/modules/core/filter/filter-container/filter-container.component.ts b/src/app/modules/core/filter/filter-container/filter-container.component.ts index 9d38e617..0bd669a3 100644 --- a/src/app/modules/core/filter/filter-container/filter-container.component.ts +++ b/src/app/modules/core/filter/filter-container/filter-container.component.ts @@ -11,6 +11,7 @@ import { startWith, switchMap } from 'rxjs/operators'; import { ActivatedRoute } from '@angular/router'; import { MapService } from 'src/app/modules/explore/services/map.service'; import { SessionQuery } from 'src/app/models/session/state/session.query'; +import { LocationIqSearchResult } from 'src/app/@types/LocationIq'; @Component({ selector: 'osem-filter-container', @@ -29,7 +30,8 @@ export class FilterContainerComponent implements OnInit { user$ = this.sessionQuery.user$; searchTerm$ = this.uiQuery.selectSearchTerm$; locationAutocompleteResults$ = this.uiQuery.selectLocationAutocompleteResults$; - + searchResults$ = this.uiQuery.selectSearchResults$; + filters$ = this.uiQuery.selectFilters$; stats$ = this.uiQuery.selectStats$; @@ -38,7 +40,7 @@ export class FilterContainerComponent implements OnInit { searchTimeout; autoCompleteResults$; minimizedBoolean = false; - change:boolean = true; + change: boolean = true; resultsActive = false; @@ -53,7 +55,7 @@ export class FilterContainerComponent implements OnInit { private uiQuery: UiQuery) { } ngOnInit() { - + // fetch data for timerange-display // combineLatest(this.selectedDateRange$, this.selectedPheno$).subscribe(res => { // if(res[0] && res[1]){ @@ -71,7 +73,7 @@ export class FilterContainerComponent implements OnInit { this.autoCompleteResults$ = this.searchTerm$.pipe( startWith(''), switchMap(value => { - if(value && value.length > 2){ + if (value && value.length > 2) { return this.boxQuery.selectSearchResultsWithSensors(value); } else { return of([]); @@ -79,87 +81,84 @@ export class FilterContainerComponent implements OnInit { }) ); - this.autoCompleteResults$.subscribe(res => { - this.uiService.setSearchResults(res); - }) + // this.autoCompleteResults$.subscribe(res => { + // this.uiService.setSearchResults(res); + // }) } - changeDateRange(range){ + changeDateRange(range) { this.uiService.updateDateRange(range); // this.uiService.updateActiveTimeMode("timerange"); this.sensorService.resetHasData(); } - changeStartDate(startDate){ + changeStartDate(startDate) { this.uiService.updateStartDate(startDate); } - changeEndDate(startDate){ + changeEndDate(startDate) { this.uiService.updateEndDate(startDate); } - selectPheno(pheno){ + selectPheno(pheno) { //set dataLoaded to false if timeline active this.boxService.setDataFetched(false); this.uiService.updateSelectedPheno(pheno); this.change = false; } - setActiveTab(activeTab){ + setActiveTab(activeTab) { this.uiService.setActiveTab(activeTab) - if(this.minimizedBoolean) + if (this.minimizedBoolean) this.minimizedBoolean = false; } - minimize(){ + minimize() { this.minimizedBoolean = !this.minimizedBoolean; } - toggleMinimizeFilter(){ + toggleMinimizeFilter() { this.uiService.toggleFilterVisible(); } - search(searchTerm){ - if(searchTerm.length > 1){ - this.uiService.fetchGeocodeResults(searchTerm).subscribe(res => { - // console.log(res); - }, (err) => { - // console.log(err) - }); + search(searchTerm) { + if (searchTerm.length > 3) { + this.uiService.fetchGeocodeResults(searchTerm).subscribe(); + this.uiService.fetchDevices(searchTerm).subscribe(); this.uiService.setSearchTerm(searchTerm); } else { this.uiService.setSearchTerm(""); } } - selectResult(box){ - // this.mapService.flyTo(box.currentLocation.coordinates); + selectResult(box) { + this.mapService.flyTo(box.currentLocation.coordinates); } - selectLocResult(loc){ + selectLocResult(loc: LocationIqSearchResult) { this.mapService.flyTo([loc.lon, loc.lat]); } - enter(){ + enter() { this.resultsActive = true; } - leave(){ + leave() { let that = this; - setTimeout(function(){ + setTimeout(function () { that.resultsActive = false; - },100) + }, 100) } - toggleChange(){ + toggleChange() { this.change = !this.change; } - - selectInfoPheno(pheno){ + + selectInfoPheno(pheno) { this.uiService.setInfoPheno(pheno); } setFilters(filters) { this.uiService.setFilters(filters); } - toggleDateModal(showDateModal){ + toggleDateModal(showDateModal) { this.uiService.setShowDateModal(!showDateModal); } } diff --git a/src/app/modules/core/filter/search/search.component.html b/src/app/modules/core/filter/search/search.component.html index b6884e90..b2bed2d9 100644 --- a/src/app/modules/core/filter/search/search.component.html +++ b/src/app/modules/core/filter/search/search.component.html @@ -1,13 +1,7 @@

- + @@ -15,77 +9,40 @@

-
-
+
-
+

{{box.name}}

-
-
- -
-
- -
-
-
+
+ +
-
- {{autoCompleteResults.length}} {{'BOXES' | translate}} - {{'SHOW_ALL' | translate}} -
-
+
-

{{res.display_name}}

+

{{res.display_name}}

- +
-
+
-
+
\ No newline at end of file diff --git a/src/app/modules/core/filter/search/search.component.ts b/src/app/modules/core/filter/search/search.component.ts index db29f869..2c22d33c 100644 --- a/src/app/modules/core/filter/search/search.component.ts +++ b/src/app/modules/core/filter/search/search.component.ts @@ -1,5 +1,6 @@ import { Component, OnInit, EventEmitter, Output, Input, ChangeDetectionStrategy } from '@angular/core'; import { Router, ActivatedRoute } from '@angular/router'; +import { LocationIqSearchResult } from 'src/app/@types/LocationIq'; import { appear } from 'src/app/helper/animations'; @Component({ @@ -21,9 +22,10 @@ export class SearchComponent implements OnInit { @Output() unfocused = new EventEmitter(); @Input() resultsActive; - @Input() autoCompleteResults; - @Input() locationAutocompleteResults; - + + @Input() searchResults; // openSenseMap search results + @Input() locationAutocompleteResults; // locationiq search results + showAll = false; autocompleteToShow; @@ -38,16 +40,15 @@ export class SearchComponent implements OnInit { ngOnInit() { } - ngOnChanges(){ + ngOnChanges() { this.showAll = false; - this.autocompleteToShow = this.autoCompleteResults.slice(0,4); - + // this.autocompleteToShow = this.autoCompleteResults.slice(0, 4); } - changeSearchTerm(){ + changeSearchTerm() { clearTimeout(this.debounceTimeout); this.debounceTimeout = setTimeout(() => { - if(this.searchTerm.length > 1){ + if (this.searchTerm.length > 3) { this.changedSearchTerm.emit(this.searchTerm); } else { this.changedSearchTerm.emit(""); @@ -57,73 +58,81 @@ export class SearchComponent implements OnInit { } keydown(key) { - if(key.keyCode == 38){ + if (key.keyCode == 38) { key.preventDefault() this.selectedAutocomplete--; - if (this.selectedAutocomplete < 0){ - this.selectedAutocomplete = this.autocompleteToShow.length-1; + if (this.selectedAutocomplete < 0) { + this.selectedAutocomplete = this.autocompleteToShow.length - 1; } - } else if(key.keyCode == 40) { + } else if (key.keyCode == 40) { key.preventDefault() this.selectedAutocomplete++; - if(this.selectedAutocomplete >= this.autocompleteToShow.length + this.locationAutocompleteResults.length){ + if (this.selectedAutocomplete >= this.searchResults.length + this.locationAutocompleteResults.length) { this.selectedAutocomplete = 0; } - } else if(key.keyCode == 13){ - if(this.autocompleteToShow.length > 0 && this.selectedAutocomplete > -1) { - // this.navToProduct(this.autocompleteToShow[this.selectedAutocomplete].slug); - if(this.autocompleteToShow[this.selectedAutocomplete]){ - this.resultSelected.emit(this.autocompleteToShow[this.selectedAutocomplete]) + } else if (key.keyCode == 13) { + if (this.selectedAutocomplete > -1) { + if (this.selectedAutocomplete < this.searchResults.length) { + this.openDetails(this.searchResults[this.selectedAutocomplete]); } else { - this.locResultSelected.emit(this.locationAutocompleteResults[this.selectedAutocomplete - this.autocompleteToShow.length]); + const location: LocationIqSearchResult = this.locationAutocompleteResults[this.selectedAutocomplete - this.searchResults.length]; + this.selectLocationResult(location); } - //HIGHLIGHT BOX } - } + // if (this.autocompleteToShow.length > 0 && this.selectedAutocomplete > -1) { + // // this.navToProduct(this.autocompleteToShow[this.selectedAutocomplete].slug); + // if (this.autocompleteToShow[this.selectedAutocomplete]) { + // this.resultSelected.emit(this.autocompleteToShow[this.selectedAutocomplete]) + // } else { + // this.locResultSelected.emit(this.locationAutocompleteResults[this.selectedAutocomplete - this.autocompleteToShow.length]); + // } + // //HIGHLIGHT BOX + // } + } } - openDetails(box){ + openDetails(box) { //fly to Box this.resultSelected.emit(box); //open box this.router.navigate(['/explore/' + box._id], { relativeTo: this.activatedRoute, queryParamsHandling: 'merge' - }); + }); } - selectResult(e, box){ + selectResult(e, box) { e.stopPropagation(); this.resultSelected.emit(box); + this.openDetails(box); } - selectLocationResult(loc){ + selectLocationResult(loc: LocationIqSearchResult) { this.locResultSelected.emit(loc); - } - showLocationResult(e, box){ + showLocationResult(e, box) { // e.stopPropagation(); // this.resultSelected.emit(box); } - enter(){ + enter() { this.focused.emit(); } - leave(){ - this.unfocused.emit(); + leave() { + this.unfocused.emit(); } - displayAll(){ - this.showAll = !this.showAll; - if(!this.showAll){ - this.autocompleteToShow = this.autoCompleteResults.slice(0,4); - } else { - this.autocompleteToShow = this.autoCompleteResults; - } - } + // displayAll() { + // this.showAll = !this.showAll; + // if (!this.showAll) { + // this.autocompleteToShow = this.autoCompleteResults.slice(0, 4); + // } else { + // this.autocompleteToShow = this.autoCompleteResults; + // } + // } - clearSearch(){ + clearSearch() { this.searchTerm = ""; this.changedSearchTerm.emit(this.searchTerm); } diff --git a/src/environments/environment.ts b/src/environments/environment.ts index dde842cc..06d04a68 100644 --- a/src/environments/environment.ts +++ b/src/environments/environment.ts @@ -4,8 +4,7 @@ export const environment = { production: false, - // api_url: "https://api.opensensemap.org", - api_url: "http://localhost:8000", + api_url: "/api", sensor_wiki_url: "http://localhost:3001", mapbox_token: "pk.eyJ1IjoidW11dDAwIiwiYSI6ImNqbnVkbnFxNDB2YnIzd3M1eTNidTA3MjUifQ.3gqG1JYEQvckOiiQ8B3NQQ", locationiq_token: "23e12b10d8c3aad04e8e"