Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(j-s): Add received date and new table state tag for indictment prison cases #17279

Merged
merged 15 commits into from
Dec 19, 2024
Merged
Show file tree
Hide file tree
Changes from 7 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
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,9 @@ export class Defendant {
@Field(() => String, { nullable: true })
readonly sentToPrisonAdminDate?: string

@Field(() => String, { nullable: true })
readonly openedByPrisonAdminDate?: string

@Field(() => PunishmentType, { nullable: true })
readonly punishmentType?: PunishmentType
}
Original file line number Diff line number Diff line change
Expand Up @@ -417,6 +417,16 @@ export const caseListInclude: Includeable[] = [
as: 'defendants',
required: false,
order: [['created', 'ASC']],
include: [
{
model: DefendantEventLog,
as: 'eventLogs',
required: false,
where: { eventType: defendantEventTypes },
order: [['created', 'DESC']],
separate: true,
},
],
separate: true,
},
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import {
NestInterceptor,
} from '@nestjs/common'

import { DefendantEventType } from '@island.is/judicial-system/types'

import { Defendant, DefendantEventLog } from '../../defendant'
import { Case } from '../models/case.model'
import { CaseString } from '../models/caseString.model'
Expand All @@ -15,8 +17,15 @@ export const transformDefendants = (defendants?: Defendant[]) => {
return defendants?.map((defendant) => ({
...defendant.toJSON(),
sentToPrisonAdminDate: defendant.isSentToPrisonAdmin
? DefendantEventLog.sentToPrisonAdminDate(defendant.eventLogs)?.created
? DefendantEventLog.getDefendantEventLogTypeDate({
defendantEventLogs: defendant.eventLogs,
eventType: DefendantEventType.SENT_TO_PRISON_ADMIN,
})
: undefined,
openedByPrisonAdminDate: DefendantEventLog.getDefendantEventLogTypeDate({
defendantEventLogs: defendant.eventLogs,
eventType: DefendantEventType.OPENED_BY_PRISON_ADMIN,
}),
}))
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import {
CallHandler,
ExecutionContext,
Injectable,
NestInterceptor,
} from '@nestjs/common'

import {
DefendantEventType,
isIndictmentCase,
isPrisonAdminUser,
User,
} from '@island.is/judicial-system/types'

import { DefendantEventLog, DefendantService } from '../../defendant'
import { Case } from '../models/case.model'

const hasValidOpenByPrisonAdminEvent = (
gudjong marked this conversation as resolved.
Show resolved Hide resolved
defendantEventLogs: DefendantEventLog[],
) => {
const sentToPrisonAdminDate = DefendantEventLog.getDefendantEventLogTypeDate({
defendantEventLogs,
eventType: DefendantEventType.SENT_TO_PRISON_ADMIN,
})
const openedByPrisonAdminDate =
DefendantEventLog.getDefendantEventLogTypeDate({
defendantEventLogs,
eventType: DefendantEventType.OPENED_BY_PRISON_ADMIN,
})
return (
sentToPrisonAdminDate &&
openedByPrisonAdminDate &&
sentToPrisonAdminDate <= openedByPrisonAdminDate
)
}

@Injectable()
export class DefendantIndictmentAccessedInterceptor implements NestInterceptor {
unakb marked this conversation as resolved.
Show resolved Hide resolved
constructor(private readonly defendantService: DefendantService) {}

intercept(context: ExecutionContext, next: CallHandler) {
const request = context.switchToHttp().getRequest()
const user: User = request.user
const theCase: Case = request.case

if (
isIndictmentCase(theCase.type) &&
isPrisonAdminUser(user)
) {
const defendantsIndictmentNotOpened = theCase.defendants?.filter(
({ isSentToPrisonAdmin, eventLogs = [] }) => isSentToPrisonAdmin && !hasValidOpenByPrisonAdminEvent(eventLogs),
)

// create new events for all defendants that prison admin has not accessed according to defendant event logs
defendantsIndictmentNotOpened?.forEach((defendant) =>
this.defendantService.createDefendantEvent({
caseId: theCase.id,
defendantId: defendant.id,
eventType: DefendantEventType.OPENED_BY_PRISON_ADMIN,
}),
)
}
return next.handle()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,16 @@ import type { User as TUser } from '@island.is/judicial-system/types'
import {
CaseState,
CaseType,
DefendantEventType,
indictmentCases,
investigationCases,
restrictionCases,
UserRole,
} from '@island.is/judicial-system/types'

import { nowFactory } from '../../factories'
import { defenderRule, prisonSystemStaffRule } from '../../guards'
import { DefendantService } from '../defendant'
import { EventService } from '../event'
import { User } from '../user'
import { TransitionCaseDto } from './dto/transitionCase.dto'
Expand All @@ -57,6 +60,7 @@ import {
} from './guards/rolesRules'
import { CaseInterceptor } from './interceptors/case.interceptor'
import { CompletedAppealAccessedInterceptor } from './interceptors/completedAppealAccessed.interceptor'
import { DefendantIndictmentAccessedInterceptor } from './interceptors/defendantIndictmentAccessed.interceptor'
import { LimitedAccessCaseFileInterceptor } from './interceptors/limitedAccessCaseFile.interceptor'
import { Case } from './models/case.model'
import { transitionCase } from './state/case.state'
Expand All @@ -73,6 +77,7 @@ export class LimitedAccessCaseController {
private readonly limitedAccessCaseService: LimitedAccessCaseService,
private readonly eventService: EventService,
private readonly pdfService: PdfService,
private readonly defendantService: DefendantService,
@Inject(LOGGER_PROVIDER) private readonly logger: Logger,
) {}

Expand All @@ -84,6 +89,7 @@ export class LimitedAccessCaseController {
)
@RolesRules(prisonSystemStaffRule, defenderRule)
@UseInterceptors(
DefendantIndictmentAccessedInterceptor,
CompletedAppealAccessedInterceptor,
LimitedAccessCaseFileInterceptor,
CaseInterceptor,
Expand All @@ -100,7 +106,7 @@ export class LimitedAccessCaseController {
): Promise<Case> {
this.logger.debug(`Getting limitedAccess case ${caseId} by id`)

if (!theCase.openedByDefender) {
if (user.role === UserRole.DEFENDER && !theCase.openedByDefender) {
unakb marked this conversation as resolved.
Show resolved Hide resolved
const updated = await this.limitedAccessCaseService.update(
theCase,
{ openedByDefender: nowFactory() },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,22 @@ export class DefendantService {
return updatedDefendant
}

async createDefendantEvent({
caseId,
defendantId,
eventType,
}: {
caseId: string
defendantId: string
eventType: DefendantEventType
}): Promise<void> {
await this.defendantEventLogModel.create({
caseId,
defendantId,
eventType,
})
}

async updateIndictmentCaseDefendant(
theCase: Case,
defendant: Defendant,
Expand All @@ -284,7 +300,7 @@ export class DefendantService {
)

if (update.isSentToPrisonAdmin) {
this.defendantEventLogModel.create({
this.createDefendantEvent({
caseId: theCase.id,
defendantId: defendant.id,
eventType: DefendantEventType.SENT_TO_PRISON_ADMIN,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,17 @@ import { Defendant } from './defendant.model'
timestamps: true,
})
export class DefendantEventLog extends Model {
static sentToPrisonAdminDate(defendantEventLogs?: DefendantEventLog[]) {
// gets the latest log date of a given type, since the defendant event logs are sorted
static getDefendantEventLogTypeDate({
defendantEventLogs,
eventType,
}: {
defendantEventLogs?: DefendantEventLog[]
eventType: DefendantEventType
}) {
return defendantEventLogs?.find(
(defendantEventLog) =>
defendantEventLog.eventType === DefendantEventType.SENT_TO_PRISON_ADMIN,
)
(defendantEventLog) => defendantEventLog.eventType === eventType,
)?.created
}

@Column({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ query Case($input: CaseQueryInput!) {
subpoenaType
isSentToPrisonAdmin
sentToPrisonAdminDate
openedByPrisonAdminDate
punishmentType
subpoenas {
id
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ query LimitedAccessCase($input: CaseQueryInput!) {
subpoenaType
isSentToPrisonAdmin
sentToPrisonAdminDate
openedByPrisonAdminDate
punishmentType
subpoenas {
id
Expand Down
14 changes: 14 additions & 0 deletions apps/judicial-system/web/src/components/Tags/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,3 +119,17 @@ export const getIndictmentRulingDecisionTag = (
return { color: 'darkerBlue', text: strings.complete }
}
}

export const getPrisonCaseStatusTag = (prisonCaseState: CaseState): {
color: TagVariant
text: { id: string; defaultMessage: string; description: string }
} => {
switch (prisonCaseState) {
case CaseState.NEW:
return { color: 'purple', text: strings.new }
case CaseState.RECEIVED:
return { color: 'blue', text: strings.received }
default:
return { color: 'darkerBlue', text: strings.complete }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,12 @@ export const strings = defineMessages({
indictmentCompletedTitle: {
id: 'judicial.system.core:indictment_overview.indictment_completed_title',
defaultMessage: 'Dómsuppkvaðning {date}',
description: 'Titill á yfirliti ákæru fyrir fangelsi',
description: 'Undirtitill á yfirliti ákæru fyrir fangelsi',
},
indictmentReceivedTitle: {
id: 'judicial.system.core:indictment_overview.indictment_received_title',
defaultMessage: 'Móttekið {date}',
description: 'Undirtitill á yfirliti ákæru fyrir fangelsi',
},
infoCardDefendantsTitle: {
id: 'judicial.system.core:indictment_overview.info_card_defendants_title',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,13 @@ const IndictmentOverview = () => {
})}
</Text>
)}
{defendant?.openedByPrisonAdminDate && (
<Text variant="h4" as="h3">
{formatMessage(strings.indictmentReceivedTitle, {
date: formatDate(defendant.openedByPrisonAdminDate, 'PPP'),
})}
</Text>
)}
</Box>
<Box marginBottom={5}>
<InfoCardClosedIndictment displayVerdictViewDate />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
titles,
} from '@island.is/judicial-system-web/messages'
import {
CaseTag,
Logo,
PageHeader,
SectionHeading,
Expand All @@ -31,6 +32,8 @@ import {
getDurationDate,
} from '@island.is/judicial-system-web/src/components/Table'
import Table from '@island.is/judicial-system-web/src/components/Table/Table'
import { strings as tagCaseStateStrings } from '@island.is/judicial-system-web/src/components/TagCaseState/TagCaseState.strings'
import { getPrisonCaseStatusTag } from '@island.is/judicial-system-web/src/components/Tags/utils'
import {
CaseListEntry,
CaseState,
Expand Down Expand Up @@ -217,11 +220,23 @@ export const PrisonCases: FC = () => {
),
},
{
cell: () => (
<Tag variant="purple" outlined disabled truncate>
{'Nýtt'}
</Tag>
),
cell: (row) => {
const prisonCaseState =
row.defendants &&
row.defendants?.length > 0 &&
row.defendants[0].openedByPrisonAdminDate
? CaseState.RECEIVED
: CaseState.NEW
const prisonCaseStateTag =
getPrisonCaseStatusTag(prisonCaseState)

return (
<CaseTag
color={prisonCaseStateTag.color}
text={formatMessage(prisonCaseStateTag.text)}
/>
)
},
},
]}
generateContextMenuItems={(row) => [openCaseInNewTabMenuItem(row.id)]}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ query Cases {
defenderChoice
verdictViewDate
isSentToPrisonAdmin
openedByPrisonAdminDate
}
courtDate
isValidToDateInThePast
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ query PrisonCases {
name
noNationalId
defenderChoice
openedByPrisonAdminDate
}
courtDate
isValidToDateInThePast
Expand Down
1 change: 1 addition & 0 deletions libs/judicial-system/types/src/lib/eventLog.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export const eventTypes = Object.values(EventType)

export enum DefendantEventType {
SENT_TO_PRISON_ADMIN = 'SENT_TO_PRISON_ADMIN',
OPENED_BY_PRISON_ADMIN = 'OPENED_BY_PRISON_ADMIN',
}

export const defendantEventTypes = Object.values(DefendantEventType)
Loading