Small fixes and improvements:

- GuestDocument - At least one contact field is required.
- GuestDocument - List Page - Hide not useful columns: "version"
- StayEntry - Show stayEntry ID in UI msg after creation.
- StayEntry - Create Page - Time fields don't reset anymore when dates change.
- Show local times in UI instead of UTC times.
- Validators - Use expresions for dates so they are recalculated each time.
This commit is contained in:
2026-09-12 15:28:25 +02:00
parent 491ecc4cd1
commit c5d8487046
9 changed files with 26 additions and 15 deletions
@@ -21,12 +21,14 @@
<MudDivider DividerType="DividerType.Middle" Class="mb-4" /> <MudDivider DividerType="DividerType.Middle" Class="mb-4" />
<MudStack Row style="@FieldMarginY"> <MudStack Row style="@FieldMarginY">
<MudDatePicker @bind-Date="Model.DateIn" For="@(() => Model.DateIn)" <MudDatePicker Date="Model.DateIn" For="@(() => Model.DateIn)"
DateChanged="@((newVal) => Model.DateIn = GetDateTimeFromDateAndTime(newVal, Model.DateIn?.TimeOfDay))"
Label="@LanguageLocale.dto_StayEntry_DateIn" Clearable OpenTo="OpenTo.Date" Editable Label="@LanguageLocale.dto_StayEntry_DateIn" Clearable OpenTo="OpenTo.Date" Editable
AutoClose="true" /> AutoClose="true" />
<MudTimePicker Time="Model.DateIn?.TimeOfDay" Label=" " Editable <MudTimePicker Time="Model.DateIn?.TimeOfDay" Label=" " Editable
TimeChanged="@((newVal) => Model.DateIn = GetDateTimeFromDateAndTime(Model.DateIn, newVal))" /> TimeChanged="@((newVal) => Model.DateIn = GetDateTimeFromDateAndTime(Model.DateIn, newVal))" />
<MudDatePicker @bind-Date="Model.DateOut" For="@(() => Model.DateOut)" <MudDatePicker Date="Model.DateOut" For="@(() => Model.DateOut)"
DateChanged="@((newVal) => Model.DateOut = GetDateTimeFromDateAndTime(newVal, Model.DateOut?.TimeOfDay))"
Label="@LanguageLocale.dto_StayEntry_DateOut" Clearable OpenTo="OpenTo.Date" Editable Label="@LanguageLocale.dto_StayEntry_DateOut" Clearable OpenTo="OpenTo.Date" Editable
AutoClose="true" /> AutoClose="true" />
<MudTimePicker Time="Model.DateOut?.TimeOfDay" Label=" " Editable <MudTimePicker Time="Model.DateOut?.TimeOfDay" Label=" " Editable
@@ -43,8 +43,9 @@
</MudStack> </MudStack>
</ToolBarContent> </ToolBarContent>
<Columns> <Columns>
<PropertyColumn Property="x => x.Id" Title="@LanguageLocale.dto_GuestDocument_Id" /> <PropertyColumn Property="x => x.Id" Title="@LanguageLocale.dto_GuestDocument_Id" Hideable="false" />
<PropertyColumn Property="x => x.Version" Title="@LanguageLocale.dto_GuestDocument_Version" /> <PropertyColumn Property="x => x.Version" Title="@LanguageLocale.dto_GuestDocument_Version" Hidden
Hideable="true" />
<PropertyColumn Title="@LanguageLocale.dto_GuestDocument_DocumentType" <PropertyColumn Title="@LanguageLocale.dto_GuestDocument_DocumentType"
Property="x => dataListService.GetLocalizedValue(GuestConsts.DataList_DocumentTypes, x.DocumentType)" Property="x => dataListService.GetLocalizedValue(GuestConsts.DataList_DocumentTypes, x.DocumentType)"
Hideable="false" /> Hideable="false" />
@@ -60,7 +60,7 @@
return; return;
} }
userMessage.ShowMessage($"StayEntry Created!", MessageKind.Success); userMessage.ShowMessage("StayEntry Created: (Id: {0})", MessageKind.Success, createResult.Context ?? ["???"]);
Navigation.NavigateTo(GuestConsts.Page_StayEntry_List); Navigation.NavigateTo(GuestConsts.Page_StayEntry_List);
} }
@@ -16,6 +16,8 @@ public sealed record Result(
) : IResult ) : IResult
{ {
public static Result Ok() => new(IsSuccess: true, ResultCode: ResultCode.Ok, Context: null); public static Result Ok() => new(IsSuccess: true, ResultCode: ResultCode.Ok, Context: null);
public static Result OkWithContext(params object[] context)
=> new(IsSuccess: true, ResultCode: ResultCode.Ok, Context: context);
public static Result Fail(ResultCode resultCode) => new(IsSuccess: false, resultCode, Context: null); public static Result Fail(ResultCode resultCode) => new(IsSuccess: false, resultCode, Context: null);
public static Result FailWithContext(ResultCode resultCode, params object[] context) public static Result FailWithContext(ResultCode resultCode, params object[] context)
+5 -5
View File
@@ -30,8 +30,8 @@ internal static class EntityMapping
AddressState = entity.AddressDetails?.AddressState ?? "", AddressState = entity.AddressDetails?.AddressState ?? "",
AddressCountry = entity.AddressDetails?.AddressCountry! ?? "", AddressCountry = entity.AddressDetails?.AddressCountry! ?? "",
ZipCode = entity.AddressDetails?.ZipCode ?? "", ZipCode = entity.AddressDetails?.ZipCode ?? "",
CreateTime = entity.CreateTime, CreateTime = entity.CreateTime.ToLocalTime(),
UpdateTime = entity.UpdateTime, UpdateTime = entity.UpdateTime.ToLocalTime(),
}; };
} }
@@ -45,8 +45,8 @@ internal static class EntityMapping
RoomCount = entity.RoomCount, RoomCount = entity.RoomCount,
RoomNumber = entity.RoomNumber, RoomNumber = entity.RoomNumber,
PaymentMethod = entity.PaymentMethod, PaymentMethod = entity.PaymentMethod,
CreateTime = entity.CreateTime, CreateTime = entity.CreateTime.ToLocalTime(),
UpdateTime = entity.UpdateTime, UpdateTime = entity.UpdateTime.ToLocalTime(),
GuestDocuments = includeGuests ? [.. entity.GuestDocuments.Select(e => MapGuestDocumentEntityToDTO(e))] : null, GuestDocuments = includeGuests ? [.. entity.GuestDocuments.Select(e => MapGuestDocumentEntityToDTO(e))] : null,
}; };
} }
@@ -68,7 +68,7 @@ internal static class EntityMapping
ExportResult = entity.ExportResult, ExportResult = entity.ExportResult,
ExportedPath = entity.ExportedPath, ExportedPath = entity.ExportedPath,
ExportDetails = entity.ExportDetails, ExportDetails = entity.ExportDetails,
ExportTime = entity.ExportTime, ExportTime = entity.ExportTime.ToLocalTime(),
}; };
} }
@@ -67,7 +67,7 @@ public class StayEntryEntityService(
await dbContext.SaveChangesAsync(); await dbContext.SaveChangesAsync();
logger.LogInformation("StayEntryService - CreateEntryAsync: StayEntry Created: '{id}'", dbStay.GetFullKey()); logger.LogInformation("StayEntryService - CreateEntryAsync: StayEntry Created: '{id}'", dbStay.GetFullKey());
return Result.Ok(); return Result.OkWithContext(dbStay.GetFullKey());
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -195,7 +195,7 @@ public class StayExportService(
throw new InvalidOperationException($"StayExportFile - ExportType {exportParams.ExportType} require date start/end. Null dates found"); throw new InvalidOperationException($"StayExportFile - ExportType {exportParams.ExportType} require date start/end. Null dates found");
} }
//Get Stays in period. //Get Stays in period -> Local time should be used so it match with entities local-time.
StayEntryFilterDTO filter = new() StayEntryFilterDTO filter = new()
{ {
DateInStart = exportParams.ExportPeriodStart, DateInStart = exportParams.ExportPeriodStart,
@@ -25,7 +25,7 @@ public class GuestDocumentDTOValidator : ValueValidator<GuestDocumentDTO>
.Cascade(CascadeMode.Stop) .Cascade(CascadeMode.Stop)
.NotEmpty() .NotEmpty()
.When(x => x.Nationality != GuestConsts.CountryCode_ESP) .When(x => x.Nationality != GuestConsts.CountryCode_ESP)
.LessThanOrEqualTo(DateTime.Today); .LessThanOrEqualTo(x => DateTime.Today);
RuleFor(x => x.SupportNum) RuleFor(x => x.SupportNum)
.Cascade(CascadeMode.Stop) .Cascade(CascadeMode.Stop)
@@ -49,7 +49,7 @@ public class GuestDocumentDTOValidator : ValueValidator<GuestDocumentDTO>
RuleFor(x => x.BirthDate) RuleFor(x => x.BirthDate)
.NotEmpty() .NotEmpty()
.LessThanOrEqualTo(DateTime.Today); .LessThanOrEqualTo(x => DateTime.Today);
RuleFor(x => x.Nationality) RuleFor(x => x.Nationality)
.Cascade(CascadeMode.Stop) .Cascade(CascadeMode.Stop)
@@ -66,6 +66,12 @@ public class GuestDocumentDTOValidator : ValueValidator<GuestDocumentDTO>
.Matches(RegexUtils.RegexPhoneNumber()).WithMessage("Invalid format") .Matches(RegexUtils.RegexPhoneNumber()).WithMessage("Invalid format")
.When(x => !string.IsNullOrEmpty(x.PhoneNumber)); .When(x => !string.IsNullOrEmpty(x.PhoneNumber));
// Phone is required if mail is empty.
RuleFor(x => x.PhoneNumber)
.NotNull()
.When(x => string.IsNullOrEmpty(x.EmailAddress))
.WithMessage("At least 1 contact field (phone or email) is required!");
RuleFor(x => x.AddressCountry) RuleFor(x => x.AddressCountry)
.NotEmpty() .NotEmpty()
.Must(val => val != null && dataListService.IsValueInList(GuestConsts.DataList_CountryCodes, val)); .Must(val => val != null && dataListService.IsValueInList(GuestConsts.DataList_CountryCodes, val));
@@ -10,7 +10,7 @@ public class StayEntryDTOValidator : ValueValidator<StayEntryDTO>
{ {
RuleFor(e => e.DateIn) RuleFor(e => e.DateIn)
.NotEmpty() .NotEmpty()
.LessThanOrEqualTo(DateTime.Today.AddDays(1).AddSeconds(-1)); .LessThanOrEqualTo(x => DateTime.Today.AddDays(1).AddSeconds(-1));
RuleFor(e => e.DateOut) RuleFor(e => e.DateOut)
.NotEmpty() .NotEmpty()