From 4b82fdf21ef700b0fd5d5e85b061977088ba4865 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=8Dvar=20Oddsson?= Date: Tue, 28 May 2024 15:18:08 +0000 Subject: [PATCH 01/47] Add POSTPONED_TO_VERDICT radio button --- .../Conclusion/Conclusion.strings.ts | 18 ++++++ .../Indictments/Conclusion/Conclusion.tsx | 60 ++++++++++++++++++- 2 files changed, 76 insertions(+), 2 deletions(-) diff --git a/apps/judicial-system/web/src/routes/Court/Indictments/Conclusion/Conclusion.strings.ts b/apps/judicial-system/web/src/routes/Court/Indictments/Conclusion/Conclusion.strings.ts index 754da4c18635..6a22a314e854 100644 --- a/apps/judicial-system/web/src/routes/Court/Indictments/Conclusion/Conclusion.strings.ts +++ b/apps/judicial-system/web/src/routes/Court/Indictments/Conclusion/Conclusion.strings.ts @@ -17,17 +17,35 @@ export const strings = defineMessages({ defaultMessage: 'Frestun', description: 'Notaður sem texti fyrir frestun valkost á Niðurstaða skrefi.', }, + postponedUntilVerdict: { + id: 'judicial.system.core:court.indictments.conclusion.postponed_until_verdict', + defaultMessage: 'Dómtekið', + description: + 'Notaður sem texti fyrir dómtekið valkost á Niðurstaða skrefi.', + }, complete: { id: 'judicial.system.core:court.indictments.conclusion.complete', defaultMessage: 'Lokið', description: 'Notaður sem texti fyrir lokið valkost á Niðurstaða skrefi.', }, + arrangeVerdictTitle: { + id: 'judicial.system.core:court.indictments.conclusion.arrange_verdict', + defaultMessage: 'Dómsuppkvaðning', + description: + 'Notaður sem texti fyrir Dómsuppkvaðning valkost á Niðurstaða skrefi.', + }, arrangeAnotherHearing: { id: 'judicial.system.core:court.indictments.conclusion.arrange_another_hearing', defaultMessage: 'Bóka annað þinghald', description: 'Notaður sem texti fyrir bóka annað þinghald valkost á Niðurstaða skrefi.', }, + arrangeVerdict: { + id: 'judicial.system.core:court.indictments.conclusion.postpone_until_verdict', + defaultMessage: 'Boða til dómsuppkvaðningar', + description: + 'Notaður sem texti fyrir boða til dómsuppkvaðningar valkost á Niðurstaða skrefi.', + }, postponedIndefinitely: { id: 'judicial.system.core:court.indictments.conclusion.postponed_indefinitely', defaultMessage: 'Frestað um ótilgreindan tíma', diff --git a/apps/judicial-system/web/src/routes/Court/Indictments/Conclusion/Conclusion.tsx b/apps/judicial-system/web/src/routes/Court/Indictments/Conclusion/Conclusion.tsx index 02feab53e48a..89081c42a499 100644 --- a/apps/judicial-system/web/src/routes/Court/Indictments/Conclusion/Conclusion.tsx +++ b/apps/judicial-system/web/src/routes/Court/Indictments/Conclusion/Conclusion.tsx @@ -16,6 +16,7 @@ import { BlueBox, CourtArrangements, CourtCaseInfo, + DateTime, FormContentContainer, FormContext, FormFooter, @@ -39,13 +40,18 @@ import { import { strings } from './Conclusion.strings' -type Actions = 'POSTPONE' | 'REDISTRIBUTE' | 'COMPLETE' +type Actions = + | 'POSTPONE' + | 'REDISTRIBUTE' + | 'COMPLETE' + | 'POSTPONE_UNTIL_VERDICT' type Decision = | CaseIndictmentRulingDecision.FINE | CaseIndictmentRulingDecision.RULING interface Postponement { postponedIndefinitely?: boolean + postonedUntilVerdict?: boolean reason?: string } @@ -57,6 +63,7 @@ const Conclusion: React.FC = () => { const [selectedAction, setSelectedAction] = useState() const [selectedDecision, setSelectedDecision] = useState() const [postponement, setPostponement] = useState() + const { courtDate, handleCourtDateChange, @@ -217,6 +224,19 @@ const Conclusion: React.FC = () => { label={formatMessage(strings.postponed)} /> + + { + setSelectedAction('POSTPONE_UNTIL_VERDICT') + }} + large + backgroundColor="white" + label={formatMessage(strings.postponedUntilVerdict)} + /> + { )} + {selectedAction === 'POSTPONE_UNTIL_VERDICT' && ( + + + + + { + setPostponement((prev) => ({ + ...prev, + postonedUntilVerdict: !prev?.postonedUntilVerdict, + })) + }} + large + backgroundColor="white" + label={formatMessage(strings.arrangeVerdict)} + /> + + { + console.log('asd') + }} + blueBox={false} + disabled={!postponement?.postonedUntilVerdict} + /> + + + )} {selectedAction === 'COMPLETE' && ( @@ -332,7 +385,10 @@ const Conclusion: React.FC = () => { )} {selectedAction && ( - + Date: Tue, 28 May 2024 16:13:46 +0000 Subject: [PATCH 02/47] Change Radio to Checkbox --- .../src/routes/Court/Indictments/Conclusion/Conclusion.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/judicial-system/web/src/routes/Court/Indictments/Conclusion/Conclusion.tsx b/apps/judicial-system/web/src/routes/Court/Indictments/Conclusion/Conclusion.tsx index 89081c42a499..d37a12517d03 100644 --- a/apps/judicial-system/web/src/routes/Court/Indictments/Conclusion/Conclusion.tsx +++ b/apps/judicial-system/web/src/routes/Court/Indictments/Conclusion/Conclusion.tsx @@ -325,7 +325,7 @@ const Conclusion: React.FC = () => { /> - { postonedUntilVerdict: !prev?.postonedUntilVerdict, })) }} - large backgroundColor="white" label={formatMessage(strings.arrangeVerdict)} + large + filled /> Date: Wed, 29 May 2024 10:21:02 +0000 Subject: [PATCH 03/47] Add column to Case table -- IndictmentDecision --- .../app/modules/case/dto/updateCase.input.ts | 7 ++++ .../src/app/modules/case/models/case.model.ts | 5 +++ .../migrations/20240528163733-update-case.js | 32 +++++++++++++++++++ .../app/modules/case/dto/updateCase.dto.ts | 6 ++++ .../src/app/modules/case/models/case.model.ts | 12 +++++++ .../src/components/FormProvider/case.graphql | 1 + .../utils/hooks/useCase/updateCase.graphql | 1 + libs/judicial-system/types/src/index.ts | 1 + libs/judicial-system/types/src/lib/case.ts | 7 ++++ 9 files changed, 72 insertions(+) create mode 100644 apps/judicial-system/backend/migrations/20240528163733-update-case.js diff --git a/apps/judicial-system/api/src/app/modules/case/dto/updateCase.input.ts b/apps/judicial-system/api/src/app/modules/case/dto/updateCase.input.ts index 0f1a1017aa6d..95e833d4f400 100644 --- a/apps/judicial-system/api/src/app/modules/case/dto/updateCase.input.ts +++ b/apps/judicial-system/api/src/app/modules/case/dto/updateCase.input.ts @@ -25,6 +25,7 @@ import { CaseLegalProvisions, CaseType, IndictmentCaseReviewDecision, + IndictmentDecision, RequestSharedWithDefender, SessionArrangements, UserRole, @@ -486,6 +487,12 @@ export class UpdateCaseInput { readonly indictmentReviewerId?: string @Allow() + @IsOptional() @Field(() => IndictmentCaseReviewDecision, { nullable: true }) readonly indictmentReviewDecision?: IndictmentCaseReviewDecision + + @Allow() + @IsOptional() + @Field(() => IndictmentDecision, { nullable: true }) + readonly indictmentDecision?: IndictmentDecision } diff --git a/apps/judicial-system/api/src/app/modules/case/models/case.model.ts b/apps/judicial-system/api/src/app/modules/case/models/case.model.ts index 9106303bbec5..9973ee3a7191 100644 --- a/apps/judicial-system/api/src/app/modules/case/models/case.model.ts +++ b/apps/judicial-system/api/src/app/modules/case/models/case.model.ts @@ -19,6 +19,7 @@ import { CaseType, CourtDocument, IndictmentCaseReviewDecision, + IndictmentDecision, RequestSharedWithDefender, SessionArrangements, UserRole, @@ -51,6 +52,7 @@ registerEnumType(CaseIndictmentRulingDecision, { registerEnumType(IndictmentCaseReviewDecision, { name: 'IndictmentCaseReviewDecision', }) +registerEnumType(IndictmentDecision, { name: 'IndictmentDecision' }) @ObjectType() class DateLog { @@ -434,4 +436,7 @@ export class Case { @Field(() => String, { nullable: true }) readonly indictmentVerdictAppealDeadline?: string + + @Field(() => IndictmentDecision, { nullable: true }) + readonly indictmentDecision?: IndictmentDecision } diff --git a/apps/judicial-system/backend/migrations/20240528163733-update-case.js b/apps/judicial-system/backend/migrations/20240528163733-update-case.js new file mode 100644 index 000000000000..9e2e17c3de56 --- /dev/null +++ b/apps/judicial-system/backend/migrations/20240528163733-update-case.js @@ -0,0 +1,32 @@ +'use strict' + +module.exports = { + async up(queryInterface, Sequelize) { + return queryInterface.sequelize.transaction((t) => + queryInterface.addColumn( + 'case', + 'indictment_decision', + { + type: Sequelize.STRING, + allowNull: true, + }, + { transaction: t }, + ), + ) + }, + + async down(queryInterface) { + return queryInterface.sequelize.transaction((t) => + queryInterface + .removeColumn('case', 'indictment_decision', { + transaction: t, + }) + .then(() => { + queryInterface.sequelize.query( + 'DROP TYPE "enum_case_indictment_decision";', + { transaction: t }, + ) + }), + ) + }, +} diff --git a/apps/judicial-system/backend/src/app/modules/case/dto/updateCase.dto.ts b/apps/judicial-system/backend/src/app/modules/case/dto/updateCase.dto.ts index 22375301121d..f5cd707ef59d 100644 --- a/apps/judicial-system/backend/src/app/modules/case/dto/updateCase.dto.ts +++ b/apps/judicial-system/backend/src/app/modules/case/dto/updateCase.dto.ts @@ -28,6 +28,7 @@ import { CaseType, CourtDocument, IndictmentCaseReviewDecision, + IndictmentDecision, RequestSharedWithDefender, SessionArrangements, UserRole, @@ -496,4 +497,9 @@ export class UpdateCaseDto { @IsEnum(IndictmentCaseReviewDecision) @ApiPropertyOptional({ enum: IndictmentCaseReviewDecision }) readonly indictmentReviewDecision?: IndictmentCaseReviewDecision + + @IsOptional() + @IsEnum(IndictmentDecision) + @ApiPropertyOptional({ enum: IndictmentDecision }) + readonly indictmentDecision?: IndictmentDecision } diff --git a/apps/judicial-system/backend/src/app/modules/case/models/case.model.ts b/apps/judicial-system/backend/src/app/modules/case/models/case.model.ts index 81117d9db4cf..fbac4b0d76e2 100644 --- a/apps/judicial-system/backend/src/app/modules/case/models/case.model.ts +++ b/apps/judicial-system/backend/src/app/modules/case/models/case.model.ts @@ -30,6 +30,7 @@ import { CaseType, CourtDocument, IndictmentCaseReviewDecision, + IndictmentDecision, RequestSharedWithDefender, SessionArrangements, UserRole, @@ -1013,4 +1014,15 @@ export class Case extends Model { }) @ApiPropertyOptional({ enum: IndictmentCaseReviewDecision }) indictmentReviewDecision?: IndictmentCaseReviewDecision + + /********** + * The judge's pending decision in indictment cases - example: POSTPONING + **********/ + @Column({ + type: DataType.ENUM, + allowNull: true, + values: Object.values(IndictmentDecision), + }) + @ApiPropertyOptional({ enum: IndictmentDecision }) + indictmentDecision?: IndictmentDecision } diff --git a/apps/judicial-system/web/src/components/FormProvider/case.graphql b/apps/judicial-system/web/src/components/FormProvider/case.graphql index a38e90c4fc42..773d00f7c1be 100644 --- a/apps/judicial-system/web/src/components/FormProvider/case.graphql +++ b/apps/judicial-system/web/src/components/FormProvider/case.graphql @@ -263,5 +263,6 @@ query Case($input: CaseQueryInput!) { indictmentAppealDeadline indictmentVerdictViewedByAll indictmentVerdictAppealDeadline + indictmentDecision } } diff --git a/apps/judicial-system/web/src/utils/hooks/useCase/updateCase.graphql b/apps/judicial-system/web/src/utils/hooks/useCase/updateCase.graphql index f9f3a850d7d6..2698876687b6 100644 --- a/apps/judicial-system/web/src/utils/hooks/useCase/updateCase.graphql +++ b/apps/judicial-system/web/src/utils/hooks/useCase/updateCase.graphql @@ -219,5 +219,6 @@ mutation UpdateCase($input: UpdateCaseInput!) { } indictmentDeniedExplanation indictmentReturnedExplanation + indictmentDecision } } diff --git a/libs/judicial-system/types/src/index.ts b/libs/judicial-system/types/src/index.ts index 2e9249225945..b66524a36e1a 100644 --- a/libs/judicial-system/types/src/index.ts +++ b/libs/judicial-system/types/src/index.ts @@ -55,6 +55,7 @@ export { restrictionCases, investigationCases, IndictmentCaseReviewDecision, + IndictmentDecision, isIndictmentCase, isRestrictionCase, isInvestigationCase, diff --git a/libs/judicial-system/types/src/lib/case.ts b/libs/judicial-system/types/src/lib/case.ts index 64aaaf215897..9aca6a3d7c5e 100644 --- a/libs/judicial-system/types/src/lib/case.ts +++ b/libs/judicial-system/types/src/lib/case.ts @@ -215,6 +215,13 @@ export enum CaseDecision { DISMISSING = 'DISMISSING', } +export enum IndictmentDecision { + POSTPONING = 'POSTPONING', + REDISTRIBUTING = 'REDISTRIBUTING', + COMPLETING = 'COMPLETING', + POSTPONING_UNTIL_VERDICT = 'POSTPONING_UNTIL_VERDICT', +} + export enum CaseAppealRulingDecision { ACCEPTING = 'ACCEPTING', REPEAL = 'REPEAL', From 4a3ec3fe7dd9498a982cda0365fde2b37beea6a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=8Dvar=20Oddsson?= Date: Wed, 29 May 2024 14:08:00 +0000 Subject: [PATCH 04/47] Update IndictmentDecision --- .../src/app/modules/case/guards/rolesRules.ts | 1 + .../Conclusion/Conclusion.strings.ts | 6 +- .../Indictments/Conclusion/Conclusion.tsx | 238 +++++++++++++----- .../web/src/utils/formHelper.ts | 2 + .../web/src/utils/hooks/useCase/index.ts | 9 +- libs/judicial-system/types/src/lib/case.ts | 4 +- 6 files changed, 183 insertions(+), 77 deletions(-) diff --git a/apps/judicial-system/backend/src/app/modules/case/guards/rolesRules.ts b/apps/judicial-system/backend/src/app/modules/case/guards/rolesRules.ts index c36d5d7d0266..caf236254b97 100644 --- a/apps/judicial-system/backend/src/app/modules/case/guards/rolesRules.ts +++ b/apps/judicial-system/backend/src/app/modules/case/guards/rolesRules.ts @@ -91,6 +91,7 @@ const districtCourtFields: (keyof UpdateCaseDto)[] = [ 'indictmentReturnedExplanation', 'postponedIndefinitelyExplanation', 'indictmentRulingDecision', + 'indictmentDecision', ] const courtOfAppealsFields: (keyof UpdateCaseDto)[] = [ diff --git a/apps/judicial-system/web/src/routes/Court/Indictments/Conclusion/Conclusion.strings.ts b/apps/judicial-system/web/src/routes/Court/Indictments/Conclusion/Conclusion.strings.ts index 6a22a314e854..31de51f7f5dc 100644 --- a/apps/judicial-system/web/src/routes/Court/Indictments/Conclusion/Conclusion.strings.ts +++ b/apps/judicial-system/web/src/routes/Court/Indictments/Conclusion/Conclusion.strings.ts @@ -82,10 +82,10 @@ export const strings = defineMessages({ description: 'Notaður sem titill á hlaða upp takka á Niðurstaða skrefi.', }, redistribute: { - id: 'judicial.system.core:court.indictments.conclusion.redistribute', - defaultMessage: 'Fer í útlutun til dómara', + id: 'judicial.system.core:court.indictments.conclusion.redistribute_v1', + defaultMessage: 'Fer í úthlutun til dómara', description: - 'Notaður sem texti fyrir Fer í útlutun til dómara á Niðurstaða skrefi.', + 'Notaður sem texti fyrir Fer í úthlutun til dómara á Niðurstaða skrefi.', }, decision: { id: 'judicial.system.core:court.indictments.conclusion.decision', diff --git a/apps/judicial-system/web/src/routes/Court/Indictments/Conclusion/Conclusion.tsx b/apps/judicial-system/web/src/routes/Court/Indictments/Conclusion/Conclusion.tsx index d37a12517d03..521949a778db 100644 --- a/apps/judicial-system/web/src/routes/Court/Indictments/Conclusion/Conclusion.tsx +++ b/apps/judicial-system/web/src/routes/Court/Indictments/Conclusion/Conclusion.tsx @@ -30,6 +30,7 @@ import { CaseFileCategory, CaseIndictmentRulingDecision, CaseTransition, + IndictmentDecision, } from '@island.is/judicial-system-web/src/graphql/schema' import { stepValidationsType } from '@island.is/judicial-system-web/src/utils/formHelper' import { @@ -40,11 +41,6 @@ import { import { strings } from './Conclusion.strings' -type Actions = - | 'POSTPONE' - | 'REDISTRIBUTE' - | 'COMPLETE' - | 'POSTPONE_UNTIL_VERDICT' type Decision = | CaseIndictmentRulingDecision.FINE | CaseIndictmentRulingDecision.RULING @@ -60,7 +56,7 @@ const Conclusion: React.FC = () => { const { workingCase, setWorkingCase, isLoadingWorkingCase, caseNotFound } = useContext(FormContext) - const [selectedAction, setSelectedAction] = useState() + const [selectedAction, setSelectedAction] = useState() const [selectedDecision, setSelectedDecision] = useState() const [postponement, setPostponement] = useState() @@ -85,76 +81,173 @@ const Conclusion: React.FC = () => { workingCase.id, ) - const handleRedistribution = useCallback(async () => { - const transitionSuccessful = await transitionCase( - workingCase.id, - CaseTransition.REDISTRIBUTE, - ) + const handleRedistribution = useCallback( + async (destination: string) => { + const transitionSuccessful = await transitionCase( + workingCase.id, + CaseTransition.REDISTRIBUTE, + ) - if (transitionSuccessful) { - router.push(constants.CASES_ROUTE) - } else { - toast.error(formatMessage(errors.transitionCase)) - } - }, [transitionCase, workingCase.id, formatMessage]) - - const handleCompletion = useCallback(async () => { - await setAndSendCaseToServer( - [ - { - indictmentRulingDecision: selectedDecision, - force: true, - }, - ], - workingCase, + const success = await setAndSendCaseToServer( + [ + { + indictmentDecision: IndictmentDecision.REDISTRIBUTING, + force: true, + }, + ], + workingCase, + setWorkingCase, + ) + + if (!transitionSuccessful || !success) { + return + } + + router.push(destination) + }, + [setAndSendCaseToServer, setWorkingCase, transitionCase, workingCase], + ) + + const handleCompletion = useCallback( + async (destination: string) => { + const success = await setAndSendCaseToServer( + [ + { + indictmentRulingDecision: selectedDecision, + indictmentDecision: IndictmentDecision.COMPLETING, + force: true, + }, + ], + workingCase, + setWorkingCase, + ) + + if (!success) { + return + } + + router.push(`${destination}/${workingCase.id}`) + }, + [selectedDecision, setAndSendCaseToServer, setWorkingCase, workingCase], + ) + + const handlePostponementUntilVerdict = useCallback( + async (destination: string) => { + const success = await setAndSendCaseToServer( + [ + { + indictmentDecision: IndictmentDecision.POSTPONING_UNTIL_VERDICT, + force: true, + }, + ], + workingCase, + setWorkingCase, + ) + + if (!success) { + return + } + + router.push(`${destination}/${workingCase.id}`) + }, + [setAndSendCaseToServer, setWorkingCase, workingCase], + ) + + const handlePostponementIndefinitely = useCallback( + async (destination: string) => { + const updateSuccess = await setAndSendCaseToServer( + [ + { + courtDate: null, + postponedIndefinitelyExplanation: postponement?.reason, + }, + ], + workingCase, + setWorkingCase, + ) + + if (!updateSuccess) { + return + } + + router.push(`${destination}/${workingCase.id}`) + }, + [postponement?.reason, setAndSendCaseToServer, setWorkingCase, workingCase], + ) + + const handlePostponement = useCallback( + async (destination: string) => { + const updateCourtDateSuccess = await sendCourtDateToServer([ + { postponedIndefinitelyExplanation: null, force: true }, + ]) + + const updateSuccess = await setAndSendCaseToServer( + [ + { + indictmentDecision: IndictmentDecision.POSTPONING, + }, + ], + workingCase, + setWorkingCase, + ) + + if (!updateCourtDateSuccess || !updateSuccess) { + return + } + + router.push(`${destination}/${workingCase.id}`) + }, + [ + sendCourtDateToServer, + setAndSendCaseToServer, setWorkingCase, - ) - }, [selectedDecision, setAndSendCaseToServer, setWorkingCase, workingCase]) + workingCase, + ], + ) const handleNavigationTo = useCallback( async (destination: keyof stepValidationsType) => { - if (selectedAction === 'REDISTRIBUTE') { - handleRedistribution() - } else if (selectedAction === 'COMPLETE') { - handleCompletion() + if (selectedAction === IndictmentDecision.REDISTRIBUTING) { + handleRedistribution(destination) + } else if (selectedAction === IndictmentDecision.COMPLETING) { + handleCompletion(destination) + } else if ( + selectedAction === IndictmentDecision.POSTPONING_UNTIL_VERDICT + ) { + await handlePostponementUntilVerdict(destination) } else if (postponement?.postponedIndefinitely) { - const updateSuccess = await updateCase(workingCase.id, { - courtDate: null, - postponedIndefinitelyExplanation: postponement.reason, - }) - - if (!updateSuccess) { - return - } + handlePostponementIndefinitely(destination) } else { - await sendCourtDateToServer([ - { postponedIndefinitelyExplanation: null, force: true }, - ]) + handlePostponement(destination) } - - router.push(`${destination}/${workingCase.id}`) }, [ selectedAction, postponement?.postponedIndefinitely, - postponement?.reason, - workingCase.id, handleRedistribution, handleCompletion, - updateCase, - sendCourtDateToServer, + handlePostponementUntilVerdict, + handlePostponementIndefinitely, + handlePostponement, ], ) + const isDecisionChecked = (decision: IndictmentDecision) => { + return ( + selectedAction === decision || + (!selectedAction && workingCase.indictmentDecision === decision) + ) + } + useEffect(() => { if (workingCase.indictmentRulingDecision) { setSelectedDecision(workingCase.indictmentRulingDecision) - setSelectedAction('COMPLETE') + setSelectedAction(IndictmentDecision.COMPLETING) } else if ( workingCase.courtDate?.date || workingCase.postponedIndefinitelyExplanation ) { - setSelectedAction('POSTPONE') + setSelectedAction(IndictmentDecision.POSTPONING) if (workingCase.postponedIndefinitelyExplanation) { setPostponement({ @@ -176,11 +269,11 @@ const Conclusion: React.FC = () => { return false } - if (selectedAction === 'REDISTRIBUTE') { + if (selectedAction === IndictmentDecision.REDISTRIBUTING) { return uploadFiles.find( (file) => file.category === CaseFileCategory.COURT_RECORD, ) - } else if (selectedAction === 'POSTPONE') { + } else if (selectedAction === IndictmentDecision.POSTPONING) { return ( Boolean( postponement?.postponedIndefinitely @@ -188,8 +281,11 @@ const Conclusion: React.FC = () => { : courtDate?.date, ) && allFilesDoneOrError ) - } else if (selectedAction === 'COMPLETE') { - return selectedDecision !== undefined && allFilesDoneOrError + } else if ( + selectedAction === IndictmentDecision.COMPLETING || + selectedAction === IndictmentDecision.POSTPONING_UNTIL_VERDICT + ) { + return allFilesDoneOrError } } @@ -215,9 +311,9 @@ const Conclusion: React.FC = () => { { - setSelectedAction('POSTPONE') + setSelectedAction(IndictmentDecision.POSTPONING) }} large backgroundColor="white" @@ -228,9 +324,11 @@ const Conclusion: React.FC = () => { { - setSelectedAction('POSTPONE_UNTIL_VERDICT') + setSelectedAction(IndictmentDecision.POSTPONING_UNTIL_VERDICT) }} large backgroundColor="white" @@ -241,9 +339,9 @@ const Conclusion: React.FC = () => { { - setSelectedAction('COMPLETE') + setSelectedAction(IndictmentDecision.COMPLETING) }} large backgroundColor="white" @@ -253,9 +351,9 @@ const Conclusion: React.FC = () => { { - setSelectedAction('REDISTRIBUTE') + setSelectedAction(IndictmentDecision.REDISTRIBUTING) }} large backgroundColor="white" @@ -263,7 +361,7 @@ const Conclusion: React.FC = () => { /> - {selectedAction === 'POSTPONE' && ( + {selectedAction === IndictmentDecision.POSTPONING && ( <> { )} - {selectedAction === 'POSTPONE_UNTIL_VERDICT' && ( + {selectedAction === IndictmentDecision.POSTPONING_UNTIL_VERDICT && ( { )} - {selectedAction === 'COMPLETE' && ( + {selectedAction === IndictmentDecision.COMPLETING && ( @@ -392,7 +490,7 @@ const Conclusion: React.FC = () => { > { previousUrl={`${constants.INDICTMENTS_DEFENDER_ROUTE}/${workingCase.id}`} onNextButtonClick={() => handleNavigationTo( - selectedAction === 'COMPLETE' + selectedAction === IndictmentDecision.COMPLETING ? constants.INDICTMENTS_SUMMARY_ROUTE + : selectedAction === IndictmentDecision.REDISTRIBUTING + ? constants.CASES_ROUTE : constants.INDICTMENTS_COURT_OVERVIEW_ROUTE, ) } diff --git a/apps/judicial-system/web/src/utils/formHelper.ts b/apps/judicial-system/web/src/utils/formHelper.ts index bc47dc522288..0520df1ae177 100644 --- a/apps/judicial-system/web/src/utils/formHelper.ts +++ b/apps/judicial-system/web/src/utils/formHelper.ts @@ -137,6 +137,7 @@ export const hasDateChanged = ( } export type stepValidationsType = { + [constants.CASES_ROUTE]: () => boolean [constants.CREATE_RESTRICTION_CASE_ROUTE]: (theCase: Case) => boolean [constants.CREATE_TRAVEL_BAN_ROUTE]: (theCase: Case) => boolean [constants.RESTRICTION_CASE_DEFENDANT_ROUTE]: (theCase: Case) => boolean @@ -202,6 +203,7 @@ export type stepValidationsType = { export const stepValidations = (): stepValidationsType => { return { + [constants.CASES_ROUTE]: () => true, [constants.CREATE_RESTRICTION_CASE_ROUTE]: (theCase: Case) => validations.isDefendantStepValidRC(theCase, theCase.policeCaseNumbers), [constants.CREATE_TRAVEL_BAN_ROUTE]: (theCase: Case) => diff --git a/apps/judicial-system/web/src/utils/hooks/useCase/index.ts b/apps/judicial-system/web/src/utils/hooks/useCase/index.ts index 8a2d6e6e4ab0..9f0e235aa7e8 100644 --- a/apps/judicial-system/web/src/utils/hooks/useCase/index.ts +++ b/apps/judicial-system/web/src/utils/hooks/useCase/index.ts @@ -385,7 +385,7 @@ const useCase = () => { delete updatesToCase.force if (Object.keys(updatesToCase).length === 0) { - return + return false } setWorkingCase((prevWorkingCase) => ({ @@ -394,16 +394,19 @@ const useCase = () => { })) if (!workingCase.id) { - return + return false } const newWorkingCase = await updateCase(workingCase.id, updatesToCase) if (!newWorkingCase) { - throw new Error() + return false } + + return true } catch (error) { toast.error(formatMessage(errors.updateCase)) + return false } } diff --git a/libs/judicial-system/types/src/lib/case.ts b/libs/judicial-system/types/src/lib/case.ts index 9aca6a3d7c5e..618377f942b1 100644 --- a/libs/judicial-system/types/src/lib/case.ts +++ b/libs/judicial-system/types/src/lib/case.ts @@ -217,9 +217,9 @@ export enum CaseDecision { export enum IndictmentDecision { POSTPONING = 'POSTPONING', - REDISTRIBUTING = 'REDISTRIBUTING', - COMPLETING = 'COMPLETING', POSTPONING_UNTIL_VERDICT = 'POSTPONING_UNTIL_VERDICT', + COMPLETING = 'COMPLETING', + REDISTRIBUTING = 'REDISTRIBUTING', } export enum CaseAppealRulingDecision { From 9061138baf01eb3cce432ac95c0e5c203c253d35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=8Dvar=20Oddsson?= Date: Thu, 30 May 2024 13:48:41 +0000 Subject: [PATCH 05/47] Postponed until verdict tag in cases --- .../case-list/models/caseList.model.ts | 4 + .../case/interceptors/caseList.interceptor.ts | 1 + .../TagCaseState/TagCaseState.strings.ts | 5 ++ .../components/TagCaseState/TagCaseState.tsx | 81 +++++++++++-------- .../src/routes/Shared/Cases/ActiveCases.tsx | 1 + .../web/src/routes/Shared/Cases/cases.graphql | 1 + 6 files changed, 58 insertions(+), 35 deletions(-) diff --git a/apps/judicial-system/api/src/app/modules/case-list/models/caseList.model.ts b/apps/judicial-system/api/src/app/modules/case-list/models/caseList.model.ts index fda810ed9962..c5f5e7aa020a 100644 --- a/apps/judicial-system/api/src/app/modules/case-list/models/caseList.model.ts +++ b/apps/judicial-system/api/src/app/modules/case-list/models/caseList.model.ts @@ -8,6 +8,7 @@ import { CaseState, CaseType, IndictmentCaseReviewDecision, + IndictmentDecision, } from '@island.is/judicial-system/types' import { Defendant } from '../../defendant' @@ -120,4 +121,7 @@ export class CaseListEntry { @Field(() => String, { nullable: true }) readonly indictmentVerdictAppealDeadline?: string + + @Field(() => IndictmentDecision, { nullable: true }) + readonly indictmentDecision?: IndictmentDecision } diff --git a/apps/judicial-system/backend/src/app/modules/case/interceptors/caseList.interceptor.ts b/apps/judicial-system/backend/src/app/modules/case/interceptors/caseList.interceptor.ts index af0efc03b223..0ca1727294c4 100644 --- a/apps/judicial-system/backend/src/app/modules/case/interceptors/caseList.interceptor.ts +++ b/apps/judicial-system/backend/src/app/modules/case/interceptors/caseList.interceptor.ts @@ -58,6 +58,7 @@ export class CaseListInterceptor implements NestInterceptor { )?.comment, indictmentReviewer: theCase.indictmentReviewer, indictmentReviewDecision: theCase.indictmentReviewDecision, + indictmentDecision: theCase.indictmentDecision, } }), ), diff --git a/apps/judicial-system/web/src/components/TagCaseState/TagCaseState.strings.ts b/apps/judicial-system/web/src/components/TagCaseState/TagCaseState.strings.ts index 2bcb77190931..d6d841b7e06b 100644 --- a/apps/judicial-system/web/src/components/TagCaseState/TagCaseState.strings.ts +++ b/apps/judicial-system/web/src/components/TagCaseState/TagCaseState.strings.ts @@ -67,4 +67,9 @@ export const strings = defineMessages({ defaultMessage: 'Móttekið', description: 'Notað sem merki þegar mál í stöðu "Móttekið" í málalista', }, + postponedUntilVerdict: { + id: 'judicial.system.core:tag_case_state.postponed_until_verdict', + defaultMessage: 'Dómtekið', + description: 'Notað sem merki þegar mál í stöðu "Dómtekið" í málalista', + }, }) diff --git a/apps/judicial-system/web/src/components/TagCaseState/TagCaseState.tsx b/apps/judicial-system/web/src/components/TagCaseState/TagCaseState.tsx index e920234c4642..568fe454d70e 100644 --- a/apps/judicial-system/web/src/components/TagCaseState/TagCaseState.tsx +++ b/apps/judicial-system/web/src/components/TagCaseState/TagCaseState.tsx @@ -1,4 +1,4 @@ -import React from 'react' +import React, { FC } from 'react' import { IntlShape, useIntl } from 'react-intl' import { Tag, TagVariant } from '@island.is/island-ui/core' @@ -9,6 +9,7 @@ import { import { CaseState, CaseType, + IndictmentDecision, User, } from '@island.is/judicial-system-web/src/graphql/schema' @@ -26,6 +27,7 @@ interface Props { state?: CaseState | null, indictmentReviewer?: User | null, // TODO: Refactor so we have a more generalized interface for the info passed in to the component ) => { color: TagVariant; text: string } + indictmentDecision?: IndictmentDecision | null } export const mapIndictmentCaseStateToTagVariant = ( @@ -53,43 +55,50 @@ export const mapCaseStateToTagVariant = ( isValidToDateInThePast?: boolean | null, scheduledDate?: string | null, isCourtRole?: boolean, + indictmentDecision?: IndictmentDecision | null, ): { color: TagVariant; text: string } => { - switch (state) { - case CaseState.NEW: - case CaseState.DRAFT: - case CaseState.WAITING_FOR_CONFIRMATION: - return { color: 'red', text: formatMessage(strings.draft) } - case CaseState.SUBMITTED: - return { - color: 'purple', - text: formatMessage(isCourtRole ? strings.new : strings.sent), - } - case CaseState.RECEIVED: - return scheduledDate - ? { color: 'mint', text: formatMessage(strings.scheduled) } - : { color: 'blueberry', text: formatMessage(strings.received) } - case CaseState.MAIN_HEARING: - return { color: 'blue', text: formatMessage(strings.reassignment) } - case CaseState.ACCEPTED: - case CaseState.COMPLETED: - return isIndictmentCase(caseType) || isValidToDateInThePast - ? { color: 'darkerBlue', text: formatMessage(strings.inactive) } - : { - color: 'blue', - text: formatMessage( - isInvestigationCase(caseType) ? strings.accepted : strings.active, - ), - } - case CaseState.REJECTED: - return { color: 'rose', text: formatMessage(strings.rejected) } - case CaseState.DISMISSED: - return { color: 'dark', text: formatMessage(strings.dismissed) } - default: - return { color: 'white', text: formatMessage(strings.unknown) } + if (indictmentDecision === IndictmentDecision.POSTPONING_UNTIL_VERDICT) { + return { color: 'mint', text: formatMessage(strings.postponedUntilVerdict) } + } else { + switch (state) { + case CaseState.NEW: + case CaseState.DRAFT: + case CaseState.WAITING_FOR_CONFIRMATION: + return { color: 'red', text: formatMessage(strings.draft) } + case CaseState.SUBMITTED: + return { + color: 'purple', + text: formatMessage(isCourtRole ? strings.new : strings.sent), + } + case CaseState.RECEIVED: + return scheduledDate + ? { color: 'mint', text: formatMessage(strings.scheduled) } + : { color: 'blueberry', text: formatMessage(strings.received) } + case CaseState.MAIN_HEARING: + return { color: 'blue', text: formatMessage(strings.reassignment) } + case CaseState.ACCEPTED: + case CaseState.COMPLETED: + return isIndictmentCase(caseType) || isValidToDateInThePast + ? { color: 'darkerBlue', text: formatMessage(strings.inactive) } + : { + color: 'blue', + text: formatMessage( + isInvestigationCase(caseType) + ? strings.accepted + : strings.active, + ), + } + case CaseState.REJECTED: + return { color: 'rose', text: formatMessage(strings.rejected) } + case CaseState.DISMISSED: + return { color: 'dark', text: formatMessage(strings.dismissed) } + default: + return { color: 'white', text: formatMessage(strings.unknown) } + } } } -const TagCaseState: React.FC> = (Props) => { +const TagCaseState: FC = (props) => { const { formatMessage } = useIntl() const { caseState, @@ -99,7 +108,8 @@ const TagCaseState: React.FC> = (Props) => { courtDate, indictmentReviewer, customMapCaseStateToTag, - } = Props + indictmentDecision, + } = props const tagVariant = customMapCaseStateToTag ? customMapCaseStateToTag(formatMessage, caseState, indictmentReviewer) @@ -110,6 +120,7 @@ const TagCaseState: React.FC> = (Props) => { isValidToDateInThePast, courtDate, isCourtRole, + indictmentDecision, ) if (!tagVariant) return null diff --git a/apps/judicial-system/web/src/routes/Shared/Cases/ActiveCases.tsx b/apps/judicial-system/web/src/routes/Shared/Cases/ActiveCases.tsx index 1c52098aa36d..b7dd231cba17 100644 --- a/apps/judicial-system/web/src/routes/Shared/Cases/ActiveCases.tsx +++ b/apps/judicial-system/web/src/routes/Shared/Cases/ActiveCases.tsx @@ -326,6 +326,7 @@ const ActiveCases: React.FC> = (props) => { isCourtRole={isDistrictCourtUser(user)} isValidToDateInThePast={c.isValidToDateInThePast} courtDate={c.courtDate} + indictmentDecision={c.indictmentDecision} /> {c.appealState && ( diff --git a/apps/judicial-system/web/src/routes/Shared/Cases/cases.graphql b/apps/judicial-system/web/src/routes/Shared/Cases/cases.graphql index 2fd62e99ff51..81ec77b8733a 100644 --- a/apps/judicial-system/web/src/routes/Shared/Cases/cases.graphql +++ b/apps/judicial-system/web/src/routes/Shared/Cases/cases.graphql @@ -92,5 +92,6 @@ query Cases { indictmentAppealDeadline indictmentVerdictViewedByAll indictmentVerdictAppealDeadline + indictmentDecision } } From d0ff81b4df2d139d7ec375ec8e2560a7043b98b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=8Dvar=20Oddsson?= Date: Thu, 30 May 2024 14:11:10 +0000 Subject: [PATCH 06/47] Disable subpoena screen if a case is postponed until verdict --- .../Court/Indictments/Subpoena/Subpoena.tsx | 29 ++++++++++++------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/apps/judicial-system/web/src/routes/Court/Indictments/Subpoena/Subpoena.tsx b/apps/judicial-system/web/src/routes/Court/Indictments/Subpoena/Subpoena.tsx index 54a951301427..084b3c9078b8 100644 --- a/apps/judicial-system/web/src/routes/Court/Indictments/Subpoena/Subpoena.tsx +++ b/apps/judicial-system/web/src/routes/Court/Indictments/Subpoena/Subpoena.tsx @@ -18,7 +18,10 @@ import { SectionHeading, useCourtArrangements, } from '@island.is/judicial-system-web/src/components' -import { NotificationType } from '@island.is/judicial-system-web/src/graphql/schema' +import { + IndictmentDecision, + NotificationType, +} from '@island.is/judicial-system-web/src/graphql/schema' import type { stepValidationsType } from '@island.is/judicial-system-web/src/utils/formHelper' import { useCase } from '@island.is/judicial-system-web/src/utils/hooks' import { hasSentNotification } from '@island.is/judicial-system-web/src/utils/stepHelper' @@ -40,8 +43,20 @@ const Subpoena: React.FC> = () => { } = useCourtArrangements(workingCase, setWorkingCase, 'arraignmentDate') const { sendNotification } = useCase() + const isPostponed = Boolean( + workingCase.indictmentDecision === + IndictmentDecision.POSTPONING_UNTIL_VERDICT || + workingCase.courtDate?.date || + workingCase.postponedIndefinitelyExplanation, + ) + const handleNavigationTo = useCallback( async (destination: keyof stepValidationsType) => { + if (isPostponed) { + router.push(`${destination}/${workingCase.id}`) + return + } + await sendCourtDateToServer() if ( @@ -57,6 +72,7 @@ const Subpoena: React.FC> = () => { } }, [ + isPostponed, sendCourtDateToServer, workingCase.notifications, workingCase.id, @@ -65,9 +81,6 @@ const Subpoena: React.FC> = () => { ) const stepIsValid = isSubpoenaStepValid(workingCase, courtDate?.date) - const isPostponed = Boolean( - workingCase.courtDate?.date || workingCase.postponedIndefinitelyExplanation, - ) return ( > = () => { previousUrl={`${constants.INDICTMENTS_RECEPTION_AND_ASSIGNMENT_ROUTE}/${workingCase.id}`} nextIsLoading={isLoadingWorkingCase} onNextButtonClick={() => { - if (isPostponed) { - router.push( - `${constants.INDICTMENTS_DEFENDER_ROUTE}/${workingCase.id}`, - ) - } else { - handleNavigationTo(constants.INDICTMENTS_DEFENDER_ROUTE) - } + handleNavigationTo(constants.INDICTMENTS_DEFENDER_ROUTE) }} nextButtonText={ isPostponed ? undefined : formatMessage(strings.nextButtonText) From f9119f8920693da9397ea0647fa505c92b8f00d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=8Dvar=20Oddsson?= Date: Thu, 30 May 2024 14:36:26 +0000 Subject: [PATCH 07/47] Add a postpone until verdict tag for defenders --- apps/judicial-system/web/src/routes/Defender/Cases/Cases.tsx | 4 ++-- .../routes/Defender/Cases/components/DefenderCasesTable.tsx | 1 + .../web/src/routes/Defender/Cases/defenderCases.graphql | 1 + 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/judicial-system/web/src/routes/Defender/Cases/Cases.tsx b/apps/judicial-system/web/src/routes/Defender/Cases/Cases.tsx index 6db5fdd17694..3fde1fce30e1 100644 --- a/apps/judicial-system/web/src/routes/Defender/Cases/Cases.tsx +++ b/apps/judicial-system/web/src/routes/Defender/Cases/Cases.tsx @@ -1,4 +1,4 @@ -import React, { useEffect, useMemo, useState } from 'react' +import React, { FC, useEffect, useMemo, useState } from 'react' import { useIntl } from 'react-intl' import partition from 'lodash/partition' @@ -17,7 +17,7 @@ import { useDefenderCasesQuery } from './defenderCases.generated' import { defenderCases as m } from './Cases.strings' import * as styles from './Cases.css' -export const Cases: React.FC> = () => { +export const Cases: FC = () => { const { formatMessage } = useIntl() const availableTabs = ['active', 'completed'] diff --git a/apps/judicial-system/web/src/routes/Defender/Cases/components/DefenderCasesTable.tsx b/apps/judicial-system/web/src/routes/Defender/Cases/components/DefenderCasesTable.tsx index 0e6e2b411cf6..3732026e2fe7 100644 --- a/apps/judicial-system/web/src/routes/Defender/Cases/components/DefenderCasesTable.tsx +++ b/apps/judicial-system/web/src/routes/Defender/Cases/components/DefenderCasesTable.tsx @@ -158,6 +158,7 @@ export const DefenderCasesTable: React.FC> = ( caseType={column.type} isValidToDateInThePast={column.isValidToDateInThePast} courtDate={column.courtDate} + indictmentDecision={column.indictmentDecision} /> {column.appealState && ( diff --git a/apps/judicial-system/web/src/routes/Defender/Cases/defenderCases.graphql b/apps/judicial-system/web/src/routes/Defender/Cases/defenderCases.graphql index 230b576c0c32..04ccc2539fe9 100644 --- a/apps/judicial-system/web/src/routes/Defender/Cases/defenderCases.graphql +++ b/apps/judicial-system/web/src/routes/Defender/Cases/defenderCases.graphql @@ -27,5 +27,6 @@ query DefenderCases($input: CaseListQueryInput) { initialRulingDate rulingDate postponedIndefinitelyExplanation + indictmentDecision } } From c5e92f5b11a0d57dc6a8654e109b6d470283da09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=8Dvar=20Oddsson?= Date: Thu, 30 May 2024 15:14:53 +0000 Subject: [PATCH 08/47] Checkpoint --- .../Conclusion/Conclusion.strings.ts | 5 ++ .../Indictments/Conclusion/Conclusion.tsx | 54 ++++++++++++++----- 2 files changed, 46 insertions(+), 13 deletions(-) diff --git a/apps/judicial-system/web/src/routes/Court/Indictments/Conclusion/Conclusion.strings.ts b/apps/judicial-system/web/src/routes/Court/Indictments/Conclusion/Conclusion.strings.ts index 31de51f7f5dc..9cd43f90e31b 100644 --- a/apps/judicial-system/web/src/routes/Court/Indictments/Conclusion/Conclusion.strings.ts +++ b/apps/judicial-system/web/src/routes/Court/Indictments/Conclusion/Conclusion.strings.ts @@ -109,4 +109,9 @@ export const strings = defineMessages({ description: 'Notaður sem texti í viðurlagaákvörðun valmöguleika á Niðurstaða skrefi.', }, + nextButtonTextConfirm: { + id: 'judicial.system.core:court.indictments.conclusion.next_button_text_confirm', + defaultMessage: 'Staðfesta', + description: 'Notaður sem texti á halda áfram takka.', + }, }) diff --git a/apps/judicial-system/web/src/routes/Court/Indictments/Conclusion/Conclusion.tsx b/apps/judicial-system/web/src/routes/Court/Indictments/Conclusion/Conclusion.tsx index 521949a778db..c07a2bad14a3 100644 --- a/apps/judicial-system/web/src/routes/Court/Indictments/Conclusion/Conclusion.tsx +++ b/apps/judicial-system/web/src/routes/Court/Indictments/Conclusion/Conclusion.tsx @@ -232,17 +232,20 @@ const Conclusion: React.FC = () => { ], ) - const isDecisionChecked = (decision: IndictmentDecision) => { - return ( - selectedAction === decision || - (!selectedAction && workingCase.indictmentDecision === decision) - ) - } - useEffect(() => { + if ( + workingCase.indictmentDecision === + IndictmentDecision.POSTPONING_UNTIL_VERDICT + ) { + setSelectedAction(IndictmentDecision.POSTPONING_UNTIL_VERDICT) + + return + } if (workingCase.indictmentRulingDecision) { setSelectedDecision(workingCase.indictmentRulingDecision) setSelectedAction(IndictmentDecision.COMPLETING) + + return } else if ( workingCase.courtDate?.date || workingCase.postponedIndefinitelyExplanation @@ -262,6 +265,7 @@ const Conclusion: React.FC = () => { workingCase.courtDate?.date, workingCase.postponedIndefinitelyExplanation, workingCase.indictmentRulingDecision, + workingCase.indictmentDecision, ]) const stepIsValid = () => { @@ -311,7 +315,12 @@ const Conclusion: React.FC = () => { { setSelectedAction(IndictmentDecision.POSTPONING) }} @@ -324,9 +333,13 @@ const Conclusion: React.FC = () => { { setSelectedAction(IndictmentDecision.POSTPONING_UNTIL_VERDICT) }} @@ -339,7 +352,12 @@ const Conclusion: React.FC = () => { { setSelectedAction(IndictmentDecision.COMPLETING) }} @@ -351,7 +369,12 @@ const Conclusion: React.FC = () => { { setSelectedAction(IndictmentDecision.REDISTRIBUTING) }} @@ -551,6 +574,11 @@ const Conclusion: React.FC = () => { : constants.INDICTMENTS_COURT_OVERVIEW_ROUTE, ) } + nextButtonText={ + selectedAction === IndictmentDecision.COMPLETING + ? undefined + : formatMessage(strings.nextButtonTextConfirm) + } nextIsDisabled={!stepIsValid()} nextIsLoading={isUpdatingCase} /> From d75eeba26375e146485ba63d2ace587134ac42a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=8Dvar=20Oddsson?= Date: Thu, 30 May 2024 15:33:08 +0000 Subject: [PATCH 09/47] Checkpoint --- .../Court/Indictments/Conclusion/Conclusion.tsx | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/apps/judicial-system/web/src/routes/Court/Indictments/Conclusion/Conclusion.tsx b/apps/judicial-system/web/src/routes/Court/Indictments/Conclusion/Conclusion.tsx index c07a2bad14a3..8e58ddf4c7cf 100644 --- a/apps/judicial-system/web/src/routes/Court/Indictments/Conclusion/Conclusion.tsx +++ b/apps/judicial-system/web/src/routes/Court/Indictments/Conclusion/Conclusion.tsx @@ -67,8 +67,7 @@ const Conclusion: React.FC = () => { sendCourtDateToServer, } = useCourtArrangements(workingCase, setWorkingCase, 'courtDate') - const { updateCase, isUpdatingCase, transitionCase, setAndSendCaseToServer } = - useCase() + const { isUpdatingCase, transitionCase, setAndSendCaseToServer } = useCase() const { uploadFiles, @@ -143,14 +142,20 @@ const Conclusion: React.FC = () => { workingCase, setWorkingCase, ) + const updateCourtDateSuccess = await sendCourtDateToServer() - if (!success) { + if (!success || !updateCourtDateSuccess) { return } router.push(`${destination}/${workingCase.id}`) }, - [setAndSendCaseToServer, setWorkingCase, workingCase], + [ + sendCourtDateToServer, + setAndSendCaseToServer, + setWorkingCase, + workingCase, + ], ) const handlePostponementIndefinitely = useCallback( From e73e0377f6f54be24e43630837b392d52138fe53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=8Dvar=20Oddsson?= Date: Fri, 31 May 2024 09:08:51 +0000 Subject: [PATCH 10/47] Merge --- .../Court/Indictments/Conclusion/Conclusion.tsx | 12 ++++-------- .../Defender/Cases/components/DefenderCasesTable.tsx | 3 --- 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/apps/judicial-system/web/src/routes/Court/Indictments/Conclusion/Conclusion.tsx b/apps/judicial-system/web/src/routes/Court/Indictments/Conclusion/Conclusion.tsx index 66f883d51401..7549534b9496 100644 --- a/apps/judicial-system/web/src/routes/Court/Indictments/Conclusion/Conclusion.tsx +++ b/apps/judicial-system/web/src/routes/Court/Indictments/Conclusion/Conclusion.tsx @@ -281,19 +281,19 @@ const Conclusion: React.FC = () => { } switch (selectedAction) { - case 'POSTPONE': + case IndictmentDecision.POSTPONING: return Boolean( postponement?.postponedIndefinitely ? postponement.reason : courtDate?.date, ) - case 'REDISTRIBUTE': + case IndictmentDecision.REDISTRIBUTING: return uploadFiles.some( (file) => file.category === CaseFileCategory.COURT_RECORD && file.status === 'done', ) - case 'COMPLETE': + case IndictmentDecision.COMPLETING: switch (selectedDecision) { case CaseIndictmentRulingDecision.RULING: case CaseIndictmentRulingDecision.DISMISSAL: @@ -576,11 +576,7 @@ const Conclusion: React.FC = () => { > >>>>>> 8c99a2ba5c7c08486b09c31f3276d3487329f0f3 /> { /> )} - {selectedAction === 'COMPLETE' && + {selectedAction === IndictmentDecision.COMPLETING && (selectedDecision === CaseIndictmentRulingDecision.RULING || selectedDecision === CaseIndictmentRulingDecision.DISMISSAL) && ( diff --git a/apps/judicial-system/web/src/routes/Defender/Cases/components/DefenderCasesTable.tsx b/apps/judicial-system/web/src/routes/Defender/Cases/components/DefenderCasesTable.tsx index 9af67c73de40..53357ebb4dc9 100644 --- a/apps/judicial-system/web/src/routes/Defender/Cases/components/DefenderCasesTable.tsx +++ b/apps/judicial-system/web/src/routes/Defender/Cases/components/DefenderCasesTable.tsx @@ -158,11 +158,8 @@ export const DefenderCasesTable: React.FC> = ( caseType={column.type} isValidToDateInThePast={column.isValidToDateInThePast} courtDate={column.courtDate} -<<<<<<< HEAD indictmentDecision={column.indictmentDecision} -======= indictmentRulingDecision={column.indictmentRulingDecision} ->>>>>>> 8c99a2ba5c7c08486b09c31f3276d3487329f0f3 /> {column.appealState && ( From ed6ba894b045cba33bee62a5e0b87fa7e122ed79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=8Dvar=20Oddsson?= Date: Fri, 31 May 2024 11:06:20 +0000 Subject: [PATCH 11/47] Determining when step is valid when postponing until verdict --- .../Indictments/Conclusion/Conclusion.tsx | 96 ++++++++++--------- 1 file changed, 51 insertions(+), 45 deletions(-) diff --git a/apps/judicial-system/web/src/routes/Court/Indictments/Conclusion/Conclusion.tsx b/apps/judicial-system/web/src/routes/Court/Indictments/Conclusion/Conclusion.tsx index 7549534b9496..3deb874d94ec 100644 --- a/apps/judicial-system/web/src/routes/Court/Indictments/Conclusion/Conclusion.tsx +++ b/apps/judicial-system/web/src/routes/Court/Indictments/Conclusion/Conclusion.tsx @@ -49,7 +49,7 @@ type Decision = interface Postponement { postponedIndefinitely?: boolean - postonedUntilVerdict?: boolean + isSettingVerdictDate?: boolean reason?: string } @@ -61,6 +61,7 @@ const Conclusion: React.FC = () => { const [selectedAction, setSelectedAction] = useState() const [selectedDecision, setSelectedDecision] = useState() const [postponement, setPostponement] = useState() + const [selectedCourtDate, setSelectedCourtDate] = useState() const { courtDate, @@ -276,51 +277,55 @@ const Conclusion: React.FC = () => { ]) const stepIsValid = () => { - if (!allFilesDoneOrError) { + if (selectedAction === IndictmentDecision.POSTPONING_UNTIL_VERDICT) { + return postponement?.isSettingVerdictDate + ? Boolean(selectedCourtDate) + : false + } else if (!allFilesDoneOrError) { return false - } - - switch (selectedAction) { - case IndictmentDecision.POSTPONING: - return Boolean( - postponement?.postponedIndefinitely - ? postponement.reason - : courtDate?.date, - ) - case IndictmentDecision.REDISTRIBUTING: - return uploadFiles.some( - (file) => - file.category === CaseFileCategory.COURT_RECORD && - file.status === 'done', - ) - case IndictmentDecision.COMPLETING: - switch (selectedDecision) { - case CaseIndictmentRulingDecision.RULING: - case CaseIndictmentRulingDecision.DISMISSAL: - return ( - uploadFiles.some( + } else { + switch (selectedAction) { + case IndictmentDecision.POSTPONING: + return Boolean( + postponement?.postponedIndefinitely + ? postponement.reason + : courtDate?.date, + ) + case IndictmentDecision.REDISTRIBUTING: + return uploadFiles.some( + (file) => + file.category === CaseFileCategory.COURT_RECORD && + file.status === 'done', + ) + case IndictmentDecision.COMPLETING: + switch (selectedDecision) { + case CaseIndictmentRulingDecision.RULING: + case CaseIndictmentRulingDecision.DISMISSAL: + return ( + uploadFiles.some( + (file) => + file.category === CaseFileCategory.COURT_RECORD && + file.status === 'done', + ) && + uploadFiles.some( + (file) => + file.category === CaseFileCategory.RULING && + file.status === 'done', + ) + ) + case CaseIndictmentRulingDecision.FINE: + case CaseIndictmentRulingDecision.CANCELLATION: + return uploadFiles.some( (file) => file.category === CaseFileCategory.COURT_RECORD && file.status === 'done', - ) && - uploadFiles.some( - (file) => - file.category === CaseFileCategory.RULING && - file.status === 'done', ) - ) - case CaseIndictmentRulingDecision.FINE: - case CaseIndictmentRulingDecision.CANCELLATION: - return uploadFiles.some( - (file) => - file.category === CaseFileCategory.COURT_RECORD && - file.status === 'done', - ) - default: - return false - } - default: - return false + default: + return false + } + default: + return false + } } } @@ -480,11 +485,11 @@ const Conclusion: React.FC = () => { { setPostponement((prev) => ({ ...prev, - postonedUntilVerdict: !prev?.postonedUntilVerdict, + isSettingVerdictDate: !prev?.isSettingVerdictDate, })) }} backgroundColor="white" @@ -496,10 +501,11 @@ const Conclusion: React.FC = () => { { - console.log('asd') + setSelectedCourtDate(date) }} blueBox={false} - disabled={!postponement?.postonedUntilVerdict} + disabled={!postponement?.isSettingVerdictDate} + required={postponement?.isSettingVerdictDate} /> From 7cf3da02320ee03eec8acb53b0df097ad3ce0c1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=8Dvar=20Oddsson?= Date: Fri, 31 May 2024 11:47:04 +0000 Subject: [PATCH 12/47] Checkpoint --- .../Indictments/Conclusion/Conclusion.tsx | 2 +- .../Indictments/Summary/Summary.strings.ts | 10 ++++++++++ .../Court/Indictments/Summary/Summary.tsx | 19 ++++++++++++++++--- 3 files changed, 27 insertions(+), 4 deletions(-) diff --git a/apps/judicial-system/web/src/routes/Court/Indictments/Conclusion/Conclusion.tsx b/apps/judicial-system/web/src/routes/Court/Indictments/Conclusion/Conclusion.tsx index 3deb874d94ec..b27ce2b28ee3 100644 --- a/apps/judicial-system/web/src/routes/Court/Indictments/Conclusion/Conclusion.tsx +++ b/apps/judicial-system/web/src/routes/Court/Indictments/Conclusion/Conclusion.tsx @@ -280,7 +280,7 @@ const Conclusion: React.FC = () => { if (selectedAction === IndictmentDecision.POSTPONING_UNTIL_VERDICT) { return postponement?.isSettingVerdictDate ? Boolean(selectedCourtDate) - : false + : true } else if (!allFilesDoneOrError) { return false } else { diff --git a/apps/judicial-system/web/src/routes/Court/Indictments/Summary/Summary.strings.ts b/apps/judicial-system/web/src/routes/Court/Indictments/Summary/Summary.strings.ts index fc389fc02139..b5677d2c62ce 100644 --- a/apps/judicial-system/web/src/routes/Court/Indictments/Summary/Summary.strings.ts +++ b/apps/judicial-system/web/src/routes/Court/Indictments/Summary/Summary.strings.ts @@ -45,4 +45,14 @@ export const strings = defineMessages({ 'Gögn hafa verið send á ákæranda og verjanda hafi þeim verið hlaðið upp.', description: 'Notaður sem texti í staðfestingarglugga um að mál sé lokið.', }, + scheduledInfoCardTitle: { + id: 'judicial.system.core:indictments.summary.scheduled_info_card_title', + defaultMessage: 'Á dagskrá', + description: 'Notaður sem titill á Á dagskrá upplýsingakorti.', + }, + scheduledInfoCardValue: { + id: 'judicial.system.core:indictments.summary.scheduled_info_card_value', + defaultMessage: 'Málið er dómtekið', + description: 'Notaður sem gildi á Á dagskrá upplýsingakorti.', + }, }) diff --git a/apps/judicial-system/web/src/routes/Court/Indictments/Summary/Summary.tsx b/apps/judicial-system/web/src/routes/Court/Indictments/Summary/Summary.tsx index 3e4630c1ad1d..8c96c6a23134 100644 --- a/apps/judicial-system/web/src/routes/Court/Indictments/Summary/Summary.tsx +++ b/apps/judicial-system/web/src/routes/Court/Indictments/Summary/Summary.tsx @@ -9,6 +9,8 @@ import { FormContentContainer, FormContext, FormFooter, + InfoCard, + InfoCardCaseScheduledIndictment, InfoCardClosedIndictment, Modal, PageHeader, @@ -85,18 +87,29 @@ const Summary: React.FC = () => { {formatMessage(strings.title)} - + {formatMessage(core.caseNumber, { caseNumber: workingCase.courtCaseNumber, })} - + - + + + + From 2b5c478143945d78d8f526986d7224ca941cd68c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=8Dvar=20Oddsson?= Date: Fri, 31 May 2024 11:57:45 +0000 Subject: [PATCH 13/47] Change all instances of Array to something[] --- .../src/app/modules/case/limitedAccessCase.service.ts | 6 ++---- .../web/src/components/InfoCard/InfoCard.tsx | 6 +++--- apps/judicial-system/web/src/utils/hooks/useCase/index.ts | 5 +---- apps/judicial-system/web/src/utils/hooks/useDeb/index.tsx | 2 +- 4 files changed, 7 insertions(+), 12 deletions(-) diff --git a/apps/judicial-system/backend/src/app/modules/case/limitedAccessCase.service.ts b/apps/judicial-system/backend/src/app/modules/case/limitedAccessCase.service.ts index 1be2398a862e..3cef3a2f246c 100644 --- a/apps/judicial-system/backend/src/app/modules/case/limitedAccessCase.service.ts +++ b/apps/judicial-system/backend/src/app/modules/case/limitedAccessCase.service.ts @@ -377,9 +377,7 @@ export class LimitedAccessCaseService { }) } - private zipFiles( - files: Array<{ data: Buffer; name: string }>, - ): Promise { + private zipFiles(files: { data: Buffer; name: string }[]): Promise { return new Promise((resolve, reject) => { const buffs: Buffer[] = [] const converter = new Writable() @@ -410,7 +408,7 @@ export class LimitedAccessCaseService { } async getAllFilesZip(theCase: Case, user: TUser): Promise { - const filesToZip: Array<{ data: Buffer; name: string }> = [] + const filesToZip: { data: Buffer; name: string }[] = [] const caseFilesByCategory = theCase.caseFiles?.filter( diff --git a/apps/judicial-system/web/src/components/InfoCard/InfoCard.tsx b/apps/judicial-system/web/src/components/InfoCard/InfoCard.tsx index 75a92e5a2259..32a9c07c9d6d 100644 --- a/apps/judicial-system/web/src/components/InfoCard/InfoCard.tsx +++ b/apps/judicial-system/web/src/components/InfoCard/InfoCard.tsx @@ -28,12 +28,12 @@ interface UniqueDefendersProps { } interface DataSection { - data: Array<{ title: string; value?: React.ReactNode }> + data: { title: string; value?: React.ReactNode }[] } interface Props { - courtOfAppealData?: Array<{ title: string; value?: React.ReactNode }> - data: Array<{ title: string; value?: React.ReactNode }> + courtOfAppealData?: { title: string; value?: React.ReactNode }[] + data: { title: string; value?: React.ReactNode }[] defendants?: { title: string items: Defendant[] diff --git a/apps/judicial-system/web/src/utils/hooks/useCase/index.ts b/apps/judicial-system/web/src/utils/hooks/useCase/index.ts index 8a2d6e6e4ab0..55cea551369b 100644 --- a/apps/judicial-system/web/src/utils/hooks/useCase/index.ts +++ b/apps/judicial-system/web/src/utils/hooks/useCase/index.ts @@ -109,10 +109,7 @@ export const update = (update: UpdateCase, workingCase: Case): UpdateCase => { return validUpdates } -export const formatUpdates = ( - updates: Array, - workingCase: Case, -) => { +export const formatUpdates = (updates: UpdateCase[], workingCase: Case) => { const changes: UpdateCase[] = updates.map((entry) => { if (entry.force) { return overwrite(entry) diff --git a/apps/judicial-system/web/src/utils/hooks/useDeb/index.tsx b/apps/judicial-system/web/src/utils/hooks/useDeb/index.tsx index 0e926219eea2..47a2352c4878 100644 --- a/apps/judicial-system/web/src/utils/hooks/useDeb/index.tsx +++ b/apps/judicial-system/web/src/utils/hooks/useDeb/index.tsx @@ -4,7 +4,7 @@ import { TempCase as Case } from '@island.is/judicial-system-web/src/types' import useCase from '../useCase' -const useDeb = (workingCase: Case, keys: Array | keyof Case) => { +const useDeb = (workingCase: Case, keys: (keyof Case)[] | keyof Case) => { const { updateCase } = useCase() const newKeys = Array.isArray(keys) ? keys : [keys] From 164ea3363de08a948a7f33046b99a8e0080b84df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=8Dvar=20Oddsson?= Date: Fri, 31 May 2024 14:39:33 +0000 Subject: [PATCH 14/47] Only show InfoCard on summary page if indictment decison is POSTPONING_UNTIL_VERDICT --- .../Court/Indictments/Summary/Summary.tsx | 27 ++++++++++--------- 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/apps/judicial-system/web/src/routes/Court/Indictments/Summary/Summary.tsx b/apps/judicial-system/web/src/routes/Court/Indictments/Summary/Summary.tsx index 8c96c6a23134..5ef6f1379b54 100644 --- a/apps/judicial-system/web/src/routes/Court/Indictments/Summary/Summary.tsx +++ b/apps/judicial-system/web/src/routes/Court/Indictments/Summary/Summary.tsx @@ -10,7 +10,6 @@ import { FormContext, FormFooter, InfoCard, - InfoCardCaseScheduledIndictment, InfoCardClosedIndictment, Modal, PageHeader, @@ -27,6 +26,7 @@ import { CaseFile, CaseFileCategory, CaseTransition, + IndictmentDecision, } from '@island.is/judicial-system-web/src/graphql/schema' import { useCase, @@ -98,17 +98,20 @@ const Summary: React.FC = () => { - - - + {workingCase.indictmentDecision === + IndictmentDecision.POSTPONING_UNTIL_VERDICT && ( + + + + )} From 8b6c049ce708eeb7332a2b15ef67c421da64693d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=8Dvar=20Oddsson?= Date: Mon, 3 Jun 2024 11:48:07 +0000 Subject: [PATCH 15/47] Wipe courtDate out when postponing until verdict --- .../Court/Indictments/Conclusion/Conclusion.tsx | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/apps/judicial-system/web/src/routes/Court/Indictments/Conclusion/Conclusion.tsx b/apps/judicial-system/web/src/routes/Court/Indictments/Conclusion/Conclusion.tsx index b27ce2b28ee3..f596efeb7180 100644 --- a/apps/judicial-system/web/src/routes/Court/Indictments/Conclusion/Conclusion.tsx +++ b/apps/judicial-system/web/src/routes/Court/Indictments/Conclusion/Conclusion.tsx @@ -139,26 +139,21 @@ const Conclusion: React.FC = () => { [ { indictmentDecision: IndictmentDecision.POSTPONING_UNTIL_VERDICT, + courtDate: null, force: true, }, ], workingCase, setWorkingCase, ) - const updateCourtDateSuccess = await sendCourtDateToServer() - if (!success || !updateCourtDateSuccess) { + if (!success) { return } router.push(`${destination}/${workingCase.id}`) }, - [ - sendCourtDateToServer, - setAndSendCaseToServer, - setWorkingCase, - workingCase, - ], + [setAndSendCaseToServer, setWorkingCase, workingCase], ) const handlePostponementIndefinitely = useCallback( From a01f34c0e7092a1b3f37e6693ad564f8647ef64d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=8Dvar=20Oddsson?= Date: Mon, 3 Jun 2024 11:56:55 +0000 Subject: [PATCH 16/47] Move scheduled info card to overview page --- .../Indictments/Overview/Overview.strings.ts | 10 ++++++++++ .../Court/Indictments/Overview/Overview.tsx | 20 ++++++++++++++++++- .../Indictments/Summary/Summary.strings.ts | 10 ---------- .../Court/Indictments/Summary/Summary.tsx | 16 --------------- 4 files changed, 29 insertions(+), 27 deletions(-) diff --git a/apps/judicial-system/web/src/routes/Court/Indictments/Overview/Overview.strings.ts b/apps/judicial-system/web/src/routes/Court/Indictments/Overview/Overview.strings.ts index 86819bf38a17..a813ba6954bf 100644 --- a/apps/judicial-system/web/src/routes/Court/Indictments/Overview/Overview.strings.ts +++ b/apps/judicial-system/web/src/routes/Court/Indictments/Overview/Overview.strings.ts @@ -35,4 +35,14 @@ export const strings = defineMessages({ description: 'Notaður sem texti á takka í staðfestingarglugga um að mál hafi verið sent til Ríkissaksóknara.', }, + scheduledInfoCardTitle: { + id: 'judicial.system.core:indictment_overview.scheduled_info_card_title', + defaultMessage: 'Á dagskrá', + description: 'Notaður sem titill á Á dagskrá upplýsingakorti.', + }, + scheduledInfoCardValue: { + id: 'judicial.system.core:indictment_overview.scheduled_info_card_value', + defaultMessage: 'Málið er dómtekið', + description: 'Notaður sem gildi á Á dagskrá upplýsingakorti.', + }, }) diff --git a/apps/judicial-system/web/src/routes/Court/Indictments/Overview/Overview.tsx b/apps/judicial-system/web/src/routes/Court/Indictments/Overview/Overview.tsx index d47a9bace956..49b05d362a62 100644 --- a/apps/judicial-system/web/src/routes/Court/Indictments/Overview/Overview.tsx +++ b/apps/judicial-system/web/src/routes/Court/Indictments/Overview/Overview.tsx @@ -12,6 +12,7 @@ import { FormFooter, IndictmentCaseFilesList, IndictmentsLawsBrokenAccordionItem, + InfoCard, InfoCardActiveIndictment, InfoCardCaseScheduledIndictment, InfoCardClosedIndictment, @@ -21,7 +22,10 @@ import { PageTitle, useIndictmentsLawsBroken, } from '@island.is/judicial-system-web/src/components' -import { CaseState } from '@island.is/judicial-system-web/src/graphql/schema' +import { + CaseState, + IndictmentDecision, +} from '@island.is/judicial-system-web/src/graphql/schema' import { useDefendants } from '@island.is/judicial-system-web/src/utils/hooks' import ReturnIndictmentModal from '../ReturnIndictmentCaseModal/ReturnIndictmentCaseModal' @@ -71,6 +75,20 @@ const IndictmentOverview = () => { : formatMessage(strings.inProgressTitle)} + {workingCase.indictmentDecision === + IndictmentDecision.POSTPONING_UNTIL_VERDICT && ( + + + + )} {caseHasBeenReceivedByCourt && workingCase.court && latestDate?.date && ( { - {workingCase.indictmentDecision === - IndictmentDecision.POSTPONING_UNTIL_VERDICT && ( - - - - )} From 048ff3a7692588fd145389b9d5d0d4bddfe91019 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=8Dvar=20Oddsson?= Date: Mon, 3 Jun 2024 14:52:52 +0000 Subject: [PATCH 17/47] Save court date when postponing until verdict --- .../Indictments/Conclusion/Conclusion.tsx | 17 ++++- .../Court/Indictments/Overview/Overview.tsx | 62 ++++++++++++------- 2 files changed, 54 insertions(+), 25 deletions(-) diff --git a/apps/judicial-system/web/src/routes/Court/Indictments/Conclusion/Conclusion.tsx b/apps/judicial-system/web/src/routes/Court/Indictments/Conclusion/Conclusion.tsx index f596efeb7180..8dd2035c7056 100644 --- a/apps/judicial-system/web/src/routes/Court/Indictments/Conclusion/Conclusion.tsx +++ b/apps/judicial-system/web/src/routes/Court/Indictments/Conclusion/Conclusion.tsx @@ -34,6 +34,7 @@ import { } from '@island.is/judicial-system-web/src/graphql/schema' import { stepValidationsType } from '@island.is/judicial-system-web/src/utils/formHelper' import { + formatDateForServer, useCase, useS3Upload, useUploadFiles, @@ -50,6 +51,7 @@ type Decision = interface Postponement { postponedIndefinitely?: boolean isSettingVerdictDate?: boolean + verdictDate?: string reason?: string } @@ -139,7 +141,12 @@ const Conclusion: React.FC = () => { [ { indictmentDecision: IndictmentDecision.POSTPONING_UNTIL_VERDICT, - courtDate: null, + courtDate: { + date: + postponement?.isSettingVerdictDate && selectedCourtDate + ? formatDateForServer(selectedCourtDate) + : null, + }, force: true, }, ], @@ -153,7 +160,13 @@ const Conclusion: React.FC = () => { router.push(`${destination}/${workingCase.id}`) }, - [setAndSendCaseToServer, setWorkingCase, workingCase], + [ + postponement?.isSettingVerdictDate, + selectedCourtDate, + setAndSendCaseToServer, + setWorkingCase, + workingCase, + ], ) const handlePostponementIndefinitely = useCallback( diff --git a/apps/judicial-system/web/src/routes/Court/Indictments/Overview/Overview.tsx b/apps/judicial-system/web/src/routes/Court/Indictments/Overview/Overview.tsx index 49b05d362a62..afdee427cb78 100644 --- a/apps/judicial-system/web/src/routes/Court/Indictments/Overview/Overview.tsx +++ b/apps/judicial-system/web/src/routes/Court/Indictments/Overview/Overview.tsx @@ -2,7 +2,7 @@ import React, { useCallback, useContext, useState } from 'react' import { useIntl } from 'react-intl' import { useRouter } from 'next/router' -import { Box, toast } from '@island.is/island-ui/core' +import { Box, Text, toast } from '@island.is/island-ui/core' import * as constants from '@island.is/judicial-system/consts' import { core, errors, titles } from '@island.is/judicial-system-web/messages' import { @@ -42,7 +42,6 @@ const IndictmentOverview = () => { 'RETURN_INDICTMENT' | 'SEND_TO_PUBLIC_PROSECUTOR' >() - const caseHasBeenReceivedByCourt = workingCase.state === CaseState.RECEIVED const latestDate = workingCase.courtDate ?? workingCase.arraignmentDate const caseIsClosed = workingCase.state === CaseState.COMPLETED @@ -78,29 +77,46 @@ const IndictmentOverview = () => { {workingCase.indictmentDecision === IndictmentDecision.POSTPONING_UNTIL_VERDICT && ( - - - )} - {caseHasBeenReceivedByCourt && workingCase.court && latestDate?.date && ( - - + {workingCase.courtDate && + workingCase.courtDate.date && + workingCase.court ? ( + + ) : ( + + {formatMessage(strings.scheduledInfoCardValue)} + + ), + }, + ]} + icon="calendar" + /> + )} )} + {workingCase.indictmentDecision === IndictmentDecision.POSTPONING && + workingCase.court && + latestDate && + latestDate.date && ( + + + + )} {caseIsClosed ? ( From 1dc584d6cf2e215f15b8e9a93766522dcac5a3a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=8Dvar=20Oddsson?= Date: Mon, 3 Jun 2024 15:23:36 +0000 Subject: [PATCH 18/47] Checkpoint --- .../Court/Indictments/Conclusion/Conclusion.tsx | 16 +++++++++++----- .../web/src/utils/hooks/useSections/index.ts | 10 ++++++++-- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/apps/judicial-system/web/src/routes/Court/Indictments/Conclusion/Conclusion.tsx b/apps/judicial-system/web/src/routes/Court/Indictments/Conclusion/Conclusion.tsx index 55de7e8c0ba2..734ced65563d 100644 --- a/apps/judicial-system/web/src/routes/Court/Indictments/Conclusion/Conclusion.tsx +++ b/apps/judicial-system/web/src/routes/Court/Indictments/Conclusion/Conclusion.tsx @@ -139,13 +139,18 @@ const Conclusion: React.FC = () => { const success = await setAndSendCaseToServer( [ { - indictmentDecision: IndictmentDecision.POSTPONING_UNTIL_VERDICT, - courtDate: { - date: - postponement?.isSettingVerdictDate && selectedCourtDate + ...(workingCase.indictmentDecision !== + IndictmentDecision.POSTPONING_UNTIL_VERDICT && { + indictmentDecision: IndictmentDecision.POSTPONING_UNTIL_VERDICT, + }), + ...((postponement?.isSettingVerdictDate || + workingCase.courtDate) && { + courtDate: { + date: selectedCourtDate ? formatDateForServer(selectedCourtDate) : null, - }, + }, + }), force: true, }, ], @@ -153,6 +158,7 @@ const Conclusion: React.FC = () => { setWorkingCase, ) + console.log('success', success) if (!success) { return } diff --git a/apps/judicial-system/web/src/utils/hooks/useSections/index.ts b/apps/judicial-system/web/src/utils/hooks/useSections/index.ts index 8d0c0f1363ff..3e1eabe2d2e7 100644 --- a/apps/judicial-system/web/src/utils/hooks/useSections/index.ts +++ b/apps/judicial-system/web/src/utils/hooks/useSections/index.ts @@ -25,6 +25,7 @@ import { CaseState, CaseType, Gender, + IndictmentDecision, InstitutionType, User, } from '@island.is/judicial-system-web/src/graphql/schema' @@ -594,7 +595,6 @@ const useSections = ( user?: User, ): RouteSection => { const { id, parentCase, state } = workingCase - return { name: formatMessage(sections.courtSection.title), isActive: @@ -894,7 +894,7 @@ const useSections = ( } const getIndictmentsCourtSections = (workingCase: Case, user?: User) => { - const { id, state } = workingCase + const { id, state, indictmentDecision } = workingCase return { name: formatMessage(sections.indictmentsCourtSection.title), @@ -998,6 +998,12 @@ const useSections = ( href: `${constants.INDICTMENTS_SUMMARY_ROUTE}/${id}`, onClick: !isActive(constants.INDICTMENTS_SUMMARY_ROUTE) && + /** + * This is a special case where we need to check the intent of the judge + * because this last step should only be clicable if the judge intends to + * close the case. + */ + indictmentDecision === IndictmentDecision.COMPLETING && validateFormStepper( isValid, [ From 8649b7b690f4b7a94e647cbb425499b7b32c6b41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=8Dvar=20Oddsson?= Date: Mon, 3 Jun 2024 21:32:14 +0000 Subject: [PATCH 19/47] Fixing update functionality --- .../Indictments/Conclusion/Conclusion.tsx | 47 ++++++++++--------- 1 file changed, 25 insertions(+), 22 deletions(-) diff --git a/apps/judicial-system/web/src/routes/Court/Indictments/Conclusion/Conclusion.tsx b/apps/judicial-system/web/src/routes/Court/Indictments/Conclusion/Conclusion.tsx index 734ced65563d..2ef86b0fb672 100644 --- a/apps/judicial-system/web/src/routes/Court/Indictments/Conclusion/Conclusion.tsx +++ b/apps/judicial-system/web/src/routes/Court/Indictments/Conclusion/Conclusion.tsx @@ -136,29 +136,32 @@ const Conclusion: React.FC = () => { const handlePostponementUntilVerdict = useCallback( async (destination: string) => { - const success = await setAndSendCaseToServer( - [ - { - ...(workingCase.indictmentDecision !== - IndictmentDecision.POSTPONING_UNTIL_VERDICT && { - indictmentDecision: IndictmentDecision.POSTPONING_UNTIL_VERDICT, - }), - ...((postponement?.isSettingVerdictDate || - workingCase.courtDate) && { - courtDate: { - date: selectedCourtDate - ? formatDateForServer(selectedCourtDate) - : null, - }, - }), - force: true, - }, - ], - workingCase, - setWorkingCase, - ) + const updates = { + ...(workingCase.indictmentDecision !== + IndictmentDecision.POSTPONING_UNTIL_VERDICT && { + indictmentDecision: IndictmentDecision.POSTPONING_UNTIL_VERDICT, + }), + ...((postponement?.isSettingVerdictDate || workingCase.courtDate) && { + courtDate: selectedCourtDate + ? { date: formatDateForServer(selectedCourtDate) } + : null, + }), + } + + const success = + Object.keys(updates).length > 0 + ? await setAndSendCaseToServer( + [ + { + ...updates, + force: true, + }, + ], + workingCase, + setWorkingCase, + ) + : true - console.log('success', success) if (!success) { return } From d08c1e37ed6326298db4a3386edd9acb30ef81c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=8Dvar=20Oddsson?= Date: Mon, 3 Jun 2024 21:43:10 +0000 Subject: [PATCH 20/47] Fix case state on cases page --- .../web/src/components/TagCaseState/TagCaseState.tsx | 2 +- apps/judicial-system/web/src/routes/Shared/Cases/cases.graphql | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/judicial-system/web/src/components/TagCaseState/TagCaseState.tsx b/apps/judicial-system/web/src/components/TagCaseState/TagCaseState.tsx index bed0100643b6..15de59551ee9 100644 --- a/apps/judicial-system/web/src/components/TagCaseState/TagCaseState.tsx +++ b/apps/judicial-system/web/src/components/TagCaseState/TagCaseState.tsx @@ -128,8 +128,8 @@ const TagCaseState: FC = (props) => { isValidToDateInThePast, courtDate, isCourtRole, - indictmentDecision, indictmentRulingDecision, + indictmentDecision, ) if (!tagVariant) return null diff --git a/apps/judicial-system/web/src/routes/Shared/Cases/cases.graphql b/apps/judicial-system/web/src/routes/Shared/Cases/cases.graphql index a60971d44f0e..0bb9915ac204 100644 --- a/apps/judicial-system/web/src/routes/Shared/Cases/cases.graphql +++ b/apps/judicial-system/web/src/routes/Shared/Cases/cases.graphql @@ -93,5 +93,6 @@ query Cases { indictmentVerdictViewedByAll indictmentVerdictAppealDeadline indictmentRulingDecision + indictmentDecision } } From 4bdf63a22ee81643d5b60ab2041598a30d5dbc88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=8Dvar=20Oddsson?= Date: Mon, 3 Jun 2024 21:47:06 +0000 Subject: [PATCH 21/47] Fix migration --- .../migrations/20240528163733-update-case.js | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/apps/judicial-system/backend/migrations/20240528163733-update-case.js b/apps/judicial-system/backend/migrations/20240528163733-update-case.js index 9e2e17c3de56..3182c0ff2c0a 100644 --- a/apps/judicial-system/backend/migrations/20240528163733-update-case.js +++ b/apps/judicial-system/backend/migrations/20240528163733-update-case.js @@ -17,16 +17,9 @@ module.exports = { async down(queryInterface) { return queryInterface.sequelize.transaction((t) => - queryInterface - .removeColumn('case', 'indictment_decision', { - transaction: t, - }) - .then(() => { - queryInterface.sequelize.query( - 'DROP TYPE "enum_case_indictment_decision";', - { transaction: t }, - ) - }), + queryInterface.removeColumn('case', 'indictment_decision', { + transaction: t, + }), ) }, } From 5ec53d6223d8524ef25de7b7994edfe411ce4d9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=8Dvar=20Oddsson?= Date: Mon, 3 Jun 2024 22:52:09 +0000 Subject: [PATCH 22/47] Add location to verdict date --- .../Indictments/Conclusion/Conclusion.tsx | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/apps/judicial-system/web/src/routes/Court/Indictments/Conclusion/Conclusion.tsx b/apps/judicial-system/web/src/routes/Court/Indictments/Conclusion/Conclusion.tsx index 2ef86b0fb672..bf9d8255ccf8 100644 --- a/apps/judicial-system/web/src/routes/Court/Indictments/Conclusion/Conclusion.tsx +++ b/apps/judicial-system/web/src/routes/Court/Indictments/Conclusion/Conclusion.tsx @@ -62,7 +62,6 @@ const Conclusion: React.FC = () => { const [selectedAction, setSelectedAction] = useState() const [selectedDecision, setSelectedDecision] = useState() const [postponement, setPostponement] = useState() - const [selectedCourtDate, setSelectedCourtDate] = useState() const { courtDate, @@ -142,8 +141,11 @@ const Conclusion: React.FC = () => { indictmentDecision: IndictmentDecision.POSTPONING_UNTIL_VERDICT, }), ...((postponement?.isSettingVerdictDate || workingCase.courtDate) && { - courtDate: selectedCourtDate - ? { date: formatDateForServer(selectedCourtDate) } + courtDate: courtDate?.date + ? { + date: formatDateForServer(new Date(courtDate.date)), + location: courtDate?.location, + } : null, }), } @@ -170,7 +172,6 @@ const Conclusion: React.FC = () => { }, [ postponement?.isSettingVerdictDate, - selectedCourtDate, setAndSendCaseToServer, setWorkingCase, workingCase, @@ -295,7 +296,7 @@ const Conclusion: React.FC = () => { const stepIsValid = () => { if (selectedAction === IndictmentDecision.POSTPONING_UNTIL_VERDICT) { return postponement?.isSettingVerdictDate - ? Boolean(selectedCourtDate) + ? Boolean(courtDate?.date) : true } else if (!allFilesDoneOrError) { return false @@ -514,14 +515,13 @@ const Conclusion: React.FC = () => { filled /> - { - setSelectedCourtDate(date) - }} + From 9e77317542067b78384d43478b5deaa130fd1510 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=8Dvar=20Oddsson?= Date: Tue, 4 Jun 2024 10:41:46 +0000 Subject: [PATCH 23/47] Cleanup --- .../web/src/routes/Court/Indictments/Conclusion/Conclusion.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/judicial-system/web/src/routes/Court/Indictments/Conclusion/Conclusion.tsx b/apps/judicial-system/web/src/routes/Court/Indictments/Conclusion/Conclusion.tsx index bf9d8255ccf8..271c4a2fd276 100644 --- a/apps/judicial-system/web/src/routes/Court/Indictments/Conclusion/Conclusion.tsx +++ b/apps/judicial-system/web/src/routes/Court/Indictments/Conclusion/Conclusion.tsx @@ -15,7 +15,6 @@ import { BlueBox, CourtArrangements, CourtCaseInfo, - DateTime, FormContentContainer, FormContext, FormFooter, @@ -171,6 +170,8 @@ const Conclusion: React.FC = () => { router.push(`${destination}/${workingCase.id}`) }, [ + courtDate?.date, + courtDate?.location, postponement?.isSettingVerdictDate, setAndSendCaseToServer, setWorkingCase, From 35feba701680bd11f2b662c6a18e482da04922d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=8Dvar=20Oddsson?= Date: Tue, 4 Jun 2024 14:42:03 +0000 Subject: [PATCH 24/47] Allow judges to remove set court date --- .../CourtArrangements/CourtArrangements.tsx | 22 ++++++++++++---- .../Indictments/Conclusion/Conclusion.tsx | 25 +++++++++++++------ 2 files changed, 35 insertions(+), 12 deletions(-) diff --git a/apps/judicial-system/web/src/components/CourtArrangements/CourtArrangements.tsx b/apps/judicial-system/web/src/components/CourtArrangements/CourtArrangements.tsx index 84d7070a9468..32abcfe639b4 100644 --- a/apps/judicial-system/web/src/components/CourtArrangements/CourtArrangements.tsx +++ b/apps/judicial-system/web/src/components/CourtArrangements/CourtArrangements.tsx @@ -51,7 +51,9 @@ export const useCourtArrangements = ( date: Date | undefined | null, valid = true, ) => { - if (date && valid) { + if (!date) { + setCourtDate(null) + } else if (date && valid) { const oldDate = workingCase[dateKey] if ( oldDate?.date && @@ -72,10 +74,16 @@ export const useCourtArrangements = ( } } - const handleCourtRoomChange = (courtRoom?: string) => { - setCourtDate((previous) => - previous ? { ...previous, location: courtRoom } : { location: courtRoom }, - ) + const handleCourtRoomChange = (courtRoom?: string | null) => { + if (!courtRoom) { + setCourtDate((prev) => ({ ...prev, location: null })) + } else { + setCourtDate((previous) => + previous + ? { ...previous, location: courtRoom } + : { location: courtRoom }, + ) + } } const sendCourtDateToServer = (otherUpdates: UpdateCase[] = []) => { @@ -120,6 +128,10 @@ export const CourtArrangements: React.FC = (props) => { const [courtRoomValue, setCourtRoomValue] = useState('') useEffect(() => { + if (courtDate?.location === null) { + setCourtRoomValue('') + } + if (courtDate?.location) { setCourtRoomValue(courtDate.location) } diff --git a/apps/judicial-system/web/src/routes/Court/Indictments/Conclusion/Conclusion.tsx b/apps/judicial-system/web/src/routes/Court/Indictments/Conclusion/Conclusion.tsx index 271c4a2fd276..5873f6f42c8a 100644 --- a/apps/judicial-system/web/src/routes/Court/Indictments/Conclusion/Conclusion.tsx +++ b/apps/judicial-system/web/src/routes/Court/Indictments/Conclusion/Conclusion.tsx @@ -49,7 +49,6 @@ type Decision = interface Postponement { postponedIndefinitely?: boolean isSettingVerdictDate?: boolean - verdictDate?: string reason?: string } @@ -140,12 +139,13 @@ const Conclusion: React.FC = () => { indictmentDecision: IndictmentDecision.POSTPONING_UNTIL_VERDICT, }), ...((postponement?.isSettingVerdictDate || workingCase.courtDate) && { - courtDate: courtDate?.date - ? { - date: formatDateForServer(new Date(courtDate.date)), - location: courtDate?.location, - } - : null, + courtDate: + postponement?.isSettingVerdictDate && courtDate?.date + ? { + date: formatDateForServer(new Date(courtDate.date)), + location: courtDate.location, + } + : null, }), } @@ -292,8 +292,17 @@ const Conclusion: React.FC = () => { workingCase.postponedIndefinitelyExplanation, workingCase.indictmentRulingDecision, workingCase.indictmentDecision, + courtDate, + postponement?.isSettingVerdictDate, ]) + useEffect(() => { + setPostponement((prev) => ({ + ...prev, + isSettingVerdictDate: Boolean(workingCase.courtDate?.date), + })) + }, [workingCase.courtDate?.date]) + const stepIsValid = () => { if (selectedAction === IndictmentDecision.POSTPONING_UNTIL_VERDICT) { return postponement?.isSettingVerdictDate @@ -509,6 +518,8 @@ const Conclusion: React.FC = () => { ...prev, isSettingVerdictDate: !prev?.isSettingVerdictDate, })) + handleCourtDateChange(null) + handleCourtRoomChange(null) }} backgroundColor="white" label={formatMessage(strings.arrangeVerdict)} From fc6b01e2e1b29318332511780d69f9d0deb3d567 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=8Dvar=20Oddsson?= Date: Tue, 4 Jun 2024 14:54:21 +0000 Subject: [PATCH 25/47] Added test --- .../TagCaseState/TagCaseState.spec.ts | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/apps/judicial-system/web/src/components/TagCaseState/TagCaseState.spec.ts b/apps/judicial-system/web/src/components/TagCaseState/TagCaseState.spec.ts index d742df360bc2..05f720db43d7 100644 --- a/apps/judicial-system/web/src/components/TagCaseState/TagCaseState.spec.ts +++ b/apps/judicial-system/web/src/components/TagCaseState/TagCaseState.spec.ts @@ -1,5 +1,9 @@ import { createIntl } from 'react-intl' +import { + CaseIndictmentRulingDecision, + IndictmentDecision, +} from '@island.is/judicial-system/types' import { tables } from '@island.is/judicial-system-web/messages' import { CaseState, @@ -21,6 +25,8 @@ describe('mapCaseStateToTagVariant', () => { caseType: CaseType, isValidToDateInThePast?: boolean, courtDate?: string, + indictmendRulingDecision?: CaseIndictmentRulingDecision | null, + indictmentDecision?: IndictmentDecision | null, ) => mapCaseStateToTagVariant( formatMessage, @@ -29,6 +35,8 @@ describe('mapCaseStateToTagVariant', () => { isValidToDateInThePast, courtDate, isCourtRole, + indictmendRulingDecision, + indictmentDecision, ) test('should return draft state', () => { @@ -118,4 +126,21 @@ describe('mapCaseStateToTagVariant', () => { text: strings.reassignment.defaultMessage, }) }) + + test('should return postponed until verdict state', () => { + expect( + fn( + CaseState.RECEIVED, + false, + CaseType.INDICTMENT, + false, + '2020-01-01', + null, + IndictmentDecision.POSTPONING_UNTIL_VERDICT, + ), + ).toEqual({ + color: 'mint', + text: strings.postponedUntilVerdict.defaultMessage, + }) + }) }) From 47afac6ce855b8a4484fe8511c6d45480a76f03e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gu=C3=B0j=C3=B3n=20Gu=C3=B0j=C3=B3nsson?= Date: Wed, 5 Jun 2024 10:47:53 +0000 Subject: [PATCH 26/47] Allows prosecutors to cancel submitted indictments --- .../migrations/20240531113155-update-case.js | 53 ++++++++++++++++++ .../src/app/modules/case/case.controller.ts | 6 ++ .../src/app/modules/case/case.service.ts | 2 +- .../app/modules/case/filters/case.filter.ts | 3 + .../app/modules/case/filters/cases.filter.ts | 4 ++ .../case/filters/test/cases.filter.spec.ts | 5 ++ .../filters/test/defenceUserFilter.spec.ts | 2 + .../test/districtCourtUserFilter.spec.ts | 2 + .../test/prosecutionUserFilter.spec.ts | 4 ++ .../src/app/modules/case/guards/rolesRules.ts | 1 + .../app/modules/case/internalCase.service.ts | 2 +- .../app/modules/case/state/case.state.spec.ts | 56 +++++++++++++++++++ .../src/app/modules/case/state/case.state.ts | 7 +++ .../test/caseController/transition.spec.ts | 2 + .../TagCaseState/TagCaseState.strings.ts | 5 ++ .../components/TagCaseState/TagCaseState.tsx | 5 ++ .../web/src/routes/Defender/Cases/Cases.tsx | 10 +++- .../Indictments/Overview/Overview.strings.ts | 32 ++++++++++- .../Indictments/Overview/Overview.tsx | 40 +++++++++++++ .../web/src/routes/Shared/Cases/Cases.tsx | 32 ++++++++--- libs/judicial-system/types/src/lib/case.ts | 46 ++++++++------- 21 files changed, 287 insertions(+), 32 deletions(-) create mode 100644 apps/judicial-system/backend/migrations/20240531113155-update-case.js diff --git a/apps/judicial-system/backend/migrations/20240531113155-update-case.js b/apps/judicial-system/backend/migrations/20240531113155-update-case.js new file mode 100644 index 000000000000..18fd14e47380 --- /dev/null +++ b/apps/judicial-system/backend/migrations/20240531113155-update-case.js @@ -0,0 +1,53 @@ +'use strict' + +module.exports = { + async up(queryInterface, Sequelize) { + return queryInterface.sequelize.transaction((transaction) => + queryInterface + .changeColumn( + 'case', + 'state', + { type: Sequelize.STRING, allowNull: false }, + { transaction }, + ) + .then(() => + queryInterface.sequelize.query('DROP TYPE "enum_case_state"', { + transaction, + }), + ), + ) + }, + + async down(queryInterface, Sequelize) { + return queryInterface.sequelize.transaction((transaction) => + queryInterface + .changeColumn( + 'case', + 'state', + { + type: Sequelize.ENUM( + 'NEW', + 'DRAFT', + 'WAITING_FOR_CONFIRMATION', + 'SUBMITTED', + 'RECEIVED', + 'MAIN_HEARING', + 'COMPLETED', + 'ACCEPTED', + 'REJECTED', + 'DISMISSED', + 'DELETED', + ), + allowNull: false, + }, + { transaction }, + ) + .then(() => + queryInterface.sequelize.query( + `ALTER TABLE "case" ALTER COLUMN state SET DEFAULT 'NEW'`, + { transaction }, + ), + ), + ) + }, +} diff --git a/apps/judicial-system/backend/src/app/modules/case/case.controller.ts b/apps/judicial-system/backend/src/app/modules/case/case.controller.ts index d055e66339fb..8dac765b2028 100644 --- a/apps/judicial-system/backend/src/app/modules/case/case.controller.ts +++ b/apps/judicial-system/backend/src/app/modules/case/case.controller.ts @@ -404,6 +404,12 @@ export class CaseController { case CaseTransition.REDISTRIBUTE: update.judgeId = null break + case CaseTransition.ASK_FOR_CANCELLATION: + if (theCase.indictmentDecision) { + throw new ForbiddenException( + `Cannot ask for cancellation of an indictment that is already in progress at the district court`, + ) + } } const updatedCase = await this.caseService.update( diff --git a/apps/judicial-system/backend/src/app/modules/case/case.service.ts b/apps/judicial-system/backend/src/app/modules/case/case.service.ts index 408ad4b46bd6..05151c8a9163 100644 --- a/apps/judicial-system/backend/src/app/modules/case/case.service.ts +++ b/apps/judicial-system/backend/src/app/modules/case/case.service.ts @@ -430,7 +430,7 @@ export class CaseService { ...caseToCreate, state: isIndictmentCase(caseToCreate.type) ? CaseState.DRAFT - : undefined, + : CaseState.NEW, }, { transaction }, ) diff --git a/apps/judicial-system/backend/src/app/modules/case/filters/case.filter.ts b/apps/judicial-system/backend/src/app/modules/case/filters/case.filter.ts index ae961f3745f8..b2998ffb9706 100644 --- a/apps/judicial-system/backend/src/app/modules/case/filters/case.filter.ts +++ b/apps/judicial-system/backend/src/app/modules/case/filters/case.filter.ts @@ -38,6 +38,7 @@ const canProsecutionUserAccessCase = ( CaseState.DRAFT, CaseState.WAITING_FOR_CONFIRMATION, CaseState.SUBMITTED, + CaseState.WAITING_FOR_CANCELLATION, CaseState.RECEIVED, CaseState.MAIN_HEARING, CaseState.ACCEPTED, @@ -115,6 +116,7 @@ const canDistrictCourtUserAccessCase = (theCase: Case, user: User): boolean => { } else if ( ![ CaseState.SUBMITTED, + CaseState.WAITING_FOR_CANCELLATION, CaseState.RECEIVED, CaseState.MAIN_HEARING, CaseState.COMPLETED, @@ -232,6 +234,7 @@ const canDefenceUserAccessCase = (theCase: Case, user: User): boolean => { if ( ![ CaseState.SUBMITTED, + CaseState.WAITING_FOR_CANCELLATION, CaseState.RECEIVED, CaseState.MAIN_HEARING, CaseState.ACCEPTED, diff --git a/apps/judicial-system/backend/src/app/modules/case/filters/cases.filter.ts b/apps/judicial-system/backend/src/app/modules/case/filters/cases.filter.ts index 838275876e6d..3f1c0a9ecdd0 100644 --- a/apps/judicial-system/backend/src/app/modules/case/filters/cases.filter.ts +++ b/apps/judicial-system/backend/src/app/modules/case/filters/cases.filter.ts @@ -32,6 +32,7 @@ const getProsecutionUserCasesQueryFilter = (user: User): WhereOptions => { CaseState.DRAFT, CaseState.WAITING_FOR_CONFIRMATION, CaseState.SUBMITTED, + CaseState.WAITING_FOR_CANCELLATION, CaseState.RECEIVED, CaseState.MAIN_HEARING, CaseState.ACCEPTED, @@ -99,6 +100,7 @@ const getDistrictCourtUserCasesQueryFilter = (user: User): WhereOptions => { { state: [ CaseState.SUBMITTED, + CaseState.WAITING_FOR_CANCELLATION, CaseState.RECEIVED, CaseState.MAIN_HEARING, CaseState.COMPLETED, @@ -129,6 +131,7 @@ const getDistrictCourtUserCasesQueryFilter = (user: User): WhereOptions => { { state: [ CaseState.SUBMITTED, + CaseState.WAITING_FOR_CANCELLATION, CaseState.RECEIVED, CaseState.MAIN_HEARING, CaseState.COMPLETED, @@ -243,6 +246,7 @@ const getDefenceUserCasesQueryFilter = (user: User): WhereOptions => { { type: indictmentCases }, { state: [ + CaseState.WAITING_FOR_CANCELLATION, CaseState.RECEIVED, CaseState.MAIN_HEARING, CaseState.COMPLETED, diff --git a/apps/judicial-system/backend/src/app/modules/case/filters/test/cases.filter.spec.ts b/apps/judicial-system/backend/src/app/modules/case/filters/test/cases.filter.spec.ts index ae76694aef42..62fe763b7161 100644 --- a/apps/judicial-system/backend/src/app/modules/case/filters/test/cases.filter.spec.ts +++ b/apps/judicial-system/backend/src/app/modules/case/filters/test/cases.filter.spec.ts @@ -47,6 +47,7 @@ describe('getCasesQueryFilter', () => { CaseState.DRAFT, CaseState.WAITING_FOR_CONFIRMATION, CaseState.SUBMITTED, + CaseState.WAITING_FOR_CANCELLATION, CaseState.RECEIVED, CaseState.MAIN_HEARING, CaseState.ACCEPTED, @@ -106,6 +107,7 @@ describe('getCasesQueryFilter', () => { CaseState.DRAFT, CaseState.WAITING_FOR_CONFIRMATION, CaseState.SUBMITTED, + CaseState.WAITING_FOR_CANCELLATION, CaseState.RECEIVED, CaseState.MAIN_HEARING, CaseState.ACCEPTED, @@ -181,6 +183,7 @@ describe('getCasesQueryFilter', () => { { state: [ CaseState.SUBMITTED, + CaseState.WAITING_FOR_CANCELLATION, CaseState.RECEIVED, CaseState.MAIN_HEARING, CaseState.COMPLETED, @@ -228,6 +231,7 @@ describe('getCasesQueryFilter', () => { { state: [ CaseState.SUBMITTED, + CaseState.WAITING_FOR_CANCELLATION, CaseState.RECEIVED, CaseState.MAIN_HEARING, CaseState.COMPLETED, @@ -427,6 +431,7 @@ describe('getCasesQueryFilter', () => { { type: indictmentCases }, { state: [ + CaseState.WAITING_FOR_CANCELLATION, CaseState.RECEIVED, CaseState.MAIN_HEARING, ...completedIndictmentCaseStates, diff --git a/apps/judicial-system/backend/src/app/modules/case/filters/test/defenceUserFilter.spec.ts b/apps/judicial-system/backend/src/app/modules/case/filters/test/defenceUserFilter.spec.ts index 927e3ecd7238..a306275a4f0b 100644 --- a/apps/judicial-system/backend/src/app/modules/case/filters/test/defenceUserFilter.spec.ts +++ b/apps/judicial-system/backend/src/app/modules/case/filters/test/defenceUserFilter.spec.ts @@ -22,6 +22,7 @@ describe.each(defenceRoles)('defence user %s', (role) => { `r-case type %s`, (type) => { const accessibleCaseStates = [ + CaseState.WAITING_FOR_CANCELLATION, CaseState.SUBMITTED, CaseState.RECEIVED, CaseState.MAIN_HEARING, @@ -171,6 +172,7 @@ describe.each(defenceRoles)('defence user %s', (role) => { describe.each(indictmentCases)(`s-case type %s`, (type) => { const accessibleCaseStates = [ + CaseState.WAITING_FOR_CANCELLATION, CaseState.RECEIVED, CaseState.MAIN_HEARING, ...completedCaseStates, diff --git a/apps/judicial-system/backend/src/app/modules/case/filters/test/districtCourtUserFilter.spec.ts b/apps/judicial-system/backend/src/app/modules/case/filters/test/districtCourtUserFilter.spec.ts index 54588b5af2a2..fe9e21a68855 100644 --- a/apps/judicial-system/backend/src/app/modules/case/filters/test/districtCourtUserFilter.spec.ts +++ b/apps/judicial-system/backend/src/app/modules/case/filters/test/districtCourtUserFilter.spec.ts @@ -39,7 +39,9 @@ const continueFromCaseState = (user: User, type: string, state: string) => { const continueFromIndictmentType = (user: User, type: string) => { const accessibleCaseStates = [ CaseState.SUBMITTED, + CaseState.WAITING_FOR_CANCELLATION, CaseState.RECEIVED, + CaseState.MAIN_HEARING, CaseState.COMPLETED, ] diff --git a/apps/judicial-system/backend/src/app/modules/case/filters/test/prosecutionUserFilter.spec.ts b/apps/judicial-system/backend/src/app/modules/case/filters/test/prosecutionUserFilter.spec.ts index 8a6d1d70de0d..f86f1f6a7199 100644 --- a/apps/judicial-system/backend/src/app/modules/case/filters/test/prosecutionUserFilter.spec.ts +++ b/apps/judicial-system/backend/src/app/modules/case/filters/test/prosecutionUserFilter.spec.ts @@ -122,11 +122,15 @@ const continueFromType = (user: User, type: CaseType) => { const accessibleCaseStates = [ CaseState.NEW, CaseState.DRAFT, + CaseState.WAITING_FOR_CONFIRMATION, CaseState.SUBMITTED, + CaseState.WAITING_FOR_CANCELLATION, CaseState.RECEIVED, + CaseState.MAIN_HEARING, CaseState.ACCEPTED, CaseState.REJECTED, CaseState.DISMISSED, + CaseState.COMPLETED, ] describe.each( diff --git a/apps/judicial-system/backend/src/app/modules/case/guards/rolesRules.ts b/apps/judicial-system/backend/src/app/modules/case/guards/rolesRules.ts index caf236254b97..623e3cc1c605 100644 --- a/apps/judicial-system/backend/src/app/modules/case/guards/rolesRules.ts +++ b/apps/judicial-system/backend/src/app/modules/case/guards/rolesRules.ts @@ -189,6 +189,7 @@ export const prosecutorTransitionRule: RolesRule = { CaseTransition.OPEN, CaseTransition.ASK_FOR_CONFIRMATION, CaseTransition.SUBMIT, + CaseTransition.ASK_FOR_CANCELLATION, CaseTransition.DELETE, CaseTransition.APPEAL, CaseTransition.WITHDRAW_APPEAL, diff --git a/apps/judicial-system/backend/src/app/modules/case/internalCase.service.ts b/apps/judicial-system/backend/src/app/modules/case/internalCase.service.ts index 028c0a158b3f..907bdf0c9aa2 100644 --- a/apps/judicial-system/backend/src/app/modules/case/internalCase.service.ts +++ b/apps/judicial-system/backend/src/app/modules/case/internalCase.service.ts @@ -341,7 +341,7 @@ export class InternalCaseService { ...caseToCreate, state: isIndictmentCase(caseToCreate.type) ? CaseState.DRAFT - : undefined, + : CaseState.NEW, origin: CaseOrigin.LOKE, creatingProsecutorId: creator.id, prosecutorId: diff --git a/apps/judicial-system/backend/src/app/modules/case/state/case.state.spec.ts b/apps/judicial-system/backend/src/app/modules/case/state/case.state.spec.ts index 8114e399c09c..e4eb6b9e1169 100644 --- a/apps/judicial-system/backend/src/app/modules/case/state/case.state.spec.ts +++ b/apps/judicial-system/backend/src/app/modules/case/state/case.state.spec.ts @@ -296,6 +296,62 @@ describe('Transition Case', () => { }, ) + describe.each(indictmentCases)('ask for cancellation %s', (type) => { + const allowedFromStates = [CaseState.SUBMITTED, CaseState.RECEIVED] + + describe.each(allowedFromStates)( + 'state %s - should ask for cancellation', + (fromState) => { + // Act + const res = transitionCase( + CaseTransition.ASK_FOR_CANCELLATION, + type, + fromState, + ) + + // Assert + expect(res).toEqual({ state: CaseState.WAITING_FOR_CANCELLATION }) + }, + ) + + describe.each( + Object.values(CaseState).filter( + (state) => !allowedFromStates.includes(state), + ), + )('state %s - should not ask for cancellation', (fromState) => { + // Arrange + const act = () => + transitionCase(CaseTransition.ASK_FOR_CANCELLATION, type, fromState) + + // Act and assert + expect(act).toThrow(ForbiddenException) + }) + }) + + describe.each([...restrictionCases, ...investigationCases])( + 'ask for cancellation %s', + (type) => { + describe.each(Object.values(CaseState))('state %s', (fromState) => { + it.each([undefined, ...Object.values(CaseAppealState)])( + 'appeal state %s - should not ask for cancellation', + (fromAppealState) => { + // Arrange + const act = () => + transitionCase( + CaseTransition.ASK_FOR_CANCELLATION, + type, + fromState, + fromAppealState, + ) + + // Act and assert + expect(act).toThrow(ForbiddenException) + }, + ) + }) + }, + ) + describe.each(indictmentCases)('receive %s', (type) => { const allowedFromStates = [CaseState.SUBMITTED] diff --git a/apps/judicial-system/backend/src/app/modules/case/state/case.state.ts b/apps/judicial-system/backend/src/app/modules/case/state/case.state.ts index fbae47a66af0..80fa6200ae7a 100644 --- a/apps/judicial-system/backend/src/app/modules/case/state/case.state.ts +++ b/apps/judicial-system/backend/src/app/modules/case/state/case.state.ts @@ -67,6 +67,13 @@ const indictmentCaseStateMachine: Map< to: { state: IndictmentCaseState.SUBMITTED }, }, ], + [ + IndictmentCaseTransition.ASK_FOR_CANCELLATION, + { + fromStates: [IndictmentCaseState.SUBMITTED, IndictmentCaseState.RECEIVED], + to: { state: IndictmentCaseState.WAITING_FOR_CANCELLATION }, + }, + ], [ IndictmentCaseTransition.RECEIVE, { diff --git a/apps/judicial-system/backend/src/app/modules/case/test/caseController/transition.spec.ts b/apps/judicial-system/backend/src/app/modules/case/test/caseController/transition.spec.ts index 5a3ff83919e4..774152c08b7b 100644 --- a/apps/judicial-system/backend/src/app/modules/case/test/caseController/transition.spec.ts +++ b/apps/judicial-system/backend/src/app/modules/case/test/caseController/transition.spec.ts @@ -295,6 +295,8 @@ describe('CaseController - Transition', () => { ${CaseTransition.ASK_FOR_CONFIRMATION} | ${CaseState.DRAFT} | ${CaseState.WAITING_FOR_CONFIRMATION} ${CaseTransition.DENY_INDICTMENT} | ${CaseState.WAITING_FOR_CONFIRMATION} | ${CaseState.DRAFT} ${CaseTransition.SUBMIT} | ${CaseState.WAITING_FOR_CONFIRMATION} | ${CaseState.SUBMITTED} + ${CaseTransition.ASK_FOR_CANCELLATION} | ${CaseState.SUBMITTED} | ${CaseState.WAITING_FOR_CANCELLATION} + ${CaseTransition.ASK_FOR_CANCELLATION} | ${CaseState.RECEIVED} | ${CaseState.WAITING_FOR_CANCELLATION} ${CaseTransition.RECEIVE} | ${CaseState.SUBMITTED} | ${CaseState.RECEIVED} ${CaseTransition.RETURN_INDICTMENT} | ${CaseState.RECEIVED} | ${CaseState.DRAFT} ${CaseTransition.REDISTRIBUTE} | ${CaseState.RECEIVED} | ${CaseState.MAIN_HEARING} diff --git a/apps/judicial-system/web/src/components/TagCaseState/TagCaseState.strings.ts b/apps/judicial-system/web/src/components/TagCaseState/TagCaseState.strings.ts index 0f472acf678e..f48fe981bc43 100644 --- a/apps/judicial-system/web/src/components/TagCaseState/TagCaseState.strings.ts +++ b/apps/judicial-system/web/src/components/TagCaseState/TagCaseState.strings.ts @@ -78,4 +78,9 @@ export const strings = defineMessages({ '{indictmentRulingDecision, select, RULING {Dómur} FINE {Viðurlagaákvörðun} DISMISSAL {Frávísun} CANCELLATION {Niðurfelling} other {Lokið}}', description: 'Notað sem merki þegar mál í stöðu "Dómþulur" í málalista', }, + cancelled: { + id: 'judicial.system.core:tag_case_state.cancelled', + defaultMessage: 'Afturkallað', + description: 'Notað sem merki þegar mál í stöðu "Afturkallað" í málalista', + }, }) diff --git a/apps/judicial-system/web/src/components/TagCaseState/TagCaseState.tsx b/apps/judicial-system/web/src/components/TagCaseState/TagCaseState.tsx index 15de59551ee9..6ef9eeeaa792 100644 --- a/apps/judicial-system/web/src/components/TagCaseState/TagCaseState.tsx +++ b/apps/judicial-system/web/src/components/TagCaseState/TagCaseState.tsx @@ -99,6 +99,11 @@ export const mapCaseStateToTagVariant = ( color: 'darkerBlue', text: formatMessage(strings.completed, { indictmentRulingDecision }), } + case CaseState.WAITING_FOR_CANCELLATION: + return { + color: 'rose', + text: formatMessage(strings.cancelled), + } default: return { color: 'white', text: formatMessage(strings.unknown) } } diff --git a/apps/judicial-system/web/src/routes/Defender/Cases/Cases.tsx b/apps/judicial-system/web/src/routes/Defender/Cases/Cases.tsx index 3fde1fce30e1..91b69fe242ae 100644 --- a/apps/judicial-system/web/src/routes/Defender/Cases/Cases.tsx +++ b/apps/judicial-system/web/src/routes/Defender/Cases/Cases.tsx @@ -9,6 +9,7 @@ import { PageHeader, SharedPageLayout, } from '@island.is/judicial-system-web/src/components' +import { CaseState } from '@island.is/judicial-system-web/src/graphql/schema' import DefenderCasesTable from './components/DefenderCasesTable' import FilterCheckboxes from './components/FilterCheckboxes' @@ -44,7 +45,14 @@ export const Cases: FC = () => { return [[], []] } - return partition(cases, (c) => !isCompletedCase(c.state)) + return partition( + cases, + (c) => + !( + isCompletedCase(c.state) || + c.state === CaseState.WAITING_FOR_CANCELLATION + ), + ) }, [cases]) const { diff --git a/apps/judicial-system/web/src/routes/Prosecutor/Indictments/Overview/Overview.strings.ts b/apps/judicial-system/web/src/routes/Prosecutor/Indictments/Overview/Overview.strings.ts index 499ba7861d5c..24e17b69be86 100644 --- a/apps/judicial-system/web/src/routes/Prosecutor/Indictments/Overview/Overview.strings.ts +++ b/apps/judicial-system/web/src/routes/Prosecutor/Indictments/Overview/Overview.strings.ts @@ -68,7 +68,6 @@ export const overview = { defaultMessage: 'Hætta við', description: 'Texti í takka í modal glugga á Yfirlit ákæru skefi í ákærum.', }), - indictmentSentToCourt: defineMessage({ id: 'judicial.system.indictments:overview.indictment_sent_to_court', defaultMessage: 'Ákæra hefur verið send dómstól', @@ -99,4 +98,35 @@ export const overview = { description: 'Notaður sem titill á "Ákæra endursend" hluta af yfirliti ákæru á Yfirlit ákæru skefi í ákærum.', }), + askForCancellationButtonText: defineMessage({ + id: 'judicial.system.indictments:overview.ask_for_cancellation_button_text', + defaultMessage: 'Afturkalla ákæru', + description: + 'Texti á takka til að afturkalla ákæru á Yfirlit ákæru skefi í ákærum.', + }), + askForCancellationModalTitle: defineMessage({ + id: 'judicial.system.indictments:overview.ask_for_cancellation_modal_title', + defaultMessage: 'Viltu afturkall ákæru?', + description: + 'Titill í afturkalla modal glugga á Yfirlit ákæru skefi í ákærum.', + }), + askForCancellationModalText: defineMessage({ + id: 'judicial.system.indictments:overview.ask_for_cancellation_modal_text', + defaultMessage: + 'Dómurinn fær tilkynningu um afturköllun ákæru ásamt verjanda hafi verjandi verið skráður.', + description: + 'Texti í afturkalla modal glugga á Yfirlit ákæru skefi í ákærum.', + }), + askForCancellationPrimaryButtonText: defineMessage({ + id: 'judicial.system.indictments:overview.ask_for_cancellation_primary_button_text', + defaultMessage: 'Afturkalla ákæru', + description: + 'Texti í staðfesta takka í afturkalla modal glugga á Yfirlit ákæru skefi í ákærum.', + }), + askForCancellationSecondaryButtonText: defineMessage({ + id: 'judicial.system.indictments:overview.ask_for_cancellation_secondary_button_text', + defaultMessage: 'Hætta við', + description: + 'Texti í hætta við takka í afturkalla modal glugga á Yfirlit ákæru skefi í ákærum.', + }), } diff --git a/apps/judicial-system/web/src/routes/Prosecutor/Indictments/Overview/Overview.tsx b/apps/judicial-system/web/src/routes/Prosecutor/Indictments/Overview/Overview.tsx index a06f031d8364..0e1c283cf97c 100644 --- a/apps/judicial-system/web/src/routes/Prosecutor/Indictments/Overview/Overview.tsx +++ b/apps/judicial-system/web/src/routes/Prosecutor/Indictments/Overview/Overview.tsx @@ -48,6 +48,7 @@ const Overview: React.FC> = () => { | 'caseSubmitModal' | 'caseSentForConfirmationModal' | 'caseDeniedModal' + | 'askForCancellationModal' >('noModal') const [indictmentConfirmationDecision, setIndictmentConfirmationDecision] = useState<'confirm' | 'deny'>() @@ -124,6 +125,18 @@ const Overview: React.FC> = () => { router.push(constants.CASES_ROUTE) } + const handleAskForCancellation = async () => { + const transitionSuccess = await handleTransition( + CaseTransition.ASK_FOR_CANCELLATION, + ) + + if (!transitionSuccess) { + return + } + + router.push(constants.CASES_ROUTE) + } + return ( > = () => { nextIsDisabled={ userCanSendCaseToCourt && !indictmentConfirmationDecision } + actionButtonText={formatMessage(strings.askForCancellationButtonText)} + actionButtonColorScheme={'destructive'} + actionButtonIsDisabled={ + !( + workingCase.state && + [CaseState.SUBMITTED, CaseState.RECEIVED].includes( + workingCase.state, + ) && + !workingCase.indictmentDecision + ) + } + onActionButtonClick={() => setModal('askForCancellationModal')} /> @@ -274,6 +299,21 @@ const Overview: React.FC> = () => { onClose={() => setModal('noModal')} onComplete={() => router.push(constants.CASES_ROUTE)} /> + ) : modal === 'askForCancellationModal' ? ( + setModal('noModal')} + secondaryButtonText={formatMessage( + strings.askForCancellationSecondaryButtonText, + )} + onSecondaryButtonClick={() => setModal('noModal')} + onPrimaryButtonClick={handleAskForCancellation} + primaryButtonText={formatMessage( + strings.askForCancellationPrimaryButtonText, + )} + isPrimaryButtonLoading={isTransitioningCase} + /> ) : null} diff --git a/apps/judicial-system/web/src/routes/Shared/Cases/Cases.tsx b/apps/judicial-system/web/src/routes/Shared/Cases/Cases.tsx index 370da48a6d1a..77b07b4edf04 100644 --- a/apps/judicial-system/web/src/routes/Shared/Cases/Cases.tsx +++ b/apps/judicial-system/web/src/routes/Shared/Cases/Cases.tsx @@ -146,7 +146,10 @@ export const Cases: React.FC = () => { ) const casesAwaitingAssignment = filterCases( - (c) => isIndictmentCase(c.type) && c.judge === null, + (c) => + isIndictmentCase(c.type) && + c.state !== CaseState.WAITING_FOR_CANCELLATION && + c.judge === null, ) const casesAwaitingReview = filterCases( @@ -163,11 +166,27 @@ export const Cases: React.FC = () => { return false } - if (isIndictmentCase(c.type) || !isDistrictCourtUser(user)) { - return !isCompletedCase(c.state) - } else { - return !(isCompletedCase(c.state) && c.rulingSignatureDate) + if (isDistrictCourtUser(user)) { + if (isIndictmentCase(c.type)) { + return !isCompletedCase(c.state) + } else { + return !(isCompletedCase(c.state) && c.rulingSignatureDate) + } + } + + if (isProsecutionUser(user)) { + if (isIndictmentCase(c.type)) { + return !( + isCompletedCase(c.state) || + c.state === CaseState.WAITING_FOR_CANCELLATION + ) + } else { + return !isCompletedCase(c.state) + } } + + // This componenet is only used for prosecution and district court users + return false }) const pastCases = filterCases( @@ -200,8 +219,7 @@ export const Cases: React.FC = () => { caseToDelete.state === CaseState.DRAFT || caseToDelete.state === CaseState.WAITING_FOR_CONFIRMATION || caseToDelete.state === CaseState.SUBMITTED || - caseToDelete.state === CaseState.RECEIVED || - caseToDelete.state === CaseState.MAIN_HEARING + caseToDelete.state === CaseState.RECEIVED ) { await transitionCase(caseToDelete.id, CaseTransition.DELETE) refetch() diff --git a/libs/judicial-system/types/src/lib/case.ts b/libs/judicial-system/types/src/lib/case.ts index b530063dcf1f..85d807939542 100644 --- a/libs/judicial-system/types/src/lib/case.ts +++ b/libs/judicial-system/types/src/lib/case.ts @@ -96,6 +96,7 @@ export enum CaseState { SUBMITTED = 'SUBMITTED', RECEIVED = 'RECEIVED', MAIN_HEARING = 'MAIN_HEARING', + WAITING_FOR_CANCELLATION = 'WAITING_FOR_CANCELLATION', COMPLETED = 'COMPLETED', ACCEPTED = 'ACCEPTED', REJECTED = 'REJECTED', @@ -109,6 +110,7 @@ export enum IndictmentCaseState { SUBMITTED = CaseState.SUBMITTED, RECEIVED = CaseState.RECEIVED, MAIN_HEARING = CaseState.MAIN_HEARING, + WAITING_FOR_CANCELLATION = CaseState.WAITING_FOR_CANCELLATION, COMPLETED = CaseState.COMPLETED, DELETED = CaseState.DELETED, } @@ -136,6 +138,7 @@ export enum CaseTransition { ASK_FOR_CONFIRMATION = 'ASK_FOR_CONFIRMATION', DENY_INDICTMENT = 'DENY_INDICTMENT', SUBMIT = 'SUBMIT', + ASK_FOR_CANCELLATION = 'ASK_FOR_CANCELLATION', RECEIVE = 'RECEIVE', RETURN_INDICTMENT = 'RETURN_INDICTMENT', REDISTRIBUTE = 'REDISTRIBUTE', @@ -153,30 +156,31 @@ export enum CaseTransition { } export enum IndictmentCaseTransition { - ASK_FOR_CONFIRMATION = 'ASK_FOR_CONFIRMATION', - DENY_INDICTMENT = 'DENY_INDICTMENT', - SUBMIT = 'SUBMIT', - RECEIVE = 'RECEIVE', - RETURN_INDICTMENT = 'RETURN_INDICTMENT', - REDISTRIBUTE = 'REDISTRIBUTE', - COMPLETE = 'COMPLETE', - DELETE = 'DELETE', + ASK_FOR_CONFIRMATION = CaseTransition.ASK_FOR_CONFIRMATION, + DENY_INDICTMENT = CaseTransition.DENY_INDICTMENT, + SUBMIT = CaseTransition.SUBMIT, + ASK_FOR_CANCELLATION = CaseTransition.ASK_FOR_CANCELLATION, + RECEIVE = CaseTransition.RECEIVE, + RETURN_INDICTMENT = CaseTransition.RETURN_INDICTMENT, + REDISTRIBUTE = CaseTransition.REDISTRIBUTE, + COMPLETE = CaseTransition.COMPLETE, + DELETE = CaseTransition.DELETE, } export enum RequestCaseTransition { - OPEN = 'OPEN', - SUBMIT = 'SUBMIT', - RECEIVE = 'RECEIVE', - ACCEPT = 'ACCEPT', - REJECT = 'REJECT', - DISMISS = 'DISMISS', - DELETE = 'DELETE', - REOPEN = 'REOPEN', - APPEAL = 'APPEAL', - RECEIVE_APPEAL = 'RECEIVE_APPEAL', - COMPLETE_APPEAL = 'COMPLETE_APPEAL', - REOPEN_APPEAL = 'REOPEN_APPEAL', - WITHDRAW_APPEAL = 'WITHDRAW_APPEAL', + OPEN = CaseTransition.OPEN, + SUBMIT = CaseTransition.SUBMIT, + RECEIVE = CaseTransition.RECEIVE, + ACCEPT = CaseTransition.ACCEPT, + REJECT = CaseTransition.REJECT, + DISMISS = CaseTransition.DISMISS, + DELETE = CaseTransition.DELETE, + REOPEN = CaseTransition.REOPEN, + APPEAL = CaseTransition.APPEAL, + RECEIVE_APPEAL = CaseTransition.RECEIVE_APPEAL, + COMPLETE_APPEAL = CaseTransition.COMPLETE_APPEAL, + REOPEN_APPEAL = CaseTransition.REOPEN_APPEAL, + WITHDRAW_APPEAL = CaseTransition.WITHDRAW_APPEAL, } /* eslint-disable @typescript-eslint/naming-convention */ From 74176d65287ec01cb605aef9be1fb85000e72dd9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gu=C3=B0j=C3=B3n=20Gu=C3=B0j=C3=B3nsson?= Date: Wed, 5 Jun 2024 11:36:18 +0000 Subject: [PATCH 27/47] Hides buttons when prosecutor has asked for cancellation --- .../web/src/components/FormFooter/FormFooter.tsx | 3 ++- .../routes/Prosecutor/Indictments/Overview/Overview.tsx | 8 +++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/apps/judicial-system/web/src/components/FormFooter/FormFooter.tsx b/apps/judicial-system/web/src/components/FormFooter/FormFooter.tsx index 548f9bb4885d..5dc0054a10ed 100644 --- a/apps/judicial-system/web/src/components/FormFooter/FormFooter.tsx +++ b/apps/judicial-system/web/src/components/FormFooter/FormFooter.tsx @@ -32,6 +32,7 @@ interface Props { actionButtonColorScheme?: 'destructive' actionButtonIsDisabled?: boolean onActionButtonClick?: () => void + hideActionButton?: boolean infoBoxText?: string } @@ -66,7 +67,7 @@ const FormFooter: React.FC> = (props: Props) => { {!isMobile && (props.previousButtonText || formatMessage(core.back))} - {props.actionButtonText && ( + {!props.hideActionButton && props.actionButtonText && ( - -
- { - setCreateCourtCaseSuccess(false) - removeTabsValidateAndSet( - 'courtCaseNumber', - event.target.value, - [ - 'empty', - isIndictmentCase(workingCase.type) - ? 'S-case-number' - : 'R-case-number', - ], - setWorkingCase, - courtCaseNumberEM, - setCourtCaseNumberEM, - ) - }} - onBlur={(event) => { - validateAndSendToServer( - 'courtCaseNumber', - event.target.value, - [ - 'empty', - isIndictmentCase(workingCase.type) - ? 'S-case-number' - : 'R-case-number', - ], - workingCase, - updateCourtCaseNumber, - setCourtCaseNumberEM, - ) - }} - disabled={ - workingCase.state !== CaseState.SUBMITTED && - workingCase.state !== CaseState.RECEIVED && - workingCase.state !== CaseState.MAIN_HEARING - } - required - /> -
-
- - + ) } diff --git a/apps/judicial-system/web/src/routes/Court/components/CourtCaseNumber/CourtCaseNumberInput.tsx b/apps/judicial-system/web/src/routes/Court/components/CourtCaseNumber/CourtCaseNumberInput.tsx new file mode 100644 index 000000000000..46b8c3edd1a7 --- /dev/null +++ b/apps/judicial-system/web/src/routes/Court/components/CourtCaseNumber/CourtCaseNumberInput.tsx @@ -0,0 +1,161 @@ +import React, { useState } from 'react' +import { useIntl } from 'react-intl' + +import { Box, Button, Input } from '@island.is/island-ui/core' +import { isIndictmentCase } from '@island.is/judicial-system/types' +import { BlueBox } from '@island.is/judicial-system-web/src/components' +import { CaseState } from '@island.is/judicial-system-web/src/graphql/schema' +import { TempCase as Case } from '@island.is/judicial-system-web/src/types' +import { + removeTabsValidateAndSet, + validateAndSendToServer, +} from '@island.is/judicial-system-web/src/utils/formHelper' +import { + UpdateCase, + useCase, +} from '@island.is/judicial-system-web/src/utils/hooks' +import { validate } from '@island.is/judicial-system-web/src/utils/validate' + +import { courtCaseNumber } from './CourtCaseNumber.strings' +import * as styles from './CourtCaseNumber.css' + +interface Props { + workingCase: Case + setWorkingCase: React.Dispatch> +} + +const CourtCaseNumberInput: React.FC> = ( + props, +) => { + const { workingCase, setWorkingCase } = props + + const { formatMessage } = useIntl() + const { updateCase, createCourtCase, isCreatingCourtCase } = useCase() + const [courtCaseNumberErrorMessage, setCourtCaseNumberErrorMessage] = + useState('') + const [createCourtCaseSuccess, setCreateCourtCaseSuccess] = + useState(false) + + const handleCreateCourtCase = async (workingCase: Case) => { + const courtCaseNumber = await createCourtCase(workingCase, setWorkingCase) + + if (courtCaseNumber !== '') { + setCourtCaseNumberErrorMessage('') + setCreateCourtCaseSuccess(true) + } else { + setCourtCaseNumberErrorMessage( + 'Ekki tókst að stofna nýtt mál, reyndu aftur eða sláðu inn málsnúmer', + ) + } + } + + const updateCourtCaseNumber = async (id: string, update: UpdateCase) => { + const isValid = validate([ + [ + update.courtCaseNumber, + [ + 'empty', + isIndictmentCase(workingCase.type) + ? 'S-case-number' + : 'R-case-number', + ], + ], + ]).isValid + + if (!isValid) { + return + } + + await updateCase(id, update) + } + + return ( + +
+ +
+ +
+
+ { + setCreateCourtCaseSuccess(false) + removeTabsValidateAndSet( + 'courtCaseNumber', + event.target.value, + [ + 'empty', + isIndictmentCase(workingCase.type) + ? 'S-case-number' + : 'R-case-number', + ], + setWorkingCase, + courtCaseNumberErrorMessage, + setCourtCaseNumberErrorMessage, + ) + }} + onBlur={(event) => { + validateAndSendToServer( + 'courtCaseNumber', + event.target.value, + [ + 'empty', + isIndictmentCase(workingCase.type) + ? 'S-case-number' + : 'R-case-number', + ], + workingCase, + updateCourtCaseNumber, + setCourtCaseNumberErrorMessage, + ) + }} + disabled={ + workingCase.state !== CaseState.SUBMITTED && + workingCase.state !== CaseState.WAITING_FOR_CANCELLATION && + workingCase.state !== CaseState.RECEIVED && + workingCase.state !== CaseState.MAIN_HEARING + } + required + /> +
+
+
+
+ ) +} + +export default CourtCaseNumberInput diff --git a/apps/judicial-system/web/src/routes/Court/components/ReceptionAndAssignment/ReceptionAndAssignment.tsx b/apps/judicial-system/web/src/routes/Court/components/ReceptionAndAssignment/ReceptionAndAssignment.tsx index 5d0a48490ac5..177b9ee89677 100644 --- a/apps/judicial-system/web/src/routes/Court/components/ReceptionAndAssignment/ReceptionAndAssignment.tsx +++ b/apps/judicial-system/web/src/routes/Court/components/ReceptionAndAssignment/ReceptionAndAssignment.tsx @@ -18,8 +18,6 @@ import { PageLayout, } from '@island.is/judicial-system-web/src/components' import { Gender } from '@island.is/judicial-system-web/src/graphql/schema' -import { TempCase as Case } from '@island.is/judicial-system-web/src/types' -import { useCase } from '@island.is/judicial-system-web/src/utils/hooks' import { getDefendantPleaText } from '@island.is/judicial-system-web/src/utils/stepHelper' import { isReceptionAndAssignmentStepValid } from '@island.is/judicial-system-web/src/utils/validate' @@ -31,27 +29,10 @@ const ReceptionAndAssignment = () => { const router = useRouter() const id = router.query.id const { formatMessage } = useIntl() - const [courtCaseNumberEM, setCourtCaseNumberEM] = useState('') - const [createCourtCaseSuccess, setCreateCourtCaseSuccess] = - useState(false) - const { workingCase, setWorkingCase, isLoadingWorkingCase, caseNotFound } = + const { workingCase, isLoadingWorkingCase, caseNotFound } = useContext(FormContext) - const { createCourtCase, isCreatingCourtCase } = useCase() - - const handleCreateCourtCase = async (workingCase: Case) => { - const courtCaseNumber = await createCourtCase( - workingCase, - setWorkingCase, - setCourtCaseNumberEM, - ) - - if (courtCaseNumber !== '') { - setCreateCourtCaseSuccess(true) - } - } - const getNextRoute = () => { return isRestrictionCase(workingCase.type) ? constants.RESTRICTION_CASE_COURT_OVERVIEW_ROUTE @@ -137,16 +118,7 @@ const ReceptionAndAssignment = () => { - + diff --git a/apps/judicial-system/web/src/routes/Court/components/index.ts b/apps/judicial-system/web/src/routes/Court/components/index.ts index 5cd387b1bf71..7eb21ae65d86 100644 --- a/apps/judicial-system/web/src/routes/Court/components/index.ts +++ b/apps/judicial-system/web/src/routes/Court/components/index.ts @@ -1,5 +1,6 @@ export { default as AppealSections } from './AppealSections/AppealSections' export { default as CourtCaseNumber } from './CourtCaseNumber/CourtCaseNumber' +export { default as CourtCaseNumberInput } from './CourtCaseNumber/CourtCaseNumberInput' export { default as DraftConclusionModal } from './DraftConclusionModal/DraftConclusionModal' export { default as ReceptionAndAssignment } from './ReceptionAndAssignment/ReceptionAndAssignment' export { default as RulingModifiedModal } from './RulingModifiedModal/RulingModifiedModal' diff --git a/apps/judicial-system/web/src/routes/Shared/Cases/ActiveCases.tsx b/apps/judicial-system/web/src/routes/Shared/Cases/ActiveCases.tsx index 3d57cd455f43..fb426c242984 100644 --- a/apps/judicial-system/web/src/routes/Shared/Cases/ActiveCases.tsx +++ b/apps/judicial-system/web/src/routes/Shared/Cases/ActiveCases.tsx @@ -21,6 +21,7 @@ import { import { core, tables } from '@island.is/judicial-system-web/messages' import { ContextMenu, + FormContext, Modal, TagAppealState, TagCaseState, @@ -57,6 +58,7 @@ interface Props { cases: CaseListEntry[] isDeletingCase: boolean onDeleteCase?: (caseToDelete: CaseListEntry) => Promise + onCancelCase?: (caseToCancel: CaseListEntry) => Promise } const ActiveCases: React.FC> = (props) => { @@ -72,12 +74,14 @@ const ActiveCases: React.FC> = (props) => { direction: 'descending', }, ) - const [displayCases, setDisplayCases] = useState([]) - const [modalVisible, setVisibleModal] = useState<'DELETE_CASE'>() - // The index of requset that's about to be removed - const [requestToRemoveIndex, setRequestToRemoveIndex] = useState(-1) const { isOpeningCaseId, showLoading, handleOpenCase, LoadingIndicator } = useCaseList() + const [displayCases, setDisplayCases] = useState([]) + const [modalVisible, setVisibleModal] = useState< + 'DELETE_CASE' | 'CANCEL_CASE' + >() + // The id of the case that's about to be removed + const [caseToRemove, setCaseToRemove] = useState() useEffect(() => { setDisplayCases(cases) @@ -138,7 +142,13 @@ const ActiveCases: React.FC> = (props) => { {displayCases.map((theCase: CaseListEntry) => ( handleOpenCase(theCase.id)} + onClick={() => { + if (c.state === CaseState.WAITING_FOR_CANCELLATION) { + setVisibleModal('CANCEL_CASE') + } else { + handleOpenCase(c.id) + } + }} theCase={theCase} isCourtRole={isDistrictCourtUser(user)} isLoading={isOpeningCaseId === theCase.id && showLoading} @@ -236,7 +246,11 @@ const ActiveCases: React.FC> = (props) => { aria-label="Opna kröfu" aria-disabled={isDeletingCase || isOpeningCaseId === c.id} onClick={() => { - handleOpenCase(c.id) + if (c.state === CaseState.WAITING_FOR_CANCELLATION) { + setVisibleModal('CANCEL_CASE') + } else { + handleOpenCase(c.id) + } }} > @@ -368,52 +382,54 @@ const ActiveCases: React.FC> = (props) => { )} - - {isOpeningCaseId === c.id && showLoading ? ( -
- -
- ) : ( - handleOpenCase(c.id, true), - icon: 'open', - }, - ...(isProsecutionUser(user) && - (isRequestCase(c.type) || - c.state === CaseState.DRAFT || - c.state === CaseState.WAITING_FOR_CONFIRMATION) - ? [ - { - title: formatMessage( - contextMenuStrings.deleteCase, - ), - onClick: () => { - setRequestToRemoveIndex(i) - setVisibleModal('DELETE_CASE') + {c.state !== CaseState.WAITING_FOR_CANCELLATION && ( + + {isOpeningCaseId === c.id && showLoading ? ( +
+ +
+ ) : ( + handleOpenCase(c.id, true), + icon: 'open', + }, + ...(isProsecutionUser(user) && + (isRequestCase(c.type) || + c.state === CaseState.DRAFT || + c.state === CaseState.WAITING_FOR_CONFIRMATION) + ? [ + { + title: formatMessage( + contextMenuStrings.deleteCase, + ), + onClick: () => { + setCaseToRemove(c) + setVisibleModal('DELETE_CASE') + }, + icon: 'trash' as IconMapIcon, }, - icon: 'trash' as IconMapIcon, - }, - ] - : []), - ]} - disclosure={ - { - evt.stopPropagation() - }} - /> - } - /> - )} -
+ ] + : []), + ]} + disclosure={ + { + evt.stopPropagation() + }} + /> + } + /> + )} +
+ )} ))} @@ -426,12 +442,12 @@ const ActiveCases: React.FC> = (props) => { title={formatMessage(m.activeRequests.deleteCaseModal.title)} text={formatMessage(m.activeRequests.deleteCaseModal.text)} onPrimaryButtonClick={async () => { - if (onDeleteCase && requestToRemoveIndex !== -1) { - await onDeleteCase(cases[requestToRemoveIndex]) + if (onDeleteCase && caseToRemove) { + await onDeleteCase(caseToRemove) setDisplayCases((prev) => - prev.filter((c) => c.id !== cases[requestToRemoveIndex].id), + prev.filter((c) => c.id !== caseToRemove.id), ) - setRequestToRemoveIndex(-1) + setCaseToRemove(undefined) setVisibleModal(undefined) } }} @@ -448,6 +464,18 @@ const ActiveCases: React.FC> = (props) => { isPrimaryButtonLoading={isDeletingCase} /> )} + {modalVisible === 'CANCEL_CASE' && ( + { + setVisibleModal(undefined) + }} + /> + )} ) } diff --git a/apps/judicial-system/web/src/routes/Shared/Cases/Cases.strings.ts b/apps/judicial-system/web/src/routes/Shared/Cases/Cases.strings.ts index 8116e4451042..042749ccc670 100644 --- a/apps/judicial-system/web/src/routes/Shared/Cases/Cases.strings.ts +++ b/apps/judicial-system/web/src/routes/Shared/Cases/Cases.strings.ts @@ -108,6 +108,25 @@ export const cases = { description: 'Notaður sem texti á Halda áfram takka í Afturkalla mál.', }, }), + cancelCaseModal: defineMessages({ + title: { + id: 'judicial.system.core:cases.active_requests.cancel_case_modal.title', + defaultMessage: 'Mál afturkallað', + description: 'Notaður sem titill í Afturkalla mál dómstóla modal.', + }, + text: { + id: 'judicial.system.core:cases.active_requests.cancel_case_modal.text', + defaultMessage: + 'Ákæruvaldið hefur afturkallað ákæruna. Hægt er að skrá málsnúmer og ljúka málinu hér.', + description: 'Notaður sem texti í Afturkalla mál dómstóla modal.', + }, + secondaryButtonText: { + id: 'judicial.system.core:cases.active_requests.delete_case_modal.secondary_button_text', + defaultMessage: 'Hætta við', + description: + 'Notaður sem texti á Hætta við takka í Afturkalla mál dómstóla modal.', + }, + }), }, pastRequests: { table: { diff --git a/apps/judicial-system/web/src/utils/hooks/useCase/index.ts b/apps/judicial-system/web/src/utils/hooks/useCase/index.ts index 7724dcc2408f..25e92dd60ca1 100644 --- a/apps/judicial-system/web/src/utils/hooks/useCase/index.ts +++ b/apps/judicial-system/web/src/utils/hooks/useCase/index.ts @@ -209,9 +209,6 @@ const useCase = () => { async ( workingCase: Case, setWorkingCase: React.Dispatch>, - setCourtCaseNumberErrorMessage: React.Dispatch< - React.SetStateAction - >, ): Promise => { try { if (isCreatingCourtCase === false) { @@ -225,16 +222,11 @@ const useCase = () => { courtCaseNumber: (data.createCourtCase as Case).courtCaseNumber, })) - setCourtCaseNumberErrorMessage('') - return data.createCourtCase.courtCaseNumber } } } catch (error) { - // Catch all so we can set an eror message - setCourtCaseNumberErrorMessage( - 'Ekki tókst að stofna nýtt mál, reyndu aftur eða sláðu inn málsnúmer', - ) + // Catch all so we can return the empty string } return '' From cdad57dbf0d295a6706f16029b1e421f26a96577 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gu=C3=B0j=C3=B3n=20Gu=C3=B0j=C3=B3nsson?= Date: Fri, 7 Jun 2024 16:46:27 +0000 Subject: [PATCH 33/47] Fixes back navigation --- .../src/routes/Prosecutor/Indictments/Overview/Overview.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/judicial-system/web/src/routes/Prosecutor/Indictments/Overview/Overview.tsx b/apps/judicial-system/web/src/routes/Prosecutor/Indictments/Overview/Overview.tsx index 6faf5e5898d2..342f703ee25c 100644 --- a/apps/judicial-system/web/src/routes/Prosecutor/Indictments/Overview/Overview.tsx +++ b/apps/judicial-system/web/src/routes/Prosecutor/Indictments/Overview/Overview.tsx @@ -231,7 +231,8 @@ const Overview: React.FC> = () => { Date: Fri, 7 Jun 2024 16:50:05 +0000 Subject: [PATCH 34/47] Update apps/judicial-system/web/src/routes/Prosecutor/Indictments/Overview/Overview.tsx MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Ívar Oddsson --- .../web/src/routes/Prosecutor/Indictments/Overview/Overview.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/judicial-system/web/src/routes/Prosecutor/Indictments/Overview/Overview.tsx b/apps/judicial-system/web/src/routes/Prosecutor/Indictments/Overview/Overview.tsx index 6faf5e5898d2..4bc0478854c0 100644 --- a/apps/judicial-system/web/src/routes/Prosecutor/Indictments/Overview/Overview.tsx +++ b/apps/judicial-system/web/src/routes/Prosecutor/Indictments/Overview/Overview.tsx @@ -259,7 +259,7 @@ const Overview: React.FC> = () => { workingCase.state === CaseState.WAITING_FOR_CANCELLATION } actionButtonText={formatMessage(strings.askForCancellationButtonText)} - actionButtonColorScheme={'destructive'} + actionButtonColorScheme="destructive" actionButtonIsDisabled={ !( workingCase.state && From c78316058a22db826c6ae6c0d84583221d3501d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gu=C3=B0j=C3=B3n=20Gu=C3=B0j=C3=B3nsson?= Date: Fri, 7 Jun 2024 17:20:33 +0000 Subject: [PATCH 35/47] Refactors code --- .../Indictments/Overview/Overview.tsx | 61 +++++++++---------- 1 file changed, 28 insertions(+), 33 deletions(-) diff --git a/apps/judicial-system/web/src/routes/Prosecutor/Indictments/Overview/Overview.tsx b/apps/judicial-system/web/src/routes/Prosecutor/Indictments/Overview/Overview.tsx index 342f703ee25c..7554c44a55e3 100644 --- a/apps/judicial-system/web/src/routes/Prosecutor/Indictments/Overview/Overview.tsx +++ b/apps/judicial-system/web/src/routes/Prosecutor/Indictments/Overview/Overview.tsx @@ -57,16 +57,23 @@ const Overview: React.FC> = () => { const { transitionCase, isTransitioningCase } = useCase() const lawsBroken = useIndictmentsLawsBroken(workingCase) - const isNewIndictment = workingCase.state === CaseState.DRAFT - const isSubmittedIndictment = workingCase.state === CaseState.SUBMITTED - const caseHasBeenReceivedByCourt = + const latestDate = workingCase.courtDate ?? workingCase.arraignmentDate + + const isIndictmentNew = workingCase.state === CaseState.DRAFT + const isIndictmentSubmitted = workingCase.state === CaseState.SUBMITTED + const isIndictmentWaitingForCancellation = + workingCase.state === CaseState.WAITING_FOR_CANCELLATION + const isIndictmentReceived = workingCase.state === CaseState.RECEIVED || workingCase.state === CaseState.MAIN_HEARING - const latestDate = workingCase.courtDate ?? workingCase.arraignmentDate - const userCanSendCaseToCourt = Boolean( - user?.canConfirmIndictment && - workingCase.state === CaseState.WAITING_FOR_CONFIRMATION, - ) + + const userCanSendIndictmentToCourt = + Boolean(user?.canConfirmIndictment) && + workingCase.state === CaseState.WAITING_FOR_CONFIRMATION + const userCanCancelIndictment = + (workingCase.state === CaseState.SUBMITTED || + workingCase.state === CaseState.RECEIVED) && + !workingCase.indictmentDecision const handleTransition = async (transitionType: CaseTransition) => { const caseTransitioned = await transitionCase( @@ -87,15 +94,15 @@ const Overview: React.FC> = () => { let transitionType let modalType: typeof modal = 'noModal' - if (userCanSendCaseToCourt) { + if (userCanSendIndictmentToCourt) { if (indictmentConfirmationDecision === 'confirm') { modalType = 'caseSubmitModal' } else if (indictmentConfirmationDecision === 'deny') { modalType = 'caseDeniedModal' - } else if (isSubmittedIndictment) { + } else if (isIndictmentSubmitted) { transitionType = CaseTransition.ASK_FOR_CONFIRMATION } - } else if (isNewIndictment || isSubmittedIndictment) { + } else if (isIndictmentNew || isIndictmentSubmitted) { transitionType = CaseTransition.ASK_FOR_CONFIRMATION modalType = 'caseSentForConfirmationModal' } else if (workingCase.state === CaseState.WAITING_FOR_CONFIRMATION) { @@ -193,10 +200,10 @@ const Overview: React.FC> = () => {
)} - + - {userCanSendCaseToCourt && ( + {userCanSendIndictmentToCourt && ( > = () => { setModal('askForCancellationModal')} /> From b1309f59395672910833aba834edbb23d34151d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gu=C3=B0j=C3=B3n=20Gu=C3=B0j=C3=B3nsson?= Date: Fri, 7 Jun 2024 17:24:35 +0000 Subject: [PATCH 36/47] Rewrites condition --- apps/judicial-system/web/src/routes/Shared/Cases/Cases.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/judicial-system/web/src/routes/Shared/Cases/Cases.tsx b/apps/judicial-system/web/src/routes/Shared/Cases/Cases.tsx index 77b07b4edf04..aab52dd2cf4b 100644 --- a/apps/judicial-system/web/src/routes/Shared/Cases/Cases.tsx +++ b/apps/judicial-system/web/src/routes/Shared/Cases/Cases.tsx @@ -149,7 +149,7 @@ export const Cases: React.FC = () => { (c) => isIndictmentCase(c.type) && c.state !== CaseState.WAITING_FOR_CANCELLATION && - c.judge === null, + !c.judge, ) const casesAwaitingReview = filterCases( From 7fcdd3eadb6c3dcd1aeb405311947a1d266eabb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gu=C3=B0j=C3=B3n=20Gu=C3=B0j=C3=B3nsson?= Date: Sun, 9 Jun 2024 17:47:34 +0000 Subject: [PATCH 37/47] Completes cancellation --- .../app/modules/case/state/case.state.spec.ts | 5 +- .../src/app/modules/case/state/case.state.ts | 5 +- .../web/messages/Core/tables.ts | 5 + .../components/Table/CourtDate/CourtDate.tsx | 44 ++++ .../web/src/components/Table/Table.tsx | 57 +++-- .../web/src/components/Table/index.ts | 1 + .../CasesInProgressTable.strings.ts | 42 ++++ .../CasesInProgressTable.tsx | 205 ++++++++++++++++++ .../src/routes/Shared/Cases/ActiveCases.tsx | 136 +++++------- .../src/routes/Shared/Cases/Cases.strings.ts | 19 -- .../web/src/routes/Shared/Cases/Cases.tsx | 68 +++--- .../web/src/utils/hooks/useCaseList/index.tsx | 14 +- 12 files changed, 432 insertions(+), 169 deletions(-) create mode 100644 apps/judicial-system/web/src/components/Table/CourtDate/CourtDate.tsx create mode 100644 apps/judicial-system/web/src/routes/Court/components/CasesInProgressTable/CasesInProgressTable.strings.ts create mode 100644 apps/judicial-system/web/src/routes/Court/components/CasesInProgressTable/CasesInProgressTable.tsx diff --git a/apps/judicial-system/backend/src/app/modules/case/state/case.state.spec.ts b/apps/judicial-system/backend/src/app/modules/case/state/case.state.spec.ts index e4eb6b9e1169..59a1ac2adec3 100644 --- a/apps/judicial-system/backend/src/app/modules/case/state/case.state.spec.ts +++ b/apps/judicial-system/backend/src/app/modules/case/state/case.state.spec.ts @@ -554,7 +554,10 @@ describe('Transition Case', () => { ) describe.each(indictmentCases)('complete %s', (type) => { - const allowedFromStates = [CaseState.RECEIVED] + const allowedFromStates = [ + CaseState.WAITING_FOR_CANCELLATION, + CaseState.RECEIVED, + ] describe.each(allowedFromStates)( 'state %s - should complete', diff --git a/apps/judicial-system/backend/src/app/modules/case/state/case.state.ts b/apps/judicial-system/backend/src/app/modules/case/state/case.state.ts index 80fa6200ae7a..9865ba48b1dd 100644 --- a/apps/judicial-system/backend/src/app/modules/case/state/case.state.ts +++ b/apps/judicial-system/backend/src/app/modules/case/state/case.state.ts @@ -98,7 +98,10 @@ const indictmentCaseStateMachine: Map< [ IndictmentCaseTransition.COMPLETE, { - fromStates: [IndictmentCaseState.RECEIVED], + fromStates: [ + IndictmentCaseState.WAITING_FOR_CANCELLATION, + IndictmentCaseState.RECEIVED, + ], to: { state: IndictmentCaseState.COMPLETED }, }, ], diff --git a/apps/judicial-system/web/messages/Core/tables.ts b/apps/judicial-system/web/messages/Core/tables.ts index 9cf5cab7a30f..d6ce53eb22b1 100644 --- a/apps/judicial-system/web/messages/Core/tables.ts +++ b/apps/judicial-system/web/messages/Core/tables.ts @@ -103,4 +103,9 @@ export const tables = defineMessages({ description: 'Notaður sem titill fyrir birtingarstaða dálk í lista yfir mál.', }, + postponed: { + id: 'judicial.system.core:tables.postponed', + defaultMessage: 'Frestað', + description: 'Notaður sem texti þegar mál er frestað.', + }, }) diff --git a/apps/judicial-system/web/src/components/Table/CourtDate/CourtDate.tsx b/apps/judicial-system/web/src/components/Table/CourtDate/CourtDate.tsx new file mode 100644 index 000000000000..aa658d74ff45 --- /dev/null +++ b/apps/judicial-system/web/src/components/Table/CourtDate/CourtDate.tsx @@ -0,0 +1,44 @@ +import { useIntl } from 'react-intl' +import format from 'date-fns/format' +import localeIS from 'date-fns/locale/is' +import parseISO from 'date-fns/parseISO' + +import { Box, Text } from '@island.is/island-ui/core' +import { capitalize } from '@island.is/judicial-system/formatters' +import { tables } from '@island.is/judicial-system-web/messages' + +interface Props { + courtDate?: string | null + postponedIndefinitelyExplanation?: string | null +} + +const CourtDate: React.FC = (props: Props) => { + const { courtDate, postponedIndefinitelyExplanation } = props + const { formatMessage } = useIntl() + + if (!courtDate && !postponedIndefinitelyExplanation) { + return null + } + + return postponedIndefinitelyExplanation ? ( + {formatMessage(tables.postponed)} + ) : ( + courtDate && ( + <> + + + {capitalize( + format(parseISO(courtDate), 'EEEE d. LLLL y', { + locale: localeIS, + }), + ).replace('dagur', 'd.')} + + + + kl. {format(parseISO(courtDate), 'kk:mm')} + + + ) + ) +} +export default CourtDate diff --git a/apps/judicial-system/web/src/components/Table/Table.tsx b/apps/judicial-system/web/src/components/Table/Table.tsx index 027599968ca0..7c5269a99166 100644 --- a/apps/judicial-system/web/src/components/Table/Table.tsx +++ b/apps/judicial-system/web/src/components/Table/Table.tsx @@ -34,6 +34,7 @@ interface TableProps { data: CaseListEntry[] columns: { cell: (row: CaseListEntry) => ReactNode }[] generateContextMenuItems?: (row: CaseListEntry) => ContextMenuItem[] + onClick?: (row: CaseListEntry) => boolean } interface TableWrapperProps { @@ -80,7 +81,7 @@ export const useTable = () => { } const Table: React.FC = (props) => { - const { thead, data, columns, generateContextMenuItems } = props + const { thead, data, columns, generateContextMenuItems, onClick } = props const { isOpeningCaseId, handleOpenCase, LoadingIndicator, showLoading } = useCaseList() const { sortConfig, requestSort, getClassNamesFor } = useTable() @@ -122,7 +123,11 @@ const Table: React.FC = (props) => { {data.map((theCase: CaseListEntry) => ( handleOpenCase(theCase.id)} + onClick={() => { + if (!(onClick && onClick(theCase))) { + handleOpenCase(theCase.id) + } + }} theCase={theCase} isCourtRole={isDistrictCourtUser(user)} isLoading={isOpeningCaseId === theCase.id && showLoading} @@ -185,7 +190,9 @@ const Table: React.FC = (props) => { aria-disabled={isOpeningCaseId === row.id || isTransitioningCase} className={styles.tableRowContainer} onClick={() => { - handleOpenCase(row.id) + if (!(onClick && onClick(row))) { + handleOpenCase(row.id) + } }} > {columns.map((td) => ( @@ -195,27 +202,29 @@ const Table: React.FC = (props) => { ))} {generateContextMenuItems && ( - - {isOpeningCaseId === row.id && showLoading ? ( - - - - ) : ( - { - evt.stopPropagation() - }} - /> - } - /> - )} - + {generateContextMenuItems(row).length > 0 && ( + + {isOpeningCaseId === row.id && showLoading ? ( + + + + ) : ( + { + evt.stopPropagation() + }} + /> + } + /> + )} + + )} )} diff --git a/apps/judicial-system/web/src/components/Table/index.ts b/apps/judicial-system/web/src/components/Table/index.ts index deda840f4234..72f23966d38c 100644 --- a/apps/judicial-system/web/src/components/Table/index.ts +++ b/apps/judicial-system/web/src/components/Table/index.ts @@ -12,3 +12,4 @@ export { export { default as CreatedDate } from './CreatedDate/CreatedDate' export { default as AppealCasesTable } from './AppealCasesTable/AppealCasesTable' export { default as PastCasesTable } from './PastCasesTable/PastCasesTable' +export { default as CourtDate } from './CourtDate/CourtDate' diff --git a/apps/judicial-system/web/src/routes/Court/components/CasesInProgressTable/CasesInProgressTable.strings.ts b/apps/judicial-system/web/src/routes/Court/components/CasesInProgressTable/CasesInProgressTable.strings.ts new file mode 100644 index 000000000000..4a7547e2a962 --- /dev/null +++ b/apps/judicial-system/web/src/routes/Court/components/CasesInProgressTable/CasesInProgressTable.strings.ts @@ -0,0 +1,42 @@ +import { defineMessages } from 'react-intl' + +export const strings = defineMessages({ + title: { + id: 'judicial.system.core:court.cases_in_progress.title', + defaultMessage: 'Mál í vinnslu', + description: 'Notaður sem titill í málalista', + }, + noCasesTitle: { + id: 'judicial.system.core:court.cases_in_progress.no_cases_title', + defaultMessage: 'Engin mál í vinnslu.', + description: 'Notaður sem titill þegar engin mál eru til vinnslu', + }, + noCasesMessage: { + id: 'judicial.system.core:court.cases_in_progress.no_cases_message', + defaultMessage: 'Öll mál hafa verið afgreidd.', + description: 'Notað sem skilaboð þegar engin mál eru til vinnslu', + }, + cancelCaseModalTitle: { + id: 'judicial.system.core:cases.active_requests.cancel_case_modal_title', + defaultMessage: 'Mál afturkallað', + description: 'Notaður sem titill í Afturkalla mál dómstóla modal.', + }, + cancelCaseModalText: { + id: 'judicial.system.core:cases.active_requests.cancel_case_modal_text', + defaultMessage: + 'Ákæruvaldið hefur afturkallað ákæruna. Hægt er að skrá málsnúmer og ljúka málinu hér.', + description: 'Notaður sem texti í Afturkalla mál dómstóla modal.', + }, + cancelCaseModalPrimaryButtonText: { + id: 'judicial.system.core:cases.active_requests.cancel_case_modal_primary_button_text', + defaultMessage: 'Ljúka máli', + description: + 'Notaður sem texti á Ljúka máli takka í Afturkalla mál dómstóla modal.', + }, + cancelCaseModalSecondaryButtonText: { + id: 'judicial.system.core:cases.active_requests.delete_case_modal_secondary_button_text', + defaultMessage: 'Hætta við', + description: + 'Notaður sem texti á Hætta við takka í Afturkalla mál dómstóla modal.', + }, +}) diff --git a/apps/judicial-system/web/src/routes/Court/components/CasesInProgressTable/CasesInProgressTable.tsx b/apps/judicial-system/web/src/routes/Court/components/CasesInProgressTable/CasesInProgressTable.tsx new file mode 100644 index 000000000000..f9654b20d722 --- /dev/null +++ b/apps/judicial-system/web/src/routes/Court/components/CasesInProgressTable/CasesInProgressTable.tsx @@ -0,0 +1,205 @@ +import React, { useContext, useEffect, useState } from 'react' +import { useIntl } from 'react-intl' +import { AnimatePresence } from 'framer-motion' + +import { Box, toast } from '@island.is/island-ui/core' +import { capitalize } from '@island.is/judicial-system/formatters' +import { CaseIndictmentRulingDecision } from '@island.is/judicial-system/types' +import { core, errors, tables } from '@island.is/judicial-system-web/messages' +import { + FormContext, + Modal, + SectionHeading, + TagCaseState, +} from '@island.is/judicial-system-web/src/components' +import { useContextMenu } from '@island.is/judicial-system-web/src/components/ContextMenu/ContextMenu' +import { + ColumnCaseType, + CourtCaseNumber, + CourtDate, + CreatedDate, + DefendantInfo, +} from '@island.is/judicial-system-web/src/components/Table' +import Table, { + TableWrapper, +} from '@island.is/judicial-system-web/src/components/Table/Table' +import TableInfoContainer from '@island.is/judicial-system-web/src/components/Table/TableInfoContainer/TableInfoContainer' +import { + CaseListEntry, + CaseState, + CaseTransition, +} from '@island.is/judicial-system-web/src/graphql/schema' +import { TempCase as Case } from '@island.is/judicial-system-web/src/types' +import { useCase } from '@island.is/judicial-system-web/src/utils/hooks' + +import CourtCaseNumberInput from '../CourtCaseNumber/CourtCaseNumberInput' +import { strings } from './CasesInProgressTable.strings' + +interface CasesInProgressTableProps { + loading: boolean + isFiltering: boolean + cases: CaseListEntry[] + refetch: () => Promise +} + +const CasesInProgressTable: React.FC = (props) => { + const { loading, isFiltering, cases, refetch } = props + + const { formatMessage } = useIntl() + const { openCaseInNewTabMenuItem } = useContextMenu() + const { getCase } = useContext(FormContext) + const [caseToCancelId, setCaseToCancelId] = useState() + const [caseToCancel, setCaseToCancel] = useState() + const { updateCase, isUpdatingCase, transitionCase, isTransitioningCase } = + useCase() + + useEffect(() => { + if (caseToCancelId) { + getCase(caseToCancelId, setCaseToCancel, () => + toast.error(formatMessage(errors.getCaseToOpen)), + ) + } + }, [caseToCancelId, formatMessage, getCase]) + + const handlePrimaryButtonClick = async () => { + if (!caseToCancelId) { + return + } + + const updated = await updateCase(caseToCancelId, { + indictmentRulingDecision: CaseIndictmentRulingDecision.CANCELLATION, + }) + + if (!updated) { + return + } + + const cancelled = await transitionCase( + caseToCancelId, + CaseTransition.COMPLETE, + ) + + if (!cancelled) { + return + } + + refetch() + + setCaseToCancelId(undefined) + } + + const handleSecondaryButtonClick = () => { + setCaseToCancelId(undefined) + } + + return ( + <> + + + + {cases.length > 0 ? ( + ( + + ), + }, + { + cell: (row) => , + }, + { cell: (row) => }, + { cell: (row) => }, + { + cell: (row) => ( + + ), + }, + { + cell: (row) => ( + + ), + }, + ]} + generateContextMenuItems={(row) => { + return row.state === CaseState.WAITING_FOR_CANCELLATION + ? [] + : [openCaseInNewTabMenuItem(row.id)] + }} + onClick={(row) => { + if (row.state === CaseState.WAITING_FOR_CANCELLATION) { + setCaseToCancelId(row.id) + return true + } else { + return false + } + }} + /> + ) : ( + + )} + + + {caseToCancel && caseToCancel.id === caseToCancelId && ( + + + > + } + /> + + + )} + + ) +} + +export default CasesInProgressTable diff --git a/apps/judicial-system/web/src/routes/Shared/Cases/ActiveCases.tsx b/apps/judicial-system/web/src/routes/Shared/Cases/ActiveCases.tsx index fb426c242984..4a5912af93e8 100644 --- a/apps/judicial-system/web/src/routes/Shared/Cases/ActiveCases.tsx +++ b/apps/judicial-system/web/src/routes/Shared/Cases/ActiveCases.tsx @@ -1,4 +1,4 @@ -import React, { useContext, useEffect, useMemo, useState } from 'react' +import React, { useEffect, useMemo, useState } from 'react' import { useIntl } from 'react-intl' import { useLocalStorage } from 'react-use' import format from 'date-fns/format' @@ -13,19 +13,13 @@ import { displayFirstPlusRemaining, formatDOB, } from '@island.is/judicial-system/formatters' -import { - isDistrictCourtUser, - isProsecutionUser, - isRequestCase, -} from '@island.is/judicial-system/types' +import { isRequestCase } from '@island.is/judicial-system/types' import { core, tables } from '@island.is/judicial-system-web/messages' import { ContextMenu, - FormContext, Modal, TagAppealState, TagCaseState, - UserContext, } from '@island.is/judicial-system-web/src/components' import { contextMenu as contextMenuStrings } from '@island.is/judicial-system-web/src/components/ContextMenu/ContextMenu.strings' import IconButton from '@island.is/judicial-system-web/src/components/IconButton/IconButton' @@ -58,13 +52,11 @@ interface Props { cases: CaseListEntry[] isDeletingCase: boolean onDeleteCase?: (caseToDelete: CaseListEntry) => Promise - onCancelCase?: (caseToCancel: CaseListEntry) => Promise } const ActiveCases: React.FC> = (props) => { const { cases, isDeletingCase, onDeleteCase } = props - const { user } = useContext(UserContext) const { formatMessage } = useIntl() const { width } = useViewport() const [sortConfig, setSortConfig] = useLocalStorage( @@ -77,9 +69,7 @@ const ActiveCases: React.FC> = (props) => { const { isOpeningCaseId, showLoading, handleOpenCase, LoadingIndicator } = useCaseList() const [displayCases, setDisplayCases] = useState([]) - const [modalVisible, setVisibleModal] = useState< - 'DELETE_CASE' | 'CANCEL_CASE' - >() + const [modalVisible, setVisibleModal] = useState<'DELETE_CASE'>() // The id of the case that's about to be removed const [caseToRemove, setCaseToRemove] = useState() @@ -143,14 +133,10 @@ const ActiveCases: React.FC> = (props) => { { - if (c.state === CaseState.WAITING_FOR_CANCELLATION) { - setVisibleModal('CANCEL_CASE') - } else { - handleOpenCase(c.id) - } + handleOpenCase(theCase.id) }} theCase={theCase} - isCourtRole={isDistrictCourtUser(user)} + isCourtRole={false} isLoading={isOpeningCaseId === theCase.id && showLoading} > {theCase.state && @@ -236,7 +222,7 @@ const ActiveCases: React.FC> = (props) => { - {cases.map((c, i) => ( + {cases.map((c) => ( > = (props) => { aria-label="Opna kröfu" aria-disabled={isDeletingCase || isOpeningCaseId === c.id} onClick={() => { - if (c.state === CaseState.WAITING_FOR_CANCELLATION) { - setVisibleModal('CANCEL_CASE') - } else { - handleOpenCase(c.id) - } + handleOpenCase(c.id) }} > ))} @@ -464,18 +442,6 @@ const ActiveCases: React.FC> = (props) => { isPrimaryButtonLoading={isDeletingCase} /> )} - {modalVisible === 'CANCEL_CASE' && ( - { - setVisibleModal(undefined) - }} - /> - )} ) } diff --git a/apps/judicial-system/web/src/routes/Shared/Cases/Cases.strings.ts b/apps/judicial-system/web/src/routes/Shared/Cases/Cases.strings.ts index 042749ccc670..8116e4451042 100644 --- a/apps/judicial-system/web/src/routes/Shared/Cases/Cases.strings.ts +++ b/apps/judicial-system/web/src/routes/Shared/Cases/Cases.strings.ts @@ -108,25 +108,6 @@ export const cases = { description: 'Notaður sem texti á Halda áfram takka í Afturkalla mál.', }, }), - cancelCaseModal: defineMessages({ - title: { - id: 'judicial.system.core:cases.active_requests.cancel_case_modal.title', - defaultMessage: 'Mál afturkallað', - description: 'Notaður sem titill í Afturkalla mál dómstóla modal.', - }, - text: { - id: 'judicial.system.core:cases.active_requests.cancel_case_modal.text', - defaultMessage: - 'Ákæruvaldið hefur afturkallað ákæruna. Hægt er að skrá málsnúmer og ljúka málinu hér.', - description: 'Notaður sem texti í Afturkalla mál dómstóla modal.', - }, - secondaryButtonText: { - id: 'judicial.system.core:cases.active_requests.delete_case_modal.secondary_button_text', - defaultMessage: 'Hætta við', - description: - 'Notaður sem texti á Hætta við takka í Afturkalla mál dómstóla modal.', - }, - }), }, pastRequests: { table: { diff --git a/apps/judicial-system/web/src/routes/Shared/Cases/Cases.tsx b/apps/judicial-system/web/src/routes/Shared/Cases/Cases.tsx index aab52dd2cf4b..cde1b2b43836 100644 --- a/apps/judicial-system/web/src/routes/Shared/Cases/Cases.tsx +++ b/apps/judicial-system/web/src/routes/Shared/Cases/Cases.tsx @@ -38,6 +38,7 @@ import { import { useCase } from '@island.is/judicial-system-web/src/utils/hooks' import CasesAwaitingAssignmentTable from '../../Court/components/CasesAwaitingAssignmentTable/CasesAwaitingAssignmentTable' +import CasesInProgressTable from '../../Court/components/CasesInProgressTable/CasesInProgressTable' import CasesAwaitingConfirmationTable from '../../Prosecutor/components/CasesAwaitingConfirmationTable/CasesAwaitingConfirmationTable' import CasesAwaitingReview from '../../PublicProsecutor/Tables/CasesAwaitingReview' import ActiveCases from './ActiveCases' @@ -101,15 +102,13 @@ const CreateCaseButton: React.FC = (props) => { export const Cases: React.FC = () => { const { formatMessage } = useIntl() - - const [isFiltering, setIsFiltering] = useState(false) - const [modalVisible, setVisibleModal] = useState() - const { user } = useContext(UserContext) - const { transitionCase, isTransitioningCase, isSendingNotification } = useCase() + const [isFiltering, setIsFiltering] = useState(false) + const [modalVisible, setVisibleModal] = useState() + const { data, error, loading, refetch } = useCasesQuery({ fetchPolicy: 'no-cache', errorPolicy: 'all', @@ -292,34 +291,47 @@ export const Cases: React.FC = () => { cases={casesAwaitingReview} /> )} + + + {activeCases.length > 0 ? ( + + ) : ( +
+ +
+ )} +
)} - {isDistrictCourtUser(user) && filter.value !== 'INVESTIGATION' && ( - - )} - - - {activeCases.length > 0 ? ( - + + - ) : ( -
- -
- )} -
+ + )} {loading || pastCases.length > 0 ? ( { if (clickedCase[0] !== id && !openInNewTab) { setClickedCase([id, false]) - timeouts.push( - setTimeout(() => { - setClickedCase([id, true]) - }, 2000), - ) + timeouts.push(setTimeout(() => setClickedCase([id, true]), 2000)) } const getCaseToOpen = (id: string) => { getCase( id, - (caseData) => { - openCase(caseData, openInNewTab) - }, - () => { - toast.error(formatMessage(errors.getCaseToOpen)) - }, + (caseData) => openCase(caseData, openInNewTab), + () => toast.error(formatMessage(errors.getCaseToOpen)), ) } From f07c7fcfa931186dfe63480c76878d10a76846b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gu=C3=B0j=C3=B3n=20Gu=C3=B0j=C3=B3nsson?= Date: Mon, 10 Jun 2024 13:36:39 +0000 Subject: [PATCH 38/47] Removes obsolete unit tests --- .../src/routes/Shared/Cases/Cases.spec.tsx | 42 ------------------- 1 file changed, 42 deletions(-) diff --git a/apps/judicial-system/web/src/routes/Shared/Cases/Cases.spec.tsx b/apps/judicial-system/web/src/routes/Shared/Cases/Cases.spec.tsx index b72884663f11..59e70732318f 100644 --- a/apps/judicial-system/web/src/routes/Shared/Cases/Cases.spec.tsx +++ b/apps/judicial-system/web/src/routes/Shared/Cases/Cases.spec.tsx @@ -289,27 +289,6 @@ describe('Cases', () => { }) describe('Court users', () => { - test('should list all cases that do not have status NEW (never returned from the server), DELETED, ACCEPTED or REJECTED in a active cases table', async () => { - render( - - - - - - - , - ) - - expect( - await waitFor( - () => screen.getAllByTestId('custody-cases-table-row').length, - ), - ).toEqual(4) - }) - test('should display the judge logo', async () => { render( { }) }) - describe('Prison users', () => { - test('should list active and past cases in separate tables based on validToDate', async () => { - render( - - - - - - - , - ) - - await waitFor(() => { - expect(screen.getAllByRole('table').length).toEqual(2) - }) - }) - }) - describe('All user types - sorting', () => { test('should order the table data by accused name in ascending order when the user clicks the accused name table header', async () => { const user = userEvent.setup() From ecb6b5aa67283c562d05310bcfb88f0fb26ff11c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gu=C3=B0j=C3=B3n=20Gu=C3=B0j=C3=B3nsson?= Date: Mon, 10 Jun 2024 14:53:37 +0000 Subject: [PATCH 39/47] Fixes test helpers --- apps/judicial-system/web/src/utils/testHelpers.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/judicial-system/web/src/utils/testHelpers.tsx b/apps/judicial-system/web/src/utils/testHelpers.tsx index 2ac5b5455299..2c51369653b9 100644 --- a/apps/judicial-system/web/src/utils/testHelpers.tsx +++ b/apps/judicial-system/web/src/utils/testHelpers.tsx @@ -40,6 +40,7 @@ export const FormContextWrapper = ({ caseNotFound: false, isCaseUpToDate: true, refreshCase: jest.fn(), + getCase: jest.fn(), }} > {children} From 6cc32e2686a3f02393a993a015a09c89851541d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gu=C3=B0j=C3=B3n=20Gu=C3=B0j=C3=B3nsson?= Date: Tue, 11 Jun 2024 11:49:59 +0000 Subject: [PATCH 40/47] Simplifies code --- .../components/CasesInProgressTable/CasesInProgressTable.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/judicial-system/web/src/routes/Court/components/CasesInProgressTable/CasesInProgressTable.tsx b/apps/judicial-system/web/src/routes/Court/components/CasesInProgressTable/CasesInProgressTable.tsx index f9654b20d722..74e1fb2fb6a5 100644 --- a/apps/judicial-system/web/src/routes/Court/components/CasesInProgressTable/CasesInProgressTable.tsx +++ b/apps/judicial-system/web/src/routes/Court/components/CasesInProgressTable/CasesInProgressTable.tsx @@ -161,9 +161,9 @@ const CasesInProgressTable: React.FC = (props) => { if (row.state === CaseState.WAITING_FOR_CANCELLATION) { setCaseToCancelId(row.id) return true - } else { - return false } + + return false }} /> ) : ( From bbcc4935f8319bae18ac23fbe55e21ae3fa82fee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gu=C3=B0j=C3=B3n=20Gu=C3=B0j=C3=B3nsson?= Date: Tue, 11 Jun 2024 11:53:47 +0000 Subject: [PATCH 41/47] Simplifies code --- apps/judicial-system/web/src/components/Table/Table.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/judicial-system/web/src/components/Table/Table.tsx b/apps/judicial-system/web/src/components/Table/Table.tsx index 7c5269a99166..d14dec363cc1 100644 --- a/apps/judicial-system/web/src/components/Table/Table.tsx +++ b/apps/judicial-system/web/src/components/Table/Table.tsx @@ -124,7 +124,7 @@ const Table: React.FC = (props) => { { - if (!(onClick && onClick(theCase))) { + if (!onClick?.(theCase)) { handleOpenCase(theCase.id) } }} @@ -190,7 +190,7 @@ const Table: React.FC = (props) => { aria-disabled={isOpeningCaseId === row.id || isTransitioningCase} className={styles.tableRowContainer} onClick={() => { - if (!(onClick && onClick(row))) { + if (!onClick?.(row)) { handleOpenCase(row.id) } }} From 604b4022fe2ccf79787fbdaabb13a01dc981a504 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gu=C3=B0j=C3=B3n=20Gu=C3=B0j=C3=B3nsson?= Date: Tue, 11 Jun 2024 11:55:29 +0000 Subject: [PATCH 42/47] Improves imports --- .../web/src/components/Table/CourtDate/CourtDate.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/judicial-system/web/src/components/Table/CourtDate/CourtDate.tsx b/apps/judicial-system/web/src/components/Table/CourtDate/CourtDate.tsx index aa658d74ff45..9c3cd97e8edc 100644 --- a/apps/judicial-system/web/src/components/Table/CourtDate/CourtDate.tsx +++ b/apps/judicial-system/web/src/components/Table/CourtDate/CourtDate.tsx @@ -1,3 +1,4 @@ +import { FC } from 'react' import { useIntl } from 'react-intl' import format from 'date-fns/format' import localeIS from 'date-fns/locale/is' @@ -12,7 +13,7 @@ interface Props { postponedIndefinitelyExplanation?: string | null } -const CourtDate: React.FC = (props: Props) => { +const CourtDate: FC = (props) => { const { courtDate, postponedIndefinitelyExplanation } = props const { formatMessage } = useIntl() From ab3f1fc23b9929e6719b6f36b9b615a63b9abfac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gu=C3=B0j=C3=B3n=20Gu=C3=B0j=C3=B3nsson?= Date: Tue, 11 Jun 2024 11:56:31 +0000 Subject: [PATCH 43/47] Improves imports --- .../components/CasesInProgressTable/CasesInProgressTable.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/judicial-system/web/src/routes/Court/components/CasesInProgressTable/CasesInProgressTable.tsx b/apps/judicial-system/web/src/routes/Court/components/CasesInProgressTable/CasesInProgressTable.tsx index 74e1fb2fb6a5..33803e90afe9 100644 --- a/apps/judicial-system/web/src/routes/Court/components/CasesInProgressTable/CasesInProgressTable.tsx +++ b/apps/judicial-system/web/src/routes/Court/components/CasesInProgressTable/CasesInProgressTable.tsx @@ -1,4 +1,4 @@ -import React, { useContext, useEffect, useState } from 'react' +import React, { FC, useContext, useEffect, useState } from 'react' import { useIntl } from 'react-intl' import { AnimatePresence } from 'framer-motion' @@ -42,7 +42,7 @@ interface CasesInProgressTableProps { refetch: () => Promise } -const CasesInProgressTable: React.FC = (props) => { +const CasesInProgressTable: FC = (props) => { const { loading, isFiltering, cases, refetch } = props const { formatMessage } = useIntl() From 6ee56d5ce86dacd060d674b56c0e7aa4722c15e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gu=C3=B0j=C3=B3n=20Gu=C3=B0j=C3=B3nsson?= Date: Tue, 11 Jun 2024 12:00:47 +0000 Subject: [PATCH 44/47] Improves imports --- .../CasesInProgressTable/CasesInProgressTable.tsx | 13 +++++++++---- .../CourtCaseNumber/CourtCaseNumberInput.tsx | 6 ++---- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/apps/judicial-system/web/src/routes/Court/components/CasesInProgressTable/CasesInProgressTable.tsx b/apps/judicial-system/web/src/routes/Court/components/CasesInProgressTable/CasesInProgressTable.tsx index 33803e90afe9..65e95e8e4bd9 100644 --- a/apps/judicial-system/web/src/routes/Court/components/CasesInProgressTable/CasesInProgressTable.tsx +++ b/apps/judicial-system/web/src/routes/Court/components/CasesInProgressTable/CasesInProgressTable.tsx @@ -1,4 +1,11 @@ -import React, { FC, useContext, useEffect, useState } from 'react' +import React, { + Dispatch, + FC, + SetStateAction, + useContext, + useEffect, + useState, +} from 'react' import { useIntl } from 'react-intl' import { AnimatePresence } from 'framer-motion' @@ -191,9 +198,7 @@ const CasesInProgressTable: FC = (props) => { > - } + setWorkingCase={setCaseToCancel as Dispatch>} />
diff --git a/apps/judicial-system/web/src/routes/Court/components/CourtCaseNumber/CourtCaseNumberInput.tsx b/apps/judicial-system/web/src/routes/Court/components/CourtCaseNumber/CourtCaseNumberInput.tsx index 46b8c3edd1a7..ebcbe3eb1f45 100644 --- a/apps/judicial-system/web/src/routes/Court/components/CourtCaseNumber/CourtCaseNumberInput.tsx +++ b/apps/judicial-system/web/src/routes/Court/components/CourtCaseNumber/CourtCaseNumberInput.tsx @@ -1,4 +1,4 @@ -import React, { useState } from 'react' +import React, { FC, PropsWithChildren, useState } from 'react' import { useIntl } from 'react-intl' import { Box, Button, Input } from '@island.is/island-ui/core' @@ -24,9 +24,7 @@ interface Props { setWorkingCase: React.Dispatch> } -const CourtCaseNumberInput: React.FC> = ( - props, -) => { +const CourtCaseNumberInput: FC> = (props) => { const { workingCase, setWorkingCase } = props const { formatMessage } = useIntl() From 3efe030fb2a17dd5b4e13bff9138ff01928fecfe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gu=C3=B0j=C3=B3n=20Gu=C3=B0j=C3=B3nsson?= Date: Tue, 11 Jun 2024 12:05:37 +0000 Subject: [PATCH 45/47] Simplifies type --- .../judicial-system/web/src/routes/Shared/Cases/ActiveCases.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/judicial-system/web/src/routes/Shared/Cases/ActiveCases.tsx b/apps/judicial-system/web/src/routes/Shared/Cases/ActiveCases.tsx index 4a5912af93e8..fc29d1b8771a 100644 --- a/apps/judicial-system/web/src/routes/Shared/Cases/ActiveCases.tsx +++ b/apps/judicial-system/web/src/routes/Shared/Cases/ActiveCases.tsx @@ -71,7 +71,7 @@ const ActiveCases: React.FC> = (props) => { const [displayCases, setDisplayCases] = useState([]) const [modalVisible, setVisibleModal] = useState<'DELETE_CASE'>() // The id of the case that's about to be removed - const [caseToRemove, setCaseToRemove] = useState() + const [caseToRemove, setCaseToRemove] = useState() useEffect(() => { setDisplayCases(cases) From 590277662c8917f440838b4f35ab580fbf35fd43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gu=C3=B0j=C3=B3n=20Gu=C3=B0j=C3=B3nsson?= Date: Tue, 11 Jun 2024 12:13:15 +0000 Subject: [PATCH 46/47] Simplifies expressions --- apps/judicial-system/web/src/utils/hooks/useCase/index.ts | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/apps/judicial-system/web/src/utils/hooks/useCase/index.ts b/apps/judicial-system/web/src/utils/hooks/useCase/index.ts index 25e92dd60ca1..842f5f0fd94a 100644 --- a/apps/judicial-system/web/src/utils/hooks/useCase/index.ts +++ b/apps/judicial-system/web/src/utils/hooks/useCase/index.ts @@ -251,9 +251,7 @@ const useCase = () => { const res = data as UpdateCaseMutation & LimitedAccessUpdateCaseMutation - return ( - res && res[limitedAccess ? 'limitedAccessUpdateCase' : 'updateCase'] - ) + return res?.[limitedAccess ? 'limitedAccessUpdateCase' : 'updateCase'] } catch (error) { toast.error(formatMessage(errors.updateCase)) } @@ -294,8 +292,8 @@ const useCase = () => { const res = data as TransitionCaseMutation & LimitedAccessTransitionCaseMutation - const state = res && res[resultType]?.state - const appealState = res && res[resultType]?.appealState + const state = res?.[resultType]?.state + const appealState = res?.[resultType]?.appealState if (!state && !appealState) { return false From 2e49084aedfe241aff4bf8434b8f4bd48795b456 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gu=C3=B0j=C3=B3n=20Gu=C3=B0j=C3=B3nsson?= Date: Tue, 11 Jun 2024 13:11:17 +0000 Subject: [PATCH 47/47] Correct function declaration --- .../components/CourtCaseNumber/CourtCaseNumberInput.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/judicial-system/web/src/routes/Court/components/CourtCaseNumber/CourtCaseNumberInput.tsx b/apps/judicial-system/web/src/routes/Court/components/CourtCaseNumber/CourtCaseNumberInput.tsx index ebcbe3eb1f45..60c8eb89efcc 100644 --- a/apps/judicial-system/web/src/routes/Court/components/CourtCaseNumber/CourtCaseNumberInput.tsx +++ b/apps/judicial-system/web/src/routes/Court/components/CourtCaseNumber/CourtCaseNumberInput.tsx @@ -1,4 +1,4 @@ -import React, { FC, PropsWithChildren, useState } from 'react' +import React, { Dispatch, FC, SetStateAction, useState } from 'react' import { useIntl } from 'react-intl' import { Box, Button, Input } from '@island.is/island-ui/core' @@ -21,10 +21,10 @@ import * as styles from './CourtCaseNumber.css' interface Props { workingCase: Case - setWorkingCase: React.Dispatch> + setWorkingCase: Dispatch> } -const CourtCaseNumberInput: FC> = (props) => { +const CourtCaseNumberInput: FC = (props) => { const { workingCase, setWorkingCase } = props const { formatMessage } = useIntl()
@@ -338,7 +320,6 @@ const ActiveCases: React.FC> = (props) => { > = (props) => { )} - {c.state !== CaseState.WAITING_FOR_CANCELLATION && ( - - {isOpeningCaseId === c.id && showLoading ? ( -
- -
- ) : ( - handleOpenCase(c.id, true), - icon: 'open', - }, - ...(isProsecutionUser(user) && - (isRequestCase(c.type) || - c.state === CaseState.DRAFT || - c.state === CaseState.WAITING_FOR_CONFIRMATION) - ? [ - { - title: formatMessage( - contextMenuStrings.deleteCase, - ), - onClick: () => { - setCaseToRemove(c) - setVisibleModal('DELETE_CASE') - }, - icon: 'trash' as IconMapIcon, + + {isOpeningCaseId === c.id && showLoading ? ( +
+ +
+ ) : ( + handleOpenCase(c.id, true), + icon: 'open', + }, + ...(isRequestCase(c.type) || + c.state === CaseState.DRAFT || + c.state === CaseState.WAITING_FOR_CONFIRMATION + ? [ + { + title: formatMessage( + contextMenuStrings.deleteCase, + ), + onClick: () => { + setCaseToRemove(c) + setVisibleModal('DELETE_CASE') }, - ] - : []), - ]} - disclosure={ - { - evt.stopPropagation() - }} - /> - } - /> - )} -
- )} + icon: 'trash' as IconMapIcon, + }, + ] + : []), + ]} + disclosure={ + { + evt.stopPropagation() + }} + /> + } + /> + )} +