✨ Trip: Archive review
This commit is contained in:
parent
3cc466e518
commit
41f275fae3
@ -1,5 +1,5 @@
|
|||||||
<section class="mt-4" [class.prettyprint]="isPrinting">
|
<section class="mt-4" [class.prettyprint]="isPrinting">
|
||||||
<div class="p-4 print:p-0 flex items-center justify-between">
|
<div class="p-4 print:p-0 flex flex-wrap items-center justify-between">
|
||||||
<div class="flex items-center gap-2">
|
<div class="flex items-center gap-2">
|
||||||
<p-button text icon="pi pi-chevron-left" class="print:hidden" (click)="back()" severity="secondary" />
|
<p-button text icon="pi pi-chevron-left" class="print:hidden" (click)="back()" severity="secondary" />
|
||||||
<div class="flex flex-col max-w-[55vw] md:max-w-full">
|
<div class="flex flex-col max-w-[55vw] md:max-w-full">
|
||||||
@ -16,6 +16,20 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@if (trip?.archived) {
|
||||||
|
<div class="mx-auto p-4 mt-4 md:mt-0 w-full md:w-fit text-orange-800 rounded-md bg-orange-50"
|
||||||
|
[class.prettyprint]="isPrinting">
|
||||||
|
<div class="text-center font-semibold">This Trip is archived, you cannot modify it.</div>
|
||||||
|
<div class="mt-2 flex items-center justify-between">
|
||||||
|
@if (trip?.archival_review) {
|
||||||
|
<p-button text icon="pi pi-comment" [label]="isArchivalReviewDisplayed ? 'Hide review' : 'View review'"
|
||||||
|
(click)="isArchivalReviewDisplayed = !isArchivalReviewDisplayed" />
|
||||||
|
}
|
||||||
|
<p-button text icon="pi pi-box" label="Restore" severity="success" (click)="openUnarchiveTripModal()" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
<div class="hidden print:flex flex-col items-center">
|
<div class="hidden print:flex flex-col items-center">
|
||||||
<img src="favicon.png" class="size-20">
|
<img src="favicon.png" class="size-20">
|
||||||
<div class="flex gap-2 items-center text-xs text-gray-500"><i class="pi pi-github"></i>itskovacs/trip</div>
|
<div class="flex gap-2 items-center text-xs text-gray-500"><i class="pi pi-github"></i>itskovacs/trip</div>
|
||||||
@ -29,18 +43,13 @@
|
|||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
|
||||||
|
|
||||||
@if (trip?.archived) {
|
@if (isArchivalReviewDisplayed) {
|
||||||
<div class="mx-auto p-4 my-4 w-fit max-w-[400px] text-center text-orange-800 rounded-lg bg-orange-50"
|
<div
|
||||||
[class.prettyprint]="isPrinting">
|
class="m-4 whitespace-pre-line text-gray-800 dark:text-gray-200 max-h-[600px] overflow-y-auto p-4 rounded border border-gray-300 dark:border-gray-600 bg-gray-50 dark:bg-gray-800">
|
||||||
<div class="flex items-center justify-between">
|
{{ trip?.archival_review }}</div>
|
||||||
<div class="font-semibold">Archived</div>
|
}
|
||||||
<p-button text icon="pi pi-box" label="Restore" (click)="toggleArchiveTrip()" [size]="'small'" />
|
</section>
|
||||||
</div>
|
|
||||||
This Trip is archived, you cannot modify it.
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
|
|
||||||
<section class="p-4 print:px-1 grid lg:grid-cols-3 gap-4 print:block" [class.prettyprint]="isPrinting">
|
<section class="p-4 print:px-1 grid lg:grid-cols-3 gap-4 print:block" [class.prettyprint]="isPrinting">
|
||||||
<div [ngClass]="isExpanded ? 'lg:col-span-3' : 'lg:col-span-2'" class="p-4 shadow self-start rounded-md max-w-screen">
|
<div [ngClass]="isExpanded ? 'lg:col-span-3' : 'lg:col-span-2'" class="p-4 shadow self-start rounded-md max-w-screen">
|
||||||
|
|||||||
@ -63,6 +63,7 @@ import { TripInviteMemberModalComponent } from "../../modals/trip-invite-member-
|
|||||||
import { calculateDistanceBetween } from "../../shared/haversine";
|
import { calculateDistanceBetween } from "../../shared/haversine";
|
||||||
import { orderByPipe } from "../../shared/order-by.pipe";
|
import { orderByPipe } from "../../shared/order-by.pipe";
|
||||||
import { TripNotesModalComponent } from "../../modals/trip-notes-modal/trip-notes-modal.component";
|
import { TripNotesModalComponent } from "../../modals/trip-notes-modal/trip-notes-modal.component";
|
||||||
|
import { TripArchiveModalComponent } from "../../modals/trip-archive-modal/trip-archive-modal.component";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: "app-trip",
|
selector: "app-trip",
|
||||||
@ -99,6 +100,7 @@ export class TripComponent implements AfterViewInit {
|
|||||||
selectedItem?: TripItem & { status?: TripStatus };
|
selectedItem?: TripItem & { status?: TripStatus };
|
||||||
tableExpandableMode = false;
|
tableExpandableMode = false;
|
||||||
isPrinting = false;
|
isPrinting = false;
|
||||||
|
isArchivalReviewDisplayed = false;
|
||||||
|
|
||||||
isMapFullscreen = false;
|
isMapFullscreen = false;
|
||||||
isMapFullscreenDays = false;
|
isMapFullscreenDays = false;
|
||||||
@ -185,7 +187,7 @@ export class TripComponent implements AfterViewInit {
|
|||||||
label: "Archive",
|
label: "Archive",
|
||||||
icon: "pi pi-box",
|
icon: "pi pi-box",
|
||||||
command: () => {
|
command: () => {
|
||||||
this.toggleArchiveTrip();
|
this.openArchiveTripModal();
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -942,30 +944,59 @@ export class TripComponent implements AfterViewInit {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
toggleArchiveTrip() {
|
openUnarchiveTripModal() {
|
||||||
const currentArchiveStatus = this.trip?.archived;
|
|
||||||
const modal = this.dialogService.open(YesNoModalComponent, {
|
const modal = this.dialogService.open(YesNoModalComponent, {
|
||||||
header: "Confirm Action",
|
header: "Restore Trip",
|
||||||
modal: true,
|
modal: true,
|
||||||
closable: true,
|
closable: true,
|
||||||
dismissableMask: true,
|
dismissableMask: true,
|
||||||
breakpoints: {
|
breakpoints: {
|
||||||
"640px": "90vw",
|
"640px": "90vw",
|
||||||
},
|
},
|
||||||
data: `${currentArchiveStatus ? "Restore" : "Archive"} ${this.trip?.name} ?${currentArchiveStatus ? "" : " This will make everything read-only."}`,
|
data: `Restore ${this.trip?.name} ?`,
|
||||||
})!;
|
})!;
|
||||||
|
|
||||||
modal.onClose.pipe(take(1)).subscribe({
|
modal.onClose.pipe(take(1)).subscribe({
|
||||||
next: (bool) => {
|
next: (bool) => {
|
||||||
if (bool)
|
if (!bool) return;
|
||||||
this.apiService
|
this.apiService
|
||||||
.putTrip({ archived: !currentArchiveStatus }, this.trip?.id!)
|
.putTrip({ archived: false }, this.trip?.id!)
|
||||||
.pipe(take(1))
|
.pipe(take(1))
|
||||||
.subscribe({
|
.subscribe({
|
||||||
next: () => {
|
next: (trip) => (this.trip = trip),
|
||||||
this.trip!.archived = !currentArchiveStatus;
|
});
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
openArchiveTripModal() {
|
||||||
|
if (!this.trip) return;
|
||||||
|
const currentArchiveStatus = this.trip?.archived;
|
||||||
|
const modal = this.dialogService.open(TripArchiveModalComponent, {
|
||||||
|
header: `Archive ${this.trip.name}`,
|
||||||
|
modal: true,
|
||||||
|
closable: true,
|
||||||
|
dismissableMask: true,
|
||||||
|
width: "30vw",
|
||||||
|
breakpoints: {
|
||||||
|
"1024px": "60vw",
|
||||||
|
"640px": "90vw",
|
||||||
|
},
|
||||||
|
data: this.trip,
|
||||||
|
})!;
|
||||||
|
|
||||||
|
modal.onClose.pipe(take(1)).subscribe({
|
||||||
|
next: (review: string) => {
|
||||||
|
if (review === undefined) return;
|
||||||
|
this.apiService
|
||||||
|
.putTrip(
|
||||||
|
{ archived: !currentArchiveStatus, archival_review: review },
|
||||||
|
this.trip?.id!,
|
||||||
|
)
|
||||||
|
.pipe(take(1))
|
||||||
|
.subscribe({
|
||||||
|
next: (trip) => (this.trip = trip),
|
||||||
|
});
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -1853,7 +1884,7 @@ export class TripComponent implements AfterViewInit {
|
|||||||
next: (notes: string) => {
|
next: (notes: string) => {
|
||||||
if (notes === undefined) return;
|
if (notes === undefined) return;
|
||||||
this.apiService
|
this.apiService
|
||||||
.putTrip({ notes: notes ?? "" }, this.trip!.id)
|
.putTrip({ notes: notes }, this.trip!.id)
|
||||||
.pipe(take(1))
|
.pipe(take(1))
|
||||||
.subscribe({
|
.subscribe({
|
||||||
next: (trip) => (this.trip = trip),
|
next: (trip) => (this.trip = trip),
|
||||||
|
|||||||
@ -0,0 +1,17 @@
|
|||||||
|
<section>
|
||||||
|
<div class="p-4 mb-4 text-sm text-blue-800 rounded-md bg-blue-50 dark:bg-gray-800 dark:text-blue-400">
|
||||||
|
<span class="font-semibold">You're about to archive your Trip!</span> This will make the Trip read-only.<br>
|
||||||
|
You can review your trip and add general feedback. You can also skip this part and delete everything.
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<p-floatlabel variant="in">
|
||||||
|
<textarea pTextarea id="review" [formControl]="review" rows="12" fluid></textarea>
|
||||||
|
<label for="review">Review Notes</label>
|
||||||
|
</p-floatlabel>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mt-6 text-center">
|
||||||
|
<p-button (click)="closeDialog()" label="Archive Trip" icon="pi pi-box" severity="secondary" />
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
@ -0,0 +1,54 @@
|
|||||||
|
import { Component } from "@angular/core";
|
||||||
|
import { FormControl, ReactiveFormsModule } from "@angular/forms";
|
||||||
|
import { ButtonModule } from "primeng/button";
|
||||||
|
import { DynamicDialogConfig, DynamicDialogRef } from "primeng/dynamicdialog";
|
||||||
|
import { FloatLabelModule } from "primeng/floatlabel";
|
||||||
|
import { TextareaModule } from "primeng/textarea";
|
||||||
|
import { Trip } from "../../types/trip";
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: "app-trip-archive-modal",
|
||||||
|
imports: [
|
||||||
|
FloatLabelModule,
|
||||||
|
TextareaModule,
|
||||||
|
ButtonModule,
|
||||||
|
ReactiveFormsModule,
|
||||||
|
],
|
||||||
|
standalone: true,
|
||||||
|
templateUrl: "./trip-archive-modal.component.html",
|
||||||
|
styleUrl: "./trip-archive-modal.component.scss",
|
||||||
|
})
|
||||||
|
export class TripArchiveModalComponent {
|
||||||
|
review = new FormControl("");
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private ref: DynamicDialogRef,
|
||||||
|
private config: DynamicDialogConfig,
|
||||||
|
) {
|
||||||
|
this.computeReviewPlaceholder(this.config.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
computeReviewPlaceholder(trip: Trip) {
|
||||||
|
if (trip.archival_review) {
|
||||||
|
this.review.setValue(trip.archival_review);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!trip.days.length) return;
|
||||||
|
let placeholder = "General feedback:\n\n";
|
||||||
|
trip.days.forEach((day, index) => {
|
||||||
|
placeholder += `\nDay ${index + 1} (${day.label})\n`;
|
||||||
|
if (!day.items.length) placeholder += " No activities.\n";
|
||||||
|
else
|
||||||
|
day.items.forEach(
|
||||||
|
(item) => (placeholder += ` - ${item.time} | ${item.text}\n`),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
placeholder += "\nAnything else?";
|
||||||
|
this.review.setValue(placeholder);
|
||||||
|
}
|
||||||
|
|
||||||
|
closeDialog() {
|
||||||
|
// Normalize data for API POST
|
||||||
|
this.ref.close(this.review.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -18,7 +18,7 @@ import { TextareaModule } from "primeng/textarea";
|
|||||||
styleUrl: "./trip-notes-modal.component.scss",
|
styleUrl: "./trip-notes-modal.component.scss",
|
||||||
})
|
})
|
||||||
export class TripNotesModalComponent {
|
export class TripNotesModalComponent {
|
||||||
notes = new FormControl('');
|
notes = new FormControl("");
|
||||||
isEditing: boolean = false;
|
isEditing: boolean = false;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
|
|||||||
@ -21,6 +21,7 @@ export interface Trip {
|
|||||||
collaborators: TripMember[];
|
collaborators: TripMember[];
|
||||||
currency: string;
|
currency: string;
|
||||||
notes?: string;
|
notes?: string;
|
||||||
|
archival_review?: string;
|
||||||
|
|
||||||
// POST / PUT
|
// POST / PUT
|
||||||
places: Place[];
|
places: Place[];
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user