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.
This commit is contained in:
2026-08-18 22:17:16 +02:00
parent 340bc583b7
commit 0de4e1ba10
12 changed files with 227 additions and 36 deletions
@@ -34,6 +34,14 @@
@if (!isLoading)
{
@* Only show on first load *@
@if (loadCount == 1)
{
<MudText Align="Align.Center" GutterBottom>
@LanguageLocale.control_GuestDocumentSearchDialog_txtSuggestedGuests
</MudText>
}
<MudList T="GuestDocumentDTO" @bind-SelectedValue="SelectedResult"
SelectionMode="SelectionMode.SingleSelection" Color="Color.Info">
@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
}
@@ -0,0 +1,44 @@
@using System.ComponentModel
@using Somnia.GuestLog.Models.DTOs
@using Somnia.GuestLog.Services
@inject IDataListService dataListService;
<MudForm Model="@Filter" IsTouchedChanged="@(() => FilterChanged.InvokeAsync(Filter))">
<MudStack Row Breakpoint="Breakpoint.LgAndDown" StretchItems="StretchItems.All">
<MudStack Row style="margin-block: 0.2em;">
<MudDatePicker @bind-Date="Filter.DateInStart" For="@(() => Filter.DateInStart)"
Label="@LanguageLocale.general_dateStart" OpenTo="OpenTo.Date" Editable Required="@DateRequired" />
<MudDatePicker @bind-Date="Filter.DateInEnd" For="@(() => Filter.DateInEnd)"
Label="@LanguageLocale.general_dateEnd" OpenTo="OpenTo.Date" Editable Required="@DateRequired" />
</MudStack>
<MudStack Row style="margin-block: 0.2em;">
<MudTextField @bind-Value="Filter.RoomNumber" For="@(() => Filter.RoomNumber)"
Label="@LanguageLocale.dto_StayEntry_RoomNumber" FullWidth Clearable />
<MudSelect @bind-Value="Filter.PaymentMethod" For="@(() => Filter.PaymentMethod)"
Label="@LanguageLocale.dto_StayEntry_PaymentMethod" FullWidth Clearable>
@foreach (string paymentType in
dataListService.GetDataListByName(GuestConsts.DataList_PaymentMethods))
{
<MudSelectItem Value="paymentType">
@dataListService.GetLocalizedValue(GuestConsts.DataList_PaymentMethods, paymentType)
</MudSelectItem>
}
</MudSelect>
</MudStack>
</MudStack>
</MudForm>
@code {
[Parameter, Bindable(true)]
public StayEntryFilterDTO Filter { get; set; } = new();
[Parameter]
public EventCallback<StayEntryFilterDTO> FilterChanged { get; set; }
[Parameter]
public bool DateRequired { get; set; } = true;
}
@@ -69,10 +69,7 @@
<MudTh>@LanguageLocale.dto_GuestDocument_Name</MudTh>
<MudTh>@LanguageLocale.dto_GuestDocument_Surname</MudTh>
<MudTh>@LanguageLocale.dto_GuestDocument_Surname2</MudTh>
@if (!ReadOnly)
{
<MudTh>@LanguageLocale.general_actions</MudTh>
}
<MudTh>@LanguageLocale.general_actions</MudTh>
</HeaderContent>
<RowTemplate>
<MudTd DataLabel="@LanguageLocale.dto_GuestDocument_DocumentType">
@@ -97,6 +94,13 @@
OnClick="@(() => BtnDeleteGuest(context.DocumentType!, context.DocumentNum!))" />
</MudTd>
}
@if (ReadOnly)
{
<MudTd DataLabel="@LanguageLocale.general_actions">
<MudIconButton Icon="@Icons.Material.Filled.Info"
OnClick="@(() => BtnViewGuestDetails(context))" />
</MudTd>
}
</RowTemplate>
</MudTable>
@@ -181,7 +185,15 @@
private async Task BtnAddGuest()
{
var dialog = await dialogService.ShowAsync<GuestDocumentSearchDialog>();
DialogOptions dialogOptions = new()
{
MaxWidth = MaxWidth.Medium,
FullWidth = true,
BackdropClick = false,
CloseOnEscapeKey = true,
};
var dialog = await dialogService.ShowAsync<GuestDocumentSearchDialog>(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<GuestDocDetailsDialog> { { x => x.DocumentDTO, item } };
var options = new DialogOptions()
{
FullScreen = true,
CloseButton = true,
CloseOnEscapeKey = true,
};
await dialogService.ShowAsync<GuestDocDetailsDialog>("GuestDoc Details", parameters, options);
}
#endregion
}
@@ -1,12 +1,16 @@
<MudNavMenu>
<MudNavMenu>
<MudNavLink Href="" Match="NavLinkMatch.All" Icon="@Icons.Material.Filled.Home">Home</MudNavLink>
@*
<MudNavLink Href="counter" Match="NavLinkMatch.Prefix" Icon="@Icons.Material.Filled.Add">Counter</MudNavLink>
<MudNavLink Href="weather" Match="NavLinkMatch.Prefix" Icon="@Icons.Material.Filled.List">Weather</MudNavLink>
*@
<MudNavLink Href="@GuestConsts.Page_GuestDocs_List" Match="NavLinkMatch.Prefix" Icon="@Icons.Material.Filled.DocumentScanner">Guests</MudNavLink>
<MudNavLink Href="@GuestConsts.Page_StayEntry_List" Match="NavLinkMatch.Prefix" Icon="@Icons.Material.Filled.Book">Stays</MudNavLink>
<MudNavLink Href="@GuestConsts.Page_GuestDocs_List" Match="NavLinkMatch.Prefix"
Icon="@Icons.Material.Filled.DocumentScanner">
@LanguageLocale.navMenu_GuestDocumentList
</MudNavLink>
<MudNavLink Href="@GuestConsts.Page_StayEntry_List" Match="NavLinkMatch.Prefix" Icon="@Icons.Material.Filled.Book">
@LanguageLocale.navMenu_StayEntryList
</MudNavLink>
</MudNavMenu>
@@ -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 @@
<MudTh>@LanguageLocale.dto_StayEntry_DateOut</MudTh>
<MudTh>@LanguageLocale.dto_StayEntry_RoomCount</MudTh>
<MudTh>@LanguageLocale.dto_StayEntry_RoomNumber</MudTh>
<MudTh>@LanguageLocale.general_actions</MudTh>
</HeaderContent>
<RowTemplate>
<MudTd DataLabel="@LanguageLocale.dto_StayEntry_DateIn">
@@ -56,6 +58,9 @@
<MudTd DataLabel="@LanguageLocale.dto_StayEntry_RoomNumber">
@context.RoomNumber
</MudTd>
<MudTd DataLabel="@LanguageLocale.general_actions">
<MudIconButton Icon="@Icons.Material.Filled.Info" OnClick="@(() => BtnViewStayDetails(context))" />
</MudTd>
</RowTemplate>
<NoRecordsContent>
<MudText>@LanguageLocale.general_noResults</MudText>
@@ -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<string, string?>(GuestConsts.QueryParam_ReturnUrl, relativeUri)
]);
Navigation.NavigateTo(uri);
}
#endregion
}
@@ -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);
}
}
@@ -24,6 +24,10 @@
</MudButton>
</MudStack>
<MudPaper Class="pa-4 my-4" Elevation="2" Height="100%">
<StayEntryFilterForm @bind-Filter="stayFilter" />
</MudPaper>
<MudDataGrid @ref="_dataGrid" T="StayEntryDTO" Items="@stayEntryList" Loading="@_dataLoading" ReadOnly="true"
Elevation="2">
<ToolBarContent>
@@ -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<StayEntryDTO> stayEntryList = [];
private MudDataGrid<StayEntryDTO> _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)
{