diff --git a/src/src/app/components/dashboard/dashboard.component.html b/src/src/app/components/dashboard/dashboard.component.html
index 9b4573c..9b95ada 100644
--- a/src/src/app/components/dashboard/dashboard.component.html
+++ b/src/src/app/components/dashboard/dashboard.component.html
@@ -2,7 +2,8 @@
@if (selectedPlace) {
+ (favoriteEmitter)="favoritePlace()" (gpxEmitter)="getPlaceGPX()" (visitEmitter)="visitPlace()"
+ (closeEmitter)="closePlaceBox()">
}
diff --git a/src/src/app/components/dashboard/dashboard.component.ts b/src/src/app/components/dashboard/dashboard.component.ts
index 91e63c1..1e485bb 100644
--- a/src/src/app/components/dashboard/dashboard.component.ts
+++ b/src/src/app/components/dashboard/dashboard.component.ts
@@ -25,7 +25,12 @@ import { FloatLabelModule } from "primeng/floatlabel";
import { BatchCreateModalComponent } from "../../modals/batch-create-modal/batch-create-modal.component";
import { UtilsService } from "../../services/utils.service";
import { Info } from "../../types/info";
-import { createMap, placeToMarker, createClusterGroup } from "../../shared/map";
+import {
+ createMap,
+ placeToMarker,
+ createClusterGroup,
+ gpxToPolyline,
+} from "../../shared/map";
import { Router } from "@angular/router";
import { SelectModule } from "primeng/select";
import { MultiSelectModule } from "primeng/multiselect";
@@ -82,6 +87,7 @@ export class DashboardComponent implements AfterViewInit {
hoveredElements: HTMLElement[] = [];
map: any;
+ mapDisplayedTrace: L.Polyline[] = [];
settings: Settings | undefined;
currencySigns: { c: string; s: string }[] = [];
doNotDisplayOptions: SelectItemGroup[] = [];
@@ -499,6 +505,42 @@ export class DashboardComponent implements AfterViewInit {
});
}
+ displayGPXOnMap(gpx: string) {
+ try {
+ // HINT: For now, delete traces everytime we display a GPX
+ // TODO: Handle multiple polygons and handle Click events
+ this.mapDisplayedTrace.forEach((p) => this.map.removeLayer(p));
+ this.mapDisplayedTrace = [];
+
+ const gpxPolyline = gpxToPolyline(gpx).addTo(this.map);
+ gpxPolyline.on("click", () => {
+ this.map.removeLayer(gpxPolyline);
+ });
+
+ this.mapDisplayedTrace.push(gpxPolyline);
+ } catch {
+ this.utilsService.toast("error", "Error", "Couldn't parse GPX data");
+ return;
+ }
+ }
+
+ getPlaceGPX() {
+ if (!this.selectedPlace) return;
+ this.apiService.getPlaceGPX(this.selectedPlace.id).subscribe({
+ next: (p) => {
+ if (!p.gpx) {
+ this.utilsService.toast(
+ "error",
+ "Error",
+ "Couldn't retrieve GPX data",
+ );
+ return;
+ }
+ this.displayGPXOnMap(p.gpx);
+ },
+ });
+ }
+
toggleSettings() {
this.viewSettings = !this.viewSettings;
if (this.viewSettings && this.settings) {
diff --git a/src/src/app/modals/place-create-modal/place-create-modal.component.html b/src/src/app/modals/place-create-modal/place-create-modal.component.html
index 5ad97c5..7231410 100644
--- a/src/src/app/modals/place-create-modal/place-create-modal.component.html
+++ b/src/src/app/modals/place-create-modal/place-create-modal.component.html
@@ -43,14 +43,25 @@
-
+
+
-
-
-
+
+
+
+ @if (placeForm.get('gpx')?.value) {
+
+ } @else {
+
+ }
+
+
@@ -61,7 +72,7 @@
@if (placeForm.get("image_id")?.value) {
-
+
Click to edit
-
} @else {
@if (placeForm.get("image")?.value) {
@@ -81,7 +91,7 @@
} @else {
-
diff --git a/src/src/app/modals/place-create-modal/place-create-modal.component.scss b/src/src/app/modals/place-create-modal/place-create-modal.component.scss
index d0a7019..ec08078 100644
--- a/src/src/app/modals/place-create-modal/place-create-modal.component.scss
+++ b/src/src/app/modals/place-create-modal/place-create-modal.component.scss
@@ -14,8 +14,3 @@
.p-floatlabel:has(.p-inputwrapper-focus) input::placeholder {
color: var(--p-inputtext-placeholder-color) !important;
}
-
-.p-tooltip > .p-tooltip-text {
- width: 350px !important;
- background: red;
-}
diff --git a/src/src/app/modals/place-create-modal/place-create-modal.component.ts b/src/src/app/modals/place-create-modal/place-create-modal.component.ts
index cf1b12c..ec6a418 100644
--- a/src/src/app/modals/place-create-modal/place-create-modal.component.ts
+++ b/src/src/app/modals/place-create-modal/place-create-modal.component.ts
@@ -91,8 +91,9 @@ export class PlaceCreateModalComponent {
price: "",
allowdog: false,
visited: false,
- image: "",
+ image: null,
image_id: null,
+ gpx: null,
});
if (this.config.data) {
@@ -172,7 +173,7 @@ export class PlaceCreateModalComponent {
this.placeForm.get("name")?.setValue(place);
}
- onFileSelected(event: Event) {
+ onImageSelected(event: Event) {
const input = event.target as HTMLInputElement;
if (input.files && input.files.length > 0) {
const file = input.files[0];
@@ -201,4 +202,24 @@ export class PlaceCreateModalComponent {
this.placeForm.get("image")?.setValue(this.previous_image);
}
}
+
+ onGPXSelected(event: Event) {
+ const input = event.target as HTMLInputElement;
+ if (input.files && input.files.length > 0) {
+ const file = input.files[0];
+ const reader = new FileReader();
+
+ reader.onload = (e) => {
+ this.placeForm.get("gpx")?.setValue(e.target?.result as string);
+ this.placeForm.get("gpx")?.markAsDirty();
+ };
+
+ reader.readAsText(file);
+ }
+ }
+
+ clearGPX() {
+ this.placeForm.get("gpx")?.setValue(null);
+ this.placeForm.get("gpx")?.markAsDirty();
+ }
}
diff --git a/src/src/app/services/api.service.ts b/src/src/app/services/api.service.ts
index 087f101..6bf145f 100644
--- a/src/src/app/services/api.service.ts
+++ b/src/src/app/services/api.service.ts
@@ -164,6 +164,12 @@ export class ApiService {
);
}
+ getPlaceGPX(place_id: number): Observable
{
+ return this.httpClient
+ .get(`${this.apiBaseUrl}/places/${place_id}`)
+ .pipe(map((p) => this._normalizePlaceImage(p)));
+ }
+
getTrips(): Observable {
return this.httpClient.get(`${this.apiBaseUrl}/trips`).pipe(
map((resp) => {
diff --git a/src/src/app/shared/map.ts b/src/src/app/shared/map.ts
index c230aaf..946de93 100644
--- a/src/src/app/shared/map.ts
+++ b/src/src/app/shared/map.ts
@@ -99,3 +99,18 @@ export function placeToMarker(place: Place): L.Marker {
}
return marker;
}
+
+export function gpxToPolyline(gpx: string): L.Polyline {
+ const parser = new DOMParser();
+ const gpxDoc = parser.parseFromString(gpx, "application/xml");
+
+ const trkpts = Array.from(gpxDoc.querySelectorAll("trkpt"));
+ const latlngs = trkpts.map((pt) => {
+ return [
+ parseFloat(pt.getAttribute("lat")!),
+ parseFloat(pt.getAttribute("lon")!),
+ ] as [number, number];
+ });
+
+ return L.polyline(latlngs, { color: "blue" });
+}