⚡ Trip performance and code improvements
This commit is contained in:
parent
39d69199fe
commit
0b7af7ce99
@ -28,7 +28,14 @@ import { TripPlaceSelectModalComponent } from "../../modals/trip-place-select-mo
|
|||||||
import { TripCreateDayModalComponent } from "../../modals/trip-create-day-modal/trip-create-day-modal.component";
|
import { TripCreateDayModalComponent } from "../../modals/trip-create-day-modal/trip-create-day-modal.component";
|
||||||
import { TripCreateDayItemModalComponent } from "../../modals/trip-create-day-item-modal/trip-create-day-item-modal.component";
|
import { TripCreateDayItemModalComponent } from "../../modals/trip-create-day-item-modal/trip-create-day-item-modal.component";
|
||||||
import { TripCreateItemsModalComponent } from "../../modals/trip-create-items-modal/trip-create-items-modal.component";
|
import { TripCreateItemsModalComponent } from "../../modals/trip-create-items-modal/trip-create-items-modal.component";
|
||||||
import { combineLatest, forkJoin, map, Observable, tap } from "rxjs";
|
import {
|
||||||
|
combineLatest,
|
||||||
|
forkJoin,
|
||||||
|
Observable,
|
||||||
|
switchMap,
|
||||||
|
take,
|
||||||
|
tap,
|
||||||
|
} from "rxjs";
|
||||||
import { YesNoModalComponent } from "../../modals/yes-no-modal/yes-no-modal.component";
|
import { YesNoModalComponent } from "../../modals/yes-no-modal/yes-no-modal.component";
|
||||||
import { UtilsService } from "../../services/utils.service";
|
import { UtilsService } from "../../services/utils.service";
|
||||||
import { TripCreateModalComponent } from "../../modals/trip-create-modal/trip-create-modal.component";
|
import { TripCreateModalComponent } from "../../modals/trip-create-modal/trip-create-modal.component";
|
||||||
@ -37,6 +44,7 @@ import { MenuItem } from "primeng/api";
|
|||||||
import { MenuModule } from "primeng/menu";
|
import { MenuModule } from "primeng/menu";
|
||||||
import { LinkifyPipe } from "../../shared/linkify.pipe";
|
import { LinkifyPipe } from "../../shared/linkify.pipe";
|
||||||
import { PlaceCreateModalComponent } from "../../modals/place-create-modal/place-create-modal.component";
|
import { PlaceCreateModalComponent } from "../../modals/place-create-modal/place-create-modal.component";
|
||||||
|
import { Settings } from "../../types/settings";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: "app-trip",
|
selector: "app-trip",
|
||||||
@ -57,44 +65,26 @@ import { PlaceCreateModalComponent } from "../../modals/place-create-modal/place
|
|||||||
styleUrls: ["./trip.component.scss"],
|
styleUrls: ["./trip.component.scss"],
|
||||||
})
|
})
|
||||||
export class TripComponent implements AfterViewInit {
|
export class TripComponent implements AfterViewInit {
|
||||||
map: any;
|
|
||||||
markerClusterGroup: any;
|
|
||||||
selectedItem: (TripItem & { status?: TripStatus }) | undefined;
|
|
||||||
statuses: TripStatus[] = [];
|
|
||||||
hoveredElement: HTMLElement | undefined;
|
|
||||||
currency$: Observable<string>;
|
currency$: Observable<string>;
|
||||||
placesUsedInTable = new Set<number>();
|
statuses: TripStatus[] = [];
|
||||||
|
trip?: Trip;
|
||||||
trip: Trip | undefined;
|
|
||||||
tripMapAntLayer: L.LayerGroup<any> | undefined;
|
|
||||||
tripMapAntLayerDayID: number | undefined;
|
|
||||||
isMapFullscreen: boolean = false;
|
|
||||||
|
|
||||||
totalPrice: number = 0;
|
|
||||||
dayStatsCache = new Map<number, { price: number; places: number }>();
|
|
||||||
|
|
||||||
places: Place[] = [];
|
places: Place[] = [];
|
||||||
flattenedTripItems: FlattenedTripItem[] = [];
|
flattenedTripItems: FlattenedTripItem[] = [];
|
||||||
menuTripActionsItems: MenuItem[] = [];
|
selectedItem?: TripItem & { status?: TripStatus };
|
||||||
|
|
||||||
menuTripDayActionsItems: MenuItem[] = [];
|
isMapFullscreen = false;
|
||||||
selectedTripDayForMenu: TripDay | undefined;
|
totalPrice = 0;
|
||||||
|
collapsedTripDays = false;
|
||||||
|
collapsedTripPlaces = false;
|
||||||
|
collapsedTripStatuses = false;
|
||||||
|
|
||||||
collapsedTripPlaces: boolean = false;
|
map?: L.Map;
|
||||||
collapsedTripDays: boolean = false;
|
markerClusterGroup?: L.MarkerClusterGroup;
|
||||||
collapsedTripStatuses: boolean = false;
|
hoveredElement?: HTMLElement;
|
||||||
|
tripMapAntLayer?: L.LayerGroup<any>;
|
||||||
|
tripMapAntLayerDayID?: number;
|
||||||
|
|
||||||
constructor(
|
readonly menuTripActionsItems: MenuItem[] = [
|
||||||
private apiService: ApiService,
|
|
||||||
private router: Router,
|
|
||||||
private dialogService: DialogService,
|
|
||||||
private utilsService: UtilsService,
|
|
||||||
private route: ActivatedRoute,
|
|
||||||
) {
|
|
||||||
this.currency$ = this.utilsService.currency$;
|
|
||||||
this.statuses = this.utilsService.statuses;
|
|
||||||
|
|
||||||
this.menuTripActionsItems = [
|
|
||||||
{
|
{
|
||||||
label: "Actions",
|
label: "Actions",
|
||||||
items: [
|
items: [
|
||||||
@ -125,7 +115,7 @@ export class TripComponent implements AfterViewInit {
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
this.menuTripDayActionsItems = [
|
readonly menuTripDayActionsItems: MenuItem[] = [
|
||||||
{
|
{
|
||||||
label: "Actions",
|
label: "Actions",
|
||||||
items: [
|
items: [
|
||||||
@ -157,34 +147,53 @@ export class TripComponent implements AfterViewInit {
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
}
|
selectedTripDayForMenu?: TripDay;
|
||||||
|
|
||||||
back() {
|
dayStatsCache = new Map<number, { price: number; places: number }>();
|
||||||
this.router.navigateByUrl("/trips");
|
placesUsedInTable = new Set<number>();
|
||||||
}
|
|
||||||
|
|
||||||
printTable() {
|
constructor(
|
||||||
this.selectedItem = undefined;
|
private apiService: ApiService,
|
||||||
setTimeout(() => {
|
private router: Router,
|
||||||
window.print();
|
private dialogService: DialogService,
|
||||||
}, 30);
|
private utilsService: UtilsService,
|
||||||
|
private route: ActivatedRoute,
|
||||||
|
) {
|
||||||
|
this.currency$ = this.utilsService.currency$;
|
||||||
|
this.statuses = this.utilsService.statuses;
|
||||||
}
|
}
|
||||||
|
|
||||||
ngAfterViewInit(): void {
|
ngAfterViewInit(): void {
|
||||||
this.route.paramMap.subscribe((params) => {
|
this.route.paramMap
|
||||||
|
.pipe(
|
||||||
|
take(1),
|
||||||
|
tap((params) => {
|
||||||
const id = params.get("id");
|
const id = params.get("id");
|
||||||
if (id) {
|
if (id) this.loadTripData(+id);
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.subscribe();
|
||||||
|
}
|
||||||
|
|
||||||
|
loadTripData(id: number): void {
|
||||||
combineLatest({
|
combineLatest({
|
||||||
trip: this.apiService.getTrip(+id),
|
trip: this.apiService.getTrip(+id),
|
||||||
settings: this.apiService.getSettings(),
|
settings: this.apiService.getSettings(),
|
||||||
})
|
})
|
||||||
.pipe(
|
.pipe(
|
||||||
|
take(1),
|
||||||
tap(({ trip, settings }) => {
|
tap(({ trip, settings }) => {
|
||||||
this.trip = trip;
|
this.trip = trip;
|
||||||
this.flattenTripDayItems();
|
this.flattenTripDayItems();
|
||||||
this.updateTotalPrice();
|
this.updateTotalPrice();
|
||||||
|
this.setupMap(settings);
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.subscribe();
|
||||||
|
}
|
||||||
|
|
||||||
let contentMenuItems = [
|
setupMap(settings: Settings): void {
|
||||||
|
const contentMenuItems = [
|
||||||
{
|
{
|
||||||
text: "Copy coordinates",
|
text: "Copy coordinates",
|
||||||
callback: (e: any) => {
|
callback: (e: any) => {
|
||||||
@ -199,13 +208,19 @@ export class TripComponent implements AfterViewInit {
|
|||||||
this.markerClusterGroup = createClusterGroup().addTo(this.map);
|
this.markerClusterGroup = createClusterGroup().addTo(this.map);
|
||||||
this.setPlacesAndMarkers();
|
this.setPlacesAndMarkers();
|
||||||
|
|
||||||
this.map.setView([48.107, -2.988]);
|
this.map.setView([settings.map_lat, settings.map_lng]);
|
||||||
this.resetMapBounds();
|
this.resetMapBounds();
|
||||||
}),
|
|
||||||
)
|
|
||||||
.subscribe();
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
back() {
|
||||||
|
this.router.navigateByUrl("/trips");
|
||||||
|
}
|
||||||
|
|
||||||
|
printTable() {
|
||||||
|
this.selectedItem = undefined;
|
||||||
|
setTimeout(() => {
|
||||||
|
window.print();
|
||||||
|
}, 30);
|
||||||
}
|
}
|
||||||
|
|
||||||
sortTripDays() {
|
sortTripDays() {
|
||||||
@ -213,9 +228,7 @@ export class TripComponent implements AfterViewInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getDayStats(day: TripDay): { price: number; places: number } {
|
getDayStats(day: TripDay): { price: number; places: number } {
|
||||||
if (this.dayStatsCache.has(day.id)) {
|
if (this.dayStatsCache.has(day.id)) return this.dayStatsCache.get(day.id)!;
|
||||||
return this.dayStatsCache.get(day.id)!;
|
|
||||||
}
|
|
||||||
|
|
||||||
const stats = day.items.reduce(
|
const stats = day.items.reduce(
|
||||||
(acc, item) => {
|
(acc, item) => {
|
||||||
@ -225,7 +238,6 @@ export class TripComponent implements AfterViewInit {
|
|||||||
},
|
},
|
||||||
{ price: 0, places: 0 },
|
{ price: 0, places: 0 },
|
||||||
);
|
);
|
||||||
|
|
||||||
this.dayStatsCache.set(day.id, stats);
|
this.dayStatsCache.set(day.id, stats);
|
||||||
return stats;
|
return stats;
|
||||||
}
|
}
|
||||||
@ -233,14 +245,13 @@ export class TripComponent implements AfterViewInit {
|
|||||||
get getWatchlistData(): (TripItem & { status: TripStatus })[] {
|
get getWatchlistData(): (TripItem & { status: TripStatus })[] {
|
||||||
if (!this.trip?.days) return [];
|
if (!this.trip?.days) return [];
|
||||||
|
|
||||||
const data = this.trip!.days.map((day) =>
|
return this.trip.days
|
||||||
|
.flatMap((day) =>
|
||||||
day.items.filter((item) =>
|
day.items.filter((item) =>
|
||||||
["constraint", "pending"].includes(item.status as string),
|
["constraint", "pending"].includes(item.status as string),
|
||||||
),
|
),
|
||||||
).flat();
|
)
|
||||||
if (!data.length) return [];
|
.map((item) => ({
|
||||||
|
|
||||||
return data.map((item) => ({
|
|
||||||
...item,
|
...item,
|
||||||
status: this.statusToTripStatus(item.status as string),
|
status: this.statusToTripStatus(item.status as string),
|
||||||
})) as (TripItem & { status: TripStatus })[];
|
})) as (TripItem & { status: TripStatus })[];
|
||||||
@ -252,7 +263,7 @@ export class TripComponent implements AfterViewInit {
|
|||||||
|
|
||||||
statusToTripStatus(status?: string): TripStatus | undefined {
|
statusToTripStatus(status?: string): TripStatus | undefined {
|
||||||
if (!status) return undefined;
|
if (!status) return undefined;
|
||||||
return this.statuses.find((s) => s.label == status) as TripStatus;
|
return this.statuses.find((s) => s.label == status);
|
||||||
}
|
}
|
||||||
|
|
||||||
flattenTripDayItems() {
|
flattenTripDayItems() {
|
||||||
@ -279,16 +290,16 @@ export class TripComponent implements AfterViewInit {
|
|||||||
|
|
||||||
computePlacesUsedInTable() {
|
computePlacesUsedInTable() {
|
||||||
this.placesUsedInTable.clear();
|
this.placesUsedInTable.clear();
|
||||||
this.flattenedTripItems.forEach((i) => {
|
this.flattenedTripItems.forEach((item) => {
|
||||||
if (i.place?.id) this.placesUsedInTable.add(i.place.id);
|
if (item.place?.id) this.placesUsedInTable.add(item.place.id);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
setPlacesAndMarkers() {
|
setPlacesAndMarkers() {
|
||||||
this.computePlacesUsedInTable();
|
this.computePlacesUsedInTable();
|
||||||
this.places = this.trip?.places || [];
|
this.places = [...(this.trip?.places ?? [])].sort((a, b) =>
|
||||||
this.places.sort((a, b) => a.name.localeCompare(b.name));
|
a.name.localeCompare(b.name),
|
||||||
|
);
|
||||||
this.markerClusterGroup?.clearLayers();
|
this.markerClusterGroup?.clearLayers();
|
||||||
this.places.forEach((p) => {
|
this.places.forEach((p) => {
|
||||||
const marker = placeToMarker(p, false, !this.placesUsedInTable.has(p.id));
|
const marker = placeToMarker(p, false, !this.placesUsedInTable.has(p.id));
|
||||||
@ -298,7 +309,7 @@ export class TripComponent implements AfterViewInit {
|
|||||||
|
|
||||||
resetMapBounds() {
|
resetMapBounds() {
|
||||||
if (!this.places.length) return;
|
if (!this.places.length) return;
|
||||||
this.map.fitBounds(
|
this.map?.fitBounds(
|
||||||
this.places.map((p) => [p.lat, p.lng]),
|
this.places.map((p) => [p.lat, p.lng]),
|
||||||
{ padding: [30, 30] },
|
{ padding: [30, 30] },
|
||||||
);
|
);
|
||||||
@ -309,14 +320,16 @@ export class TripComponent implements AfterViewInit {
|
|||||||
document.body.classList.toggle("overflow-hidden");
|
document.body.classList.toggle("overflow-hidden");
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
this.map.invalidateSize();
|
this.map?.invalidateSize();
|
||||||
this.resetMapBounds();
|
this.resetMapBounds();
|
||||||
}, 50);
|
}, 50);
|
||||||
}
|
}
|
||||||
|
|
||||||
updateTotalPrice(n?: number) {
|
updateTotalPrice(n?: number) {
|
||||||
if (n) this.totalPrice += n;
|
if (n) {
|
||||||
else
|
this.totalPrice += n;
|
||||||
|
return;
|
||||||
|
}
|
||||||
this.totalPrice =
|
this.totalPrice =
|
||||||
this.trip?.days
|
this.trip?.days
|
||||||
.flatMap((d) => d.items)
|
.flatMap((d) => d.items)
|
||||||
@ -327,17 +340,13 @@ export class TripComponent implements AfterViewInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
resetPlaceHighlightMarker() {
|
resetPlaceHighlightMarker() {
|
||||||
if (this.hoveredElement) {
|
if (!this.hoveredElement) return;
|
||||||
this.hoveredElement.classList.remove("listHover");
|
this.hoveredElement.classList.remove("listHover");
|
||||||
this.hoveredElement = undefined;
|
this.hoveredElement = undefined;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
placeHighlightMarker(lat: number, lng: number) {
|
placeHighlightMarker(lat: number, lng: number) {
|
||||||
if (this.hoveredElement) {
|
this.resetPlaceHighlightMarker();
|
||||||
this.hoveredElement.classList.remove("listHover");
|
|
||||||
this.hoveredElement = undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
let marker: L.Marker | undefined;
|
let marker: L.Marker | undefined;
|
||||||
this.markerClusterGroup?.eachLayer((layer: any) => {
|
this.markerClusterGroup?.eachLayer((layer: any) => {
|
||||||
@ -347,14 +356,13 @@ export class TripComponent implements AfterViewInit {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (!marker) return;
|
if (!marker) return;
|
||||||
let markerElement = marker.getElement() as HTMLElement; // search for Marker. If 'null', is inside Cluster
|
const markerElement = marker.getElement() as HTMLElement; // search for Marker. If 'null', is inside Cluster
|
||||||
|
|
||||||
if (markerElement) {
|
if (markerElement) {
|
||||||
// marker, not clustered
|
// marker, not clustered
|
||||||
markerElement.classList.add("listHover");
|
markerElement.classList.add("listHover");
|
||||||
this.hoveredElement = markerElement;
|
this.hoveredElement = markerElement;
|
||||||
} else {
|
} else {
|
||||||
// marker , clustered
|
// marker is clustered
|
||||||
const parentCluster = (this.markerClusterGroup as any).getVisibleParent(
|
const parentCluster = (this.markerClusterGroup as any).getVisibleParent(
|
||||||
marker,
|
marker,
|
||||||
);
|
);
|
||||||
@ -368,37 +376,11 @@ export class TripComponent implements AfterViewInit {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
toggleTripDaysHighlight() {
|
highlightTripPath(
|
||||||
if (this.tripMapAntLayerDayID == -1) {
|
items: { text: string; lat: number; lng: number; isPlace: boolean }[],
|
||||||
this.map.removeLayer(this.tripMapAntLayer);
|
layerId: number,
|
||||||
this.tripMapAntLayerDayID = undefined;
|
antDelay = 400,
|
||||||
this.resetMapBounds();
|
): void {
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!this.trip) return;
|
|
||||||
|
|
||||||
const items = this.trip.days
|
|
||||||
.flatMap((day) => day.items.sort((a, b) => a.time.localeCompare(b.time)))
|
|
||||||
.map((item) => {
|
|
||||||
if (item.lat && item.lng)
|
|
||||||
return {
|
|
||||||
text: item.text,
|
|
||||||
lat: item.lat,
|
|
||||||
lng: item.lng,
|
|
||||||
isPlace: !!item.place,
|
|
||||||
};
|
|
||||||
if (item.place && item.place)
|
|
||||||
return {
|
|
||||||
text: item.text,
|
|
||||||
lat: item.place.lat,
|
|
||||||
lng: item.place.lng,
|
|
||||||
isPlace: true,
|
|
||||||
};
|
|
||||||
return undefined;
|
|
||||||
})
|
|
||||||
.filter((n) => n !== undefined);
|
|
||||||
|
|
||||||
if (items.length < 2) {
|
if (items.length < 2) {
|
||||||
this.utilsService.toast(
|
this.utilsService.toast(
|
||||||
"info",
|
"info",
|
||||||
@ -408,7 +390,7 @@ export class TripComponent implements AfterViewInit {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.map.fitBounds(
|
this.map?.fitBounds(
|
||||||
items.map((c) => [c.lat, c.lng]),
|
items.map((c) => [c.lat, c.lng]),
|
||||||
{ padding: [30, 30] },
|
{ padding: [30, 30] },
|
||||||
);
|
);
|
||||||
@ -416,7 +398,7 @@ export class TripComponent implements AfterViewInit {
|
|||||||
const path = antPath(
|
const path = antPath(
|
||||||
items.map((c) => [c.lat, c.lng]),
|
items.map((c) => [c.lat, c.lng]),
|
||||||
{
|
{
|
||||||
delay: 600,
|
delay: antDelay,
|
||||||
dashArray: [10, 20],
|
dashArray: [10, 20],
|
||||||
weight: 5,
|
weight: 5,
|
||||||
color: "#0000FF",
|
color: "#0000FF",
|
||||||
@ -434,34 +416,65 @@ export class TripComponent implements AfterViewInit {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (this.tripMapAntLayer) {
|
if (this.tripMapAntLayer) {
|
||||||
this.map.removeLayer(this.tripMapAntLayer);
|
this.map?.removeLayer(this.tripMapAntLayer);
|
||||||
this.tripMapAntLayerDayID = undefined;
|
this.tripMapAntLayerDayID = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
// UX
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
layGroup.addTo(this.map);
|
layGroup.addTo(this.map!);
|
||||||
}, 200);
|
}, 200);
|
||||||
|
|
||||||
this.tripMapAntLayer = layGroup;
|
this.tripMapAntLayer = layGroup;
|
||||||
this.tripMapAntLayerDayID = -1; //Hardcoded value for global trace
|
this.tripMapAntLayerDayID = layerId;
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleTripDaysHighlight() {
|
||||||
|
if (this.tripMapAntLayerDayID == -1) {
|
||||||
|
this.map?.removeLayer(this.tripMapAntLayer!);
|
||||||
|
this.tripMapAntLayerDayID = undefined;
|
||||||
|
this.resetMapBounds();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!this.trip) return;
|
||||||
|
|
||||||
|
const items = this.trip.days
|
||||||
|
.flatMap((day) => day.items.sort((a, b) => a.time.localeCompare(b.time)))
|
||||||
|
.map((item) => {
|
||||||
|
if (item.lat && item.lng)
|
||||||
|
return {
|
||||||
|
text: item.text,
|
||||||
|
lat: item.lat,
|
||||||
|
lng: item.lng,
|
||||||
|
isPlace: !!item.place,
|
||||||
|
};
|
||||||
|
if (item.place)
|
||||||
|
return {
|
||||||
|
text: item.text,
|
||||||
|
lat: item.place.lat,
|
||||||
|
lng: item.place.lng,
|
||||||
|
isPlace: true,
|
||||||
|
};
|
||||||
|
return undefined;
|
||||||
|
})
|
||||||
|
.filter((n) => n !== undefined);
|
||||||
|
|
||||||
|
this.highlightTripPath(items, -1, 600); //Hardcoded value for global trace
|
||||||
}
|
}
|
||||||
|
|
||||||
toggleTripDayHighlightPathDay(day_id: number) {
|
toggleTripDayHighlightPathDay(day_id: number) {
|
||||||
// Click on the currently displayed day: remove
|
// Click on the currently displayed day: remove
|
||||||
if (this.tripMapAntLayerDayID == day_id) {
|
if (this.tripMapAntLayerDayID == day_id) {
|
||||||
this.map.removeLayer(this.tripMapAntLayer);
|
this.map?.removeLayer(this.tripMapAntLayer!);
|
||||||
this.tripMapAntLayerDayID = undefined;
|
this.tripMapAntLayerDayID = undefined;
|
||||||
this.resetMapBounds();
|
this.resetMapBounds();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let index = this.trip?.days.findIndex((d) => d.id === day_id);
|
const idx = this.trip?.days.findIndex((d) => d.id === day_id);
|
||||||
if (!this.trip || index == -1) return;
|
if (!this.trip || idx === undefined || idx == -1) return;
|
||||||
|
const data = this.trip.days[idx].items.sort((a, b) =>
|
||||||
const data = this.trip.days[index as number].items;
|
a.time.localeCompare(b.time),
|
||||||
|
);
|
||||||
data.sort((a, b) => a.time.localeCompare(b.time));
|
|
||||||
const items = data
|
const items = data
|
||||||
.map((item) => {
|
.map((item) => {
|
||||||
if (item.lat && item.lng)
|
if (item.lat && item.lng)
|
||||||
@ -482,52 +495,7 @@ export class TripComponent implements AfterViewInit {
|
|||||||
})
|
})
|
||||||
.filter((n) => n !== undefined);
|
.filter((n) => n !== undefined);
|
||||||
|
|
||||||
if (items.length < 2) {
|
this.highlightTripPath(items, day_id);
|
||||||
this.utilsService.toast(
|
|
||||||
"info",
|
|
||||||
"Info",
|
|
||||||
"Not enough values to map an itinerary",
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.map.fitBounds(
|
|
||||||
items.map((c) => [c.lat, c.lng]),
|
|
||||||
{ padding: [30, 30] },
|
|
||||||
);
|
|
||||||
|
|
||||||
const path = antPath(
|
|
||||||
items.map((c) => [c.lat, c.lng]),
|
|
||||||
{
|
|
||||||
delay: 400,
|
|
||||||
dashArray: [10, 20],
|
|
||||||
weight: 5,
|
|
||||||
color: "#0000FF",
|
|
||||||
pulseColor: "#FFFFFF",
|
|
||||||
paused: false,
|
|
||||||
reverse: false,
|
|
||||||
hardwareAccelerated: true,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
const layGroup = L.layerGroup();
|
|
||||||
layGroup.addLayer(path);
|
|
||||||
items.forEach((item) => {
|
|
||||||
if (!item.isPlace) layGroup.addLayer(tripDayMarker(item));
|
|
||||||
});
|
|
||||||
|
|
||||||
if (this.tripMapAntLayer) {
|
|
||||||
this.map.removeLayer(this.tripMapAntLayer);
|
|
||||||
this.tripMapAntLayerDayID = undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
// UX
|
|
||||||
setTimeout(() => {
|
|
||||||
layGroup.addTo(this.map);
|
|
||||||
}, 200);
|
|
||||||
|
|
||||||
this.tripMapAntLayer = layGroup;
|
|
||||||
this.tripMapAntLayerDayID = day_id;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onRowClick(item: FlattenedTripItem) {
|
onRowClick(item: FlattenedTripItem) {
|
||||||
@ -552,10 +520,13 @@ export class TripComponent implements AfterViewInit {
|
|||||||
data: `Delete ${this.trip?.name} ? This will delete everything.`,
|
data: `Delete ${this.trip?.name} ? This will delete everything.`,
|
||||||
});
|
});
|
||||||
|
|
||||||
modal.onClose.subscribe({
|
modal.onClose.pipe(take(1)).subscribe({
|
||||||
next: (bool) => {
|
next: (bool) => {
|
||||||
if (bool)
|
if (bool)
|
||||||
this.apiService.deleteTrip(this.trip?.id!).subscribe({
|
this.apiService
|
||||||
|
.deleteTrip(this.trip?.id!)
|
||||||
|
.pipe(take(1))
|
||||||
|
.subscribe({
|
||||||
next: () => {
|
next: () => {
|
||||||
this.router.navigateByUrl("/trips");
|
this.router.navigateByUrl("/trips");
|
||||||
},
|
},
|
||||||
@ -581,11 +552,14 @@ export class TripComponent implements AfterViewInit {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
modal.onClose.subscribe({
|
modal.onClose.pipe(take(1)).subscribe({
|
||||||
next: (new_trip: Trip | null) => {
|
next: (new_trip: Trip | null) => {
|
||||||
if (!new_trip) return;
|
if (!new_trip) return;
|
||||||
|
|
||||||
this.apiService.putTrip(new_trip, this.trip?.id!).subscribe({
|
this.apiService
|
||||||
|
.putTrip(new_trip, this.trip?.id!)
|
||||||
|
.pipe(take(1))
|
||||||
|
.subscribe({
|
||||||
next: (trip: Trip) => (this.trip = trip),
|
next: (trip: Trip) => (this.trip = trip),
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@ -605,11 +579,12 @@ export class TripComponent implements AfterViewInit {
|
|||||||
data: `${currentArchiveStatus ? "Restore" : "Archive"} ${this.trip?.name} ?${currentArchiveStatus ? "" : " This will make everything read-only."}`,
|
data: `${currentArchiveStatus ? "Restore" : "Archive"} ${this.trip?.name} ?${currentArchiveStatus ? "" : " This will make everything read-only."}`,
|
||||||
});
|
});
|
||||||
|
|
||||||
modal.onClose.subscribe({
|
modal.onClose.pipe(take(1)).subscribe({
|
||||||
next: (bool) => {
|
next: (bool) => {
|
||||||
if (bool)
|
if (bool)
|
||||||
this.apiService
|
this.apiService
|
||||||
.putTrip({ archived: !currentArchiveStatus }, this.trip?.id!)
|
.putTrip({ archived: !currentArchiveStatus }, this.trip?.id!)
|
||||||
|
.pipe(take(1))
|
||||||
.subscribe({
|
.subscribe({
|
||||||
next: () => {
|
next: () => {
|
||||||
this.trip!.archived = !currentArchiveStatus;
|
this.trip!.archived = !currentArchiveStatus;
|
||||||
@ -620,6 +595,8 @@ export class TripComponent implements AfterViewInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
addDay() {
|
addDay() {
|
||||||
|
if (!this.trip) return;
|
||||||
|
|
||||||
const modal: DynamicDialogRef = this.dialogService.open(
|
const modal: DynamicDialogRef = this.dialogService.open(
|
||||||
TripCreateDayModalComponent,
|
TripCreateDayModalComponent,
|
||||||
{
|
{
|
||||||
@ -629,20 +606,23 @@ export class TripComponent implements AfterViewInit {
|
|||||||
closable: true,
|
closable: true,
|
||||||
dismissableMask: true,
|
dismissableMask: true,
|
||||||
width: "50vw",
|
width: "50vw",
|
||||||
data: { days: this.trip?.days },
|
data: { days: this.trip.days },
|
||||||
breakpoints: {
|
breakpoints: {
|
||||||
"640px": "80vw",
|
"640px": "80vw",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
modal.onClose.subscribe({
|
modal.onClose.pipe(take(1)).subscribe({
|
||||||
next: (day: TripDay | null) => {
|
next: (day: TripDay | null) => {
|
||||||
if (!day) return;
|
if (!day) return;
|
||||||
|
|
||||||
this.apiService.postTripDay(day, this.trip?.id!).subscribe({
|
this.apiService
|
||||||
|
.postTripDay(day, this.trip?.id!)
|
||||||
|
.pipe(take(1))
|
||||||
|
.subscribe({
|
||||||
next: (day) => {
|
next: (day) => {
|
||||||
this.trip?.days.push(day);
|
this.trip!.days.push(day);
|
||||||
this.flattenTripDayItems();
|
this.flattenTripDayItems();
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@ -651,6 +631,8 @@ export class TripComponent implements AfterViewInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
editDay(day: TripDay) {
|
editDay(day: TripDay) {
|
||||||
|
if (!this.trip) return;
|
||||||
|
|
||||||
const modal: DynamicDialogRef = this.dialogService.open(
|
const modal: DynamicDialogRef = this.dialogService.open(
|
||||||
TripCreateDayModalComponent,
|
TripCreateDayModalComponent,
|
||||||
{
|
{
|
||||||
@ -660,22 +642,25 @@ export class TripComponent implements AfterViewInit {
|
|||||||
closable: true,
|
closable: true,
|
||||||
dismissableMask: true,
|
dismissableMask: true,
|
||||||
width: "50vw",
|
width: "50vw",
|
||||||
data: { day: day, days: this.trip?.days },
|
data: { day: day, days: this.trip.days },
|
||||||
breakpoints: {
|
breakpoints: {
|
||||||
"640px": "80vw",
|
"640px": "80vw",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
modal.onClose.subscribe({
|
modal.onClose.pipe(take(1)).subscribe({
|
||||||
next: (day: TripDay | null) => {
|
next: (day: TripDay | null) => {
|
||||||
if (!day) return;
|
if (!day) return;
|
||||||
|
|
||||||
this.apiService.putTripDay(day, this.trip?.id!).subscribe({
|
this.apiService
|
||||||
|
.putTripDay(day, this.trip?.id!)
|
||||||
|
.pipe(take(1))
|
||||||
|
.subscribe({
|
||||||
next: (day) => {
|
next: (day) => {
|
||||||
let index = this.trip?.days.findIndex((d) => d.id == day.id);
|
const idx = this.trip!.days.findIndex((d) => d.id == day.id);
|
||||||
if (index != -1) {
|
if (idx != -1) {
|
||||||
this.trip?.days.splice(index as number, 1, day);
|
this.trip?.days.splice(idx, 1, day);
|
||||||
this.flattenTripDayItems();
|
this.flattenTripDayItems();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -685,6 +670,8 @@ export class TripComponent implements AfterViewInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
deleteDay(day: TripDay) {
|
deleteDay(day: TripDay) {
|
||||||
|
if (!this.trip) return;
|
||||||
|
|
||||||
const modal = this.dialogService.open(YesNoModalComponent, {
|
const modal = this.dialogService.open(YesNoModalComponent, {
|
||||||
header: "Confirm deletion",
|
header: "Confirm deletion",
|
||||||
modal: true,
|
modal: true,
|
||||||
@ -696,15 +683,20 @@ export class TripComponent implements AfterViewInit {
|
|||||||
data: `Delete ${day.label} ? This will delete everything for this day.`,
|
data: `Delete ${day.label} ? This will delete everything for this day.`,
|
||||||
});
|
});
|
||||||
|
|
||||||
modal.onClose.subscribe({
|
modal.onClose.pipe(take(1)).subscribe({
|
||||||
next: (bool) => {
|
next: (bool) => {
|
||||||
if (bool)
|
if (bool)
|
||||||
this.apiService.deleteTripDay(this.trip?.id!, day.id).subscribe({
|
this.apiService
|
||||||
|
.deleteTripDay(this.trip?.id!, day.id)
|
||||||
|
.pipe(take(1))
|
||||||
|
.subscribe({
|
||||||
next: () => {
|
next: () => {
|
||||||
let index = this.trip?.days.findIndex((d) => d.id == day.id);
|
const idx = this.trip!.days.findIndex((d) => d.id == day.id);
|
||||||
this.trip?.days.splice(index as number, 1);
|
if (idx != -1) {
|
||||||
|
this.trip!.days.splice(idx, 1);
|
||||||
this.flattenTripDayItems();
|
this.flattenTripDayItems();
|
||||||
this.setPlacesAndMarkers();
|
this.setPlacesAndMarkers();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@ -712,6 +704,8 @@ export class TripComponent implements AfterViewInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
manageTripPlaces() {
|
manageTripPlaces() {
|
||||||
|
if (!this.trip) return;
|
||||||
|
|
||||||
const modal: DynamicDialogRef = this.dialogService.open(
|
const modal: DynamicDialogRef = this.dialogService.open(
|
||||||
TripPlaceSelectModalComponent,
|
TripPlaceSelectModalComponent,
|
||||||
{
|
{
|
||||||
@ -728,12 +722,13 @@ export class TripComponent implements AfterViewInit {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
modal.onClose.subscribe({
|
modal.onClose.pipe(take(1)).subscribe({
|
||||||
next: (places: Place[] | null) => {
|
next: (places: Place[] | null) => {
|
||||||
if (!places) return;
|
if (!places) return;
|
||||||
|
|
||||||
this.apiService
|
this.apiService
|
||||||
.putTrip({ place_ids: places.map((p) => p.id) }, this.trip?.id!)
|
.putTrip({ place_ids: places.map((p) => p.id) }, this.trip!.id)
|
||||||
|
.pipe(take(1))
|
||||||
.subscribe({
|
.subscribe({
|
||||||
next: (trip) => {
|
next: (trip) => {
|
||||||
this.trip = trip;
|
this.trip = trip;
|
||||||
@ -746,6 +741,8 @@ export class TripComponent implements AfterViewInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
addItem(day_id?: number) {
|
addItem(day_id?: number) {
|
||||||
|
if (!this.trip) return;
|
||||||
|
|
||||||
const modal: DynamicDialogRef = this.dialogService.open(
|
const modal: DynamicDialogRef = this.dialogService.open(
|
||||||
TripCreateDayItemModalComponent,
|
TripCreateDayItemModalComponent,
|
||||||
{
|
{
|
||||||
@ -760,22 +757,25 @@ export class TripComponent implements AfterViewInit {
|
|||||||
},
|
},
|
||||||
data: {
|
data: {
|
||||||
places: this.places,
|
places: this.places,
|
||||||
days: this.trip?.days,
|
days: this.trip.days,
|
||||||
selectedDay: day_id,
|
selectedDay: day_id,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
modal.onClose.subscribe({
|
modal.onClose.pipe(take(1)).subscribe({
|
||||||
next: (item: TripItem | null) => {
|
next: (item: TripItem | null) => {
|
||||||
if (!item) return;
|
if (!item) return;
|
||||||
|
|
||||||
this.apiService
|
this.apiService
|
||||||
.postTripDayItem(item, this.trip?.id!, item.day_id)
|
.postTripDayItem(item, this.trip!.id!, item.day_id)
|
||||||
|
.pipe(take(1))
|
||||||
.subscribe({
|
.subscribe({
|
||||||
next: (resp) => {
|
next: (resp) => {
|
||||||
let index = this.trip?.days.findIndex((d) => d.id == item.day_id);
|
const idx = this.trip!.days.findIndex((d) => d.id == item.day_id);
|
||||||
let td: TripDay = this.trip?.days[index as number]!;
|
if (idx === -1) return;
|
||||||
|
|
||||||
|
const td: TripDay = this.trip!.days[idx];
|
||||||
td.items.push(resp);
|
td.items.push(resp);
|
||||||
this.flattenTripDayItems();
|
this.flattenTripDayItems();
|
||||||
|
|
||||||
@ -792,6 +792,8 @@ export class TripComponent implements AfterViewInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
editItem(item: TripItem) {
|
editItem(item: TripItem) {
|
||||||
|
if (!this.trip) return;
|
||||||
|
|
||||||
const modal: DynamicDialogRef = this.dialogService.open(
|
const modal: DynamicDialogRef = this.dialogService.open(
|
||||||
TripCreateDayItemModalComponent,
|
TripCreateDayItemModalComponent,
|
||||||
{
|
{
|
||||||
@ -815,57 +817,16 @@ export class TripComponent implements AfterViewInit {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
modal.onClose.subscribe({
|
modal.onClose.pipe(take(1)).subscribe({
|
||||||
next: (it: TripItem | null) => {
|
next: (updated: TripItem | null) => {
|
||||||
if (!it) return;
|
if (!updated) return;
|
||||||
if (item.place?.id) this.placesUsedInTable.delete(item.place.id);
|
if (item.place?.id) this.placesUsedInTable.delete(item.place.id);
|
||||||
|
|
||||||
this.apiService
|
this.apiService
|
||||||
.putTripDayItem(it, this.trip?.id!, item.day_id, item.id)
|
.putTripDayItem(updated, this.trip!.id, item.day_id, item.id)
|
||||||
|
.pipe(take(1))
|
||||||
.subscribe({
|
.subscribe({
|
||||||
next: (new_item) => {
|
next: (new_item) => this.updateItemFromTrip(item, new_item),
|
||||||
if (item.day_id != new_item.day_id) {
|
|
||||||
let previousIndex = this.trip?.days.findIndex(
|
|
||||||
(d) => d.id == item.day_id,
|
|
||||||
);
|
|
||||||
this.trip?.days[previousIndex as number]!.items.splice(
|
|
||||||
this.trip?.days[previousIndex as number]!.items.findIndex(
|
|
||||||
(i) => i.id == new_item.id,
|
|
||||||
),
|
|
||||||
1,
|
|
||||||
);
|
|
||||||
this.dayStatsCache.delete(item.day_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
let index = this.trip?.days.findIndex(
|
|
||||||
(d) => d.id == new_item.day_id,
|
|
||||||
);
|
|
||||||
let td: TripDay = this.trip?.days[index as number]!;
|
|
||||||
td.items.splice(
|
|
||||||
td.items.findIndex((i) => i.id == new_item.id),
|
|
||||||
1,
|
|
||||||
new_item,
|
|
||||||
);
|
|
||||||
this.flattenTripDayItems();
|
|
||||||
if (this.selectedItem && this.selectedItem.id === item.id)
|
|
||||||
this.selectedItem = {
|
|
||||||
...new_item,
|
|
||||||
status: new_item.status
|
|
||||||
? this.statusToTripStatus(new_item.status as string)
|
|
||||||
: undefined,
|
|
||||||
};
|
|
||||||
this.dayStatsCache.delete(new_item.day_id);
|
|
||||||
|
|
||||||
this.computePlacesUsedInTable();
|
|
||||||
const updatedPrice = -(new_item.price || 0) + (item.price || 0);
|
|
||||||
this.updateTotalPrice(updatedPrice);
|
|
||||||
|
|
||||||
if (this.tripMapAntLayerDayID == new_item.day_id)
|
|
||||||
this.toggleTripDayHighlightPathDay(new_item.day_id);
|
|
||||||
|
|
||||||
if (new_item.place?.id || item.place?.id)
|
|
||||||
this.setPlacesAndMarkers();
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@ -883,33 +844,15 @@ export class TripComponent implements AfterViewInit {
|
|||||||
data: `Delete ${item.text.substring(0, 50)} ? This will delete everything for this day.`,
|
data: `Delete ${item.text.substring(0, 50)} ? This will delete everything for this day.`,
|
||||||
});
|
});
|
||||||
|
|
||||||
modal.onClose.subscribe({
|
modal.onClose.pipe(take(1)).subscribe({
|
||||||
next: (bool) => {
|
next: (bool) => {
|
||||||
if (bool)
|
if (!bool) return;
|
||||||
this.apiService
|
this.apiService
|
||||||
.deleteTripDayItem(this.trip?.id!, item.day_id, item.id)
|
.deleteTripDayItem(this.trip?.id!, item.day_id, item.id)
|
||||||
|
.pipe(take(1))
|
||||||
.subscribe({
|
.subscribe({
|
||||||
next: () => {
|
next: () => {
|
||||||
let index = this.trip?.days.findIndex(
|
this.removeItemFromTrip(item);
|
||||||
(d) => d.id == item.day_id,
|
|
||||||
);
|
|
||||||
|
|
||||||
let td: TripDay = this.trip?.days[index as number]!;
|
|
||||||
td.items.splice(
|
|
||||||
td.items.findIndex((i) => i.id == item.id),
|
|
||||||
1,
|
|
||||||
);
|
|
||||||
this.flattenTripDayItems();
|
|
||||||
|
|
||||||
if (item.place?.id) {
|
|
||||||
this.placesUsedInTable.delete(item.place.id);
|
|
||||||
if (item.place.price)
|
|
||||||
this.updateTotalPrice(-item.place.price);
|
|
||||||
this.setPlacesAndMarkers();
|
|
||||||
}
|
|
||||||
this.dayStatsCache.delete(item.day_id);
|
|
||||||
this.selectedItem = undefined;
|
|
||||||
this.resetPlaceHighlightMarker();
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@ -917,6 +860,8 @@ export class TripComponent implements AfterViewInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
addItems() {
|
addItems() {
|
||||||
|
if (!this.trip) return;
|
||||||
|
|
||||||
const modal: DynamicDialogRef = this.dialogService.open(
|
const modal: DynamicDialogRef = this.dialogService.open(
|
||||||
TripCreateItemsModalComponent,
|
TripCreateItemsModalComponent,
|
||||||
{
|
{
|
||||||
@ -929,29 +874,28 @@ export class TripComponent implements AfterViewInit {
|
|||||||
breakpoints: {
|
breakpoints: {
|
||||||
"1260px": "90vw",
|
"1260px": "90vw",
|
||||||
},
|
},
|
||||||
data: { days: this.trip?.days },
|
data: { days: this.trip.days },
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
modal.onClose.subscribe({
|
modal.onClose.pipe(take(1)).subscribe({
|
||||||
next: (items: TripItem[] | null) => {
|
next: (items: TripItem[] | null) => {
|
||||||
if (!items?.length) return;
|
if (!items?.length) return;
|
||||||
const day_id = items[0].day_id;
|
const day_id = items[0].day_id;
|
||||||
|
|
||||||
const obs$ = items.map((item) =>
|
const obs$ = items.map((item) =>
|
||||||
this.apiService.postTripDayItem(item, this.trip?.id!, item.day_id),
|
this.apiService.postTripDayItem(item, this.trip!.id!, item.day_id),
|
||||||
);
|
);
|
||||||
|
|
||||||
forkJoin(obs$)
|
forkJoin(obs$).subscribe({
|
||||||
.pipe(
|
next: (items: TripItem[]) => {
|
||||||
map((items) => {
|
const index = this.trip!.days.findIndex((d) => d.id == day_id);
|
||||||
let index = this.trip?.days.findIndex((d) => d.id == day_id);
|
if (index === -1) return;
|
||||||
let td: TripDay = this.trip?.days[index as number]!;
|
|
||||||
|
const td: TripDay = this.trip!.days[index]!;
|
||||||
td.items.push(...items);
|
td.items.push(...items);
|
||||||
this.flattenTripDayItems();
|
this.flattenTripDayItems();
|
||||||
}),
|
},
|
||||||
)
|
});
|
||||||
.subscribe();
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -973,16 +917,20 @@ export class TripComponent implements AfterViewInit {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
modal.onClose.subscribe({
|
modal.onClose.pipe(take(1)).subscribe({
|
||||||
next: (place: Place | null) => {
|
next: (place: Place | null) => {
|
||||||
if (!place) return;
|
if (!place) return;
|
||||||
|
|
||||||
this.apiService.postPlace(place).subscribe({
|
|
||||||
next: (place: Place) => {
|
|
||||||
this.apiService
|
this.apiService
|
||||||
.putTrip(
|
.postPlace(place)
|
||||||
{ place_ids: [place, ...this.places].map((p) => p.id) },
|
.pipe(
|
||||||
|
switchMap((createdPlace: Place) =>
|
||||||
|
this.apiService.putTrip(
|
||||||
|
{ place_ids: [createdPlace, ...this.places].map((p) => p.id) },
|
||||||
this.trip?.id!,
|
this.trip?.id!,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
take(1),
|
||||||
)
|
)
|
||||||
.subscribe({
|
.subscribe({
|
||||||
next: (trip) => {
|
next: (trip) => {
|
||||||
@ -993,7 +941,70 @@ export class TripComponent implements AfterViewInit {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
});
|
|
||||||
|
updateItemFromTrip(old: TripItem, updated: TripItem): void {
|
||||||
|
if (!this.trip) return;
|
||||||
|
|
||||||
|
if (old.day_id != updated.day_id) {
|
||||||
|
const prevDayIdx = this.trip.days.findIndex((d) => d.id == old.day_id);
|
||||||
|
if (prevDayIdx === -1) {
|
||||||
|
const prevDay = this.trip.days[prevDayIdx];
|
||||||
|
const prevItemIdx = prevDay.items.findIndex((i) => i.id == updated.id);
|
||||||
|
if (prevItemIdx != -1) prevDay.items.splice(prevItemIdx, 1);
|
||||||
|
this.dayStatsCache.delete(old.day_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const dayIdx = this.trip.days.findIndex((d) => d.id == updated.day_id);
|
||||||
|
if (dayIdx != -1) {
|
||||||
|
const day = this.trip.days[dayIdx];
|
||||||
|
const itemIdx = day.items.findIndex((i) => i.id === updated.id);
|
||||||
|
if (itemIdx !== -1) {
|
||||||
|
day.items[itemIdx] = updated;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.flattenTripDayItems();
|
||||||
|
|
||||||
|
if (this.selectedItem && this.selectedItem.id === old.id)
|
||||||
|
this.selectedItem = {
|
||||||
|
...updated,
|
||||||
|
status: updated.status
|
||||||
|
? this.statusToTripStatus(updated.status as string)
|
||||||
|
: undefined,
|
||||||
|
};
|
||||||
|
this.dayStatsCache.delete(updated.day_id);
|
||||||
|
this.computePlacesUsedInTable();
|
||||||
|
|
||||||
|
const updatedPrice = (updated.price || 0) - (old.price || 0);
|
||||||
|
this.updateTotalPrice(updatedPrice);
|
||||||
|
|
||||||
|
if (this.tripMapAntLayerDayID == updated.day_id)
|
||||||
|
this.toggleTripDayHighlightPathDay(updated.day_id);
|
||||||
|
|
||||||
|
if (updated.place?.id || old.place?.id) this.setPlacesAndMarkers();
|
||||||
|
}
|
||||||
|
|
||||||
|
removeItemFromTrip(item: TripItem): void {
|
||||||
|
if (!this.trip) return;
|
||||||
|
const dayIndex = this.trip.days.findIndex((d) => d.id === item.day_id);
|
||||||
|
if (dayIndex === -1) return;
|
||||||
|
|
||||||
|
const day = this.trip.days[dayIndex];
|
||||||
|
const itemIndex = day.items.findIndex((i) => i.id === item.id);
|
||||||
|
if (itemIndex != -1) {
|
||||||
|
day.items.splice(itemIndex, 1);
|
||||||
|
this.flattenTripDayItems();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item.place?.id) {
|
||||||
|
this.placesUsedInTable.delete(item.place.id);
|
||||||
|
if (item.place.price) this.updateTotalPrice(-item.place.price);
|
||||||
|
this.setPlacesAndMarkers();
|
||||||
|
}
|
||||||
|
this.dayStatsCache.delete(item.day_id);
|
||||||
|
this.selectedItem = undefined;
|
||||||
|
this.resetPlaceHighlightMarker();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user