diff --git a/apps/judicial-system/backend/src/app/messages/notifications.ts b/apps/judicial-system/backend/src/app/messages/notifications.ts
index 9777fdd1be49..fe12aea5011d 100644
--- a/apps/judicial-system/backend/src/app/messages/notifications.ts
+++ b/apps/judicial-system/backend/src/app/messages/notifications.ts
@@ -859,4 +859,17 @@ export const notifications = {
description: 'Texti í pósti til dómstóls þegar ákæra er afturkölluð',
},
}),
+ caseFilesUpdated: defineMessages({
+ subject: {
+ id: 'judicial.system.backend:notifications.case_files_updated.subject',
+ defaultMessage: 'Ný gögn í máli {courtCaseNumber}',
+ description: 'Fyrirsögn í pósti til aðila máls þegar ný gögn eru send',
+ },
+ body: {
+ id: 'judicial.system.backend:notifications.case_files_updated.body',
+ defaultMessage:
+ 'Ný gögn hafa borist vegna máls {courtCaseNumber}. {userHasAccessToRVG, select, true {Hægt er að nálgast gögn málsins á {linkStart}yfirlitssíðu málsins í Réttarvörslugátt{linkEnd}} other {Hægt er að nálgast gögn málsins hjá {court} ef þau hafa ekki þegar verið afhent}}.',
+ description: 'Texti í pósti til aðila máls þegar ný gögn eru send',
+ },
+ }),
}
diff --git a/apps/judicial-system/backend/src/app/modules/notification/guards/rolesRules.ts b/apps/judicial-system/backend/src/app/modules/notification/guards/rolesRules.ts
index 284c03caf5c1..dd5a3153797e 100644
--- a/apps/judicial-system/backend/src/app/modules/notification/guards/rolesRules.ts
+++ b/apps/judicial-system/backend/src/app/modules/notification/guards/rolesRules.ts
@@ -10,6 +10,7 @@ export const prosecutorNotificationRule: RolesRule = {
NotificationType.HEADS_UP,
NotificationType.READY_FOR_COURT,
NotificationType.APPEAL_CASE_FILES_UPDATED,
+ NotificationType.CASE_FILES_UPDATED,
],
} as RolesRule
@@ -18,7 +19,10 @@ export const defenderNotificationRule: RolesRule = {
role: UserRole.DEFENDER,
type: RulesType.FIELD_VALUES,
dtoField: 'type',
- dtoFieldValues: [NotificationType.APPEAL_CASE_FILES_UPDATED],
+ dtoFieldValues: [
+ NotificationType.APPEAL_CASE_FILES_UPDATED,
+ NotificationType.CASE_FILES_UPDATED,
+ ],
} as RolesRule
// Allows district court judges to send notifiications
diff --git a/apps/judicial-system/backend/src/app/modules/notification/internalNotification.service.ts b/apps/judicial-system/backend/src/app/modules/notification/internalNotification.service.ts
index b8b670d07c24..40313e0c3df0 100644
--- a/apps/judicial-system/backend/src/app/modules/notification/internalNotification.service.ts
+++ b/apps/judicial-system/backend/src/app/modules/notification/internalNotification.service.ts
@@ -47,7 +47,6 @@ import {
RequestSharedWithDefender,
SessionArrangements,
type User,
- UserRole,
} from '@island.is/judicial-system/types'
import {
@@ -75,7 +74,11 @@ import {
import { notifications } from '../../messages'
import { type Case, DateLog } from '../case'
import { CourtService } from '../court'
-import { type Defendant, DefendantService } from '../defendant'
+import {
+ type CivilClaimant,
+ type Defendant,
+ DefendantService,
+} from '../defendant'
import { EventService } from '../event'
import { DeliverResponse } from './models/deliver.response'
import { Notification, Recipient } from './models/notification.model'
@@ -1521,7 +1524,9 @@ export class InternalNotificationService extends BaseNotificationService {
SessionArrangements.ALL_PRESENT_SPOKESPERSON,
].includes(theCase.sessionArrangements)
- if (!isDefenderIncludedInSessionArrangements) return false
+ if (!isDefenderIncludedInSessionArrangements) {
+ return false
+ }
} else {
const hasDefenderBeenNotified = this.hasReceivedNotification(
[
@@ -1609,10 +1614,11 @@ export class InternalNotificationService extends BaseNotificationService {
} = civilClaimant
const shouldSend =
+ hasSpokesperson &&
this.shouldSendAdvocateAssignedNotification(
theCase,
spokespersonEmail,
- ) && hasSpokesperson
+ )
if (shouldSend === true) {
promises.push(
@@ -1757,6 +1763,116 @@ export class InternalNotificationService extends BaseNotificationService {
}
//#endregion
+ //#region CASE_FILES_UPDATED notifications
+ private sendCaseFilesUpdatedNotification(
+ courtCaseNumber?: string,
+ court?: string,
+ link?: string,
+ name?: string,
+ email?: string,
+ ) {
+ const subject = this.formatMessage(notifications.caseFilesUpdated.subject, {
+ courtCaseNumber,
+ })
+ const html = this.formatMessage(notifications.caseFilesUpdated.body, {
+ courtCaseNumber,
+ court: court?.replace('dómur', 'dómi'),
+ userHasAccessToRVG: Boolean(link),
+ linkStart: ``,
+ linkEnd: '',
+ })
+
+ return this.sendEmail(subject, html, name, email, undefined, !link)
+ }
+
+ private async sendCaseFilesUpdatedNotifications(
+ theCase: Case,
+ user: User,
+ ): Promise {
+ const promises = [
+ this.sendCaseFilesUpdatedNotification(
+ theCase.courtCaseNumber,
+ theCase.court?.name,
+ `${this.config.clientUrl}${INDICTMENTS_COURT_OVERVIEW_ROUTE}/${theCase.id}`,
+ theCase.judge?.name,
+ theCase.judge?.email,
+ ),
+ ]
+
+ const uniqueSpokespersons = _uniqBy(
+ theCase.civilClaimants?.filter((c) => c.hasSpokesperson) ?? [],
+ (c: CivilClaimant) => c.spokespersonEmail,
+ )
+ uniqueSpokespersons.forEach((civilClaimant) => {
+ if (civilClaimant.spokespersonEmail) {
+ promises.push(
+ this.sendCaseFilesUpdatedNotification(
+ theCase.courtCaseNumber,
+ theCase.court?.name,
+ civilClaimant.spokespersonNationalId &&
+ formatDefenderRoute(
+ this.config.clientUrl,
+ theCase.type,
+ theCase.id,
+ ),
+ civilClaimant.spokespersonName,
+ civilClaimant.spokespersonEmail,
+ ),
+ )
+ }
+ })
+
+ if (isProsecutionUser(user)) {
+ const uniqueDefendants = _uniqBy(
+ theCase.defendants ?? [],
+ (d: Defendant) => d.defenderEmail,
+ )
+ uniqueDefendants.forEach((defendant) => {
+ if (defendant.defenderEmail) {
+ promises.push(
+ this.sendCaseFilesUpdatedNotification(
+ theCase.courtCaseNumber,
+ theCase.court?.name,
+ defendant.defenderNationalId &&
+ formatDefenderRoute(
+ this.config.clientUrl,
+ theCase.type,
+ theCase.id,
+ ),
+ defendant.defenderName,
+ defendant.defenderEmail,
+ ),
+ )
+ }
+ })
+ }
+
+ if (isDefenceUser(user)) {
+ promises.push(
+ this.sendCaseFilesUpdatedNotification(
+ theCase.courtCaseNumber,
+ theCase.court?.name,
+ `${this.config.clientUrl}${INDICTMENTS_OVERVIEW_ROUTE}/${theCase.id}`,
+ theCase.prosecutor?.name,
+ theCase.prosecutor?.email,
+ ),
+ )
+ }
+
+ const recipients = await Promise.all(promises)
+
+ if (recipients.length > 0) {
+ return this.recordNotification(
+ theCase.id,
+ NotificationType.CASE_FILES_UPDATED,
+ recipients,
+ )
+ }
+
+ return { delivered: true }
+ }
+ //#endregion
+
//#region Appeal notifications
//#region COURT_OF_APPEAL_JUDGE_ASSIGNED notifications
private async sendCourtOfAppealJudgeAssignedNotification(
@@ -1851,7 +1967,7 @@ export class InternalNotificationService extends BaseNotificationService {
)
}
- if (user.role === UserRole.DEFENDER) {
+ if (isDefenceUser(user)) {
promises.push(
this.sendEmail(
subject,
@@ -1863,7 +1979,7 @@ export class InternalNotificationService extends BaseNotificationService {
promises.push(this.sendSms(smsText, theCase.prosecutor?.mobileNumber))
}
- if (user.role === UserRole.PROSECUTOR && theCase.defenderEmail) {
+ if (isProsecutionUser(user) && theCase.defenderEmail) {
const url =
theCase.defenderNationalId &&
formatDefenderRoute(this.config.clientUrl, theCase.type, theCase.id)
@@ -2081,7 +2197,7 @@ export class InternalNotificationService extends BaseNotificationService {
}
}
- if (user.role === UserRole.DEFENDER) {
+ if (isDefenceUser(user)) {
const prosecutorHtml = this.formatMessage(
notifications.caseAppealStatement.body,
{
@@ -2103,7 +2219,7 @@ export class InternalNotificationService extends BaseNotificationService {
)
}
- if (user.role === UserRole.PROSECUTOR && theCase.defenderEmail) {
+ if (isProsecutionUser(user)) {
const url =
theCase.defenderNationalId &&
formatDefenderRoute(this.config.clientUrl, theCase.type, theCase.id)
@@ -2186,7 +2302,7 @@ export class InternalNotificationService extends BaseNotificationService {
}
})
- if (user.role === UserRole.DEFENDER) {
+ if (isDefenceUser(user)) {
const prosecutorHtml = this.formatMessage(
notifications.caseAppealCaseFilesUpdated.body,
{
@@ -2563,6 +2679,8 @@ export class InternalNotificationService extends BaseNotificationService {
return this.sendIndictmentDeniedNotifications(theCase)
case NotificationType.INDICTMENT_RETURNED:
return this.sendIndictmentReturnedNotifications(theCase)
+ case NotificationType.CASE_FILES_UPDATED:
+ return this.sendCaseFilesUpdatedNotifications(theCase, user)
default:
throw new InternalServerErrorException(
`Invalid notification type ${type}`,
diff --git a/apps/judicial-system/backend/src/app/modules/notification/notification.service.ts b/apps/judicial-system/backend/src/app/modules/notification/notification.service.ts
index 46665cef3181..be058b8463e2 100644
--- a/apps/judicial-system/backend/src/app/modules/notification/notification.service.ts
+++ b/apps/judicial-system/backend/src/app/modules/notification/notification.service.ts
@@ -75,6 +75,7 @@ export class NotificationService {
case NotificationType.ADVOCATE_ASSIGNED:
case NotificationType.APPEAL_JUDGES_ASSIGNED:
case NotificationType.APPEAL_CASE_FILES_UPDATED:
+ case NotificationType.CASE_FILES_UPDATED:
messages = [this.getNotificationMessage(type, user, theCase)]
break
default:
diff --git a/apps/judicial-system/backend/src/app/modules/notification/test/internalNotificationController/sendAppealStatementNotifications.spec.ts b/apps/judicial-system/backend/src/app/modules/notification/test/internalNotificationController/sendAppealStatementNotifications.spec.ts
index db0ccf911fd5..7d7bdb6aff13 100644
--- a/apps/judicial-system/backend/src/app/modules/notification/test/internalNotificationController/sendAppealStatementNotifications.spec.ts
+++ b/apps/judicial-system/backend/src/app/modules/notification/test/internalNotificationController/sendAppealStatementNotifications.spec.ts
@@ -3,6 +3,7 @@ import { uuid } from 'uuidv4'
import { EmailService } from '@island.is/email-service'
import {
+ InstitutionType,
NotificationType,
User,
UserRole,
@@ -19,13 +20,12 @@ interface Then {
}
type GivenWhenThen = (
- role: UserRole,
+ user: User,
defenderNationalId?: string,
appealsCourtNumber?: string,
) => Promise
describe('InternalNotificationController - Send appeal statement notifications', () => {
- const userId = uuid()
const caseId = uuid()
const prosecutorName = uuid()
const prosecutorEmail = uuid()
@@ -54,7 +54,7 @@ describe('InternalNotificationController - Send appeal statement notifications',
mockEmailService = emailService
givenWhenThen = async (
- role: UserRole,
+ user: User,
defenderNationalId?: string,
appealCaseNumber?: string,
) => {
@@ -77,7 +77,7 @@ describe('InternalNotificationController - Send appeal statement notifications',
appealJudge1: { name: judgeName1, email: judgeEmail1 },
} as Case,
{
- user: { id: userId, role } as User,
+ user,
type: NotificationType.APPEAL_STATEMENT,
},
)
@@ -99,7 +99,14 @@ describe('InternalNotificationController - Send appeal statement notifications',
let then: Then
beforeEach(async () => {
- then = await givenWhenThen(UserRole.PROSECUTOR, uuid(), appealCaseNumber)
+ then = await givenWhenThen(
+ {
+ role: UserRole.PROSECUTOR,
+ institution: { type: InstitutionType.PROSECUTORS_OFFICE },
+ } as User,
+ uuid(),
+ appealCaseNumber,
+ )
})
it('should send notification to appeals court and defender', () => {
@@ -123,7 +130,10 @@ describe('InternalNotificationController - Send appeal statement notifications',
beforeEach(async () => {
then = await givenWhenThen(
- UserRole.PROSECUTOR,
+ {
+ role: UserRole.PROSECUTOR,
+ institution: { type: InstitutionType.PROSECUTORS_OFFICE },
+ } as User,
undefined,
appealCaseNumber,
)
@@ -149,7 +159,11 @@ describe('InternalNotificationController - Send appeal statement notifications',
let then: Then
beforeEach(async () => {
- then = await givenWhenThen(UserRole.DEFENDER, uuid(), appealCaseNumber)
+ then = await givenWhenThen(
+ { role: UserRole.DEFENDER } as User,
+ uuid(),
+ appealCaseNumber,
+ )
})
it('should send notification to appeals court and prosecutor', () => {
@@ -172,7 +186,13 @@ describe('InternalNotificationController - Send appeal statement notifications',
let then: Then
beforeEach(async () => {
- then = await givenWhenThen(UserRole.PROSECUTOR, uuid())
+ then = await givenWhenThen(
+ {
+ role: UserRole.PROSECUTOR,
+ institution: { type: InstitutionType.PROSECUTORS_OFFICE },
+ } as User,
+ uuid(),
+ )
})
it('should send notification to defender', () => {
@@ -191,7 +211,10 @@ describe('InternalNotificationController - Send appeal statement notifications',
let then: Then
beforeEach(async () => {
- then = await givenWhenThen(UserRole.PROSECUTOR)
+ then = await givenWhenThen({
+ role: UserRole.PROSECUTOR,
+ institution: { type: InstitutionType.PROSECUTORS_OFFICE },
+ } as User)
})
it('should send notification to defender', () => {
@@ -210,7 +233,7 @@ describe('InternalNotificationController - Send appeal statement notifications',
let then: Then
beforeEach(async () => {
- then = await givenWhenThen(UserRole.DEFENDER, uuid())
+ then = await givenWhenThen({ role: UserRole.DEFENDER } as User, uuid())
})
it('should send notification to prosecutor', () => {
diff --git a/apps/judicial-system/backend/src/app/modules/notification/test/internalNotificationController/sendAppealToCourtOfAppealsNotifications.spec.ts b/apps/judicial-system/backend/src/app/modules/notification/test/internalNotificationController/sendAppealToCourtOfAppealsNotifications.spec.ts
index 65bdd8473fb1..79b89a75a0f3 100644
--- a/apps/judicial-system/backend/src/app/modules/notification/test/internalNotificationController/sendAppealToCourtOfAppealsNotifications.spec.ts
+++ b/apps/judicial-system/backend/src/app/modules/notification/test/internalNotificationController/sendAppealToCourtOfAppealsNotifications.spec.ts
@@ -4,6 +4,7 @@ import { EmailService } from '@island.is/email-service'
import { SmsService } from '@island.is/nova-sms'
import {
+ InstitutionType,
NotificationType,
User,
UserRole,
@@ -19,13 +20,9 @@ interface Then {
error: Error
}
-type GivenWhenThen = (
- role: UserRole,
- defenderNationalId?: string,
-) => Promise
+type GivenWhenThen = (user: User, defenderNationalId?: string) => Promise
describe('InternalNotificationController - Send appeal to court of appeals notifications', () => {
- const userId = uuid()
const caseId = uuid()
const prosecutorName = uuid()
const prosecutorEmail = uuid()
@@ -56,7 +53,7 @@ describe('InternalNotificationController - Send appeal to court of appeals notif
mockEmailService = emailService
mockSmsService = smsService
- givenWhenThen = async (role: UserRole, defenderNationalId?: string) => {
+ givenWhenThen = async (user: User, defenderNationalId?: string) => {
const then = {} as Then
await internalNotificationController
@@ -79,7 +76,7 @@ describe('InternalNotificationController - Send appeal to court of appeals notif
courtId: courtId,
} as Case,
{
- user: { id: userId, role } as User,
+ user,
type: NotificationType.APPEAL_TO_COURT_OF_APPEALS,
},
)
@@ -93,7 +90,13 @@ describe('InternalNotificationController - Send appeal to court of appeals notif
let then: Then
beforeEach(async () => {
- then = await givenWhenThen(UserRole.PROSECUTOR, uuid())
+ then = await givenWhenThen(
+ {
+ role: UserRole.PROSECUTOR,
+ institution: { type: InstitutionType.PROSECUTORS_OFFICE },
+ } as User,
+ uuid(),
+ )
})
it('should send notification to judge, registrar, court and defender', () => {
@@ -138,7 +141,10 @@ describe('InternalNotificationController - Send appeal to court of appeals notif
let then: Then
beforeEach(async () => {
- then = await givenWhenThen(UserRole.PROSECUTOR)
+ then = await givenWhenThen({
+ role: UserRole.PROSECUTOR,
+ institution: { type: InstitutionType.PROSECUTORS_OFFICE },
+ } as User)
})
it('should send notification to judge and defender', () => {
@@ -168,7 +174,7 @@ describe('InternalNotificationController - Send appeal to court of appeals notif
let then: Then
beforeEach(async () => {
- then = await givenWhenThen(UserRole.DEFENDER, uuid())
+ then = await givenWhenThen({ role: UserRole.DEFENDER } as User, uuid())
})
it('should send notifications to judge and prosecutor', () => {
diff --git a/apps/judicial-system/backend/src/app/modules/notification/test/internalNotificationController/sendCaseFilesUpdatedNotifications.spec.ts b/apps/judicial-system/backend/src/app/modules/notification/test/internalNotificationController/sendCaseFilesUpdatedNotifications.spec.ts
new file mode 100644
index 000000000000..10102b2743d5
--- /dev/null
+++ b/apps/judicial-system/backend/src/app/modules/notification/test/internalNotificationController/sendCaseFilesUpdatedNotifications.spec.ts
@@ -0,0 +1,152 @@
+import { uuid } from 'uuidv4'
+
+import { EmailService } from '@island.is/email-service'
+
+import {
+ CaseType,
+ InstitutionType,
+ NotificationType,
+ User,
+ UserRole,
+} from '@island.is/judicial-system/types'
+
+import { createTestingNotificationModule } from '../createTestingNotificationModule'
+
+import { Case } from '../../../case'
+import { DeliverResponse } from '../../models/deliver.response'
+
+interface Then {
+ result: DeliverResponse
+ error: Error
+}
+
+type GivenWhenThen = (user: User) => Promise
+
+describe('InternalNotificationController - Send case files updated notifications', () => {
+ const caseId = uuid()
+ const courtCaseNumber = uuid()
+ const prosecutorName = uuid()
+ const prosecutorEmail = uuid()
+ const judgeName = uuid()
+ const judgeEmail = uuid()
+ const defenderNationalId = uuid()
+ const defenderName = uuid()
+ const defenderEmail = uuid()
+ const spokespersonNationalId = uuid()
+ const spokespersonName = uuid()
+ const spokespersonEmail = uuid()
+ let mockEmailService: EmailService
+ let givenWhenThen: GivenWhenThen
+
+ beforeEach(async () => {
+ const { emailService, internalNotificationController } =
+ await createTestingNotificationModule()
+
+ mockEmailService = emailService
+
+ givenWhenThen = async (user: User) => {
+ const then = {} as Then
+
+ await internalNotificationController
+ .sendCaseNotification(
+ caseId,
+ {
+ id: caseId,
+ type: CaseType.INDICTMENT,
+ courtCaseNumber,
+ court: { name: 'Héraðsdómur Reykjavíkur' },
+ prosecutor: { name: prosecutorName, email: prosecutorEmail },
+ judge: { name: judgeName, email: judgeEmail },
+ defendants: [{ defenderNationalId, defenderName, defenderEmail }],
+ civilClaimants: [
+ {
+ hasSpokesperson: true,
+ spokespersonNationalId,
+ spokespersonName,
+ spokespersonEmail,
+ },
+ ],
+ } as Case,
+ {
+ user,
+ type: NotificationType.CASE_FILES_UPDATED,
+ },
+ )
+ .then((result) => (then.result = result))
+ .catch((error) => (then.error = error))
+
+ return then
+ }
+ })
+
+ describe('notification sent by prosecutor', () => {
+ let then: Then
+
+ beforeEach(async () => {
+ then = await givenWhenThen({
+ role: UserRole.PROSECUTOR,
+ institution: { type: InstitutionType.PROSECUTORS_OFFICE },
+ } as unknown as User)
+ })
+
+ it('should send notifications', () => {
+ expect(mockEmailService.sendEmail).toHaveBeenCalledWith(
+ expect.objectContaining({
+ to: [{ name: judgeName, address: judgeEmail }],
+ subject: `Ný gögn í máli ${courtCaseNumber}`,
+ html: `Ný gögn hafa borist vegna máls ${courtCaseNumber}. Hægt er að nálgast gögn málsins á yfirlitssíðu málsins í Réttarvörslugátt.`,
+ }),
+ )
+ expect(mockEmailService.sendEmail).toHaveBeenCalledWith(
+ expect.objectContaining({
+ to: [{ name: spokespersonName, address: spokespersonEmail }],
+ subject: `Ný gögn í máli ${courtCaseNumber}`,
+ html: `Ný gögn hafa borist vegna máls ${courtCaseNumber}. Hægt er að nálgast gögn málsins á yfirlitssíðu málsins í Réttarvörslugátt.`,
+ }),
+ )
+ expect(mockEmailService.sendEmail).toHaveBeenCalledWith(
+ expect.objectContaining({
+ to: [{ name: defenderName, address: defenderEmail }],
+ subject: `Ný gögn í máli ${courtCaseNumber}`,
+ html: `Ný gögn hafa borist vegna máls ${courtCaseNumber}. Hægt er að nálgast gögn málsins á yfirlitssíðu málsins í Réttarvörslugátt.`,
+ }),
+ )
+ expect(then.result).toEqual({ delivered: true })
+ })
+ })
+
+ describe('notification sent by defender', () => {
+ let then: Then
+
+ beforeEach(async () => {
+ then = await givenWhenThen({
+ role: UserRole.DEFENDER,
+ } as User)
+ })
+
+ it('should send notifications', () => {
+ expect(mockEmailService.sendEmail).toHaveBeenCalledWith(
+ expect.objectContaining({
+ to: [{ name: judgeName, address: judgeEmail }],
+ subject: `Ný gögn í máli ${courtCaseNumber}`,
+ html: `Ný gögn hafa borist vegna máls ${courtCaseNumber}. Hægt er að nálgast gögn málsins á yfirlitssíðu málsins í Réttarvörslugátt.`,
+ }),
+ )
+ expect(mockEmailService.sendEmail).toHaveBeenCalledWith(
+ expect.objectContaining({
+ to: [{ name: spokespersonName, address: spokespersonEmail }],
+ subject: `Ný gögn í máli ${courtCaseNumber}`,
+ html: `Ný gögn hafa borist vegna máls ${courtCaseNumber}. Hægt er að nálgast gögn málsins á yfirlitssíðu málsins í Réttarvörslugátt.`,
+ }),
+ )
+ expect(mockEmailService.sendEmail).toHaveBeenCalledWith(
+ expect.objectContaining({
+ to: [{ name: prosecutorName, address: prosecutorEmail }],
+ subject: `Ný gögn í máli ${courtCaseNumber}`,
+ html: `Ný gögn hafa borist vegna máls ${courtCaseNumber}. Hægt er að nálgast gögn málsins á yfirlitssíðu málsins í Réttarvörslugátt.`,
+ }),
+ )
+ expect(then.result).toEqual({ delivered: true })
+ })
+ })
+})
diff --git a/apps/judicial-system/backend/src/app/modules/notification/test/notificationController/sendCaseFilesUpdatedNotifications.spec.ts b/apps/judicial-system/backend/src/app/modules/notification/test/notificationController/sendCaseFilesUpdatedNotifications.spec.ts
new file mode 100644
index 000000000000..d2ace5bc1743
--- /dev/null
+++ b/apps/judicial-system/backend/src/app/modules/notification/test/notificationController/sendCaseFilesUpdatedNotifications.spec.ts
@@ -0,0 +1,69 @@
+import { uuid } from 'uuidv4'
+
+import { MessageService, MessageType } from '@island.is/judicial-system/message'
+import { NotificationType, User } from '@island.is/judicial-system/types'
+
+import { createTestingNotificationModule } from '../createTestingNotificationModule'
+
+import { Case } from '../../../case'
+import { SendNotificationResponse } from '../../models/sendNotification.response'
+
+interface Then {
+ result: SendNotificationResponse
+ error: Error
+}
+
+type GivenWhenThen = (caseId: string) => Promise
+
+describe('NotificationController - Send case files updated notification', () => {
+ const userId = uuid()
+ const user = { id: userId } as User
+
+ let mockMessageService: MessageService
+ let givenWhenThen: GivenWhenThen
+
+ beforeEach(async () => {
+ const { messageService, notificationController } =
+ await createTestingNotificationModule()
+
+ mockMessageService = messageService
+
+ const mockSendMessagesToQueue =
+ messageService.sendMessagesToQueue as jest.Mock
+ mockSendMessagesToQueue.mockResolvedValue(undefined)
+
+ givenWhenThen = async (caseId) => {
+ const then = {} as Then
+
+ await notificationController
+ .sendCaseNotification(caseId, user, { id: caseId } as Case, {
+ type: NotificationType.CASE_FILES_UPDATED,
+ })
+ .then((result) => (then.result = result))
+ .catch((error) => (then.error = error))
+
+ return then
+ }
+ })
+
+ describe('message queued', () => {
+ const caseId = uuid()
+ let then: Then
+
+ beforeEach(async () => {
+ then = await givenWhenThen(caseId)
+ })
+
+ it('should send message to queue', () => {
+ expect(mockMessageService.sendMessagesToQueue).toHaveBeenCalledWith([
+ {
+ type: MessageType.NOTIFICATION,
+ user,
+ caseId,
+ body: { type: NotificationType.CASE_FILES_UPDATED },
+ },
+ ])
+ expect(then.result).toEqual({ notificationSent: true })
+ })
+ })
+})
diff --git a/apps/judicial-system/web/src/routes/Court/Indictments/Completed/Completed.tsx b/apps/judicial-system/web/src/routes/Court/Indictments/Completed/Completed.tsx
index 7cf61ddc35bb..e3643d276fcf 100644
--- a/apps/judicial-system/web/src/routes/Court/Indictments/Completed/Completed.tsx
+++ b/apps/judicial-system/web/src/routes/Court/Indictments/Completed/Completed.tsx
@@ -60,11 +60,11 @@ const Completed: FC = () => {
)
const handleNextButtonClick = useCallback(async () => {
- const allSucceeded = await handleUpload(
+ const uploadResult = await handleUpload(
uploadFiles.filter((file) => file.percent === 0),
updateUploadFile,
)
- if (!allSucceeded) {
+ if (uploadResult !== 'ALL_SUCCEEDED') {
return
}
diff --git a/apps/judicial-system/web/src/routes/Shared/AddFiles/AddFiles.tsx b/apps/judicial-system/web/src/routes/Shared/AddFiles/AddFiles.tsx
index a40748e36aa8..b4f582149df7 100644
--- a/apps/judicial-system/web/src/routes/Shared/AddFiles/AddFiles.tsx
+++ b/apps/judicial-system/web/src/routes/Shared/AddFiles/AddFiles.tsx
@@ -18,8 +18,12 @@ import {
UserContext,
} from '@island.is/judicial-system-web/src/components'
import UploadFiles from '@island.is/judicial-system-web/src/components/UploadFiles/UploadFiles'
-import { CaseFileCategory } from '@island.is/judicial-system-web/src/graphql/schema'
import {
+ CaseFileCategory,
+ NotificationType,
+} from '@island.is/judicial-system-web/src/graphql/schema'
+import {
+ useCase,
useS3Upload,
useUploadFiles,
} from '@island.is/judicial-system-web/src/utils/hooks'
@@ -47,6 +51,7 @@ const AddFiles: FC = () => {
updateUploadFile,
} = useUploadFiles()
const { handleUpload } = useS3Upload(workingCase.id)
+ const { sendNotification } = useCase()
const caseFileCategory = isDefenceUser(user)
? CaseFileCategory.DEFENDANT_CASE_FILE
@@ -82,15 +87,26 @@ const AddFiles: FC = () => {
)
const handleNextButtonClick = useCallback(async () => {
- const allSucceeded = await handleUpload(
+ const uploadResult = await handleUpload(
uploadFiles.filter((file) => file.percent === 0),
updateUploadFile,
)
- if (allSucceeded) {
+ if (uploadResult !== 'NONE_SUCCEEDED') {
+ // Some files were added successfully so we send a notification
+ sendNotification(workingCase.id, NotificationType.CASE_FILES_UPDATED)
+ }
+
+ if (uploadResult === 'ALL_SUCCEEDED') {
setVisibleModal('sendFiles')
}
- }, [handleUpload, updateUploadFile, uploadFiles])
+ }, [
+ handleUpload,
+ sendNotification,
+ updateUploadFile,
+ uploadFiles,
+ workingCase.id,
+ ])
return (
{
}/${id}`
const handleNextButtonClick = useCallback(async () => {
- const allSucceeded = await handleUpload(
+ const uploadResult = await handleUpload(
uploadFiles.filter((file) => file.percent === 0),
updateUploadFile,
)
- if (!allSucceeded) {
+ if (uploadResult !== 'ALL_SUCCEEDED') {
return
}
diff --git a/apps/judicial-system/web/src/routes/Shared/AppealToCourtOfAppeals/AppealToCourtOfAppeals.tsx b/apps/judicial-system/web/src/routes/Shared/AppealToCourtOfAppeals/AppealToCourtOfAppeals.tsx
index 72cec8d0db9b..fdea9436e1af 100644
--- a/apps/judicial-system/web/src/routes/Shared/AppealToCourtOfAppeals/AppealToCourtOfAppeals.tsx
+++ b/apps/judicial-system/web/src/routes/Shared/AppealToCourtOfAppeals/AppealToCourtOfAppeals.tsx
@@ -70,12 +70,12 @@ const AppealToCourtOfAppeals = () => {
}/${id}`
const handleNextButtonClick = useCallback(async () => {
- const allSucceeded = await handleUpload(
+ const uploadResult = await handleUpload(
uploadFiles.filter((file) => file.percent === 0),
updateUploadFile,
)
- if (!allSucceeded) {
+ if (uploadResult !== 'ALL_SUCCEEDED') {
return
}
diff --git a/apps/judicial-system/web/src/routes/Shared/Statement/Statement.tsx b/apps/judicial-system/web/src/routes/Shared/Statement/Statement.tsx
index 5924ad4e57ed..f2c74e70c11e 100644
--- a/apps/judicial-system/web/src/routes/Shared/Statement/Statement.tsx
+++ b/apps/judicial-system/web/src/routes/Shared/Statement/Statement.tsx
@@ -74,12 +74,12 @@ const Statement = () => {
}/${id}`
const handleNextButtonClick = useCallback(async () => {
- const allSucceeded = await handleUpload(
+ const uploadResult = await handleUpload(
uploadFiles.filter((file) => file.percent === 0),
updateUploadFile,
)
- if (!allSucceeded) {
+ if (uploadResult !== 'ALL_SUCCEEDED') {
return
}
diff --git a/apps/judicial-system/web/src/utils/hooks/index.ts b/apps/judicial-system/web/src/utils/hooks/index.ts
index cc4edd7be94a..b2b9f733f759 100644
--- a/apps/judicial-system/web/src/utils/hooks/index.ts
+++ b/apps/judicial-system/web/src/utils/hooks/index.ts
@@ -1,9 +1,12 @@
-export type { UpdateCase } from './useCase'
-export { default as useCase, formatDateForServer } from './useCase'
+export {
+ type UpdateCase,
+ default as useCase,
+ formatDateForServer,
+} from './useCase'
export { default as useFileList } from './useFileList'
export { default as useInstitution } from './useInstitution'
-export type { TUploadFile } from './useS3Upload/useS3Upload'
export {
+ type TUploadFile,
useUploadFiles,
default as useS3Upload,
} from './useS3Upload/useS3Upload'
@@ -11,14 +14,17 @@ export { useGetLawyers, useGetLawyer } from './useLawyers/useLawyers'
export { default as useDeb } from './useDeb'
export { default as useViewport } from './useViewport/useViewport'
export { default as useOnceOn } from './useOnceOn'
-export type { CaseFileStatus, CaseFileWithStatus } from './useCourtUpload'
-export { UploadState, useCourtUpload } from './useCourtUpload'
+export {
+ type CaseFileStatus,
+ type CaseFileWithStatus,
+ UploadState,
+ useCourtUpload,
+} from './useCourtUpload'
export {
getAppealDecision,
default as useAppealAlertBanner,
} from './useAppealAlertBanner'
export { default as useSort } from './useSort/useSort'
-
export { useGeoLocation } from './useGeoLocation/useGeoLocation'
export { default as useDefendants } from './useDefendants'
export {
diff --git a/apps/judicial-system/web/src/utils/hooks/useS3Upload/useS3Upload.ts b/apps/judicial-system/web/src/utils/hooks/useS3Upload/useS3Upload.ts
index 3da35cabd7a8..d47a6ad001f6 100644
--- a/apps/judicial-system/web/src/utils/hooks/useS3Upload/useS3Upload.ts
+++ b/apps/judicial-system/web/src/utils/hooks/useS3Upload/useS3Upload.ts
@@ -312,9 +312,17 @@ const useS3Upload = (caseId: string) => {
}
})
- return Promise.all(promises).then((results) =>
- results.every((result) => result),
- )
+ return Promise.all(promises).then((results) => {
+ if (results.every((result) => result)) {
+ return 'ALL_SUCCEEDED'
+ }
+
+ if (results.some((result) => result)) {
+ return 'SOME_SUCCEEDED'
+ }
+
+ return 'NONE_SUCCEEDED'
+ })
},
[getPresignedPost, addFileToCaseState, formatMessage],
)
diff --git a/libs/judicial-system/types/src/lib/notification.ts b/libs/judicial-system/types/src/lib/notification.ts
index 1860778fdedf..410ef203879e 100644
--- a/libs/judicial-system/types/src/lib/notification.ts
+++ b/libs/judicial-system/types/src/lib/notification.ts
@@ -18,6 +18,7 @@ export enum NotificationType {
INDICTMENT_DENIED = 'INDICTMENT_DENIED',
INDICTMENT_RETURNED = 'INDICTMENT_RETURNED',
INDICTMENTS_WAITING_FOR_CONFIRMATION = 'INDICTMENTS_WAITING_FOR_CONFIRMATION',
+ CASE_FILES_UPDATED = 'CASE_FILES_UPDATED',
SERVICE_SUCCESSFUL = 'SERVICE_SUCCESSFUL',
SERVICE_FAILED = 'SERVICE_FAILED',
DEFENDANT_SELECTED_DEFENDER = 'DEFENDANT_SELECTED_DEFENDER',