SHA256
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:
@@ -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>
|
||||
}
|
||||
</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)
|
||||
{
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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; }
|
||||
}
|
||||
@@ -166,6 +166,8 @@
|
||||
<data name="general.noResults" xml:space="preserve"><value>No Results!</value></data>
|
||||
<data name="general.showAllElements" xml:space="preserve"><value>Show all elements</value></data>
|
||||
<data name="general.wildcardHelperText" xml:space="preserve"><value>Use '%' as wildcard</value></data>
|
||||
<data name="general.dateStart" xml:space="preserve"><value>Date Start</value></data>
|
||||
<data name="general.dateEnd" xml:space="preserve"><value>Date End</value></data>
|
||||
|
||||
<data name="general.address.address" xml:space="preserve"><value>Address</value></data>
|
||||
<data name="general.address.city" xml:space="preserve"><value>City</value></data>
|
||||
@@ -174,6 +176,10 @@
|
||||
<data name="general.address.country" xml:space="preserve"><value>Country</value></data>
|
||||
<data name="general.address.zipCode" xml:space="preserve"><value>Zip Code</value></data>
|
||||
|
||||
<data name="navMenu.GuestDocumentList" xml:space="preserve"><value>Guests</value></data>
|
||||
<data name="navMenu.StayEntryList" xml:space="preserve"><value>Stays</value></data>
|
||||
|
||||
|
||||
<data name="page.GuestDocList.pageTitle" xml:space="preserve"><value>Guest Documents</value></data>
|
||||
<data name="page.GuestDocList.documentList" xml:space="preserve"><value>Document List</value></data>
|
||||
<data name="page.GuestDocList.btnNewGuest" xml:space="preserve"><value>New Guest</value></data>
|
||||
@@ -204,5 +210,6 @@
|
||||
|
||||
<data name="control.GuestDocumentSearchDialog.dialogTitle" xml:space="preserve"><value>Search Guest Document</value></data>
|
||||
<data name="control.GuestDocumentSearchDialog.btnSelectDocument" xml:space="preserve"><value>Use Guest</value></data>
|
||||
<data name="control.GuestDocumentSearchDialog.txtSuggestedGuests" xml:space="preserve"><value>Suggested Guests</value></data>
|
||||
|
||||
</root>
|
||||
@@ -12,6 +12,7 @@ public interface IStayEntryService
|
||||
|
||||
public Task<StayEntryDTO?> GetDtoByIdAsync(long id, StayEntryQueryConfig? queryConfig = null);
|
||||
public Task<IEnumerable<StayEntryDTO>> GetDtoListAsync(StayEntryQueryConfig? queryConfig = null);
|
||||
public Task<IEnumerable<StayEntryDTO>> GetDtoListByFilterAsync(StayEntryFilterDTO filter, int limit = 0, StayEntryQueryConfig? queryConfig = null);
|
||||
|
||||
|
||||
public Task<bool> IsGuestInStayInPeriod(string docType, string docNum, DateTime startTime, DateTime endTime);
|
||||
|
||||
@@ -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<IEnumerable<StayEntryDTO>> 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<bool> IsGuestInStayInPeriod(string docType, string docNum, DateTime startTime, DateTime endTime)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user