Fix date times
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
2025-06-22 13:18:22 +02:00
parent f7af144275
commit 4a8e3d02e0
9 changed files with 47 additions and 12 deletions

View File

@@ -23,6 +23,7 @@
"@ng-icons/material-icons": "^31.4.0", "@ng-icons/material-icons": "^31.4.0",
"@primeng/themes": "^19.1.3", "@primeng/themes": "^19.1.3",
"@tailwindcss/postcss": "^4.1.10", "@tailwindcss/postcss": "^4.1.10",
"dayjs": "^1.11.13",
"keycloak-angular": "^19.0.2", "keycloak-angular": "^19.0.2",
"postcss": "^8.5.6", "postcss": "^8.5.6",
"primeng": "^19.1.3", "primeng": "^19.1.3",

View File

@@ -41,6 +41,9 @@ importers:
'@tailwindcss/postcss': '@tailwindcss/postcss':
specifier: ^4.1.10 specifier: ^4.1.10
version: 4.1.10 version: 4.1.10
dayjs:
specifier: ^1.11.13
version: 1.11.13
keycloak-angular: keycloak-angular:
specifier: ^19.0.2 specifier: ^19.0.2
version: 19.0.2(@angular/common@19.2.14(@angular/core@19.2.14(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@19.2.14(rxjs@7.8.2)(zone.js@0.15.1))(@angular/router@19.2.14(@angular/common@19.2.14(@angular/core@19.2.14(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@19.2.14(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@19.2.14(@angular/animations@19.2.14(@angular/common@19.2.14(@angular/core@19.2.14(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@19.2.14(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@19.2.14(@angular/core@19.2.14(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@19.2.14(rxjs@7.8.2)(zone.js@0.15.1)))(rxjs@7.8.2))(keycloak-js@26.2.0) version: 19.0.2(@angular/common@19.2.14(@angular/core@19.2.14(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@19.2.14(rxjs@7.8.2)(zone.js@0.15.1))(@angular/router@19.2.14(@angular/common@19.2.14(@angular/core@19.2.14(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@19.2.14(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@19.2.14(@angular/animations@19.2.14(@angular/common@19.2.14(@angular/core@19.2.14(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@19.2.14(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@19.2.14(@angular/core@19.2.14(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@19.2.14(rxjs@7.8.2)(zone.js@0.15.1)))(rxjs@7.8.2))(keycloak-js@26.2.0)
@@ -2229,6 +2232,9 @@ packages:
resolution: {integrity: sha512-39BOQLs9ZjKh0/patS9nrT8wc3ioX3/eA/zgbKNopnF2wCqJEoxywwwElATYvRsXdnOxA/OQeQoFZ3rFjVajhg==} resolution: {integrity: sha512-39BOQLs9ZjKh0/patS9nrT8wc3ioX3/eA/zgbKNopnF2wCqJEoxywwwElATYvRsXdnOxA/OQeQoFZ3rFjVajhg==}
engines: {node: '>=4.0'} engines: {node: '>=4.0'}
dayjs@1.11.13:
resolution: {integrity: sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==}
debug@2.6.9: debug@2.6.9:
resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==}
peerDependencies: peerDependencies:
@@ -6763,6 +6769,8 @@ snapshots:
date-format@4.0.14: {} date-format@4.0.14: {}
dayjs@1.11.13: {}
debug@2.6.9: debug@2.6.9:
dependencies: dependencies:
ms: 2.0.0 ms: 2.0.0

View File

@@ -39,6 +39,8 @@
[firstDayOfWeek]="1" [firstDayOfWeek]="1"
placeholder="Datum auswählen" placeholder="Datum auswählen"
[showIcon]="true" [showIcon]="true"
[maxDate]="today"
[defaultDate]="today"
[inputId]="formFieldNames.date" [inputId]="formFieldNames.date"
[formControlName]="formFieldNames.date" [formControlName]="formFieldNames.date"
styleClass="w-full" styleClass="w-full"

View File

@@ -1,7 +1,8 @@
import dayjs from 'dayjs';
import { HttpErrorResponse } from '@angular/common/http'; import { HttpErrorResponse } from '@angular/common/http';
import { Component, computed, DestroyRef, inject, input, OnInit, signal, Signal } from '@angular/core'; import { Component, computed, DestroyRef, inject, input, OnInit, signal, Signal } from '@angular/core';
import { takeUntilDestroyed, toSignal } from '@angular/core/rxjs-interop'; import { takeUntilDestroyed, toSignal } from '@angular/core/rxjs-interop';
import { FormControl, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms'; import { FormControl, FormGroup, ReactiveFormsModule, ValidationErrors, Validators } from '@angular/forms';
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 { RoutingService } from '@vegasco-web/services/routing.service'; import { RoutingService } from '@vegasco-web/services/routing.service';
@@ -51,6 +52,8 @@ export class EditEntryComponent implements OnInit {
protected readonly id = input<string | undefined>(undefined); protected readonly id = input<string | undefined>(undefined);
protected readonly today = new Date();
protected readonly formFieldNames = { protected readonly formFieldNames = {
car: 'car', car: 'car',
date: 'date', date: 'date',
@@ -60,7 +63,7 @@ export class EditEntryComponent implements OnInit {
protected readonly formGroup = new FormGroup({ protected readonly formGroup = new FormGroup({
[this.formFieldNames.car]: new FormControl<Car | null>({ value: null, disabled: true }, [Validators.required]), [this.formFieldNames.car]: new FormControl<Car | null>({ value: null, disabled: true }, [Validators.required]),
[this.formFieldNames.date]: new FormControl<Date>({ value: new Date(), disabled: true }, [Validators.required]), [this.formFieldNames.date]: new FormControl<Date>({ value: new Date(), disabled: true }, [Validators.required, this.dateTimeGreaterThanOrEqualToTodayValidator]),
[this.formFieldNames.mileage]: new FormControl<number | null>({ value: null, disabled: true }, [Validators.required, Validators.min(1)]), [this.formFieldNames.mileage]: new FormControl<number | null>({ value: null, disabled: true }, [Validators.required, Validators.min(1)]),
[this.formFieldNames.amount]: new FormControl<number | null>({ value: null, disabled: true }, [Validators.required, Validators.min(1)]), [this.formFieldNames.amount]: new FormControl<number | null>({ value: null, disabled: true }, [Validators.required, Validators.min(1)]),
}); });
@@ -271,4 +274,15 @@ export class EditEntryComponent implements OnInit {
return EMPTY; return EMPTY;
} }
private dateTimeGreaterThanOrEqualToTodayValidator(control: FormControl<Date>): ValidationErrors | null {
const tomorrowStartOfDay = dayjs().add(1, 'day').startOf('day');
const controlDate = dayjs(control.value);
if (controlDate.isBefore(tomorrowStartOfDay)) {
return null;
}
return { dateTimeGreaterThanOrEqualToToday: true };
}
} }

View File

@@ -51,7 +51,6 @@ export class EntryCardComponent {
const formatted = entry.literPer100Km const formatted = entry.literPer100Km
?.toFixed(2) ?.toFixed(2)
.replace('.', ','); .replace('.', ',');
console.log('Formatted liter per 100km:', formatted);
return formatted; return formatted;
}) })

View File

@@ -25,8 +25,13 @@ public static class CreateConsumption
{ {
public Validator(TimeProvider timeProvider) public Validator(TimeProvider timeProvider)
{ {
DateTime todayEndOfDay = timeProvider.GetUtcNow()
.Date
.AddDays(1)
.AddTicks(-1);
RuleFor(x => x.DateTime.ToUniversalTime()) RuleFor(x => x.DateTime.ToUniversalTime())
.LessThanOrEqualTo(timeProvider.GetUtcNow()) .LessThanOrEqualTo(todayEndOfDay)
.WithName(nameof(Request.DateTime)); .WithName(nameof(Request.DateTime));
RuleFor(x => x.Distance) RuleFor(x => x.Distance)
@@ -70,6 +75,7 @@ public static class CreateConsumption
await dbContext.SaveChangesAsync(cancellationToken); await dbContext.SaveChangesAsync(cancellationToken);
return TypedResults.Created($"consumptions/{consumption.Id.Value}", return TypedResults.Created($"consumptions/{consumption.Id.Value}",
new Response(consumption.Id.Value, consumption.DateTime, consumption.Distance, consumption.Amount, consumption.CarId.Value)); new Response(consumption.Id.Value, consumption.DateTime, consumption.Distance, consumption.Amount,
consumption.CarId.Value));
} }
} }

View File

@@ -26,8 +26,13 @@ public static class UpdateConsumption
{ {
public Validator(TimeProvider timeProvider) public Validator(TimeProvider timeProvider)
{ {
DateTime todayEndOfDay = timeProvider.GetUtcNow()
.Date
.AddDays(1)
.AddTicks(-1);
RuleFor(x => x.DateTime.ToUniversalTime()) RuleFor(x => x.DateTime.ToUniversalTime())
.LessThanOrEqualTo(timeProvider.GetUtcNow()) .LessThanOrEqualTo(todayEndOfDay)
.WithName(nameof(Request.DateTime)); .WithName(nameof(Request.DateTime));
RuleFor(x => x.Distance) RuleFor(x => x.Distance)

View File

@@ -19,7 +19,7 @@ public class CreateConsumptionRequestValidatorTests
_sut = new CreateConsumption.Validator(_timeProvider); _sut = new CreateConsumption.Validator(_timeProvider);
_validRequest = new CreateConsumption.Request( _validRequest = new CreateConsumption.Request(
_utcNow.AddDays(-1), _utcNow.Date.AddDays(1).AddTicks(-1),
1, 1,
1, 1,
Guid.NewGuid()); Guid.NewGuid());
@@ -38,10 +38,10 @@ public class CreateConsumptionRequestValidatorTests
} }
[Fact] [Fact]
public async Task ValidateAsync_ShouldBeInvalid_WhenDateTimeIsGreaterThanUtcNow() public async Task ValidateAsync_ShouldBeInvalid_WhenDateTimeIsGreaterThanUtcToday()
{ {
// Arrange // Arrange
CreateConsumption.Request request = _validRequest with { DateTime = _utcNow.AddDays(1) }; CreateConsumption.Request request = _validRequest with { DateTime = _utcNow.Date.AddDays(1) };
// Act // Act
ValidationResult? result = await _sut.ValidateAsync(request); ValidationResult? result = await _sut.ValidateAsync(request);

View File

@@ -20,7 +20,7 @@ public class UpdateConsumptionRequestValidatorTests
_sut = new UpdateConsumption.Validator(_timeProvider); _sut = new UpdateConsumption.Validator(_timeProvider);
_validRequest = new UpdateConsumption.Request( _validRequest = new UpdateConsumption.Request(
_utcNow.AddDays(-1), _utcNow.Date.AddDays(1).AddTicks(-1),
1, 1,
1); 1);
} }
@@ -38,10 +38,10 @@ public class UpdateConsumptionRequestValidatorTests
} }
[Fact] [Fact]
public async Task ValidateAsync_ShouldBeInvalid_WhenDateTimeIsGreaterThanUtcNow() public async Task ValidateAsync_ShouldBeInvalid_WhenDateTimeIsGreaterThanUtcToday()
{ {
// Arrange // Arrange
UpdateConsumption.Request request = _validRequest with { DateTime = _utcNow.AddDays(1) }; UpdateConsumption.Request request = _validRequest with { DateTime = _utcNow.Date.AddDays(1) };
// Act // Act
ValidationResult? result = await _sut.ValidateAsync(request); ValidationResult? result = await _sut.ValidateAsync(request);