Skip to content

Commit

Permalink
feat: refactor dialogs, add dialog service and directive
Browse files Browse the repository at this point in the history
  • Loading branch information
VilemRaska committed Mar 1, 2025
1 parent ff55e9b commit 3f27400
Show file tree
Hide file tree
Showing 19 changed files with 363 additions and 167 deletions.
44 changes: 22 additions & 22 deletions apps/gapp-dashboard/src/pages/cars/cars.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,33 +8,33 @@
<loader></loader>
} @else {
<scrollable>
@for(car of carsSignal().data; track car._id) {
<div class="collapse collapse-arrow bg-base-200">
<input type="checkbox" />
<div class="collapse-title text-xl font-medium">{{ car.callsign }}</div>
<div class="collapse-content">
<p>{{ car?.description }}</p>
<div class="flex justify-end">
<button class="btn btn-error btn-sm" (click)="deleteCar(car._id)">Remove</button>
<ul class="list bg-base-200 rounded-box">
@for(car of carsSignal().data; track car._id) {
<li class="list-row hover:bg-base-300">
<div>
<div class="font-semibold">{{ car.callsign }}</div>
<div class="text-xs font-semibold opacity-60">{{ car?.description }}</div>
</div>
</div>
</div>
} @empty {
<p class="text-center">No chase cars yet.</p>
}
<div></div>
<button
[dialog]="'Delete car'"
content="Are you sure you want to delete {{ car.callsign }} car?"
(dialogResolved)="deleteCar(car._id)"
class="btn btn-sm btn-ghost"
>
<ng-icon name="tablerTrash" size="1.2rem"></ng-icon>
</button>
</li>
} @empty {
<p class="text-center">No chase cars yet.</p>
}
</ul>
</scrollable>
}
</ng-container>
</page-block>

<gapp-modal
title="Add new chase car"
[isOpen]="isCarModalOpened()"
(closed)="isCarModalOpened.set(false)"
action="Create"
[formGroup]="carForm"
(actionUsed)="createCar()"
>
<gapp-dialog #addCarDialog title="Add new car" [formGroup]="carForm" [buttons]="[modalButton]">
@if(errorMessage(); as error) {
<div role="alert" class="alert alert-error">
<span>{{ error }}</span>
Expand All @@ -53,4 +53,4 @@
<textarea class="textarea h-24 w-11/12" formControlName="description"></textarea>
<div class="fieldset-label">Car type, crew...</div>
</fieldset>
</gapp-modal>
</gapp-dialog>
46 changes: 29 additions & 17 deletions apps/gapp-dashboard/src/pages/cars/cars.component.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Car, CarsService } from '../../services/cars.service';
import { Component, DestroyRef, inject, OnInit, signal } from '@angular/core';
import { Car, CarsService } from '@/services/cars.service';
import { Component, DestroyRef, inject, OnInit, signal, viewChild } from '@angular/core';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { ModalComponent } from '@gapp/ui/modal';
import { DialogButton, DialogComponent, DialogDirective } from '@gapp/ui/dialog';
import { AbstractControl, FormBuilder, ReactiveFormsModule, Validators } from '@angular/forms';
import { filter } from 'rxjs';
import { ToastService } from '@/services/toast.service';
Expand All @@ -10,20 +10,24 @@ import { PageBlockComponent } from '@/components/page-block/page-block.component
import { ScrollableComponent } from '@gapp/ui/scrollable';
import { LoaderComponent } from '@gapp/ui/loader';
import { ErrorClassDirective } from '@gapp/forms-ui';
import { NgIcon, provideIcons } from '@ng-icons/core';
import { tablerTrash } from '@ng-icons/tabler-icons';

