improvement: task assignment notif added to notifications feature.

This commit is contained in:
2026-07-18 17:23:47 +03:30
parent 9941dca849
commit 408b2c3329
16 changed files with 76 additions and 18 deletions

View File

@@ -0,0 +1,2 @@
-- AlterEnum
ALTER TYPE "LabCaseActivityType" ADD VALUE 'TASK_ASSIGNED';

View File

@@ -429,6 +429,7 @@ enum LabCaseActivityType {
CASE_IMPORTANT
CASE_AMENDED
TASK_COMPLETED
TASK_ASSIGNED
}
enum LabCaseTabReadTarget {

View File

@@ -7,10 +7,11 @@ export const LAB_CASES_TAB_ACTIVITY_TYPES: LabCaseActivityType[] = [
LabCaseActivityType.CASE_IMPORTANT,
];
/** Lab Tasks tab — task completions and lab-side comments. */
/** Lab Tasks tab — task completions, lab-side comments, and assignments (assignee-scoped in counts). */
export const LAB_TASKS_TAB_ACTIVITY_TYPES: LabCaseActivityType[] = [
LabCaseActivityType.TASK_COMPLETED,
LabCaseActivityType.LAB_COMMENT,
LabCaseActivityType.TASK_ASSIGNED,
];
/** Clinic Treatment tab — visible lab comments and task progress. */

View File

@@ -486,13 +486,20 @@ export class CasesService {
},
});
if (assigneeUserId && assigneeUserId !== actorUserId) {
if (assigneeUserId) {
await this.labCaseActivity.record({
labCaseId,
type: LabCaseActivityType.TASK_ASSIGNED,
actorUserId,
payload: { taskId, assigneeUserId },
});
void this.userNotifications.notify({
organizationId: labOrganizationId,
type: UserNotificationType.TASK_ASSIGNED,
href: `/tasks?taskId=${encodeURIComponent(taskId)}&labCaseId=${encodeURIComponent(labCaseId)}`,
actorUserId,
payload: { labCaseId, taskId },
payload: { labCaseId, taskId, assigneeUserId },
recipientUserIds: [assigneeUserId],
});
}

View File

@@ -318,7 +318,10 @@ export class LabCaseActivityService {
const commentId = payload?.commentId;
if (typeof commentId === 'string') commentIds.push(commentId);
}
if (activity.type === LabCaseActivityType.TASK_COMPLETED) {
if (
activity.type === LabCaseActivityType.TASK_COMPLETED ||
activity.type === LabCaseActivityType.TASK_ASSIGNED
) {
const taskId = payload?.taskId;
if (typeof taskId === 'string') taskIds.push(taskId);
}
@@ -387,18 +390,44 @@ export class LabCaseActivityService {
};
const clinicLabCommentFilter = this.clinicLabCommentFilter(orgType);
const includesTaskAssigned = types.includes(LabCaseActivityType.TASK_ASSIGNED);
const otherTypes = types.filter((type) => type !== LabCaseActivityType.TASK_ASSIGNED);
// TASK_ASSIGNED: count for the assignee only (including self-assign).
// Other task-tab types: org-wide, excluding events the current user authored.
const typeFilter: Prisma.LabCaseActivityWhereInput = includesTaskAssigned
? {
OR: [
...(otherTypes.length > 0
? [
{
AND: [
{ type: { in: otherTypes } },
{
OR: [{ actorUserId: null }, { actorUserId: { not: userId } }],
},
],
},
]
: []),
{
type: LabCaseActivityType.TASK_ASSIGNED,
payload: { path: ['assigneeUserId'], equals: userId },
},
],
}
: {
AND: [
{ type: { in: types } },
{ OR: [{ actorUserId: null }, { actorUserId: { not: userId } }] },
],
};
return this.prisma.labCaseActivity.count({
where: {
type: { in: types },
createdAt: { gt: since },
labCase: labCaseScope,
AND: [
{
OR: [{ actorUserId: null }, { actorUserId: { not: userId } }],
},
clinicLabCommentFilter,
],
AND: [clinicLabCommentFilter, typeFilter],
},
});
}

View File

@@ -182,8 +182,9 @@ export class UserNotificationService {
}
async notify(input: FanoutInput): Promise<void> {
// Explicit recipients keep the actor (e.g. self-assign). Fan-out still skips the actor.
const recipientIds = input.recipientUserIds?.length
? [...new Set(input.recipientUserIds.filter((id) => id && id !== input.actorUserId))]
? [...new Set(input.recipientUserIds.filter((id): id is string => Boolean(id)))]
: await this.resolveRecipients(input);
if (recipientIds.length === 0) return;