Skip to content

Commit 3491f3a

Browse files
Simplifying + fixing issues with activity feedbacks (#1019)
* Simplifying + fixing issues with activity feedbacks * Use pie chart for individual feedback
1 parent f1abc23 commit 3491f3a

10 files changed

Lines changed: 110 additions & 228 deletions

File tree

src/Application/Features/Activities/Commands/SubmitActivityEscalationResponse.cs

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -83,33 +83,32 @@ public async Task<Result> Handle(Command request, CancellationToken cancellation
8383
{
8484
EscalationResponse.Accept => FeedbackOutcome.Approved,
8585
EscalationResponse.Return => FeedbackOutcome.Returned,
86-
EscalationResponse.Comment => FeedbackOutcome.EscalatedComment,
87-
_ => throw new ArgumentOutOfRangeException()
86+
_ => throw new ArgumentOutOfRangeException($"Cannot generate feedback for {response}")
8887
};
8988

90-
var previous = await (
91-
from q in unitOfWork.DbContext.ActivityQa2Queue
92-
where q.ActivityId == entry.ActivityId
93-
&& q.IsCompleted
94-
orderby q.LastModified descending
95-
select new
96-
{
97-
Qa1User = q.CreatedBy,
98-
q.Created
99-
}
100-
)
101-
.FirstAsync(cancellationToken);
89+
// get most recent QA1 for this activity
90+
var qa1 = await unitOfWork.DbContext
91+
.ActivityQa1Queue
92+
.Where(x => x.ActivityId == entry.ActivityId)
93+
.Where(x => x.IsCompleted)
94+
.OrderByDescending(x => x.LastModified)
95+
.Select(x =>
96+
new {
97+
Qa1User = x.LastModifiedBy,
98+
Qa1Submitted = x.LastModified,
99+
x.IsAccepted
100+
})
101+
.FirstAsync(cancellationToken);
102102

103103
var activityFeedback = ActivityFeedback.Create(
104104
entry.ActivityId,
105105
entry.ParticipantId!,
106-
previous.Qa1User!,
106+
qa1.Qa1User!,
107107
request.MessageToQa1,
108+
qa1.IsAccepted ? FeedbackOutcome.Approved : FeedbackOutcome.Returned,
108109
outcome,
109110
FeedbackStage.Escalation,
110-
previous.Created!.Value,
111-
request.CurrentUser!.UserId,
112-
entry.TenantId,
111+
qa1.Qa1Submitted!.Value,
113112
entry.Activity!.Category.Name,
114113
entry.Activity.Type.Name,
115114
request.ActivityFeedbackReason

src/Application/Features/Activities/Commands/SubmitActivityQa2Response.cs

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -85,20 +85,32 @@ public async Task<Result> Handle(Command request, CancellationToken cancellation
8585
{
8686
Qa2Response.Accept => FeedbackOutcome.Approved,
8787
Qa2Response.Return => FeedbackOutcome.Returned,
88-
Qa2Response.Escalate => FeedbackOutcome.Escalated,
89-
_ => throw new ArgumentOutOfRangeException()
88+
_ => throw new ArgumentOutOfRangeException($"Cannot generate feedback for {response}")
9089
};
90+
91+
// get most recent QA1 for this activity
92+
var qa1 = await unitOfWork.DbContext
93+
.ActivityQa1Queue
94+
.Where(x => x.ActivityId == entry.ActivityId)
95+
.Where(x => x.IsCompleted)
96+
.OrderByDescending(x => x.LastModified)
97+
.Select(x =>
98+
new {
99+
Qa1User = x.LastModifiedBy,
100+
Qa1Submitted = x.LastModified,
101+
x.IsAccepted
102+
})
103+
.FirstAsync(cancellationToken);
91104

92105
var activityFeedback = ActivityFeedback.Create(
93106
entry.ActivityId,
94107
entry.ParticipantId!,
95-
entry.CreatedBy!,
108+
qa1.Qa1User!,
96109
request.MessageToQa1,
110+
qa1.IsAccepted ? FeedbackOutcome.Approved : FeedbackOutcome.Returned,
97111
outcome,
98112
FeedbackStage.Qa2,
99-
entry.Created!.Value,
100-
request.CurrentUser!.UserId,
101-
entry.TenantId,
113+
qa1.Qa1Submitted!.Value,
102114
entry.Activity!.Category.Name,
103115
entry.Activity.Type.Name,
104116
request.ActivityFeedbackReason!

src/Application/Features/Dashboard/Queries/GetActivitiesFeedback.cs

Lines changed: 10 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -25,31 +25,24 @@ public async Task<Result<ActivitiesFeedbackDto>> Handle(
2525
{
2626
var context = unitOfWork.DbContext;
2727

28-
var query =
28+
var query =
2929
from afb in context.ActivityFeedbacks.AsNoTracking()
3030

3131
join p in context.Participants on afb.ParticipantId equals p.Id
32-
join ru in context.Users on afb.RecipientUserId equals ru.Id into ruJoin
32+
join ru in context.Users on afb.OwnerId equals ru.Id into ruJoin
3333
from ru in ruJoin.DefaultIfEmpty()
3434

3535
join cu in context.Users on afb.CreatedBy equals cu.Id into cuJoin
3636
from cu in cuJoin.DefaultIfEmpty()
3737

38-
where afb.ActivityProcessedDate >= request.StartDate.Date
39-
&& afb.ActivityProcessedDate < request.EndDate.AddDays(1).Date
40-
&& afb.TenantId.StartsWith(request.CurrentUser.TenantId!)
41-
&& (request.UserId == null || afb.RecipientUserId == request.UserId)
38+
where afb.Created >= request.StartDate.Date
39+
&& afb.Created < request.EndDate.AddDays(1).Date
40+
&& (request.UserId == null || afb.OwnerId == request.UserId)
4241

4342
select new { afb, p, ru, cu };
4443

45-
if (!string.IsNullOrWhiteSpace(request.TenantId))
46-
{
47-
query = query.Where(x =>
48-
x.afb.TenantId.StartsWith(request.TenantId));
49-
}
50-
5144
var tabularData = await query
52-
.OrderBy(x => x.afb.ActivityProcessedDate)
45+
.OrderBy(x => x.afb.Qa1Date)
5346
.Select(x => new ActivitiesFeedbackTabularData
5447
{
5548
Id = x.afb.Id,
@@ -63,7 +56,7 @@ from cu in cuJoin.DefaultIfEmpty()
6356
ActivityFeedbackReason = x.afb.ActivityFeedbackReason,
6457

6558
Queue = x.afb.Stage.Name ?? "Unknown",
66-
59+
Qa1Outcome = x.afb.Qa1Outcome.Name,
6760
Outcome = x.afb.Outcome.Name,
6861

6962
QaUser = x.cu != null
@@ -72,11 +65,8 @@ from cu in cuJoin.DefaultIfEmpty()
7265

7366
Created = x.afb.Created,
7467

75-
ActivityProcessedDate = x.afb.ActivityProcessedDate,
76-
77-
//LastModified = x.afb.LastModified ?? x.afb.Created,
78-
IsAccepted = x.afb.Outcome == FeedbackOutcome.Approved ? "Yes" : "No",
79-
68+
ActivityProcessedDate = x.afb.Qa1Date,
69+
8070
IsRead = x.afb.IsRead,
8171
Message = x.afb.Message
8272
})
@@ -126,14 +116,14 @@ public record ActivitiesFeedbackTabularData
126116

127117
public required string Queue { get; init; }
128118

119+
public required string Qa1Outcome { get; init; }
129120
public required string Outcome { get; init; }
130121
public required string QaUser { get; init; }
131122

132123
// public required DateTime? LastModified { get; set; }
133124
public DateTime? Created { get; init; }
134125
public DateTime ActivityProcessedDate { get; init; }
135126

136-
public required string IsAccepted { get; init; }
137127
public required string Message { get; init; }
138128
public required bool IsRead { get; set; }
139129
}

src/Database/CatsDb/Activities/Tables/ActivityFeedback.sql renamed to src/Database/CatsDb/Mi/Tables/ActivityFeedback.sql

Lines changed: 17 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,14 @@
1-
CREATE TABLE [Activities].[ActivityFeedback] (
1+
CREATE TABLE [Mi].[ActivityFeedback] (
22
[Id] UNIQUEIDENTIFIER NOT NULL,
33
[ActivityId] UNIQUEIDENTIFIER NOT NULL,
44
[ParticipantId] NVARCHAR (9) NOT NULL,
5-
[RecipientUserId] NVARCHAR (36) NOT NULL,
65
[Message] NVARCHAR (1000) NOT NULL,
6+
[Qa1Outcome] INT NOT NULL,
77
[Outcome] INT NOT NULL,
88
[Stage] INT NOT NULL,
9-
[ActivityProcessedDate] DATETIME2 NOT NULL,
9+
[Qa1Date] DATETIME2 NOT NULL,
1010
[IsRead] BIT NOT NULL,
1111
[ReadAt] DATETIME2 NULL,
12-
[TenantId] NVARCHAR (50) NOT NULL,
1312
[Created] DATETIME2 NOT NULL,
1413
[CreatedBy] NVARCHAR (36) NOT NULL,
1514
[LastModified] DATETIME2 NULL,
@@ -23,80 +22,66 @@ CREATE TABLE [Activities].[ActivityFeedback] (
2322

2423
GO
2524

26-
ALTER TABLE [Activities].[ActivityFeedback]
25+
ALTER TABLE [Mi].[ActivityFeedback]
2726
ADD CONSTRAINT [FK_ActivityFeedback_Activity_ActivityId] FOREIGN KEY ( [ActivityId] ) REFERENCES [Activities].[Activity] ( [Id] );
2827

2928
GO
3029

31-
ALTER TABLE [Activities].[ActivityFeedback]
30+
ALTER TABLE [Mi].[ActivityFeedback]
3231
ADD CONSTRAINT [FK_ActivityFeedback_Participant_ParticipantId] FOREIGN KEY ( [ParticipantId] ) REFERENCES [Participant].[Participant] ( [Id] );
3332

3433
GO
3534

36-
ALTER TABLE [Activities].[ActivityFeedback]
37-
ADD CONSTRAINT [FK_ActivityFeedback_Tenant_TenantId] FOREIGN KEY ( [TenantId] ) REFERENCES [Configuration].[Tenant] ( [Id] );
38-
39-
GO
40-
41-
ALTER TABLE [Activities].[ActivityFeedback]
35+
ALTER TABLE [Mi].[ActivityFeedback]
4236
ADD CONSTRAINT [FK_ActivityFeedback_User_CreatedBy] FOREIGN KEY ( [CreatedBy] ) REFERENCES [Identity].[User] ( [Id] );
4337

4438
GO
4539

46-
ALTER TABLE [Activities].[ActivityFeedback]
40+
ALTER TABLE [Mi].[ActivityFeedback]
4741
ADD CONSTRAINT [FK_ActivityFeedback_User_EditorId] FOREIGN KEY ( [EditorId] ) REFERENCES [Identity].[User] ( [Id] );
4842

4943
GO
5044

51-
ALTER TABLE [Activities].[ActivityFeedback]
45+
ALTER TABLE [Mi].[ActivityFeedback]
5246
ADD CONSTRAINT [FK_ActivityFeedback_User_OwnerId] FOREIGN KEY ( [OwnerId] ) REFERENCES [Identity].[User] ( [Id] );
5347

5448
GO
5549

56-
ALTER TABLE [Activities].[ActivityFeedback]
57-
ADD CONSTRAINT [FK_ActivityFeedback_User_RecipientUserId] FOREIGN KEY ( [RecipientUserId] ) REFERENCES [Identity].[User] ( [Id] );
58-
59-
GO
60-
6150
CREATE NONCLUSTERED INDEX [IX_ActivityFeedback_ActivityId]
62-
ON [Activities].[ActivityFeedback] ([ActivityId] ASC);
51+
ON [Mi].[ActivityFeedback] ([ActivityId] ASC);
6352

6453
GO
6554

6655
CREATE NONCLUSTERED INDEX [IX_ActivityFeedback_ActivityId_Created]
67-
ON [Activities].[ActivityFeedback] ([ActivityId] ASC, [Created] ASC);
56+
ON [Mi].[ActivityFeedback] ([ActivityId] ASC, [Created] ASC);
6857

6958
GO
7059

7160
CREATE NONCLUSTERED INDEX [IX_ActivityFeedback_CreatedBy]
72-
ON [Activities].[ActivityFeedback] ([CreatedBy] ASC);
61+
ON [Mi].[ActivityFeedback] ([CreatedBy] ASC);
7362

7463
GO
7564

7665
CREATE NONCLUSTERED INDEX [IX_ActivityFeedback_EditorId]
77-
ON [Activities].[ActivityFeedback] ([EditorId] ASC);
66+
ON [Mi].[ActivityFeedback] ([EditorId] ASC);
7867

7968
GO
8069

8170
CREATE NONCLUSTERED INDEX [IX_ActivityFeedback_OwnerId]
82-
ON [Activities].[ActivityFeedback] ([OwnerId] ASC);
71+
ON [Mi].[ActivityFeedback] ([OwnerId] ASC);
8372

8473
GO
8574

8675
CREATE NONCLUSTERED INDEX [IX_ActivityFeedback_ParticipantId]
87-
ON [Activities].[ActivityFeedback] ([ParticipantId] ASC);
76+
ON [Mi].[ActivityFeedback] ([ParticipantId] ASC);
8877

8978
GO
9079

91-
CREATE NONCLUSTERED INDEX [IX_ActivityFeedback_RecipientUserId_IsRead]
92-
ON [Activities].[ActivityFeedback] ([RecipientUserId] ASC, [IsRead] ASC);
80+
CREATE NONCLUSTERED INDEX [IX_ActivityFeedback_OwnerId_IsRead]
81+
ON [Mi].[ActivityFeedback] ([OwnerId] ASC, [IsRead] ASC);
9382

9483
GO
9584

96-
CREATE NONCLUSTERED INDEX [IX_ActivityFeedback_TenantId]
97-
ON [Activities].[ActivityFeedback] ([TenantId] ASC);
98-
99-
GO
10085

101-
ALTER TABLE [Activities].[ActivityFeedback]
86+
ALTER TABLE [Mi].[ActivityFeedback]
10287
ADD CONSTRAINT [PK_ActivityFeedback] PRIMARY KEY CLUSTERED ([Id] ASC);

src/Domain/Common/Enums/FeedbackOutcome.cs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,9 @@ public sealed class FeedbackOutcome : SmartEnum<FeedbackOutcome>
66
{
77
public static readonly FeedbackOutcome Approved = new("Approved", 0);
88
public static readonly FeedbackOutcome Returned = new("Returned", 1);
9-
public static readonly FeedbackOutcome Escalated = new("Escalated", 2);
10-
public static readonly FeedbackOutcome EscalatedComment = new(" Comment", 3);
11-
129
private FeedbackOutcome(string name, int value)
1310
: base(name, value)
1411
{
1512
}
13+
1614
}

src/Domain/Entities/Activities/ActivityFeedback.cs

Lines changed: 13 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,27 @@
11
using Cfo.Cats.Domain.Common.Entities;
22
using Cfo.Cats.Domain.Common.Enums;
3-
using Cfo.Cats.Domain.Entities.Administration;
4-
using Cfo.Cats.Domain.Entities.Participants;
53
using Cfo.Cats.Domain.Events;
6-
using Cfo.Cats.Domain.Identity;
74

85
namespace Cfo.Cats.Domain.Entities.Activities;
96

107
public class ActivityFeedback : OwnerPropertyEntity<Guid>
118
{
12-
public Guid ActivityId { get; init; }
13-
public string ParticipantId { get; init; }
9+
public Guid ActivityId { get; private set; }
10+
public string ParticipantId { get; private set; }
11+
public string Message { get; private set; }
1412

15-
public string RecipientUserId { get; init; }
16-
public ApplicationUser? RecipientUser { get; init; }
13+
public FeedbackOutcome Qa1Outcome { get; private set;}
1714

18-
public string Message { get; init; } = null!;
15+
public DateTime Qa1Date { get;set; }
1916

2017
public FeedbackOutcome Outcome { get; private set; }
21-
public FeedbackStage Stage { get; init; }
22-
23-
public DateTime ActivityProcessedDate { get; init; }
24-
18+
public FeedbackStage Stage { get; private set; }
2519
public bool IsRead { get; private set; }
2620
public DateTime? ReadAt { get; private set; }
27-
public string TenantId { get; protected init; }
28-
public ApplicationUser? CreatedByUser { get; private set; }
2921
public required string ActivityCategory { get; init; }
3022
public required string ActivityType { get; init; }
3123
public required string ActivityFeedbackReason { get; init; }
3224

33-
public virtual Activity? Activity { get; private set; }
34-
public virtual Participant? Participant { get; protected init; }
35-
public virtual Tenant? Tenant { get; init; }
36-
3725
#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
3826
private ActivityFeedback()
3927
{
@@ -43,13 +31,12 @@ private ActivityFeedback()
4331
public static ActivityFeedback Create(
4432
Guid activityId,
4533
string participantId,
46-
string recipientUserId,
34+
string qa1UserId,
4735
string message,
36+
FeedbackOutcome qa1Outcome,
4837
FeedbackOutcome outcome,
4938
FeedbackStage stage,
50-
DateTime activityProcessedDate,
51-
string createdBy,
52-
string tenantId,
39+
DateTime qa1Date,
5340
string activityCategory,
5441
string activityType,
5542
string activityFeedbackReason)
@@ -59,18 +46,16 @@ public static ActivityFeedback Create(
5946
Id = Guid.CreateVersion7(),
6047
ActivityId = activityId,
6148
ParticipantId = participantId,
62-
RecipientUserId = recipientUserId,
49+
OwnerId = qa1UserId,
6350
Message = message,
6451
Outcome = outcome,
6552
Stage = stage,
66-
ActivityProcessedDate = activityProcessedDate,
67-
CreatedBy = createdBy,
68-
Created = DateTime.UtcNow,
53+
Qa1Date = qa1Date,
6954
IsRead = false,
70-
TenantId = tenantId,
7155
ActivityCategory = activityCategory,
7256
ActivityType = activityType,
73-
ActivityFeedbackReason = activityFeedbackReason
57+
ActivityFeedbackReason = activityFeedbackReason,
58+
Qa1Outcome = qa1Outcome
7459
};
7560

7661
feedback.AddDomainEvent(

0 commit comments

Comments
 (0)