From 3407dfc81528f22b9bf7efcefdf44e4e2e79f736 Mon Sep 17 00:00:00 2001
From: Hugo SUBTIL <ext.sopra.husubtil@grandlyon.com>
Date: Fri, 27 Nov 2020 10:19:15 +0100
Subject: [PATCH] feat: add location search

---
 proxy.conf.json                             |   6 ++
 src/app/home/home.component.ts              | 102 +++++++++++++++-----
 src/app/map/components/map.component.ts     |   2 +-
 src/app/map/models/addressGeometry.model.ts |   4 +-
 src/app/models/structure.model.ts           |   4 +-
 src/app/services/geojson.service.ts         |  10 ++
 6 files changed, 99 insertions(+), 29 deletions(-)

diff --git a/proxy.conf.json b/proxy.conf.json
index cc19a8115..f5d918024 100644
--- a/proxy.conf.json
+++ b/proxy.conf.json
@@ -25,5 +25,11 @@
     "secure": false,
     "changeOrigin": true,
     "logLevel": "info"
+  },
+  "/geocoding/photon/api": {
+    "target": "https://download.data.grandlyon.com",
+    "secure": false,
+    "changeOrigin": true,
+    "logLevel": "info"
   }
 }
diff --git a/src/app/home/home.component.ts b/src/app/home/home.component.ts
index 265131817..ce2ef32e6 100644
--- a/src/app/home/home.component.ts
+++ b/src/app/home/home.component.ts
@@ -22,6 +22,8 @@ export class HomeComponent implements OnInit {
   public geolocation = false;
   public currentLocation: GeoJson;
   public currentStructure: Structure;
+  public userLatitude: number;
+  public userLongitude: number;
   constructor(private structureService: StructureService, private geoJsonService: GeojsonService) {}
 
   ngOnInit(): void {
@@ -33,37 +35,84 @@ export class HomeComponent implements OnInit {
   }
 
   public getStructures(filters: Filter[]): void {
-    this.structureService.getStructures(filters).subscribe((structures) => {
-      if (structures) {
-        Promise.all(
-          structures.map((structure) => {
-            if (this.geolocation) {
-              structure = this.getStructurePosition(structure);
-            }
-            return this.structureService.updateOpeningStructure(structure, DateTime.local());
-          })
-        ).then((structureList) => {
-          structureList = _.sortBy(structureList, ['distance']);
-          this.structures = structureList;
+    const queryString = _.find(filters, { name: 'query' });
+    if (queryString) {
+      if (this.isLocationRequest(queryString.value)) {
+        this.getCoordByAddress(queryString.value).then((res) => {
+          this.currentLocation = res;
+          this.updateStructuresdistance(
+            this.structures,
+            this.currentLocation.geometry.getLon(),
+            this.currentLocation.geometry.getLat()
+          );
         });
       } else {
-        this.structures = null;
+        this.structureService.getStructures(filters).subscribe((structures) => {
+          if (structures) {
+            this.updateStructuresdistance(structures, this.userLongitude, this.userLatitude);
+          } else {
+            this.structures = null;
+          }
+        });
       }
+    } else {
+      this.structureService.getStructures(filters).subscribe((structures) => {
+        if (structures) {
+          this.updateStructuresdistance(structures, this.userLongitude, this.userLatitude);
+        } else {
+          this.structures = null;
+        }
+      });
+    }
+  }
+
+  private updateStructuresdistance(structures: Structure[], lon: number, lat: number): void {
+    Promise.all(
+      structures.map((structure) => {
+        if (this.geolocation) {
+          structure = this.getStructurePosition(structure, lon, lat);
+        }
+        return this.structureService.updateOpeningStructure(structure, DateTime.local());
+      })
+    ).then((structureList) => {
+      structureList = _.sortBy(structureList, ['distance']);
+      this.structures = structureList;
     });
   }
 
+  /**
+   * Retrive GeoJson for a given address
+   * @param address string
+   */
+  private getCoordByAddress(address: string): Promise<GeoJson> {
+    return new Promise((resolve) => {
+      this.geoJsonService.getCoord(address, '', '69000').subscribe((res) => {
+        resolve(res);
+      });
+    });
+  }
+
+  /**
+   * Check with a regex that an address is request
+   * @param value string
+   */
+  private isLocationRequest(value: string): boolean {
+    const regex = /^\d+\s[A-z]+\s[A-z]+/g;
+    if (value.match(regex)) {
+      return true;
+    }
+    return false;
+  }
+
   /**
    * Get structures positions and add marker corresponding to those positons on the map
+   * @param structure Structure
+   * @param lon number
+   * @param lat number
    */
-  private getStructurePosition(structure: Structure): Structure {
+  private getStructurePosition(structure: Structure, lon: number, lat: number): Structure {
     structure.distance = parseInt(
-      this.geoJsonService.getDistance(
-        structure.getLon(),
-        structure.getLat(),
-        this.currentLocation.geometry.getLon(),
-        this.currentLocation.geometry.getLat(),
-        'M'
-      ),
+      this.geoJsonService.getDistance(structure.getLat(), structure.getLon(), lat, lon, 'M'),
       10
     );
     return structure;
@@ -72,13 +121,18 @@ export class HomeComponent implements OnInit {
   public getLocation(): void {
     navigator.geolocation.getCurrentPosition((position) => {
       this.geolocation = true;
-      const longitude = position.coords.longitude;
-      const latitude = position.coords.latitude;
-      this.getAddress(longitude, latitude);
+      this.userLongitude = position.coords.longitude;
+      this.userLatitude = position.coords.latitude;
+      this.getAddress(position.coords.longitude, position.coords.latitude);
       this.getStructures(null);
     });
   }
 
+  /**
+   * Get an address by coord
+   * @param longitude number
+   * @param latitude number
+   */
   private getAddress(longitude: number, latitude: number): void {
     this.geoJsonService.getAddressByCoord(longitude, latitude).subscribe(
       (location) => {
diff --git a/src/app/map/components/map.component.ts b/src/app/map/components/map.component.ts
index 6bccd2d44..875be42c0 100644
--- a/src/app/map/components/map.component.ts
+++ b/src/app/map/components/map.component.ts
@@ -111,8 +111,8 @@ export class MapComponent implements OnChanges {
     structureListe.forEach((structure: Structure) => {
       this.mapService
         .createMarker(
-          structure.getLon(),
           structure.getLat(),
+          structure.getLon(),
           MarkerType.structure,
           structure.id,
           this.buildToolTip(structure)
diff --git a/src/app/map/models/addressGeometry.model.ts b/src/app/map/models/addressGeometry.model.ts
index 71e1ce346..b7612f2fc 100644
--- a/src/app/map/models/addressGeometry.model.ts
+++ b/src/app/map/models/addressGeometry.model.ts
@@ -7,10 +7,10 @@ export class AddressGeometry {
   }
 
   public getLat(): number {
-    return this.coordinates[0];
+    return this.coordinates[1];
   }
 
   public getLon(): number {
-    return this.coordinates[1];
+    return this.coordinates[0];
   }
 }
diff --git a/src/app/models/structure.model.ts b/src/app/models/structure.model.ts
index bcc5b4a08..597234630 100644
--- a/src/app/models/structure.model.ts
+++ b/src/app/models/structure.model.ts
@@ -112,10 +112,10 @@ export class Structure {
   }
 
   public getLat(): number {
-    return this.coord[0];
+    return this.coord[1];
   }
 
   public getLon(): number {
-    return this.coord[1];
+    return this.coord[0];
   }
 }
diff --git a/src/app/services/geojson.service.ts b/src/app/services/geojson.service.ts
index befafee6c..5f15ae6d8 100644
--- a/src/app/services/geojson.service.ts
+++ b/src/app/services/geojson.service.ts
@@ -43,6 +43,16 @@ export class GeojsonService {
       .pipe(map((data: { features: any[] }) => _.map(data.features, this.parseToGeoJson)));
   }
 
+  /**
+   * Get GeoLocation with an address
+   * @param address Address
+   */
+  public getCoord(numero: string, address: string, zipcode: string): Observable<GeoJson> {
+    return this.http
+      .get('/geocoding/photon/api' + '?q=' + numero + ' ' + address + ' ' + zipcode)
+      .pipe(map((data: { features: any[]; type: string }) => new GeoJson(data.features[0])));
+  }
+
   // :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
   // :::                                                                         :::
   // :::  This routine calculates the distance between two points (given the     :::
-- 
GitLab