Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 5 additions & 17 deletions src/app/api/notification/notification.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ export class NotificationService extends BaseService {
) {
try {
// 1.Check for existing notification. Skip if duplicate

const existingNotification = task.clientId
? await this.db.clientNotification.findFirst({
where: { taskId: task.id, clientId: task.clientId, companyId: task.companyId },
Expand Down Expand Up @@ -81,12 +80,8 @@ export class NotificationService extends BaseService {
const taskViewers = ViewersSchema.parse(task.viewers)

// 3. Save notification to ClientNotification or InternalUserNotification table. Check for notification.recipientClientId too
if (
(task.assigneeType === AssigneeType.client || !!taskViewers?.length) &&
!!notification.recipientClientId &&
!opts.disableInProduct
) {
await this.addToClientNotifications(task, NotificationCreatedResponseSchema.parse(notification), taskViewers)
if (task.assigneeType === AssigneeType.client && !!notification.recipientClientId && !opts.disableInProduct) {
await this.addToClientNotifications(task, NotificationCreatedResponseSchema.parse(notification))
}
// NOTE: There are cases where task.assigneeType does not account for IU notification!
// E.g. When receiving notifications from others completing task that IU created.
Expand Down Expand Up @@ -209,12 +204,10 @@ export class NotificationService extends BaseService {
// 4. Add client notifications and internalUserNotifications to DB
console.info('NotificationService#bulkCreate | Adding client notifications to db')
if (clientNotifications.length && !opts?.disableInProduct) {
const viewer = getTaskViewers(task)

await this.db.clientNotification.createMany({
data: clientNotifications.map((notification) => ({
clientId: Uuid.parse(notification.recipientClientId),
companyId: Uuid.parse(task.companyId ?? viewer?.companyId),
companyId: Uuid.parse(task.companyId),
notificationId: notification.id,
taskId: task.id,
})),
Expand Down Expand Up @@ -245,16 +238,11 @@ export class NotificationService extends BaseService {
* @param notification Associated notification
* @returns New ClientNotification object
*/
async addToClientNotifications(
task: Task,
notification: NotificationCreatedResponse,
taskViewers?: Viewers,
): Promise<ClientNotification> {
const viewer = !!taskViewers?.length ? taskViewers[0] : undefined
async addToClientNotifications(task: Task, notification: NotificationCreatedResponse): Promise<ClientNotification> {
return await this.db.clientNotification.create({
data: {
clientId: Uuid.parse(notification.recipientClientId),
companyId: Uuid.parse(viewer?.companyId ?? task.companyId),
companyId: Uuid.parse(task.companyId),
notificationId: notification.id,
taskId: task.id,
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ export class ValidateCountService extends NotificationService {
showArchived: false,
showUnarchived: true,
showIncompleteOnly: true,
companyId: this.user.companyId, //notification counts only applied on assigned tasks, not shared tasks.
})
console.info('ValidateCount :: User tasks for company', companyId, ':', tasks.length)

Expand Down Expand Up @@ -156,15 +157,15 @@ export class ValidateCountService extends NotificationService {
// This is a duplicate notification, SKIP
continue
}
const taskViewers = getTaskViewers(task)

createNotificationPromises.push(
copilotBottleneck.schedule(() => {
console.info(`ValidateCount :: Creating missing notification for task ${task.id} - ${task.title}`)
// @ts-expect-error SDK types for new notification payload is not up to datelike always, SDK types are not up to date
return this.copilot.createNotification({
senderId: task.createdById,
recipientClientId: clientId,
recipientCompanyId: task.companyId || taskViewers?.companyId,
recipientCompanyId: task.companyId || undefined,
deliveryTargets: {
inProduct: {
// doesn't matter what you add here since notification details cannot be viewed
Expand Down
40 changes: 9 additions & 31 deletions src/app/api/tasks/task-notifications.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -257,24 +257,9 @@ export class TaskNotificationsService extends BaseService {
if (updatedTask.createdById === this.user.internalUserId) {
shouldCreateNotification = false
}
if (updatedTask.assigneeType === AssigneeType.internalUser) {
shouldCreateNotification &&
(await this.notificationService.create(NotificationTaskActions.CompletedByIU, updatedTask, { disableEmail: true }))

const viewer = getTaskViewers(updatedTask)
if (!viewer) return
if (viewer?.clientId) {
try {
await this.notificationService.markClientNotificationAsRead(updatedTask)
return
} catch (e: unknown) {
console.error(`Failed to find ClientNotification for task ${updatedTask.id}`, e)
}
} else {
await this.notificationService.markAsReadForAllRecipients(updatedTask, NotificationTaskActions.SharedToCompany)
}
// TODO: Clean code and handle notification center notification deletions here instead
} else if (updatedTask.assigneeType === AssigneeType.company) {
// TODO: Clean code and handle notification center notification deletions here instead
else if (updatedTask.assigneeType === AssigneeType.company) {
// Don't do this in parallel since this can cause rate-limits, each of them has their own bottlenecks for avoiding ratelimits
shouldCreateNotification &&
(await this.notificationService.create(NotificationTaskActions.CompletedForCompanyByIU, updatedTask, {
Expand All @@ -295,11 +280,8 @@ export class TaskNotificationsService extends BaseService {

private handleIncompleteTaskReassignment = async (prevTask: Task, updatedTask: TaskWithWorkflowState) => {
// Handle case where parent task is reassigned to a client / company, so the disjoint tasks disappear in real time
const updatedTaskViewers = getTaskViewers(updatedTask)
if (
(updatedTask.assigneeType === AssigneeType.client ||
updatedTask.assigneeType === AssigneeType.company ||
!!updatedTaskViewers) &&
(updatedTask.assigneeType === AssigneeType.client || updatedTask.assigneeType === AssigneeType.company) &&
!updatedTask.parentId
) {
// Remove all notifications for previously disjointed child tasks
Expand All @@ -317,20 +299,12 @@ export class TaskNotificationsService extends BaseService {
// Step 1: Handle notifications removal from previous user
if (prevTask.assigneeId && prevTask.assigneeType) {
const assigneeType = prevTask.assigneeType
const viewer = getTaskViewers(prevTask)

// -- If task is reassigned from client, delete past in-product notification
if (assigneeType === AssigneeType.internalUser) {
await this.notificationService.deleteInternalUserNotificationsForTask(prevTask.id)
}
// -- If task has a viewer, handle mark as read for the viewer.
if (viewer) {
if (viewer?.clientId) {
await this.notificationService.markClientNotificationAsRead(prevTask)
} else {
await this.notificationService.markAsReadForAllRecipients(prevTask, NotificationTaskActions.SharedToCompany)
}
}

// -- If task is reassigned from a client, mark prev client notification as read (not delete)
if (assigneeType === AssigneeType.client) {
await this.notificationService.markClientNotificationAsRead(prevTask)
Expand Down Expand Up @@ -400,7 +374,10 @@ export class TaskNotificationsService extends BaseService {
return
}

const notification = await this.notificationService.create(notificationType, task)
const notification = await this.notificationService.create(notificationType, task, {
disableInProduct: true,
disableEmail: false,
})
// Create a new entry in ClientNotifications table so we can mark as read on
// behalf of client later

Expand All @@ -418,6 +395,7 @@ export class TaskNotificationsService extends BaseService {
)
await this.notificationService.createBulkNotification(NotificationTaskActions.SharedToCompany, task, recipientIds, {
email: true,
disableInProduct: true,
})
}

Expand Down
Loading