From 4a8e3d02e06528e78d7753557cf714ada2af3428 Mon Sep 17 00:00:00 2001 From: ThompsonNye Date: Sun, 22 Jun 2025 13:18:22 +0200 Subject: [PATCH] Fix date times --- src/Vegasco-Web/package.json | 1 + src/Vegasco-Web/pnpm-lock.yaml | 8 ++++++++ .../edit-entry/edit-entry.component.html | 2 ++ .../entries/edit-entry/edit-entry.component.ts | 18 ++++++++++++++++-- .../entry-card/entry-card.component.ts | 1 - .../Consumptions/CreateConsumption.cs | 10 ++++++++-- .../Consumptions/UpdateConsumption.cs | 7 ++++++- .../CreateConsumptionRequestValidatorTests.cs | 6 +++--- .../UpdateConsumptionRequestValidatorTests.cs | 6 +++--- 9 files changed, 47 insertions(+), 12 deletions(-) diff --git a/src/Vegasco-Web/package.json b/src/Vegasco-Web/package.json index 14d4723..5d7764e 100644 --- a/src/Vegasco-Web/package.json +++ b/src/Vegasco-Web/package.json @@ -23,6 +23,7 @@ "@ng-icons/material-icons": "^31.4.0", "@primeng/themes": "^19.1.3", "@tailwindcss/postcss": "^4.1.10", + "dayjs": "^1.11.13", "keycloak-angular": "^19.0.2", "postcss": "^8.5.6", "primeng": "^19.1.3", diff --git a/src/Vegasco-Web/pnpm-lock.yaml b/src/Vegasco-Web/pnpm-lock.yaml index 4d19323..9f99747 100644 --- a/src/Vegasco-Web/pnpm-lock.yaml +++ b/src/Vegasco-Web/pnpm-lock.yaml @@ -41,6 +41,9 @@ importers: '@tailwindcss/postcss': specifier: ^4.1.10 version: 4.1.10 + dayjs: + specifier: ^1.11.13 + version: 1.11.13 keycloak-angular: 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) @@ -2229,6 +2232,9 @@ packages: resolution: {integrity: sha512-39BOQLs9ZjKh0/patS9nrT8wc3ioX3/eA/zgbKNopnF2wCqJEoxywwwElATYvRsXdnOxA/OQeQoFZ3rFjVajhg==} engines: {node: '>=4.0'} + dayjs@1.11.13: + resolution: {integrity: sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==} + debug@2.6.9: resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} peerDependencies: @@ -6763,6 +6769,8 @@ snapshots: date-format@4.0.14: {} + dayjs@1.11.13: {} + debug@2.6.9: dependencies: ms: 2.0.0 diff --git a/src/Vegasco-Web/src/app/modules/entries/edit-entry/edit-entry.component.html b/src/Vegasco-Web/src/app/modules/entries/edit-entry/edit-entry.component.html index 55de4e4..24bee44 100644 --- a/src/Vegasco-Web/src/app/modules/entries/edit-entry/edit-entry.component.html +++ b/src/Vegasco-Web/src/app/modules/entries/edit-entry/edit-entry.component.html @@ -39,6 +39,8 @@ [firstDayOfWeek]="1" placeholder="Datum auswählen" [showIcon]="true" + [maxDate]="today" + [defaultDate]="today" [inputId]="formFieldNames.date" [formControlName]="formFieldNames.date" styleClass="w-full" diff --git a/src/Vegasco-Web/src/app/modules/entries/edit-entry/edit-entry.component.ts b/src/Vegasco-Web/src/app/modules/entries/edit-entry/edit-entry.component.ts index e485b49..3cde557 100644 --- a/src/Vegasco-Web/src/app/modules/entries/edit-entry/edit-entry.component.ts +++ b/src/Vegasco-Web/src/app/modules/entries/edit-entry/edit-entry.component.ts @@ -1,7 +1,8 @@ +import dayjs from 'dayjs'; import { HttpErrorResponse } from '@angular/common/http'; import { Component, computed, DestroyRef, inject, input, OnInit, signal, Signal } from '@angular/core'; 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 { ConsumptionClient } from '@vegasco-web/api/consumptions/consumption-client'; import { RoutingService } from '@vegasco-web/services/routing.service'; @@ -51,6 +52,8 @@ export class EditEntryComponent implements OnInit { protected readonly id = input(undefined); + protected readonly today = new Date(); + protected readonly formFieldNames = { car: 'car', date: 'date', @@ -60,7 +63,7 @@ export class EditEntryComponent implements OnInit { protected readonly formGroup = new FormGroup({ [this.formFieldNames.car]: new FormControl({ value: null, disabled: true }, [Validators.required]), - [this.formFieldNames.date]: new FormControl({ value: new Date(), disabled: true }, [Validators.required]), + [this.formFieldNames.date]: new FormControl({ value: new Date(), disabled: true }, [Validators.required, this.dateTimeGreaterThanOrEqualToTodayValidator]), [this.formFieldNames.mileage]: new FormControl({ value: null, disabled: true }, [Validators.required, Validators.min(1)]), [this.formFieldNames.amount]: new FormControl({ value: null, disabled: true }, [Validators.required, Validators.min(1)]), }); @@ -271,4 +274,15 @@ export class EditEntryComponent implements OnInit { return EMPTY; } + + private dateTimeGreaterThanOrEqualToTodayValidator(control: FormControl): ValidationErrors | null { + const tomorrowStartOfDay = dayjs().add(1, 'day').startOf('day'); + const controlDate = dayjs(control.value); + + if (controlDate.isBefore(tomorrowStartOfDay)) { + return null; + } + + return { dateTimeGreaterThanOrEqualToToday: true }; + } } diff --git a/src/Vegasco-Web/src/app/modules/entries/entries/components/entry-card/entry-card.component.ts b/src/Vegasco-Web/src/app/modules/entries/entries/components/entry-card/entry-card.component.ts index 39f8cea..9c8558f 100644 --- a/src/Vegasco-Web/src/app/modules/entries/entries/components/entry-card/entry-card.component.ts +++ b/src/Vegasco-Web/src/app/modules/entries/entries/components/entry-card/entry-card.component.ts @@ -51,7 +51,6 @@ export class EntryCardComponent { const formatted = entry.literPer100Km ?.toFixed(2) .replace('.', ','); - console.log('Formatted liter per 100km:', formatted); return formatted; }) diff --git a/src/Vegasco.Server.Api/Consumptions/CreateConsumption.cs b/src/Vegasco.Server.Api/Consumptions/CreateConsumption.cs index 4f2fb53..9b236d3 100644 --- a/src/Vegasco.Server.Api/Consumptions/CreateConsumption.cs +++ b/src/Vegasco.Server.Api/Consumptions/CreateConsumption.cs @@ -25,8 +25,13 @@ public static class CreateConsumption { public Validator(TimeProvider timeProvider) { + DateTime todayEndOfDay = timeProvider.GetUtcNow() + .Date + .AddDays(1) + .AddTicks(-1); + RuleFor(x => x.DateTime.ToUniversalTime()) - .LessThanOrEqualTo(timeProvider.GetUtcNow()) + .LessThanOrEqualTo(todayEndOfDay) .WithName(nameof(Request.DateTime)); RuleFor(x => x.Distance) @@ -70,6 +75,7 @@ public static class CreateConsumption await dbContext.SaveChangesAsync(cancellationToken); 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)); } } \ No newline at end of file diff --git a/src/Vegasco.Server.Api/Consumptions/UpdateConsumption.cs b/src/Vegasco.Server.Api/Consumptions/UpdateConsumption.cs index c598779..80553c2 100644 --- a/src/Vegasco.Server.Api/Consumptions/UpdateConsumption.cs +++ b/src/Vegasco.Server.Api/Consumptions/UpdateConsumption.cs @@ -26,8 +26,13 @@ public static class UpdateConsumption { public Validator(TimeProvider timeProvider) { + DateTime todayEndOfDay = timeProvider.GetUtcNow() + .Date + .AddDays(1) + .AddTicks(-1); + RuleFor(x => x.DateTime.ToUniversalTime()) - .LessThanOrEqualTo(timeProvider.GetUtcNow()) + .LessThanOrEqualTo(todayEndOfDay) .WithName(nameof(Request.DateTime)); RuleFor(x => x.Distance) diff --git a/tests/Vegasco.Server.Api.Tests.Unit/Consumptions/CreateConsumptionRequestValidatorTests.cs b/tests/Vegasco.Server.Api.Tests.Unit/Consumptions/CreateConsumptionRequestValidatorTests.cs index 0ede696..e60dcca 100644 --- a/tests/Vegasco.Server.Api.Tests.Unit/Consumptions/CreateConsumptionRequestValidatorTests.cs +++ b/tests/Vegasco.Server.Api.Tests.Unit/Consumptions/CreateConsumptionRequestValidatorTests.cs @@ -19,7 +19,7 @@ public class CreateConsumptionRequestValidatorTests _sut = new CreateConsumption.Validator(_timeProvider); _validRequest = new CreateConsumption.Request( - _utcNow.AddDays(-1), + _utcNow.Date.AddDays(1).AddTicks(-1), 1, 1, Guid.NewGuid()); @@ -38,10 +38,10 @@ public class CreateConsumptionRequestValidatorTests } [Fact] - public async Task ValidateAsync_ShouldBeInvalid_WhenDateTimeIsGreaterThanUtcNow() + public async Task ValidateAsync_ShouldBeInvalid_WhenDateTimeIsGreaterThanUtcToday() { // Arrange - CreateConsumption.Request request = _validRequest with { DateTime = _utcNow.AddDays(1) }; + CreateConsumption.Request request = _validRequest with { DateTime = _utcNow.Date.AddDays(1) }; // Act ValidationResult? result = await _sut.ValidateAsync(request); diff --git a/tests/Vegasco.Server.Api.Tests.Unit/Consumptions/UpdateConsumptionRequestValidatorTests.cs b/tests/Vegasco.Server.Api.Tests.Unit/Consumptions/UpdateConsumptionRequestValidatorTests.cs index ef8d571..982458d 100644 --- a/tests/Vegasco.Server.Api.Tests.Unit/Consumptions/UpdateConsumptionRequestValidatorTests.cs +++ b/tests/Vegasco.Server.Api.Tests.Unit/Consumptions/UpdateConsumptionRequestValidatorTests.cs @@ -20,7 +20,7 @@ public class UpdateConsumptionRequestValidatorTests _sut = new UpdateConsumption.Validator(_timeProvider); _validRequest = new UpdateConsumption.Request( - _utcNow.AddDays(-1), + _utcNow.Date.AddDays(1).AddTicks(-1), 1, 1); } @@ -38,10 +38,10 @@ public class UpdateConsumptionRequestValidatorTests } [Fact] - public async Task ValidateAsync_ShouldBeInvalid_WhenDateTimeIsGreaterThanUtcNow() + public async Task ValidateAsync_ShouldBeInvalid_WhenDateTimeIsGreaterThanUtcToday() { // Arrange - UpdateConsumption.Request request = _validRequest with { DateTime = _utcNow.AddDays(1) }; + UpdateConsumption.Request request = _validRequest with { DateTime = _utcNow.Date.AddDays(1) }; // Act ValidationResult? result = await _sut.ValidateAsync(request);