From 1755bd0ba8eecc75098da4db6ed21020c3f2d3ba Mon Sep 17 00:00:00 2001 From: samgibsonmoj Date: Mon, 2 Sep 2024 14:00:24 +0100 Subject: [PATCH 1/6] Rename card header on dashboard --- src/Server.UI/Pages/Dashboard/Dashboard.razor | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Server.UI/Pages/Dashboard/Dashboard.razor b/src/Server.UI/Pages/Dashboard/Dashboard.razor index 6c799e12..92249043 100644 --- a/src/Server.UI/Pages/Dashboard/Dashboard.razor +++ b/src/Server.UI/Pages/Dashboard/Dashboard.razor @@ -35,7 +35,7 @@ - Pending Cases + Confirmed Cases From 43af1cf03744df9a181d47a0508659eda64d6927 Mon Sep 17 00:00:00 2001 From: Sam Gibson <140488216+samgibsonmoj@users.noreply.github.com> Date: Mon, 2 Sep 2024 15:01:19 +0100 Subject: [PATCH 2/6] Update src/Server.UI/Pages/Dashboard/Dashboard.razor Co-authored-by: Carl Sixsmith --- src/Server.UI/Pages/Dashboard/Dashboard.razor | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Server.UI/Pages/Dashboard/Dashboard.razor b/src/Server.UI/Pages/Dashboard/Dashboard.razor index 92249043..a10a1fe3 100644 --- a/src/Server.UI/Pages/Dashboard/Dashboard.razor +++ b/src/Server.UI/Pages/Dashboard/Dashboard.razor @@ -35,7 +35,7 @@ - Confirmed Cases + Enrolling Cases From 24a47c3a8c74ccc1d6b08802d3feb3e16a4c2e06 Mon Sep 17 00:00:00 2001 From: samgibsonmoj Date: Mon, 2 Sep 2024 13:45:01 +0100 Subject: [PATCH 3/6] Remove using statement from ui --- src/Server.UI/Pages/Identity/Authentication/ResetPassword.razor | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Server.UI/Pages/Identity/Authentication/ResetPassword.razor b/src/Server.UI/Pages/Identity/Authentication/ResetPassword.razor index 8a7cb4ad..a5d4db05 100644 --- a/src/Server.UI/Pages/Identity/Authentication/ResetPassword.razor +++ b/src/Server.UI/Pages/Identity/Authentication/ResetPassword.razor @@ -143,4 +143,3 @@ public string Token { get; set; } = ""; } } - using Cfo.Cats.Application.Features.Identity.Notifications.IdentityEvents; From d45099bfc07b7ea0cd9f1998abf1944b4a315743 Mon Sep 17 00:00:00 2001 From: VS Date: Tue, 3 Sep 2024 10:52:43 +0100 Subject: [PATCH 4/6] Added Documents tab on participant dashboard, it lists all the documents assciated with the case. From the list, user can open and view each documents --- .../Features/Documents/DTOs/DocumentDto.cs | 4 +- .../Documents/Queries/GetByParticipantId.cs | 47 ++++++++ .../Components/CaseDocuments.razor | 102 ++++++++++++++++++ .../Components/ViewDocumentDialog.razor | 86 +++++++++++++++ .../Pages/Participants/Participant.razor | 3 + 5 files changed, 241 insertions(+), 1 deletion(-) create mode 100644 src/Application/Features/Documents/Queries/GetByParticipantId.cs create mode 100644 src/Server.UI/Pages/Participants/Components/CaseDocuments.razor create mode 100644 src/Server.UI/Pages/Participants/Components/ViewDocumentDialog.razor diff --git a/src/Application/Features/Documents/DTOs/DocumentDto.cs b/src/Application/Features/Documents/DTOs/DocumentDto.cs index e824b918..cade49c5 100644 --- a/src/Application/Features/Documents/DTOs/DocumentDto.cs +++ b/src/Application/Features/Documents/DTOs/DocumentDto.cs @@ -6,7 +6,7 @@ namespace Cfo.Cats.Application.Features.Documents.DTOs; [Description("Documents")] public class DocumentDto { - [Description("Id")] public int Id { get; set; } + [Description("Id")] public Guid? Id { get; set; } [Description("Title")] public string? Title { get; set; } @@ -23,6 +23,8 @@ public class DocumentDto [Description("Tenant Name")] public string? TenantName { get; set; } [Description("Content")] public string? Content { get; set; } + [Description("Created By")] public string CreatedBy { get; set; } = string.Empty; + [Description("Created Date")] public DateTime Created { get; set; } [Description("Owner")] public ApplicationUserDto? Owner { get; set; } diff --git a/src/Application/Features/Documents/Queries/GetByParticipantId.cs b/src/Application/Features/Documents/Queries/GetByParticipantId.cs new file mode 100644 index 00000000..cf2b1005 --- /dev/null +++ b/src/Application/Features/Documents/Queries/GetByParticipantId.cs @@ -0,0 +1,47 @@ +using Cfo.Cats.Application.Common.Security; +using Cfo.Cats.Application.Common.Validators; +using Cfo.Cats.Application.Features.Documents.DTOs; +using Cfo.Cats.Application.Features.Participants.DTOs; +using Cfo.Cats.Application.SecurityConstants; +using DocumentFormat.OpenXml.InkML; +using System.Threading.Tasks; + +namespace Cfo.Cats.Application.Features.Documents.Queries; +public static class GetByParticipantId +{ + [RequestAuthorize(Policy = SecurityPolicies.AuthorizedUser)] + + public class Query : IRequest> + { + public required string ParticipantId { get; set; } + } + + public class Handler(IUnitOfWork unitOfWork, IMapper mapper) : IRequestHandler> + { + public async Task> Handle(Query request, CancellationToken cancellationToken) + { + string likeCriteria = string.Format(@"Files/{0}%", request.ParticipantId); + var query = unitOfWork.DbContext.Documents + .Where(d => EF.Functions.Like(d.URL, likeCriteria)); + + var documents = await query.ProjectTo(mapper.ConfigurationProvider) + .ToArrayAsync(cancellationToken) ?? []; + + return Result.Success(documents); + } + } + public class Validator : AbstractValidator + { + public Validator() + { + RuleFor(x => x.ParticipantId.ToString()) + .NotEmpty() + .MinimumLength(9) + .MaximumLength(9) + .Matches(ValidationConstants.AlphaNumeric) + .WithMessage(string.Format(ValidationConstants.AlphaNumericMessage, "Participant Id")); + + } + } +} + diff --git a/src/Server.UI/Pages/Participants/Components/CaseDocuments.razor b/src/Server.UI/Pages/Participants/Components/CaseDocuments.razor new file mode 100644 index 00000000..2686e150 --- /dev/null +++ b/src/Server.UI/Pages/Participants/Components/CaseDocuments.razor @@ -0,0 +1,102 @@ +@using Cfo.Cats.Application.Common.Interfaces.Identity +@using Cfo.Cats.Server.UI.Pages.Participants.Components +@using Cfo.Cats.Application.Features.Participants.DTOs +@using Cfo.Cats.Application.Features.Documents.DTOs +@using Cfo.Cats.Application.Features.Participants.Queries +@using Cfo.Cats.Application.Features.Documents.Queries +@using Cfo.Cats.Application.SecurityConstants +@using System.Net.Http.Json + +@inherits CatsComponentBase + +@inject IUserService UserService +@inject IStringLocalizer L + + +@attribute [Authorize(Policy = SecurityPolicies.AuthorizedUser)] + + + +@if (_notFound) +{ + + No documents yet. + +} +else +{ + + + + + + + + + + Open + + + + +} + +@code { + bool _loading = true; + bool _notFound = false; + private DocumentDto[] _documents = []; + private DocumentDto _currentDto = new() { Id = Guid.Empty }; + + [Parameter] + [EditorRequired] + public string ParticipantId { get; set; } = default!; + + [CascadingParameter] + public UserProfile? UserProfile { get; set; } = null!; + + protected Guid SelectedDocument { get; set; } = Guid.Empty; + + + protected override async Task OnInitializedAsync() + { + try + { + if (String.IsNullOrWhiteSpace(ParticipantId) == false) + { + _documents = await GetNewMediator().Send(new GetByParticipantId.Query() + { + ParticipantId = ParticipantId + }); + _notFound = _documents.Count() == 0; + } + }finally{ + _loading = false; + } + } + + public async Task OpenDocumentDialog(DocumentDto item) + { + await DialogService.ShowAsync( + "View Document Dialog", + new DialogParameters() + { + { x => x.Model, item } + }, + new DialogOptions + { + MaxWidth = MaxWidth.ExtraExtraLarge, + Position=DialogPosition.Center, + FullWidth = true, + CloseButton = true + }); + } +} \ No newline at end of file diff --git a/src/Server.UI/Pages/Participants/Components/ViewDocumentDialog.razor b/src/Server.UI/Pages/Participants/Components/ViewDocumentDialog.razor new file mode 100644 index 00000000..8462547c --- /dev/null +++ b/src/Server.UI/Pages/Participants/Components/ViewDocumentDialog.razor @@ -0,0 +1,86 @@ +@using Cfo.Cats.Application.Common.Interfaces.Identity +@using Cfo.Cats.Server.UI.Pages.Participants.Components +@using Cfo.Cats.Application.Features.Participants.DTOs +@using Cfo.Cats.Application.Features.Documents.DTOs +@using Cfo.Cats.Application.Features.Participants.Queries +@using Cfo.Cats.Application.Features.Documents.Queries +@using Cfo.Cats.Application.SecurityConstants +@inherits CatsComponentBase + +@inject IValidationService Validator + + + + + + @if (Model is not null) + { + @if (fileBase64 != null && extension!.Equals("pdf", StringComparison.CurrentCultureIgnoreCase)) + { + +

PDF cannot be displayed.

+
+ } + else if (IsFileRejected) + { + + File cannot be displayed. Please contact support. + + } + else + { + + } + } +
+ + @ConstantString.Close + +
+ +@code { + [CascadingParameter] private MudDialogInstance MudDialog { get; set; } = default!; + + [Parameter, EditorRequired] + public required DocumentDto Model { get; set; } + private bool IsFileRejected { get; set; } + private string? fileBase64; + private string? extension; + private void Cancel() + { + MudDialog.Cancel(); + } + protected override async Task OnInitializedAsync() + { + Guid documentId = Model.Id!.Value; + if (documentId != Guid.Empty) + { + var query = new GetDocumentById.Query() + { + Id = documentId + }; + + var result = await GetNewMediator().Send(query); + if (result.Succeeded) + { + IsFileRejected = false; + using (var memoryStream = new MemoryStream()) + { + await result.Data!.FileStream.CopyToAsync(memoryStream); + var bytes = memoryStream.ToArray(); + fileBase64 = Convert.ToBase64String(bytes); + } + extension = result.Data!.FileExtension; + } + else + { + IsFileRejected = true; + } + } + } +} diff --git a/src/Server.UI/Pages/Participants/Participant.razor b/src/Server.UI/Pages/Participants/Participant.razor index de16f593..963b1084 100644 --- a/src/Server.UI/Pages/Participants/Participant.razor +++ b/src/Server.UI/Pages/Participants/Participant.razor @@ -107,6 +107,9 @@ + + + From feca2506c3d1884d83a8862b40dc18f21f21f5ff Mon Sep 17 00:00:00 2001 From: Carl Sixsmith Date: Tue, 3 Sep 2024 11:44:21 +0100 Subject: [PATCH 5/6] Adjustments during peer review --- .../Features/Documents/DTOs/DocumentDto.cs | 6 ++- .../Components/CaseDocuments.razor | 54 ++++++++++++------- .../Components/ViewDocumentDialog.razor | 32 ++++++----- 3 files changed, 58 insertions(+), 34 deletions(-) diff --git a/src/Application/Features/Documents/DTOs/DocumentDto.cs b/src/Application/Features/Documents/DTOs/DocumentDto.cs index cade49c5..d9ee6fb3 100644 --- a/src/Application/Features/Documents/DTOs/DocumentDto.cs +++ b/src/Application/Features/Documents/DTOs/DocumentDto.cs @@ -8,7 +8,7 @@ public class DocumentDto { [Description("Id")] public Guid? Id { get; set; } - [Description("Title")] public string? Title { get; set; } + [Description("File Name")] public string? Title { get; set; } [Description("Description")] public string? Description { get; set; } @@ -24,6 +24,7 @@ public class DocumentDto [Description("Content")] public string? Content { get; set; } [Description("Created By")] public string CreatedBy { get; set; } = string.Empty; + [Description("Created By Name")] public string CreatedByName { get; set; } = string.Empty; [Description("Created Date")] public DateTime Created { get; set; } [Description("Owner")] public ApplicationUserDto? Owner { get; set; } @@ -33,7 +34,8 @@ private class Mapping : Profile public Mapping() { CreateMap(MemberList.None) - .ForMember(x => x.TenantName, s => s.MapFrom(y => y.Tenant!.Name)); + .ForMember(x => x.TenantName, s => s.MapFrom(y => y.Tenant!.Name)) + .ForMember(x => x.CreatedByName, s => s.MapFrom(y => y.Owner!.DisplayName)); CreateMap(MemberList.None) .ForMember(x => x.Tenant, s => s.Ignore()) .ForMember(x => x.Owner, s => s.Ignore()); diff --git a/src/Server.UI/Pages/Participants/Components/CaseDocuments.razor b/src/Server.UI/Pages/Participants/Components/CaseDocuments.razor index 2686e150..453a2454 100644 --- a/src/Server.UI/Pages/Participants/Components/CaseDocuments.razor +++ b/src/Server.UI/Pages/Participants/Components/CaseDocuments.razor @@ -6,6 +6,7 @@ @using Cfo.Cats.Application.Features.Documents.Queries @using Cfo.Cats.Application.SecurityConstants @using System.Net.Http.Json +@using Humanizer @inherits CatsComponentBase @@ -20,16 +21,7 @@ height: 120px !important; } - -@if (_notFound) -{ - - No documents yet. - -} -else -{ - + + + + @ConstantString.View + + + - - - + - Open +
+ @context.Item.CreatedByName + @context.Item.Created.Humanize() +
-
+
+ + +
+ @context.Item.TenantName + @context.Item.TenantId +
+
+
+ + @ConstantString.NoRecords + + + @ConstantString.Loading +
-} + @code { bool _loading = true; - bool _notFound = false; private DocumentDto[] _documents = []; private DocumentDto _currentDto = new() { Id = Guid.Empty }; @@ -76,7 +90,6 @@ else { ParticipantId = ParticipantId }); - _notFound = _documents.Count() == 0; } }finally{ _loading = false; @@ -86,7 +99,7 @@ else public async Task OpenDocumentDialog(DocumentDto item) { await DialogService.ShowAsync( - "View Document Dialog", + "Document", new DialogParameters() { { x => x.Model, item } @@ -96,7 +109,8 @@ else MaxWidth = MaxWidth.ExtraExtraLarge, Position=DialogPosition.Center, FullWidth = true, - CloseButton = true + CloseButton = true, + CloseOnEscapeKey = true, }); } } \ No newline at end of file diff --git a/src/Server.UI/Pages/Participants/Components/ViewDocumentDialog.razor b/src/Server.UI/Pages/Participants/Components/ViewDocumentDialog.razor index 8462547c..c25a29a4 100644 --- a/src/Server.UI/Pages/Participants/Components/ViewDocumentDialog.razor +++ b/src/Server.UI/Pages/Participants/Components/ViewDocumentDialog.razor @@ -16,12 +16,18 @@ } - - - @if (Model is not null) - { - @if (fileBase64 != null && extension!.Equals("pdf", StringComparison.CurrentCultureIgnoreCase)) - { +@if (Model is not null) +{ + + + + + @Model.Title + + + + @if (fileBase64 != null && extension!.Equals("pdf", StringComparison.CurrentCultureIgnoreCase)) + {

PDF cannot be displayed.

@@ -36,12 +42,14 @@ { } - } -
- - @ConstantString.Close - -
+
+ + @ConstantString.Close + +
+} + + @code { [CascadingParameter] private MudDialogInstance MudDialog { get; set; } = default!; From 6913abe90fe840a8090bc028da2540aa1d52a074 Mon Sep 17 00:00:00 2001 From: samgibsonmoj Date: Tue, 3 Sep 2024 17:34:17 +0100 Subject: [PATCH 6/6] Fix for PQA tenant restriction --- .../Features/QualityAssurance/Queries/GetPqaEntryById.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Application/Features/QualityAssurance/Queries/GetPqaEntryById.cs b/src/Application/Features/QualityAssurance/Queries/GetPqaEntryById.cs index 5c031ecd..c8d299fa 100644 --- a/src/Application/Features/QualityAssurance/Queries/GetPqaEntryById.cs +++ b/src/Application/Features/QualityAssurance/Queries/GetPqaEntryById.cs @@ -20,7 +20,7 @@ public class Handler(IUnitOfWork unitOfWork, IMapper mapper) : IRequestHandler> Handle(Query request, CancellationToken cancellationToken) { var entry = await unitOfWork.DbContext.EnrolmentPqaQueue - .Where(a => a.Id == request.Id && request.CurrentUser!.TenantId!.StartsWith(a.TenantId)) + .Where(a => a.Id == request.Id && a.TenantId.StartsWith(request.CurrentUser!.TenantId!)) .ProjectTo(mapper.ConfigurationProvider) .FirstOrDefaultAsync(cancellationToken);