SHA256
Compare commits
2
Commits
| Author | SHA256 | Date | |
|---|---|---|---|
|
|
b18bd7caa6 | ||
|
|
511bd023f2 |
@@ -1,9 +1,10 @@
|
||||
@using Somnia.GuestLog.Models.DTOs;
|
||||
@using Somnia.GuestLog.Services
|
||||
@using Somnia.GuestLog.Services.AddressQuery;
|
||||
|
||||
@inject ILogger<AddressQueryDialog> logger;
|
||||
@inject IAddressQueryFactory addressQueryFactory;
|
||||
@inject ISnackbar Snackbar
|
||||
@inject IUserMessageService userMessage
|
||||
|
||||
<MudDialog @ref="@DialogRef">
|
||||
<TitleContent>
|
||||
@@ -112,7 +113,7 @@
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogError(ex, "SearchAddress returned an error!");
|
||||
Snackbar.Add($"Error searching address: {ex.Message}", Severity.Error);
|
||||
userMessage.ShowMessage($"Error searching address: {ex.Message}", MessageKind.Error);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,7 +121,7 @@
|
||||
{
|
||||
if (SelectedAddressResult is null)
|
||||
{
|
||||
Snackbar.Add("Select an address", Severity.Warning);
|
||||
userMessage.ShowMessage("Select an address", MessageKind.Warning);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
@using Somnia.GuestLog.Services
|
||||
|
||||
@inject ILogger<AddressQueryDialog> logger;
|
||||
@inject ISnackbar Snackbar
|
||||
@inject IUserMessageService userMessage
|
||||
@inject IGuestDocumentService guestDocumentService;
|
||||
|
||||
|
||||
@@ -108,7 +108,7 @@
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogError(ex, "GuestDocument Search returned an error!");
|
||||
Snackbar.Add($"Error searching: {ex.Message}", Severity.Error);
|
||||
userMessage.ShowMessage($"Error searching: {ex.Message}", MessageKind.Error);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -119,7 +119,7 @@
|
||||
{
|
||||
if (filter.IsEmpty)
|
||||
{
|
||||
Snackbar.Add("Add some search!", Severity.Warning);
|
||||
userMessage.ShowMessage("Search can't be empty!", MessageKind.Warning);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -131,7 +131,7 @@
|
||||
{
|
||||
if (SelectedResult is null)
|
||||
{
|
||||
Snackbar.Add("Select a guest document", Severity.Warning);
|
||||
userMessage.ShowMessage("A guest document must be selected", MessageKind.Warning);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace Somnia.GuestLog.Components.Forms;
|
||||
|
||||
public enum FormMode
|
||||
{
|
||||
Create, ReadOnly, Edit
|
||||
}
|
||||
@@ -7,7 +7,7 @@
|
||||
@inject IDataListService dataListService;
|
||||
@inject IValidator<StayEntryDTO> stayValidator;
|
||||
@inject IDialogService dialogService;
|
||||
@inject ISnackbar snackbar
|
||||
@inject IUserMessageService userMessage
|
||||
|
||||
|
||||
<MudForm @ref="@_form" Model="@Model" Validation="@((stayValidator as StayEntryDTOValidator)!.ValidateValue)"
|
||||
@@ -21,12 +21,16 @@
|
||||
<MudDivider DividerType="DividerType.Middle" Class="mb-4" />
|
||||
|
||||
<MudStack Row style="@FieldMarginY">
|
||||
<MudDatePicker @bind-Date="Model.DateIn" For="@(() => Model.DateIn)"
|
||||
Label="@LanguageLocale.dto_StayEntry_DateIn" Clearable OpenTo="OpenTo.Date" Editable />
|
||||
<MudTimePicker @bind-Time="TimeIn" Label=" " Editable />
|
||||
<MudDatePicker @bind-Date="Model.DateOut" For="@(() => Model.DateOut)"
|
||||
Label="@LanguageLocale.dto_StayEntry_DateOut" Clearable OpenTo="OpenTo.Date" Editable />
|
||||
<MudTimePicker @bind-Time="TimeOut" Label=" " Editable />
|
||||
<MudDatePicker @ref="_datePickerDateIn" @bind-Date="Model.DateIn" For="@(() => Model.DateIn)"
|
||||
Label="@LanguageLocale.dto_StayEntry_DateIn" Clearable OpenTo="OpenTo.Date" Editable
|
||||
AutoClose="true" />
|
||||
<MudTimePicker Time="Model.DateIn?.TimeOfDay" Label=" " Editable
|
||||
TimeChanged="@((newVal) => Model.DateIn = GetDateTimeFromDateAndTime(Model.DateIn, newVal))" />
|
||||
<MudDatePicker @ref="_datePickerDateOut" @bind-Date="Model.DateOut" For="@(() => Model.DateOut)"
|
||||
Label="@LanguageLocale.dto_StayEntry_DateOut" Clearable OpenTo="OpenTo.Date" Editable
|
||||
AutoClose="true" />
|
||||
<MudTimePicker Time="Model.DateOut?.TimeOfDay" Label=" " Editable
|
||||
TimeChanged="@((newVal) => Model.DateOut = GetDateTimeFromDateAndTime(Model.DateOut, newVal))" />
|
||||
</MudStack>
|
||||
<MudStack Row style="@FieldMarginY">
|
||||
<MudTextField @bind-Value="Model.RoomCount" For="@(() => Model.RoomCount)"
|
||||
@@ -113,14 +117,16 @@
|
||||
[Parameter]
|
||||
public StayEntryDTO Model { private get; set; } = new();
|
||||
|
||||
[Parameter]
|
||||
public bool ReadOnly { get; set; } = false;
|
||||
[Parameter, EditorRequired]
|
||||
public FormMode FormMode { get; set; }
|
||||
|
||||
private TimeSpan? TimeIn = DateTime.Now.TimeOfDay;
|
||||
private TimeSpan? TimeOut = new(hours: 12, minutes: 0, seconds: 0);
|
||||
|
||||
private bool ReadOnly => FormMode == FormMode.ReadOnly;
|
||||
|
||||
|
||||
private MudForm _form = null!;
|
||||
private MudDatePicker _datePickerDateIn = null!;
|
||||
private MudDatePicker _datePickerDateOut = null!;
|
||||
|
||||
private const string FieldMarginY = "margin-block: 0.5em";
|
||||
private IEnumerable<string> PaymentMethodSet
|
||||
@@ -138,7 +144,20 @@
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
Model.DateIn = DateTime.Today;
|
||||
//Initialize values when not ReadOnly.
|
||||
if (FormMode == FormMode.Create)
|
||||
{
|
||||
Model.DateIn = DateTime.Now;
|
||||
|
||||
DateTime dateOut = DateTime.Today.AddDays(1);
|
||||
Model.DateOut = new(
|
||||
year: dateOut.Year, month: dateOut.Month, day: dateOut.Day,
|
||||
hour: 12, minute: 0, second: 0
|
||||
);
|
||||
|
||||
//Init Guest List
|
||||
Model.GuestDocuments = [];
|
||||
}
|
||||
}
|
||||
|
||||
#region Public Methods
|
||||
@@ -149,7 +168,7 @@
|
||||
|
||||
if (Model.GuestDocuments is null || Model.GuestDocuments.Count == 0)
|
||||
{
|
||||
snackbar.Add("At least 1 guest is required!", MudBlazor.Severity.Warning);
|
||||
userMessage.ShowMessage("At least 1 guest is required!", MessageKind.Warning);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -158,10 +177,6 @@
|
||||
|
||||
public StayEntryDTO GetModel()
|
||||
{
|
||||
//Update model times.
|
||||
Model.DateIn = GetDateTimeFromDateAndTime(Model.DateIn, TimeIn);
|
||||
Model.DateOut = GetDateTimeFromDateAndTime(Model.DateOut, TimeOut);
|
||||
|
||||
return Model;
|
||||
}
|
||||
|
||||
@@ -185,6 +200,8 @@
|
||||
|
||||
private async Task BtnAddGuest()
|
||||
{
|
||||
Debug.Assert(Model.GuestDocuments != null);
|
||||
|
||||
DialogOptions dialogOptions = new()
|
||||
{
|
||||
MaxWidth = MaxWidth.Medium,
|
||||
@@ -205,28 +222,22 @@
|
||||
|
||||
if (resultData is null)
|
||||
{
|
||||
snackbar.Add("Error! No Guest Document selected!", MudBlazor.Severity.Error);
|
||||
userMessage.ShowMessage("Error! No Guest Document selected!", MessageKind.Error);
|
||||
return;
|
||||
}
|
||||
|
||||
//Check if this guest is already added.
|
||||
if (Model.GuestDocuments is not null && Model.GuestDocuments.Count > 0)
|
||||
if (Model.GuestDocuments.Count > 0)
|
||||
{
|
||||
bool alreadyAdded = Model.GuestDocuments.Any(e => e.DocumentType == resultData.DocumentType
|
||||
&& e.DocumentNum == resultData.DocumentNum);
|
||||
if (alreadyAdded)
|
||||
{
|
||||
snackbar.Add("GuestDocument already added!", MudBlazor.Severity.Warning);
|
||||
userMessage.ShowMessage("GuestDocument already added!", MessageKind.Warning);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
//Init List.
|
||||
if (Model.GuestDocuments is null)
|
||||
{
|
||||
Model.GuestDocuments = [];
|
||||
}
|
||||
|
||||
Model.GuestDocuments.Add(resultData);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
@page "/debug/addrSearch"
|
||||
|
||||
@using Somnia.GuestLog.Models.DTOs;
|
||||
@using Somnia.GuestLog.Services;
|
||||
@using Somnia.GuestLog.Services.AddressQuery;
|
||||
|
||||
@inject ILogger<AddressQuery> logger;
|
||||
@inject IAddressQueryFactory addressQueryFactory;
|
||||
@inject ISnackbar Snackbar
|
||||
@inject IUserMessageService userMessage
|
||||
@inject IDialogService DialogService
|
||||
|
||||
<PageTitle>DEBUG - Address Query</PageTitle>
|
||||
@@ -89,7 +90,7 @@
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogError(ex, "SearchAddress returned an error!");
|
||||
Snackbar.Add($"Error searching address: {ex.Message}", Severity.Error);
|
||||
userMessage.ShowMessage($"Error searching address: {ex.Message}", MessageKind.Error);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
@page "/debug/empty"
|
||||
|
||||
@using Somnia.GuestLog.Services
|
||||
|
||||
|
||||
@inject ILogger<Empty> logger;
|
||||
@inject ISnackbar Snackbar
|
||||
@inject IUserMessageService userMessage
|
||||
@inject IDialogService DialogService
|
||||
|
||||
<PageTitle>DEBUG - Empty</PageTitle>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
@using Somnia.GuestLog.Services;
|
||||
@using Microsoft.AspNetCore.WebUtilities;
|
||||
|
||||
@inject ISnackbar Snackbar
|
||||
@inject IUserMessageService userMessage
|
||||
@inject IDialogService DialogService
|
||||
@inject NavigationManager Navigation
|
||||
@inject IGuestDocumentService guestDocService
|
||||
@@ -92,7 +92,7 @@
|
||||
{
|
||||
if (docId is null)
|
||||
{
|
||||
Snackbar.Add("No GuestDocument provided!!", Severity.Error);
|
||||
userMessage.ShowMessage("No GuestDocument provided!!", MessageKind.Error);
|
||||
Navigation.NotFound();
|
||||
return;
|
||||
}
|
||||
@@ -100,7 +100,7 @@
|
||||
GuestDocIdDTO? docIdModel = GuestDocIdDTO.DecodeFromString(docId);
|
||||
if (docIdModel is null)
|
||||
{
|
||||
Snackbar.Add($"Provided GuestDocId can't be decoded: '{docId}'", Severity.Error);
|
||||
userMessage.ShowMessage($"Provided GuestDocId can't be decoded: '{docId}'", MessageKind.Error);
|
||||
Navigation.NotFound();
|
||||
return;
|
||||
}
|
||||
@@ -109,7 +109,7 @@
|
||||
documentModel = await guestDocService.GetDtoByIdAsync(docIdModel.DocumentType, docIdModel.DocumentNum);
|
||||
if (documentModel is null)
|
||||
{
|
||||
Snackbar.Add($"GuestDocument not found with ID: '{docId}'", Severity.Error);
|
||||
userMessage.ShowMessage($"GuestDocument not found with ID: '{docId}'", MessageKind.Error);
|
||||
Navigation.NotFound();
|
||||
return;
|
||||
}
|
||||
@@ -138,7 +138,7 @@
|
||||
|
||||
private void BtnEdit()
|
||||
{
|
||||
Snackbar.Add("Not implemented yet!", Severity.Info);
|
||||
userMessage.ShowMessage("Not implemented yet!", MessageKind.Info);
|
||||
}
|
||||
|
||||
private void BtnReturn()
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
@inject IGuestDocumentService GuestDocService
|
||||
@inject NavigationManager Navigation
|
||||
@inject ISnackbar Snackbar
|
||||
@inject IUserMessageService userMessage
|
||||
@inject IDialogService DialogService
|
||||
@inject IDataListService dataListService;
|
||||
|
||||
@@ -101,7 +101,7 @@
|
||||
|
||||
if (showMsg)
|
||||
{
|
||||
Snackbar.Add("Data loaded from DB", Severity.Info, o => o.VisibleStateDuration = 1000);
|
||||
userMessage.ShowMessage("Data loaded from DB", MessageKind.Info);
|
||||
}
|
||||
_dataLoading = false;
|
||||
}
|
||||
@@ -142,14 +142,15 @@
|
||||
return;
|
||||
}
|
||||
|
||||
bool deleted = await GuestDocService.DeleteDocumentAsync(item);
|
||||
if (!deleted)
|
||||
Result deleteResult = await GuestDocService.DeleteDocumentAsync(item);
|
||||
if (!deleteResult.IsSuccess)
|
||||
{
|
||||
Snackbar.Add($"Error deleting document {item.DocumentType}-{item.DocumentNum}", Severity.Error);
|
||||
string errorMsg = $"Error deleting document {item.DocumentType}-{item.DocumentNum}";
|
||||
userMessage.ShowResultWithMessage(deleteResult, errorMsg);
|
||||
return;
|
||||
}
|
||||
|
||||
Snackbar.Add($"Document {item.DocumentType}-{item.DocumentNum} deleted!", Severity.Success);
|
||||
userMessage.ShowMessage($"Document {item.DocumentType}-{item.DocumentNum} deleted!", MessageKind.Success);
|
||||
await LoadDataAsync();
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
@using Somnia.GuestLog.Services;
|
||||
@using Somnia.GuestLog.Validators;
|
||||
|
||||
@inject ISnackbar Snackbar
|
||||
@inject IUserMessageService userMessage
|
||||
@inject IDialogService DialogService
|
||||
@inject NavigationManager Navigation
|
||||
@inject IGuestDocumentService guestDocService
|
||||
@@ -129,26 +129,25 @@
|
||||
bool isFormValid = await _form.ValidateForm();
|
||||
if (!isFormValid)
|
||||
{
|
||||
Snackbar.Add("Invalid Form!", Severity.Error);
|
||||
userMessage.ShowMessage("Invalid Form!", MessageKind.Warning);
|
||||
return;
|
||||
}
|
||||
|
||||
GuestDocumentDTO model = _form.Model;
|
||||
|
||||
Snackbar.Add($"Document '{model.DocumentNum}' creating...", Severity.Info);
|
||||
|
||||
//Show Loading dialog...
|
||||
var loadingDialog = await DialogService.ShowAsync<LoadingDialog>();
|
||||
|
||||
bool isCreated = await guestDocService.CreateDocumentAsync(model);
|
||||
if (!isCreated)
|
||||
Result createResult = await guestDocService.CreateDocumentAsync(model);
|
||||
if (!createResult.IsSuccess)
|
||||
{
|
||||
Snackbar.Add($"Error creating Document '{model.DocumentNum}'", Severity.Error);
|
||||
string errorMsg = $"Error creating Document '{model.DocumentNum}'";
|
||||
userMessage.ShowResultWithMessage(createResult, errorMsg);
|
||||
loadingDialog.Close();
|
||||
return;
|
||||
}
|
||||
|
||||
Snackbar.Add($"Document '{model.DocumentNum}' Created!", Severity.Success);
|
||||
userMessage.ShowMessage($"Document '{model.DocumentNum}' Created!", MessageKind.Success);
|
||||
Navigation.NavigateTo(GuestConsts.Page_GuestDocs_List);
|
||||
}
|
||||
|
||||
@@ -156,7 +155,7 @@
|
||||
{
|
||||
if (currentPageMode != ePageMode.alreadyExistDoc)
|
||||
{
|
||||
Snackbar.Add("Invalid operation!", Severity.Error);
|
||||
userMessage.ShowMessage("Invalid operation!", MessageKind.Error);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
@using Somnia.GuestLog.Models.DTOs;
|
||||
@using Somnia.GuestLog.Services;
|
||||
|
||||
@inject ISnackbar Snackbar
|
||||
@inject IUserMessageService userMessage
|
||||
@inject IDialogService DialogService
|
||||
@inject NavigationManager Navigation
|
||||
@inject IGuestDocumentService guestDocService
|
||||
@@ -27,7 +27,8 @@
|
||||
|
||||
@if (stayModel is not null)
|
||||
{
|
||||
<StayEntryForm Model="stayModel" ReadOnly="true" />
|
||||
<StayEntryForm Model="stayModel" FormMode="FormMode.ReadOnly" />
|
||||
<MudText Class="mt-4">@CreateTimeString</MudText>
|
||||
}
|
||||
|
||||
|
||||
@@ -41,6 +42,22 @@
|
||||
|
||||
StayEntryDTO? stayModel = null;
|
||||
|
||||
private string? CreateTimeString
|
||||
{
|
||||
get
|
||||
{
|
||||
if (stayModel is null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
List<string> textList = [];
|
||||
textList.Add($"Created at: {stayModel.CreateTime?.ToString() ?? "???"}");
|
||||
textList.Add($"Last Update Time: {stayModel.UpdateTime?.ToString() ?? "???"}");
|
||||
return string.Join("; ", textList);
|
||||
}
|
||||
}
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
@* if (StayId is default)
|
||||
@@ -54,7 +71,7 @@
|
||||
stayModel = await stayService.GetDtoByIdAsync(StayId, queryConfig: new(IncludeGuests: true));
|
||||
if (stayModel is null)
|
||||
{
|
||||
Snackbar.Add($"Stay not found with ID: '{StayId}'", Severity.Error);
|
||||
userMessage.ShowMessage($"Stay not found with ID: '{StayId}'", MessageKind.Error);
|
||||
Navigation.NotFound();
|
||||
return;
|
||||
}
|
||||
@@ -62,7 +79,7 @@
|
||||
|
||||
private void BtnEdit()
|
||||
{
|
||||
Snackbar.Add("Not implemented yet!", Severity.Info);
|
||||
userMessage.ShowMessage("Not implemented yet!", MessageKind.Info);
|
||||
}
|
||||
|
||||
private void BtnReturn()
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
@inject IStayEntryService StayEntryService
|
||||
@inject NavigationManager Navigation
|
||||
@inject ISnackbar Snackbar
|
||||
@inject IUserMessageService userMessage
|
||||
@inject IDialogService DialogService
|
||||
@inject IDataListService dataListService;
|
||||
|
||||
@@ -73,7 +73,7 @@
|
||||
private StayEntryFilterDTO stayFilter = new StayEntryFilterDTO()
|
||||
{
|
||||
DateInStart = DateTime.Today.AddDays(-14),
|
||||
DateInEnd = DateTime.Today,
|
||||
DateInEnd = DateTime.Today.AddDays(1),
|
||||
};
|
||||
|
||||
private IEnumerable<StayEntryDTO> stayEntryList = [];
|
||||
@@ -96,7 +96,7 @@
|
||||
|
||||
if (showMsg)
|
||||
{
|
||||
Snackbar.Add("Data loaded from DB", Severity.Info, o => o.VisibleStateDuration = 1000);
|
||||
userMessage.ShowMessage("Data loaded from DB", MessageKind.Info);
|
||||
}
|
||||
_dataLoading = false;
|
||||
}
|
||||
@@ -131,14 +131,15 @@
|
||||
return;
|
||||
}
|
||||
|
||||
bool deleted = await StayEntryService.DeleteEntryAsync(item);
|
||||
if (!deleted)
|
||||
Result deleteResult = await StayEntryService.DeleteEntryAsync(item);
|
||||
if (!deleteResult.IsSuccess)
|
||||
{
|
||||
Snackbar.Add($"Error deleting Stay {item.Id}", Severity.Error);
|
||||
string errorMsg = $"Error deleting Stay {item.Id}";
|
||||
userMessage.ShowResultWithMessage(deleteResult, errorMsg);
|
||||
return;
|
||||
}
|
||||
|
||||
Snackbar.Add($"Stay {item.Id} deleted!", Severity.Success);
|
||||
userMessage.ShowMessage($"Stay {item.Id} deleted!", MessageKind.Success);
|
||||
await LoadDataAsync();
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
@using Somnia.GuestLog.Services;
|
||||
|
||||
|
||||
@inject ISnackbar Snackbar
|
||||
@inject IUserMessageService userMessage
|
||||
@inject IDialogService DialogService
|
||||
@inject NavigationManager Navigation
|
||||
@inject IStayEntryService stayService
|
||||
@@ -27,7 +27,7 @@
|
||||
</MudButton>
|
||||
</MudStack>
|
||||
|
||||
<StayEntryForm @ref="_form" Model="@newStayModel" />
|
||||
<StayEntryForm @ref="_form" Model="@newStayModel" FormMode="FormMode.Create" />
|
||||
|
||||
@code {
|
||||
StayEntryForm _form = null!;
|
||||
@@ -45,22 +45,22 @@
|
||||
bool isFormValid = await _form.ValidateForm();
|
||||
if (!isFormValid)
|
||||
{
|
||||
Snackbar.Add("Invalid Form!", Severity.Warning);
|
||||
userMessage.ShowMessage("Invalid Form!", MessageKind.Warning);
|
||||
return;
|
||||
}
|
||||
|
||||
var loadingDialog = await DialogService.ShowAsync<LoadingDialog>();
|
||||
|
||||
StayEntryDTO model = _form.GetModel();
|
||||
bool isCreated = await stayService.CreateEntryAsync(model);
|
||||
if (!isCreated)
|
||||
Result createResult = await stayService.CreateEntryAsync(model);
|
||||
if (!createResult.IsSuccess)
|
||||
{
|
||||
Snackbar.Add($"Error creating StayEntry", Severity.Error);
|
||||
userMessage.ShowResultWithMessage(createResult, $"Error creating StayEntry");
|
||||
loadingDialog.Close();
|
||||
return;
|
||||
}
|
||||
|
||||
Snackbar.Add($"StayEntry Created!", Severity.Success);
|
||||
userMessage.ShowMessage($"StayEntry Created!", MessageKind.Success);
|
||||
Navigation.NavigateTo(GuestConsts.Page_StayEntry_List);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
@using System.Net.Http
|
||||
@using System.Net.Http.Json
|
||||
@using System.Linq;
|
||||
@using Microsoft.AspNetCore.Components.Forms
|
||||
@using Microsoft.AspNetCore.Components.Routing
|
||||
@using Microsoft.AspNetCore.Components.Web
|
||||
@@ -15,4 +16,4 @@
|
||||
@using Somnia.GuestLog.Components.Forms
|
||||
@using Somnia.GuestLog.Components.Controls
|
||||
@using Somnia.GuestLog.Resources
|
||||
@using System.Linq;
|
||||
@using MessageKind = Somnia.GuestLog.Services.IUserMessageService.MessageKind;
|
||||
@@ -0,0 +1,24 @@
|
||||
namespace Somnia.GuestLog.Models.DTOs;
|
||||
|
||||
public sealed record Result(bool IsSuccess, string ResultCode, params object[]? Context)
|
||||
{
|
||||
public static Result Ok() => new(IsSuccess: true, ResultCode: Models.ResultCode.Ok, Context: null);
|
||||
|
||||
public static Result Fail(string resultCode) => new(IsSuccess: false, resultCode, Context: null);
|
||||
public static Result FailWithContext(string resultCode, params object[] context)
|
||||
=> new(IsSuccess: false, resultCode, context);
|
||||
public static Result FailUnknownError()
|
||||
=> new(IsSuccess: false, ResultCode: Models.ResultCode.UnknownError, Context: null);
|
||||
|
||||
public bool IsUnknownError => !IsSuccess && ResultCode == Models.ResultCode.UnknownError;
|
||||
}
|
||||
|
||||
public sealed record Result<T>(bool IsSuccess, T? Value, string ResultCode, params object[]? Context)
|
||||
{
|
||||
public static Result<T> Ok(T value) => new(IsSuccess: true, value, ResultCode: Models.ResultCode.Ok, Context: null);
|
||||
public static Result<T> Fail(string resultCode) => new(IsSuccess: false, Value: default, resultCode, Context: null);
|
||||
public static Result<T> FailWithContext(string resultCode, params object[] context)
|
||||
=> new(IsSuccess: false, Value: default, resultCode, context);
|
||||
|
||||
public bool IsUnknownError => !IsSuccess && ResultCode == Models.ResultCode.UnknownError;
|
||||
}
|
||||
@@ -38,8 +38,8 @@ internal static class EntityMapping
|
||||
return new()
|
||||
{
|
||||
Id = entity.Id,
|
||||
DateIn = entity.DateIn,
|
||||
DateOut = entity.DateOut,
|
||||
DateIn = entity.DateIn.ToLocalTime(),
|
||||
DateOut = entity.DateOut.ToLocalTime(),
|
||||
RoomCount = entity.RoomCount,
|
||||
RoomNumber = entity.RoomNumber,
|
||||
PaymentMethod = entity.PaymentMethod,
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
namespace Somnia.GuestLog.Models;
|
||||
|
||||
public static class ResultCode
|
||||
{
|
||||
public const string Ok = "Ok";
|
||||
public const string UnknownError = "UnknownError";
|
||||
public const string FailedValidation = "FailedValidation";
|
||||
public const string NotFound = "NotFound";
|
||||
|
||||
public const string GuestCurrentlyInStay = "GuestCurrentlyInStay";
|
||||
}
|
||||
@@ -59,6 +59,8 @@ builder.Services.AddSingleton<IGuestDocumentService, GuestDocumentService>();
|
||||
builder.Services.AddSingleton<IStayEntryService, StayEntryService>();
|
||||
builder.Services.AddSingleton<IDataListService, StaticDataListService>();
|
||||
|
||||
builder.Services.AddScoped<IUserMessageService, UserMessageService>();
|
||||
|
||||
// Add Factories (and it's services)
|
||||
builder.Services.AddFactoryDI<IAddressQueryFactory, ConfigFileAddressQueryFactory>();
|
||||
|
||||
|
||||
@@ -176,6 +176,16 @@
|
||||
<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>
|
||||
|
||||
|
||||
<!-- Common codes -->
|
||||
<data name="resultCode.Ok" xml:space="preserve"><value>OK</value></data>
|
||||
<data name="resultCode.UnknownError" xml:space="preserve"><value>Unknown Error</value></data>
|
||||
<data name="resultCode.FailedValidation" xml:space="preserve"><value>Failed entity validation</value></data>
|
||||
<data name="resultCode.NotFound" xml:space="preserve"><value>Not found</value></data>
|
||||
<!-- Specific codes -->
|
||||
<data name="resultCode.GuestCurrentlyInStay" xml:space="preserve"><value>Guest ('{0}') is already in one stay during the period: {1}</value></data>
|
||||
|
||||
|
||||
<data name="navMenu.GuestDocumentList" xml:space="preserve"><value>Guests</value></data>
|
||||
<data name="navMenu.StayEntryList" xml:space="preserve"><value>Stays</value></data>
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ public class GuestDocumentService(
|
||||
IValidator<GuestDocumentDTO> dtoValidator
|
||||
) : IGuestDocumentService
|
||||
{
|
||||
public async Task<bool> CreateDocumentAsync(GuestDocumentDTO dto)
|
||||
public async Task<Result> CreateDocumentAsync(GuestDocumentDTO dto)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(dto);
|
||||
|
||||
@@ -22,7 +22,7 @@ public class GuestDocumentService(
|
||||
if (!valResult.IsValid)
|
||||
{
|
||||
logger.LogWarning("GuestDocumentService - CreateDocument: Dto validation failed. Fix the errors: {errorList}", valResult.Errors);
|
||||
return false;
|
||||
return Result.Fail(ResultCode.FailedValidation);
|
||||
}
|
||||
|
||||
//Dto must be valid, so null warings shouldn't matter.
|
||||
@@ -63,21 +63,21 @@ public class GuestDocumentService(
|
||||
await dbContext.SaveChangesAsync();
|
||||
|
||||
logger.LogInformation("GuestDocumentService - CreateDocument: GuestDocument Created: '{id}'", dbItem.GetFullKey());
|
||||
return true;
|
||||
return Result.Ok();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogError(ex, "GuestDocumentService - CreateDocument: Error creating GuestDocument: '{id}'", dbItem.GetFullKey());
|
||||
return false;
|
||||
return Result.FailUnknownError();
|
||||
}
|
||||
}
|
||||
|
||||
public Task<bool> UpdateDocumentAsync(GuestDocumentDTO dto)
|
||||
public Task<Result> UpdateDocumentAsync(GuestDocumentDTO dto)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<bool> DeleteDocumentAsync(GuestDocumentDTO dto)
|
||||
public Task<Result> DeleteDocumentAsync(GuestDocumentDTO dto)
|
||||
{
|
||||
if (dto.DocumentType is null || dto.DocumentNum is null)
|
||||
{
|
||||
@@ -87,14 +87,14 @@ public class GuestDocumentService(
|
||||
return DeleteDocumentAsync(dto.DocumentType, dto.DocumentNum);
|
||||
}
|
||||
|
||||
public async Task<bool> DeleteDocumentAsync(string docType, string docNum)
|
||||
public async Task<Result> DeleteDocumentAsync(string docType, string docNum)
|
||||
{
|
||||
using var dbContext = contextFactory.CreateDbContext();
|
||||
GuestDocument? dbItem = await dbContext.GuestDocuments.FindAsync(docType, docNum);
|
||||
if (dbItem is null)
|
||||
{
|
||||
logger.LogWarning("GuestDocumentService - DeleteDocument: Error deleting GuestDocument. Entity not found with key: '{key}-{key2}'", docType, docNum);
|
||||
return false;
|
||||
return Result.Fail(ResultCode.NotFound);
|
||||
}
|
||||
|
||||
try
|
||||
@@ -103,12 +103,12 @@ public class GuestDocumentService(
|
||||
await dbContext.SaveChangesAsync();
|
||||
|
||||
logger.LogInformation("GuestDocumentService - DeleteDocument: GuestDocument deleted: '{id}'", dbItem.GetFullKey());
|
||||
return true;
|
||||
return Result.Ok();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogError(ex, "GuestDocumentService - CreateDocument: Error deleting GuestDocument: '{id}'", dbItem.GetFullKey());
|
||||
return false;
|
||||
return Result.FailUnknownError();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,10 +4,10 @@ namespace Somnia.GuestLog.Services;
|
||||
|
||||
public interface IGuestDocumentService
|
||||
{
|
||||
public Task<bool> CreateDocumentAsync(GuestDocumentDTO dto);
|
||||
public Task<bool> UpdateDocumentAsync(GuestDocumentDTO dto);
|
||||
public Task<bool> DeleteDocumentAsync(GuestDocumentDTO dto);
|
||||
public Task<bool> DeleteDocumentAsync(string docType, string docNum);
|
||||
public Task<Result> CreateDocumentAsync(GuestDocumentDTO dto);
|
||||
public Task<Result> UpdateDocumentAsync(GuestDocumentDTO dto);
|
||||
public Task<Result> DeleteDocumentAsync(GuestDocumentDTO dto);
|
||||
public Task<Result> DeleteDocumentAsync(string docType, string docNum);
|
||||
|
||||
public Task<GuestDocumentDTO?> GetDtoByIdAsync(string docType, string docNum);
|
||||
public Task<IEnumerable<GuestDocumentDTO>> GetDtoListByFilterAsync(GuestDocFilterDTO filter, int limit = 0);
|
||||
|
||||
@@ -5,10 +5,10 @@ namespace Somnia.GuestLog.Services;
|
||||
|
||||
public interface IStayEntryService
|
||||
{
|
||||
public Task<bool> CreateEntryAsync(StayEntryDTO dto);
|
||||
public Task<bool> UpdateEntryAsync(StayEntryDTO updatedDto);
|
||||
public Task<bool> DeleteEntryAsync(StayEntryDTO dto);
|
||||
public Task<bool> DeleteEntryAsync(long id);
|
||||
public Task<Result> CreateEntryAsync(StayEntryDTO dto);
|
||||
public Task<Result> UpdateEntryAsync(StayEntryDTO updatedDto);
|
||||
public Task<Result> DeleteEntryAsync(StayEntryDTO dto);
|
||||
public Task<Result> DeleteEntryAsync(long id);
|
||||
|
||||
public Task<StayEntryDTO?> GetDtoByIdAsync(long id, StayEntryQueryConfig? queryConfig = null);
|
||||
public Task<IEnumerable<StayEntryDTO>> GetDtoListAsync(StayEntryQueryConfig? queryConfig = null);
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
using Somnia.GuestLog.Models.DTOs;
|
||||
|
||||
namespace Somnia.GuestLog.Services;
|
||||
|
||||
public interface IUserMessageService
|
||||
{
|
||||
public void ShowMessage(string text, MessageKind kind, params object[] parameters);
|
||||
|
||||
public void ShowResult(Result resultDto);
|
||||
public void ShowResultWithMessage(Result resultDto, string message);
|
||||
|
||||
|
||||
public enum MessageKind
|
||||
{
|
||||
Info, Warning, Error, Success, Normal
|
||||
}
|
||||
}
|
||||
@@ -15,7 +15,7 @@ public class StayEntryService(
|
||||
IValidator<StayEntryDTO> dtoValidator
|
||||
) : IStayEntryService
|
||||
{
|
||||
public async Task<bool> CreateEntryAsync(StayEntryDTO dto)
|
||||
public async Task<Result> CreateEntryAsync(StayEntryDTO dto)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(dto);
|
||||
|
||||
@@ -23,7 +23,7 @@ public class StayEntryService(
|
||||
if (!valResult.IsValid)
|
||||
{
|
||||
logger.LogWarning("StayEntryService - CreateEntryAsync: Dto validation failed. Fix the errors: {errorList}", valResult.Errors);
|
||||
return false;
|
||||
return Result.Fail(ResultCode.FailedValidation);
|
||||
}
|
||||
|
||||
DateTime createTime = DateTime.UtcNow;
|
||||
@@ -53,7 +53,8 @@ public class StayEntryService(
|
||||
bool isInOtherStay = await this.IsGuestInStayInPeriod(dbGuest.DocumentType, dbGuest.DocumentNum, dbStay.DateIn, dbStay.DateOut);
|
||||
if (isInOtherStay)
|
||||
{
|
||||
throw new InvalidOperationException($"Guest ('{dbGuest.GetFullKey()}') is already in a stay during the period: {dbStay.DateIn}-{dbStay.DateOut}");
|
||||
string period = $"{dbStay.DateIn}-{dbStay.DateOut}";
|
||||
return Result.FailWithContext(ResultCode.GuestCurrentlyInStay, dbGuest.GetFullKey(), period);
|
||||
}
|
||||
|
||||
//Add dbGuest to dbStay.
|
||||
@@ -64,38 +65,38 @@ public class StayEntryService(
|
||||
await dbContext.SaveChangesAsync();
|
||||
|
||||
logger.LogInformation("StayEntryService - CreateEntryAsync: StayEntry Created: '{id}'", dbStay.GetFullKey());
|
||||
return true;
|
||||
return Result.Ok();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogError(ex, "StayEntryService - CreateEntryAsync: Error creating StayEntry");
|
||||
return false;
|
||||
return Result.FailUnknownError();
|
||||
}
|
||||
}
|
||||
|
||||
public Task<bool> UpdateEntryAsync(StayEntryDTO updatedDto)
|
||||
public Task<Result> UpdateEntryAsync(StayEntryDTO updatedDto)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<bool> DeleteEntryAsync(StayEntryDTO dto)
|
||||
public async Task<Result> DeleteEntryAsync(StayEntryDTO dto)
|
||||
{
|
||||
if (dto.Id is null)
|
||||
{
|
||||
throw new InvalidOperationException("StayEntryService - DeleteEntry: A DTO without key can't be deleted!");
|
||||
}
|
||||
|
||||
return DeleteEntryAsync(dto.Id.Value);
|
||||
return await DeleteEntryAsync(dto.Id.Value);
|
||||
}
|
||||
|
||||
public async Task<bool> DeleteEntryAsync(long id)
|
||||
public async Task<Result> DeleteEntryAsync(long id)
|
||||
{
|
||||
using var dbContext = contextFactory.CreateDbContext();
|
||||
StayEntry? dbItem = await dbContext.StayEntries.FindAsync(id);
|
||||
if (dbItem is null)
|
||||
{
|
||||
logger.LogWarning("StayEntryService - DeleteEntry: Error deleting StayEntry. Entity not found with key: '{key}'", id);
|
||||
return false;
|
||||
return Result.Fail(ResultCode.NotFound);
|
||||
}
|
||||
|
||||
try
|
||||
@@ -104,12 +105,12 @@ public class StayEntryService(
|
||||
await dbContext.SaveChangesAsync();
|
||||
|
||||
logger.LogInformation("StayEntryService - DeleteEntry: StayEntry deleted: '{id}'", dbItem.GetFullKey());
|
||||
return true;
|
||||
return Result.Ok();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogError(ex, "StayEntryService - DeleteEntry: Error deleting StayEntry: '{id}'", dbItem.GetFullKey());
|
||||
return false;
|
||||
return Result.FailUnknownError();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -152,12 +153,15 @@ public class StayEntryService(
|
||||
query = query.WhereIf(!string.IsNullOrEmpty(filter.PaymentMethod),
|
||||
e => e.PaymentMethod == filter.PaymentMethod);
|
||||
|
||||
query = query.OrderByDescending(e => e.DateIn);
|
||||
|
||||
if (limit > 0)
|
||||
{
|
||||
query = query.Take(limit);
|
||||
}
|
||||
|
||||
var dbList = await query.ToListAsync();
|
||||
var dbList = await query
|
||||
.ToListAsync();
|
||||
|
||||
return dbList.Select(x => GetDtoFromDb(x, queryConfig));
|
||||
}
|
||||
@@ -182,6 +186,7 @@ public class StayEntryService(
|
||||
var rs = await dbContext.StayEntries
|
||||
.Where(s => s.GuestDocuments.Any(g => g.DocumentType == docType && g.DocumentNum == docNum))
|
||||
.AddQueryConfig(queryConfig)
|
||||
.OrderByDescending(e => e.DateIn)
|
||||
.ToListAsync();
|
||||
|
||||
return rs.Select(e => GetDtoFromDb(e, queryConfig));
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
using Microsoft.Extensions.Localization;
|
||||
using MudBlazor;
|
||||
using Somnia.GuestLog.Models;
|
||||
using Somnia.GuestLog.Models.DTOs;
|
||||
using Somnia.GuestLog.Resources;
|
||||
using MessageKind = Somnia.GuestLog.Services.IUserMessageService.MessageKind;
|
||||
|
||||
namespace Somnia.GuestLog.Services;
|
||||
|
||||
public class UserMessageService(
|
||||
IServiceProvider serviceProvider,
|
||||
ISnackbar snackbar
|
||||
) : IUserMessageService
|
||||
{
|
||||
private IStringLocalizer<LanguageLocale> _localizer
|
||||
{
|
||||
get
|
||||
{
|
||||
return serviceProvider.GetRequiredService<IStringLocalizer<LanguageLocale>>();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void ShowMessage(string text, MessageKind kind, params object[] parameters)
|
||||
{
|
||||
string formatedMsg = GetFormatedMessage(text, parameters);
|
||||
ShowSnackbar(formatedMsg, kind);
|
||||
}
|
||||
|
||||
|
||||
public void ShowResult(Result resultDto)
|
||||
{
|
||||
ShowResultWithMessage(resultDto, message: null);
|
||||
}
|
||||
|
||||
public void ShowResultWithMessage(Result resultDto, string? message)
|
||||
{
|
||||
string resultMsg = GetMsgForResultCode(resultDto.ResultCode);
|
||||
resultMsg = GetFormatedMessage(resultMsg, resultDto.Context);
|
||||
|
||||
string finalMsg = message is not null ? $"{message.Trim().TrimEnd(':')}: {resultMsg}" : resultMsg;
|
||||
|
||||
//Show success when OK, error for UnknownErrors and warning otherwise.
|
||||
MessageKind kind = resultDto switch
|
||||
{
|
||||
{ IsSuccess: true } => MessageKind.Success,
|
||||
{ ResultCode: ResultCode.UnknownError } => MessageKind.Error,
|
||||
_ => MessageKind.Warning
|
||||
};
|
||||
|
||||
ShowSnackbar(finalMsg, kind);
|
||||
}
|
||||
|
||||
|
||||
#region Internal Methods
|
||||
|
||||
private void ShowSnackbar(string msg, MessageKind kind)
|
||||
{
|
||||
snackbar.Add(message: msg, severity: GetSnackbarSeveryForMessageKind(kind));
|
||||
}
|
||||
|
||||
private string GetMsgForResultCode(string resultCode)
|
||||
{
|
||||
return _localizer[$"resultCode.{resultCode}"];
|
||||
}
|
||||
|
||||
private static string GetFormatedMessage(string template, params object[]? parameters)
|
||||
{
|
||||
if (parameters is null || parameters.Length == 0)
|
||||
{
|
||||
return template;
|
||||
}
|
||||
|
||||
return string.Format(template, parameters);
|
||||
}
|
||||
|
||||
private static MudBlazor.Severity GetSnackbarSeveryForMessageKind(MessageKind kind) => kind switch
|
||||
{
|
||||
MessageKind.Info => MudBlazor.Severity.Info,
|
||||
MessageKind.Warning => MudBlazor.Severity.Warning,
|
||||
MessageKind.Error => MudBlazor.Severity.Error,
|
||||
MessageKind.Success => MudBlazor.Severity.Success,
|
||||
MessageKind.Normal => MudBlazor.Severity.Normal,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(kind), $"Not expected MessageKind value: {kind}")
|
||||
};
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -14,7 +14,7 @@ public class StayEntryDTOValidator : ValueValidator<StayEntryDTO>
|
||||
|
||||
RuleFor(e => e.DateOut)
|
||||
.NotEmpty()
|
||||
.GreaterThan(DateTime.Today);
|
||||
.GreaterThan(e => e.DateIn);
|
||||
|
||||
RuleFor(e => e.RoomCount)
|
||||
.NotEmpty()
|
||||
|
||||
Reference in New Issue
Block a user