From 0de4e1ba10983fa87a15635cfde6d177472e62cb28bd3ee8ae1a509e276b8a77 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Daniel=20Garc=C3=ADa?=
<93217193+Daniel-Garmig@users.noreply.github.com>
Date: Tue, 18 Aug 2026 22:17:16 +0200
Subject: [PATCH] GuestLog - General Improvements.
- GuestDocument details - Added navigation to details for stays.
- StayEntry details - Added dialog to see details of GuestDocuments.
- StayEntry List - Added filter for result table.
- StayEntry New - Show suggested guests on GuestSearchDialog so no searchs are required in some cases.
- NavMenu - Removed default navigation links.
---
.../Controls/GuestDocumentSearchDialog.razor | 53 +++++++++++++++----
.../Forms/StayEntryFilterForm.razor | 44 +++++++++++++++
.../Components/Forms/StayEntryForm.razor | 37 +++++++++++--
.../Components/Layout/NavMenu.razor | 18 ++++---
.../Pages/GuestDocuments/GuestDocDetail.razor | 44 +++++++++++----
.../Pages/StayEntries/StayEntryDetail.razor | 6 ++-
.../Pages/StayEntries/StayEntryList.razor | 13 ++++-
src/Somnia.GuestLog/GuestConsts.cs | 3 ++
.../Models/DTOs/StayEntryFilterDTO.cs | 10 ++++
.../Resources/LanguageLocale.resx | 7 +++
.../Services/IStayEntryService.cs | 1 +
.../Services/StayEntryService.cs | 27 ++++++++++
12 files changed, 227 insertions(+), 36 deletions(-)
create mode 100644 src/Somnia.GuestLog/Components/Forms/StayEntryFilterForm.razor
create mode 100644 src/Somnia.GuestLog/Models/DTOs/StayEntryFilterDTO.cs
diff --git a/src/Somnia.GuestLog/Components/Controls/GuestDocumentSearchDialog.razor b/src/Somnia.GuestLog/Components/Controls/GuestDocumentSearchDialog.razor
index cd0f3b1..29c03d3 100644
--- a/src/Somnia.GuestLog/Components/Controls/GuestDocumentSearchDialog.razor
+++ b/src/Somnia.GuestLog/Components/Controls/GuestDocumentSearchDialog.razor
@@ -34,6 +34,14 @@
@if (!isLoading)
{
+ @* Only show on first load *@
+ @if (loadCount == 1)
+ {
+
+ @LanguageLocale.control_GuestDocumentSearchDialog_txtSuggestedGuests
+
+ }
+
@foreach (GuestDocumentDTO result in results)
@@ -74,10 +82,39 @@
private GuestDocumentDTO? SelectedResult { get; set; }
private bool isLoading = false;
+ private int loadCount = 0;
+
+
+ protected override async Task OnInitializedAsync()
+ {
+ //Load last 5 guests.
+ await LoadGuests(limit: 5);
+ }
private void Cancel() => MudDialog.Cancel();
+
+ private async Task LoadGuests(int limit = 25)
+ {
+
+ try
+ {
+ isLoading = true;
+ results = await guestDocumentService.GetDtoListByFilterAsync(filter);
+ isLoading = false;
+ loadCount++;
+ }
+ catch (Exception ex)
+ {
+ logger.LogError(ex, "GuestDocument Search returned an error!");
+ Snackbar.Add($"Error searching: {ex.Message}", Severity.Error);
+ }
+ }
+
+
+ #region Event Handlers
+
private async Task BtnSearchGuestDocuments()
{
if (filter.IsEmpty)
@@ -86,17 +123,8 @@
return;
}
- try
- {
- isLoading = true;
- results = await guestDocumentService.GetDtoListByFilterAsync(filter);
- isLoading = false;
- }
- catch (Exception ex)
- {
- logger.LogError(ex, "GuestDocument Search returned an error!");
- Snackbar.Add($"Error searching: {ex.Message}", Severity.Error);
- }
+ //Load unlimited guests using current filter.
+ await LoadGuests();
}
private async Task btnSelectGuest()
@@ -114,4 +142,7 @@
MudDialog.Close(dialogResult);
return;
}
+
+ #endregion
+
}
\ No newline at end of file
diff --git a/src/Somnia.GuestLog/Components/Forms/StayEntryFilterForm.razor b/src/Somnia.GuestLog/Components/Forms/StayEntryFilterForm.razor
new file mode 100644
index 0000000..751c328
--- /dev/null
+++ b/src/Somnia.GuestLog/Components/Forms/StayEntryFilterForm.razor
@@ -0,0 +1,44 @@
+@using System.ComponentModel
+@using Somnia.GuestLog.Models.DTOs
+@using Somnia.GuestLog.Services
+
+@inject IDataListService dataListService;
+
+
+
+
+
+
+
+
+
+
+
+ @foreach (string paymentType in
+ dataListService.GetDataListByName(GuestConsts.DataList_PaymentMethods))
+ {
+
+ @dataListService.GetLocalizedValue(GuestConsts.DataList_PaymentMethods, paymentType)
+
+ }
+
+
+
+
+
+@code {
+
+ [Parameter, Bindable(true)]
+ public StayEntryFilterDTO Filter { get; set; } = new();
+
+ [Parameter]
+ public EventCallback FilterChanged { get; set; }
+
+ [Parameter]
+ public bool DateRequired { get; set; } = true;
+
+}
\ No newline at end of file
diff --git a/src/Somnia.GuestLog/Components/Forms/StayEntryForm.razor b/src/Somnia.GuestLog/Components/Forms/StayEntryForm.razor
index f8491b0..991ef81 100644
--- a/src/Somnia.GuestLog/Components/Forms/StayEntryForm.razor
+++ b/src/Somnia.GuestLog/Components/Forms/StayEntryForm.razor
@@ -69,10 +69,7 @@
@LanguageLocale.dto_GuestDocument_Name
@LanguageLocale.dto_GuestDocument_Surname
@LanguageLocale.dto_GuestDocument_Surname2
- @if (!ReadOnly)
- {
- @LanguageLocale.general_actions
- }
+ @LanguageLocale.general_actions
@@ -97,6 +94,13 @@
OnClick="@(() => BtnDeleteGuest(context.DocumentType!, context.DocumentNum!))" />
}
+ @if (ReadOnly)
+ {
+
+
+
+ }
@@ -181,7 +185,15 @@
private async Task BtnAddGuest()
{
- var dialog = await dialogService.ShowAsync();
+ DialogOptions dialogOptions = new()
+ {
+ MaxWidth = MaxWidth.Medium,
+ FullWidth = true,
+ BackdropClick = false,
+ CloseOnEscapeKey = true,
+ };
+
+ var dialog = await dialogService.ShowAsync(title: "", options: dialogOptions);
DialogResult? result = await dialog.Result;
if (result is null || result.Canceled)
@@ -228,6 +240,21 @@
.ToList();
}
+
+ private async Task BtnViewGuestDetails(GuestDocumentDTO item)
+ {
+ var parameters =
+ new DialogParameters { { x => x.DocumentDTO, item } };
+ var options = new DialogOptions()
+ {
+ FullScreen = true,
+ CloseButton = true,
+ CloseOnEscapeKey = true,
+ };
+
+ await dialogService.ShowAsync("GuestDoc Details", parameters, options);
+ }
+
#endregion
}
\ No newline at end of file
diff --git a/src/Somnia.GuestLog/Components/Layout/NavMenu.razor b/src/Somnia.GuestLog/Components/Layout/NavMenu.razor
index 048b526..6969cad 100644
--- a/src/Somnia.GuestLog/Components/Layout/NavMenu.razor
+++ b/src/Somnia.GuestLog/Components/Layout/NavMenu.razor
@@ -1,12 +1,16 @@
-
-
+
Home
+
+ @*
Counter
-
Weather
+ *@
- Guests
- Stays
+
+ @LanguageLocale.navMenu_GuestDocumentList
+
+
+ @LanguageLocale.navMenu_StayEntryList
+
-
-
diff --git a/src/Somnia.GuestLog/Components/Pages/GuestDocuments/GuestDocDetail.razor b/src/Somnia.GuestLog/Components/Pages/GuestDocuments/GuestDocDetail.razor
index 3ba30d6..940f0db 100644
--- a/src/Somnia.GuestLog/Components/Pages/GuestDocuments/GuestDocDetail.razor
+++ b/src/Somnia.GuestLog/Components/Pages/GuestDocuments/GuestDocDetail.razor
@@ -2,6 +2,7 @@
@using Somnia.GuestLog.Models.DTOs;
@using Somnia.GuestLog.Services;
+@using Microsoft.AspNetCore.WebUtilities;
@inject ISnackbar Snackbar
@inject IDialogService DialogService
@@ -42,6 +43,7 @@
@LanguageLocale.dto_StayEntry_DateOut
@LanguageLocale.dto_StayEntry_RoomCount
@LanguageLocale.dto_StayEntry_RoomNumber
+ @LanguageLocale.general_actions
@@ -56,6 +58,9 @@
@context.RoomNumber
+
+
+
@LanguageLocale.general_noResults
@@ -110,16 +115,6 @@
}
}
- private void BtnEdit()
- {
- Snackbar.Add("Not implemented yet!", Severity.Info);
- }
-
- private void BtnReturn()
- {
- Navigation.NavigateTo(GuestConsts.Page_GuestDocs_List);
- }
-
private async Task LoadTabGuestStays()
{
//Only load when there is no data.
@@ -137,4 +132,33 @@
guestStayList = await stayService.GetStaysWithGuest(documentModel.DocumentType, documentModel.DocumentNum);
guestStaysLoading = false;
}
+
+
+ #region Event Handlers
+
+ private void BtnEdit()
+ {
+ Snackbar.Add("Not implemented yet!", Severity.Info);
+ }
+
+ private void BtnReturn()
+ {
+ Navigation.NavigateTo(GuestConsts.Page_GuestDocs_List);
+ }
+
+
+ private void BtnViewStayDetails(StayEntryDTO item)
+ {
+ string itemId = $"{item.Id ?? -1}";
+ string uri = GuestConsts.Page_StayEntry_Detail.Replace(GuestConsts.Page_StayEntry_Detail_Param_Id, itemId);
+
+ string relativeUri = Navigation.ToBaseRelativePath(Navigation.Uri);
+ uri = QueryHelpers.AddQueryString(uri, [
+ new KeyValuePair(GuestConsts.QueryParam_ReturnUrl, relativeUri)
+ ]);
+ Navigation.NavigateTo(uri);
+ }
+
+ #endregion
+
}
\ No newline at end of file
diff --git a/src/Somnia.GuestLog/Components/Pages/StayEntries/StayEntryDetail.razor b/src/Somnia.GuestLog/Components/Pages/StayEntries/StayEntryDetail.razor
index fed7887..a1df66e 100644
--- a/src/Somnia.GuestLog/Components/Pages/StayEntries/StayEntryDetail.razor
+++ b/src/Somnia.GuestLog/Components/Pages/StayEntries/StayEntryDetail.razor
@@ -36,6 +36,9 @@
[Parameter]
public long StayId { get; set; }
+ [SupplyParameterFromQuery(Name = GuestConsts.QueryParam_ReturnUrl)]
+ public string? ReturnUrl { get; set; }
+
StayEntryDTO? stayModel = null;
protected override async Task OnInitializedAsync()
@@ -64,7 +67,8 @@
private void BtnReturn()
{
- Navigation.NavigateTo(GuestConsts.Page_StayEntry_List);
+ string uri = ReturnUrl ?? GuestConsts.Page_StayEntry_List;
+ Navigation.NavigateTo(uri);
}
}
\ No newline at end of file
diff --git a/src/Somnia.GuestLog/Components/Pages/StayEntries/StayEntryList.razor b/src/Somnia.GuestLog/Components/Pages/StayEntries/StayEntryList.razor
index 7fed61c..af4ecda 100644
--- a/src/Somnia.GuestLog/Components/Pages/StayEntries/StayEntryList.razor
+++ b/src/Somnia.GuestLog/Components/Pages/StayEntries/StayEntryList.razor
@@ -24,6 +24,10 @@
+
+
+
+
@@ -66,6 +70,12 @@
private bool _showAllData = false;
private const int resultLimit = 200;
+ private StayEntryFilterDTO stayFilter = new StayEntryFilterDTO()
+ {
+ DateInStart = DateTime.Today.AddDays(-14),
+ DateInEnd = DateTime.Today,
+ };
+
private IEnumerable stayEntryList = [];
private MudDataGrid _dataGrid = null!;
@@ -82,8 +92,7 @@
_dataLoading = true;
int dataLimit = _showAllData ? 0 : resultLimit;
- stayEntryList = await StayEntryService.GetDtoListAsync();
- //stayEntryList = await StayEntryService.GetDtoListAsync(filter: filter, limit: dataLimit);
+ stayEntryList = await StayEntryService.GetDtoListByFilterAsync(filter: stayFilter, limit: dataLimit);
if (showMsg)
{
diff --git a/src/Somnia.GuestLog/GuestConsts.cs b/src/Somnia.GuestLog/GuestConsts.cs
index ed23428..4ea0342 100644
--- a/src/Somnia.GuestLog/GuestConsts.cs
+++ b/src/Somnia.GuestLog/GuestConsts.cs
@@ -14,6 +14,9 @@ public static class GuestConsts
public const string Page_StayEntry_Detail_Param_Id = "{StayId:long}";
+ public const string QueryParam_ReturnUrl = "returnUrl";
+
+
public const string DataList_DocumentTypes = "DocumentType";
public const string DataList_GenderOptions = "GenderOption";
public const string DataList_CountryCodes = "CountryCode";
diff --git a/src/Somnia.GuestLog/Models/DTOs/StayEntryFilterDTO.cs b/src/Somnia.GuestLog/Models/DTOs/StayEntryFilterDTO.cs
new file mode 100644
index 0000000..104639c
--- /dev/null
+++ b/src/Somnia.GuestLog/Models/DTOs/StayEntryFilterDTO.cs
@@ -0,0 +1,10 @@
+namespace Somnia.GuestLog.Models.DTOs;
+
+public class StayEntryFilterDTO
+{
+ public DateTime? DateInStart { get; set; }
+ public DateTime? DateInEnd { get; set; }
+
+ public string? RoomNumber { get; set; }
+ public string? PaymentMethod { get; set; }
+}
\ No newline at end of file
diff --git a/src/Somnia.GuestLog/Resources/LanguageLocale.resx b/src/Somnia.GuestLog/Resources/LanguageLocale.resx
index e781f48..b17142a 100644
--- a/src/Somnia.GuestLog/Resources/LanguageLocale.resx
+++ b/src/Somnia.GuestLog/Resources/LanguageLocale.resx
@@ -166,6 +166,8 @@
No Results!
Show all elements
Use '%' as wildcard
+ Date Start
+ Date End
Address
City
@@ -173,6 +175,10 @@
State
Country
Zip Code
+
+ Guests
+ Stays
+
Guest Documents
Document List
@@ -204,5 +210,6 @@
Search Guest Document
Use Guest
+ Suggested Guests
\ No newline at end of file
diff --git a/src/Somnia.GuestLog/Services/IStayEntryService.cs b/src/Somnia.GuestLog/Services/IStayEntryService.cs
index 2c63954..e3f2068 100644
--- a/src/Somnia.GuestLog/Services/IStayEntryService.cs
+++ b/src/Somnia.GuestLog/Services/IStayEntryService.cs
@@ -12,6 +12,7 @@ public interface IStayEntryService
public Task GetDtoByIdAsync(long id, StayEntryQueryConfig? queryConfig = null);
public Task> GetDtoListAsync(StayEntryQueryConfig? queryConfig = null);
+ public Task> GetDtoListByFilterAsync(StayEntryFilterDTO filter, int limit = 0, StayEntryQueryConfig? queryConfig = null);
public Task IsGuestInStayInPeriod(string docType, string docNum, DateTime startTime, DateTime endTime);
diff --git a/src/Somnia.GuestLog/Services/StayEntryService.cs b/src/Somnia.GuestLog/Services/StayEntryService.cs
index daeed77..dccba19 100644
--- a/src/Somnia.GuestLog/Services/StayEntryService.cs
+++ b/src/Somnia.GuestLog/Services/StayEntryService.cs
@@ -5,6 +5,7 @@ using Somnia.GuestLog.Models;
using Somnia.GuestLog.Models.DTOs;
using Somnia.GuestLog.Models.Entities;
using Somnia.GuestLog.Models.QueryConfigs;
+using Somnia.GuestLog.Utils;
namespace Somnia.GuestLog.Services;
@@ -135,6 +136,32 @@ public class StayEntryService(
return dbList.Select(e => GetDtoFromDb(e, queryConfig));
}
+ public async Task> GetDtoListByFilterAsync(StayEntryFilterDTO filter, int limit = 0, StayEntryQueryConfig? queryConfig = null)
+ {
+ using var dbContext = contextFactory.CreateDbContext();
+
+ var query = dbContext.StayEntries
+ .AddQueryConfig(queryConfig)
+ .AsQueryable();
+
+ query = query.WhereIf(filter.DateInStart is not null && filter.DateInEnd is not null,
+ e => e.DateIn >= filter.DateInStart!.Value.ToUniversalTime()
+ && e.DateIn < filter.DateInEnd!.Value.ToUniversalTime());
+ query = query.WhereIf(!string.IsNullOrEmpty(filter.RoomNumber),
+ e => EF.Functions.Like(e.RoomNumber, $"%{filter.RoomNumber}%"));
+ query = query.WhereIf(!string.IsNullOrEmpty(filter.PaymentMethod),
+ e => e.PaymentMethod == filter.PaymentMethod);
+
+ if (limit > 0)
+ {
+ query = query.Take(limit);
+ }
+
+ var dbList = await query.ToListAsync();
+
+ return dbList.Select(x => GetDtoFromDb(x, queryConfig));
+ }
+
public async Task IsGuestInStayInPeriod(string docType, string docNum, DateTime startTime, DateTime endTime)
{