@Component({
selector: 'gapp-cars',
templateUrl: './cars.component.html',
imports: [ModalComponent, ReactiveFormsModule, PageBlockComponent, ScrollableComponent, LoaderComponent, ErrorClassDirective],
imports: [DialogComponent, ReactiveFormsModule, PageBlockComponent, ScrollableComponent, LoaderComponent, ErrorClassDirective, NgIcon, DialogDirective],
providers: [provideIcons({ tablerTrash })],
})
export class CarsComponent implements OnInit {
private carsService = inject(CarsService);
private formBuilder = inject(FormBuilder);
private toastService = inject(ToastService);
private destroyRef = inject(DestroyRef);

public carsSignal = signal<ApiResponse<Car[]>>({ loading: true });
public readonly isCarModalOpened = signal(false);
private addCarDialog = viewChild.required<DialogComponent>('addCarDialog');

public readonly carsSignal = signal<ApiResponse<Car[]>>({ loading: true });
public readonly errorMessage = signal<string | undefined>(undefined);

public readonly carForm = this.formBuilder.group({
Expand All @@ -34,22 +38,21 @@ export class CarsComponent implements OnInit {
public readonly carInput = this.carForm.get('callsign') as AbstractControl;
public readonly descriptionInput = this.carForm.get('description') as AbstractControl;

public ngOnInit() {
this.loadCars();
public get modalButton(): DialogButton {
return {
label: 'Create',
style: 'btn-primary',
action: () => this.createCar(),
};
}

private loadCars() {
this.carsService
.getCars$()
.pipe(takeUntilDestroyed(this.destroyRef))
.subscribe((response) => {
this.carsSignal.set(response);
});
public ngOnInit() {
this.loadCars();
}

public openCarModal() {
this.errorMessage.set(undefined);
this.isCarModalOpened.set(true);
this.addCarDialog().open();
}

public createCar() {
Expand All @@ -70,7 +73,7 @@ export class CarsComponent implements OnInit {
return;
}

this.isCarModalOpened.set(false);
this.addCarDialog().close();
this.toastService.toast('alert-success', 'Chase car added');
this.loadCars();
this.carForm.reset();
Expand All @@ -88,4 +91,13 @@ export class CarsComponent implements OnInit {
this.loadCars();
});
}

private loadCars() {
this.carsService
.getCars$()
.pipe(takeUntilDestroyed(this.destroyRef))
.subscribe((response) => {
this.carsSignal.set(response);
});
}
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,20 @@
<li class="list-row">
<div class="font-bold">
{{ car()?.callsign }}
</div>

<div></div>

<div>
@if(telemetry(); as telemetry) {
<time-ago-badge [date]="telemetry._time"></time-ago-badge>
} @else {
<span class="badge badge-ghost badge-outline">Not connected</span>
}
</div>
</li>

<!--
<div tabindex="0" class="collapse collapse-arrow bg-base-200">
<input type="checkbox" />
<div class="collapse-title flex flex-row justify-between">
Expand Down Expand Up @@ -25,4 +42,4 @@
</span>
</div>
</div>
</div>
</div> -->
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,13 @@ import { Car } from '@/services/cars.service';
import { ChangeDetectionStrategy, Component, input } from '@angular/core';
import { TelemetryStatus } from './dashboard.service';
import { TimeAgoBadgeComponent } from '@/components/time-ago-badge/time-ago-badge.component';
import { NgIcon, provideIcons } from '@ng-icons/core';
import { tablerExternalLink } from '@ng-icons/tabler-icons';

@Component({
selector: 'car-status-card',
templateUrl: './car-status-card.component.html',
changeDetection: ChangeDetectionStrategy.OnPush,
imports: [TimeAgoBadgeComponent, NgIcon],
providers: [provideIcons({ tablerExternalLink })],
imports: [TimeAgoBadgeComponent],
// providers: [provideIcons({ tablerExternalLink })],
})
export class CarStatusCardComponent {
public car = input<Car>();
Expand Down
28 changes: 16 additions & 12 deletions apps/gapp-dashboard/src/pages/dashboard/dashboard.component.html
Original file line number Diff line number Diff line change
@@ -1,21 +1,25 @@
<div class="flex flex-col lg:flex-row gap-8 px-4">
<page-block title="Vessels">
<scrollable blockBody class="card bg-base-200 p-4">
@for (vessel of availableVessels()?.data; track $index) {
<vessel-status-card [vessel]="vessel" [telemetry]="getTelemetry(vessel.transmitters)()"></vessel-status-card>
} @empty { @if (availableVessels()?.loading) {
<loader></loader>
} @else { No data available. } }
<scrollable blockBody>
<ul class="list bg-base-200 rounded-box">
@for (vessel of availableVessels()?.data; track $index) {
<vessel-status-card [vessel]="vessel" [telemetry]="getTelemetry(vessel.transmitters)()"></vessel-status-card>
} @empty { @if (availableVessels()?.loading) {
<loader></loader>
} @else { No data available. } }
</ul>
</scrollable>
</page-block>

<page-block title="Cars">
<scrollable blockBody class="card bg-base-200 p-4">
@for (car of availableCars()?.data; track $index) {
<car-status-card [car]="car" [telemetry]="getTelemetry([car.callsign])()?.[0]"></car-status-card>
} @empty { @if (availableCars()?.loading) {
<loader></loader>
} @else { No data available. } }
<scrollable blockBody>
<ul class="list bg-base-200 rounded-box">
@for (car of availableCars()?.data; track $index) {
<car-status-card [car]="car" [telemetry]="getTelemetry([car.callsign])()?.[0]"></car-status-card>
} @empty { @if (availableCars()?.loading) {
<loader></loader>
} @else { No data available. } }
</ul>
</scrollable>
</page-block>
</div>
Original file line number Diff line number Diff line change
@@ -1,4 +1,20 @@
<div tabindex="0" class="collapse collapse-arrow bg-base-200">
<li class="list-row">
<div class="font-bold">
{{ vessel()?.callsign }}
</div>

<div></div>

<div>
@if(lastContact(); as lastContact) {
<time-ago-badge [date]="lastContact._time"></time-ago-badge>
} @else {
<span class="badge badge-ghost badge-outline">Not connected</span>
}
</div>
</li>

<!-- <div tabindex="0" class="collapse collapse-arrow bg-base-200">
<input type="checkbox" />
<div class="collapse-title flex flex-row justify-between">
<div class="font-bold">
Expand Down Expand Up @@ -37,4 +53,4 @@
}
</div>
</div>
</div>
</div> -->
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,13 @@ import { ChangeDetectionStrategy, Component, computed, input } from '@angular/co
import { TelemetryStatus } from './dashboard.service';
import { Vessel } from '@/services/vessels.service';
import { TimeAgoBadgeComponent } from '@/components/time-ago-badge/time-ago-badge.component';
import { NgIcon, provideIcons } from '@ng-icons/core';
import { tablerExternalLink } from '@ng-icons/tabler-icons';

@Component({
selector: 'vessel-status-card',
templateUrl: './vessel-status-card.component.html',
changeDetection: ChangeDetectionStrategy.OnPush,
imports: [TimeAgoBadgeComponent, NgIcon],
providers: [provideIcons({ tablerExternalLink })],
imports: [TimeAgoBadgeComponent],
// providers: [provideIcons({ tablerExternalLink })],
})
export class VesselStatusCardComponent {
public vessel = input<Vessel>();
Expand Down
63 changes: 27 additions & 36 deletions apps/gapp-dashboard/src/pages/vessels/vessels.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,48 +8,39 @@
<loader></loader>
} @else {
<scrollable>
@for(vessel of vesselsSignal().data; track vessel._id) {
<div class="collapse collapse-arrow bg-base-200">
<input type="checkbox" />
<div class="collapse-title text-xl font-medium">
@if(vessel.type === 'balloon') {
<ng-icon name="tablerAirBalloon" size="1.2rem"></ng-icon>
} @else if(vessel.type === 'uav') {
<ng-icon name="tablerDrone" size="1.2rem"></ng-icon>
}
{{ vessel.callsign }}
</div>
<div class="collapse-content">
<ul class="list-disc list-inside mb-2">
@for(transmitter of vessel.transmitters; track $index) {
<li>{{ transmitter }}</li>
<ul class="list bg-base-200 rounded-box">
@for(vessel of vesselsSignal().data; track vessel._id) {
<li class="list-row hover:bg-base-300">
<div class="flex items-center">
@if(vessel.type === 'balloon') {
<ng-icon name="tablerAirBalloon" size="1.6rem"></ng-icon>
} @else if(vessel.type === 'uav') {
<ng-icon name="tablerDrone" size="1.6rem"></ng-icon>
}
</ul>

<p>{{ vessel?.description }}</p>

<div class="flex justify-end">
<button class="btn btn-error btn-sm" (click)="deleteVessel(vessel._id)">Remove</button>
</div>
</div>
</div>
} @empty {
<p class="text-center">No vessels yet.</p>
}
<div>
<div class="font-semibold">{{ vessel.callsign }}</div>
<div class="text-xs font-semibold opacity-60">{{ vessel?.description }}</div>
</div>
<button
[dialog]="'Delete vessel'"
content="Are you sure you want to delete {{ vessel.callsign }} vessel?"
(dialogResolved)="deleteVessel(vessel._id)"
class="btn btn-sm btn-ghost"
>
<ng-icon name="tablerTrash" size="1.2rem"></ng-icon>
</button>
</li>
} @empty {
<p class="text-center">No vessels yet.</p>
}
</ul>
</scrollable>
}
</ng-container>
</page-block>

<gapp-modal
title="Add new mission vessel"
action="Create"
[isOpen]="isVesselModalOpened()"
[formGroup]="vesselForm"
[width]="'w-full'"
(closed)="isVesselModalOpened.set(false)"
(actionUsed)="createVessel()"
>
<gapp-dialog #addVesselDialog title="Add new mission vessel" [formGroup]="vesselForm" [buttons]="[modalButton]">
@if(errorMessage()) {
<div role="alert" class="alert alert-error">
<span>{{ errorMessage() }}</span>
Expand Down Expand Up @@ -99,4 +90,4 @@
<textarea class="textarea h-24 w-11/12" formControlName="description"></textarea>
<div class="fieldset-label">Vessel type, mission goal...</div>
</fieldset>
</gapp-modal>
</gapp-dialog>
Loading

0 comments on commit 3f27400

Please sign in to comment.