From 0fdd149dc9760dcf5f6b8d8bdd7aaab94f24a39b Mon Sep 17 00:00:00 2001 From: itskovacs Date: Sat, 16 Aug 2025 16:15:32 +0200 Subject: [PATCH] :sparkles: Trip: table filtering --- .../app/components/trip/trip.component.html | 106 +++++++++++------- src/src/app/components/trip/trip.component.ts | 58 +++++++++- 2 files changed, 118 insertions(+), 46 deletions(-) diff --git a/src/src/app/components/trip/trip.component.html b/src/src/app/components/trip/trip.component.html index 283130f..9d0c2f5 100644 --- a/src/src/app/components/trip/trip.component.html +++ b/src/src/app/components/trip/trip.component.html @@ -60,6 +60,7 @@ + @if (isFilteringMode) { +
+ + + +
+ } + @defer { @if (flattenedTripItems.length) { - Day - Time - Text - Place - Comment - LatLng - Price - Status + @if (!tableExpandableMode && tripTableSelectedColumns.includes('day')) {Day + } + @if (tripTableSelectedColumns.includes('time')) {Time} + @if (tripTableSelectedColumns.includes('text')) {Text} + @if (tripTableSelectedColumns.includes('place')) {Place} + @if (tripTableSelectedColumns.includes('comment')) {Comment} + @if (tripTableSelectedColumns.includes('LatLng')) {LatLng} + @if (tripTableSelectedColumns.includes('price')) {Price} + @if (tripTableSelectedColumns.includes('status')) {Status} @if (tableExpandableMode) { @@ -113,37 +124,41 @@ - {{ tripitem.td_label }} - {{ tripitem.time }} - -
- @if (tripitem.status) {
{{ tripitem.time }}} + @if (tripTableSelectedColumns.includes('text')) { +
+ @if (tripitem.status) {
} {{ tripitem.text }}
- - + } + @if (tripTableSelectedColumns.includes('place')) { @if (tripitem.place) { -
+
{{ tripitem.place.name }}
} @else {-} - - {{ tripitem.comment || '-' }} - -
+ } + @if (tripTableSelectedColumns.includes('comment')) { +
+ {{ tripitem.comment || '-' }} +
+ } + @if (tripTableSelectedColumns.includes('LatLng')) { +
@if (tripitem.lat) { {{ tripitem.lat }}, {{ tripitem.lng }} } @else {-}
- - @if (tripitem.price) {} + @if (tripTableSelectedColumns.includes('price')) {@if (tripitem.price) {{{ - tripitem.price }} {{ currency$ | async }}} - @if (tripitem.status) {{{ - tripitem.status.label }}} + tripitem.price }} {{ currency$ | async }}}} + @if (tripTableSelectedColumns.includes('status')) {@if (tripitem.status) {{{ + tripitem.status.label }}}} } @@ -151,22 +166,22 @@ - @if (rowgroup) { + @if (tripTableSelectedColumns.includes('day') && rowgroup) {
{{tripitem.td_label }}
} - {{ tripitem.time }} - -
- {{ tripitem.text }} - @if (tripitem.status) {
{{ tripitem.time }}} + @if (tripTableSelectedColumns.includes('text')) { +
+ @if (tripitem.status) {
} + {{ tripitem.text }}
- - + } + @if (tripTableSelectedColumns.includes('place')) { @if (tripitem.place) {
} @else {-} - - {{ tripitem.comment || '-' }} - + } + @if (tripTableSelectedColumns.includes('comment')) { +
+ {{ tripitem.comment || '-' }} +
+ } + @if (tripTableSelectedColumns.includes('LatLng')) {
@if (tripitem.lat) { {{ tripitem.lat }}, {{ tripitem.lng }} } @else {-}
- - @if (tripitem.price) {} + @if (tripTableSelectedColumns.includes('price')) {@if (tripitem.price) {{{ - tripitem.price }} {{ currency$ | async }}} - @if (tripitem.status) {{{ - tripitem.status.label }}} + tripitem.price }} {{ currency$ | async }}}} + @if (tripTableSelectedColumns.includes('status')) {@if (tripitem.status) {{{ + tripitem.status.label }}}} } diff --git a/src/src/app/components/trip/trip.component.ts b/src/src/app/components/trip/trip.component.ts index 53c8656..63de307 100644 --- a/src/src/app/components/trip/trip.component.ts +++ b/src/src/app/components/trip/trip.component.ts @@ -1,6 +1,6 @@ import { AfterViewInit, Component } from "@angular/core"; import { ApiService } from "../../services/api.service"; -import { FormsModule, ReactiveFormsModule } from "@angular/forms"; +import { FormControl, FormsModule, ReactiveFormsModule } from "@angular/forms"; import { ButtonModule } from "primeng/button"; import { InputTextModule } from "primeng/inputtext"; import { SkeletonModule } from "primeng/skeleton"; @@ -30,6 +30,7 @@ import { TripCreateDayItemModalComponent } from "../../modals/trip-create-day-it import { TripCreateItemsModalComponent } from "../../modals/trip-create-items-modal/trip-create-items-modal.component"; import { combineLatest, + debounceTime, forkJoin, Observable, of, @@ -48,16 +49,19 @@ import { PlaceCreateModalComponent } from "../../modals/place-create-modal/place import { Settings } from "../../types/settings"; import { DialogModule } from "primeng/dialog"; import { ClipboardModule } from "@angular/cdk/clipboard"; +import { TooltipModule } from "primeng/tooltip"; +import { MultiSelectModule } from "primeng/multiselect"; +import { takeUntilDestroyed } from "@angular/core/rxjs-interop"; @Component({ selector: "app-trip", standalone: true, imports: [ CommonModule, + ReactiveFormsModule, FormsModule, SkeletonModule, MenuModule, - ReactiveFormsModule, InputTextModule, AsyncPipe, LinkifyPipe, @@ -66,7 +70,9 @@ import { ClipboardModule } from "@angular/cdk/clipboard"; ButtonModule, DecimalPipe, DialogModule, + TooltipModule, ClipboardModule, + MultiSelectModule, ], templateUrl: "./trip.component.html", styleUrls: ["./trip.component.scss"], @@ -88,6 +94,7 @@ export class TripComponent implements AfterViewInit { collapsedTripStatuses = false; shareDialogVisible = false; isExpanded = false; + isFilteringMode = false; map?: L.Map; markerClusterGroup?: L.MarkerClusterGroup; @@ -152,6 +159,13 @@ export class TripComponent implements AfterViewInit { this.tripToNavigation(); }, }, + { + label: "Filter", + icon: "pi pi-filter", + command: () => { + this.toggleFiltering(); + }, + }, { label: "Expand / Group", icon: "pi pi-arrow-down-left-and-arrow-up-right-to-center", @@ -201,6 +215,24 @@ export class TripComponent implements AfterViewInit { ], }, ]; + readonly tripTableColumns: string[] = [ + "day", + "time", + "text", + "place", + "comment", + "LatLng", + "price", + "status", + ]; + tripTableSelectedColumns: string[] = [ + "day", + "time", + "text", + "place", + "comment", + ]; + tripTableSearchInput = new FormControl(""); selectedTripDayForMenu?: TripDay; dayStatsCache = new Map(); @@ -215,6 +247,14 @@ export class TripComponent implements AfterViewInit { ) { this.currency$ = this.utilsService.currency$; this.statuses = this.utilsService.statuses; + this.tripTableSearchInput.valueChanges + .pipe(takeUntilDestroyed(), debounceTime(300)) + .subscribe({ + next: (value) => { + if (value) this.flattenTripDayItems(value.toLowerCase()); + else this.flattenTripDayItems(); + }, + }); } ngAfterViewInit(): void { @@ -284,6 +324,11 @@ export class TripComponent implements AfterViewInit { this.trip?.days.sort((a, b) => a.label.localeCompare(b.label)); } + toggleFiltering() { + this.isFilteringMode = !this.isFilteringMode; + if (!this.isFilteringMode) this.flattenTripDayItems(); + } + getDayStats(day: TripDay): { price: number; places: number } { if (this.dayStatsCache.has(day.id)) return this.dayStatsCache.get(day.id)!; @@ -323,10 +368,17 @@ export class TripComponent implements AfterViewInit { return this.statuses.find((s) => s.label == status); } - flattenTripDayItems() { + flattenTripDayItems(searchValue?: string) { this.sortTripDays(); this.flattenedTripItems = this.trip!.days.flatMap((day) => [...day.items] + .filter((item) => + searchValue + ? item.text.toLowerCase().includes(searchValue) || + item.place?.name.toLowerCase().includes(searchValue) || + item.comment?.toLowerCase().includes(searchValue) + : true, + ) .sort((a, b) => a.time.localeCompare(b.time)) .map((item) => ({ td_id: day.id,