New Angular based web version #1

Closed
thomas.nuyken wants to merge 150 commits from main into ddd
11 changed files with 65 additions and 25 deletions
Showing only changes of commit f7af144275 - Show all commits

View File

@@ -1,9 +1,7 @@
import { HttpClient } from '@angular/common/http'; import { HttpClient } from '@angular/common/http';
import { inject, Injectable } from '@angular/core'; import { inject, Injectable } from '@angular/core';
import { GetConsumptionEntriesResponse } from '@vegasco-web/api/consumptions/get-consumption-entries-response';
import { map, Observable } from 'rxjs'; import { map, Observable } from 'rxjs';
import { API_BASE_PATH } from '../api-base-path'; import { API_BASE_PATH } from '../api-base-path';
import { ConsumptionEntry } from './consumption-entry';
@Injectable({ @Injectable({
providedIn: 'root', providedIn: 'root',

View File

@@ -1,4 +1,4 @@
export interface ConsumptionEntry { interface ConsumptionEntry {
id: string; id: string;
dateTime: string; dateTime: string;
distance: number; distance: number;

View File

@@ -1,4 +1,4 @@
export interface GetConsumptionEntriesEntry { interface GetConsumptionEntriesEntry {
id: string; id: string;
dateTime: string; dateTime: string;
distance: number; distance: number;
@@ -7,4 +7,5 @@ export interface GetConsumptionEntriesEntry {
id: string; id: string;
name: string; name: string;
}; };
literPer100Km: number | null;
} }

View File

@@ -1,5 +1,3 @@
import { GetConsumptionEntriesEntry } from "./get-consumption-entries-entry"; interface GetConsumptionEntriesResponse {
export interface GetConsumptionEntriesResponse {
consumptions: GetConsumptionEntriesEntry[]; consumptions: GetConsumptionEntriesEntry[];
} }

View File

@@ -12,13 +12,6 @@
</div> </div>
</div> </div>
<div class="col-span-4 sm:col-span-2 md:col-span-1 flex my-auto items-center justify-center">
<div class="flex gap-2 items-center">
<ng-icon name="matDirectionsCarOutline" />
<div>{{ entry().car.name }}</div>
</div>
</div>
<div class="col-span-4 sm:col-span-2 md:col-span-1 flex my-auto items-center justify-center"> <div class="col-span-4 sm:col-span-2 md:col-span-1 flex my-auto items-center justify-center">
<div class="flex gap-2 items-center"> <div class="flex gap-2 items-center">
<ng-icon name="matStraightenSharp" /> <ng-icon name="matStraightenSharp" />
@@ -32,6 +25,18 @@
<div>{{entry().amount }} &#8467;</div> <div>{{entry().amount }} &#8467;</div>
</div> </div>
</div> </div>
<div class="col-span-4 sm:col-span-2 md:col-span-1 flex my-auto items-center justify-center">
@if (formattedLiterPer100Km(); as formattedLiterPer100Km) {
<div class="flex gap-2 items-center">
<ng-icon name="matSpeedSharp" />
<div class="flex items-center gap-1">
{{ formattedLiterPer100Km }}
<app-fraction numerator="&#8467;" [denominator]="'100km'" />
</div>
</div>
}
</div>
</div> </div>
</div> </div>
<div class="bg-red-500 text-white rounded-r text-center flex flex-col justify-center"> <div class="bg-red-500 text-white rounded-r text-center flex flex-col justify-center">

View File

@@ -1,3 +1,3 @@
.edit-button { .edit-button {
cursor: pointer; cursor: pointer;
} }

View File

@@ -1,26 +1,23 @@
import { DatePipe } from '@angular/common'; import { DatePipe } from '@angular/common';
import { HttpErrorResponse } from '@angular/common/http'; import { HttpErrorResponse } from '@angular/common/http';
import { Component, DestroyRef, inject, input, output } from '@angular/core'; import { Component, computed, DestroyRef, inject, input, output } from '@angular/core';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { NgIconComponent, provideIcons } from '@ng-icons/core'; import { NgIconComponent, provideIcons } from '@ng-icons/core';
import {
matDirectionsCarOutline,
} from '@ng-icons/material-icons/outline';
import { import {
matCalendarMonthSharp, matCalendarMonthSharp,
matDeleteSharp, matDeleteSharp,
matLocalGasStationSharp, matLocalGasStationSharp,
matSpeedSharp,
matStraightenSharp, matStraightenSharp,
} from '@ng-icons/material-icons/sharp'; } from '@ng-icons/material-icons/sharp';
import { ConsumptionClient } from '@vegasco-web/api/consumptions/consumption-client'; import { ConsumptionClient } from '@vegasco-web/api/consumptions/consumption-client';
import { GetConsumptionEntriesEntry } from '@vegasco-web/api/consumptions/get-consumption-entries-entry';
import { RoutingService } from '@vegasco-web/services/routing.service'; import { RoutingService } from '@vegasco-web/services/routing.service';
import { ConfirmationService, MessageService } from 'primeng/api'; import { ConfirmationService, MessageService } from 'primeng/api';
import { ButtonModule } from 'primeng/button'; import { ButtonModule } from 'primeng/button';
import { CardModule } from 'primeng/card'; import { CardModule } from 'primeng/card';
import { ConfirmDialogModule } from 'primeng/confirmdialog'; import { ConfirmDialogModule } from 'primeng/confirmdialog';
import { catchError, EMPTY, Observable, tap, throwError } from 'rxjs'; import { catchError, EMPTY, Observable, tap, throwError } from 'rxjs';
import { FractionComponent } from "../fraction/fraction.component";
@Component({ @Component({
selector: 'app-entry-card', selector: 'app-entry-card',
@@ -30,12 +27,13 @@ import { catchError, EMPTY, Observable, tap, throwError } from 'rxjs';
ConfirmDialogModule, ConfirmDialogModule,
DatePipe, DatePipe,
NgIconComponent, NgIconComponent,
FractionComponent
], ],
providers: [ providers: [
provideIcons({ provideIcons({
matDeleteSharp, matDeleteSharp,
matCalendarMonthSharp, matCalendarMonthSharp,
matDirectionsCarOutline, matSpeedSharp,
matStraightenSharp, matStraightenSharp,
matLocalGasStationSharp, matLocalGasStationSharp,
}), }),
@@ -47,6 +45,16 @@ import { catchError, EMPTY, Observable, tap, throwError } from 'rxjs';
export class EntryCardComponent { export class EntryCardComponent {
readonly entry = input.required<GetConsumptionEntriesEntry>(); readonly entry = input.required<GetConsumptionEntriesEntry>();
protected readonly formattedLiterPer100Km = computed(() => {
const entry = this.entry();
const formatted = entry.literPer100Km
?.toFixed(2)
.replace('.', ',');
console.log('Formatted liter per 100km:', formatted);
return formatted;
})
readonly entryDeleted = output<GetConsumptionEntriesEntry>(); readonly entryDeleted = output<GetConsumptionEntriesEntry>();
private readonly routingService = inject(RoutingService); private readonly routingService = inject(RoutingService);

View File

@@ -0,0 +1,9 @@
<div class="flex flex-col items-center text-half-size">
<span>
{{ numerator() }}
</span>
<span class="separator"></span>
<span>
{{ denominator() }}
</span>
</div>

View File

@@ -0,0 +1,11 @@
.separator {
border-bottom-width: 1px;
width: 100%
}
.text-half-size {
// Specifically use em here to allow the parent to control the font size
// The font size here should be smaller because it is a fraction and would
// otherwise look too large
font-size: 0.75em;
}

View File

@@ -0,0 +1,12 @@
import { Component, input } from '@angular/core';
@Component({
selector: 'app-fraction',
imports: [],
templateUrl: './fraction.component.html',
styleUrl: './fraction.component.scss'
})
export class FractionComponent {
readonly numerator = input.required<number | string>();
readonly denominator = input.required<number | string>();
}

View File

@@ -10,7 +10,6 @@ import {
} from '@ng-icons/material-icons/sharp'; } from '@ng-icons/material-icons/sharp';
import { CarClient } from '@vegasco-web/api/cars/car-client'; import { CarClient } from '@vegasco-web/api/cars/car-client';
import { ConsumptionClient } from '@vegasco-web/api/consumptions/consumption-client'; import { ConsumptionClient } from '@vegasco-web/api/consumptions/consumption-client';
import { GetConsumptionEntriesEntry } from '@vegasco-web/api/consumptions/get-consumption-entries-entry';
import { MessageService } from 'primeng/api'; import { MessageService } from 'primeng/api';
import { ButtonModule } from 'primeng/button'; import { ButtonModule } from 'primeng/button';
import { DataViewModule } from 'primeng/dataview'; import { DataViewModule } from 'primeng/dataview';
@@ -30,7 +29,6 @@ import {
} from 'rxjs'; } from 'rxjs';
import { SelectedCarService } from '../services/selected-car.service'; import { SelectedCarService } from '../services/selected-car.service';
import { EntryCardComponent } from './components/entry-card/entry-card.component'; import { EntryCardComponent } from './components/entry-card/entry-card.component';
import { ConsumptionEntry } from '@vegasco-web/api/consumptions/consumption-entry';
@Component({ @Component({
selector: 'app-entries', selector: 'app-entries',
@@ -97,7 +95,7 @@ export class EntriesComponent implements OnInit {
} }
return nonDeletedEntries.filter(entry => entry.car.id === selectedCar.id); return nonDeletedEntries.filter(entry => entry.car.id === selectedCar.id);
}) }),
); );
this.cars$ = this.carClient.getAll() this.cars$ = this.carClient.getAll()