SHA256
GuestLog - User message improvements
- Added UserMessageService to have common methods for showing messages and errors to the user. - Added Result record so services can return status on operation error (so it can be shown in the UI messages). - Updated services to use the new Result record. - Updated pages to use the new IUserMessageService.
This commit is contained in:
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
Reference in New Issue
Block a user