Skip to content

Commit

Permalink
feat(j-s): Complete Cancellation (#15154)
Browse files Browse the repository at this point in the history
* Add POSTPONED_TO_VERDICT radio button

* Change Radio to Checkbox

* Add column to Case table -- IndictmentDecision

* Update IndictmentDecision

* Postponed until verdict tag in cases

* Disable subpoena screen if a case is postponed until verdict

* Add a postpone until verdict tag for defenders

* Checkpoint

* Checkpoint

* Merge

* Determining when step is valid when postponing until verdict

* Checkpoint

* Change all instances of Array<something> to something[]

* Only show InfoCard on summary page if indictment decison is POSTPONING_UNTIL_VERDICT

* Wipe courtDate out when postponing until verdict

* Move scheduled info card to overview page

* Save court date when postponing until verdict

* Checkpoint

* Fixing update functionality

* Fix case state on cases page

* Fix migration

* Add location to verdict date

* Cleanup

* Allow judges to remove set court date

* Added test

* Allows prosecutors to cancel submitted indictments

* Hides buttons when prosecutor has asked for cancellation

* Adds unit tests

* Updates unit tests

* Fixes unit tests

* Rewrite open case

* Adds modal for cancelling case

* Fixes back navigation

* Update apps/judicial-system/web/src/routes/Prosecutor/Indictments/Overview/Overview.tsx

Co-authored-by: Ívar Oddsson <ivaroddsson@gmail.com>

* Refactors code

* Rewrites condition

* Completes cancellation

* Removes obsolete unit tests

* Fixes test helpers

* Simplifies code

* Simplifies code

* Improves imports

* Improves imports

* Improves imports

* Simplifies type

* Simplifies expressions

* Correct function declaration

---------

Co-authored-by: Ívar Oddsson <ivaroddsson@gmail.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
  • Loading branch information
3 people authored Jun 11, 2024
1 parent a01ba02 commit 6b940d9
Show file tree
Hide file tree
Showing 20 changed files with 729 additions and 465 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,10 @@ const indictmentCaseStateMachine: Map<
[
IndictmentCaseTransition.COMPLETE,
{
fromStates: [IndictmentCaseState.RECEIVED],
fromStates: [
IndictmentCaseState.WAITING_FOR_CANCELLATION,
IndictmentCaseState.RECEIVED,
],
to: { state: IndictmentCaseState.COMPLETED },
},
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ const caseEvent = {
ACCEPT: ':white_check_mark: Samþykkt',
REJECT: ':negative_squared_cross_mark: Hafnað',
DISMISS: ':woman-shrugging: Vísað frá',
COMPLETE: ':white_check_mark: Lokað',
COMPLETE: ':white_check_mark: Lokið',
DELETE: ':fire: Afturkallað',
SCHEDULE_COURT_DATE: ':timer_clock: Fyrirtökutíma úthlutað',
ARCHIVE: ':file_cabinet: Sett í geymslu',
Expand Down
5 changes: 5 additions & 0 deletions apps/judicial-system/web/messages/Core/tables.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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ð.',
},
})
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React, {
createContext,
ReactNode,
useCallback,
useContext,
useEffect,
useState,
Expand All @@ -18,8 +19,11 @@ import { api } from '@island.is/judicial-system-web/src/services'
import { TempCase as Case } from '@island.is/judicial-system-web/src/types'

import { UserContext } from '../UserProvider/UserProvider'
import { useCaseLazyQuery } from './case.generated'
import { useLimitedAccessCaseLazyQuery } from './limitedAccessCase.generated'
import { CaseQuery, useCaseLazyQuery } from './case.generated'
import {
LimitedAccessCaseQuery,
useLimitedAccessCaseLazyQuery,
} from './limitedAccessCase.generated'

type ProviderState =
| 'fetch'
Expand All @@ -36,6 +40,11 @@ interface FormProvider {
caseNotFound: boolean
isCaseUpToDate: boolean
refreshCase: () => void
getCase: (
id: string,
onCompleted: (theCase: Case) => void,
onError: () => void,
) => void
}

interface Props {
Expand All @@ -60,8 +69,12 @@ export const FormContext = createContext<FormProvider>({
isLoadingWorkingCase: true,
caseNotFound: false,
isCaseUpToDate: false,
// eslint-disable-next-line @typescript-eslint/no-empty-function
refreshCase: () => {},
refreshCase: () => {
return
},
getCase: () => {
return
},
})

const MaybeFormProvider = ({ children }: Props) => {
Expand Down Expand Up @@ -123,39 +136,37 @@ const FormProvider = ({ children }: Props) => {
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [router.query.id, router.pathname])

const [getCase] = useCaseLazyQuery({
const [queryCase] = useCaseLazyQuery({
fetchPolicy: 'no-cache',
errorPolicy: 'all',
onCompleted: (caseData) => {
if (caseData && caseData.case) {
setWorkingCase(caseData.case)

// The case has been loaded from the server
setState('up-to-date')
}
},
onError: () => {
// The case was not found
setState('not-found')
},
})

const [getLimitedAccessCase] = useLimitedAccessCaseLazyQuery({
const [queryLimitedAccessCase] = useLimitedAccessCaseLazyQuery({
fetchPolicy: 'no-cache',
errorPolicy: 'all',
onCompleted: (caseData) => {
if (caseData && caseData.limitedAccessCase) {
setWorkingCase(caseData.limitedAccessCase)
})

// The case has been loaded from the server
setState('up-to-date')
}
},
onError: () => {
// The case was not found
setState('not-found')
const getCase = useCallback(
(id: string, onCompleted: (theCase: Case) => void, onError: () => void) => {
const promisedCase = limitedAccess
? queryLimitedAccessCase({ variables: { input: { id } } })
: queryCase({ variables: { input: { id } } })

promisedCase
.then((caseData) => {
if (caseData && caseData.data) {
const data = caseData.data as CaseQuery & LimitedAccessCaseQuery
const theCase = data[limitedAccess ? 'limitedAccessCase' : 'case']

if (theCase) {
onCompleted(theCase)
}
}
})
.catch(onError)
},
})
[limitedAccess, queryCase, queryLimitedAccessCase],
)

useEffect(() => {
if (!isAuthenticated && router.pathname !== '/') {
Expand All @@ -167,20 +178,29 @@ const FormProvider = ({ children }: Props) => {
id &&
(state === 'fetch' || state === 'refresh')
) {
if (limitedAccess) {
getLimitedAccessCase({ variables: { input: { id } } })
} else {
getCase({ variables: { input: { id } } })
}
getCase(
id,
(theCase: Case) => {
setWorkingCase(theCase)

// The case has been loaded from the server
setState('up-to-date')
},
() => {
// The case was not found
setState('not-found')
},
)
}
}, [
getCase,
getLimitedAccessCase,
queryCase,
queryLimitedAccessCase,
id,
isAuthenticated,
limitedAccess,
router.pathname,
state,
getCase,
])

useEffect(() => {
Expand All @@ -207,6 +227,7 @@ const FormProvider = ({ children }: Props) => {
isCaseUpToDate:
!replacingCase && !replacingPath && state === 'up-to-date',
refreshCase: () => setState('refresh'),
getCase,
}}
>
{children}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { FC } from 'react'
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: FC<Props> = (props) => {
const { courtDate, postponedIndefinitelyExplanation } = props
const { formatMessage } = useIntl()

if (!courtDate && !postponedIndefinitelyExplanation) {
return null
}

return postponedIndefinitelyExplanation ? (
<Text>{formatMessage(tables.postponed)}</Text>
) : (
courtDate && (
<>
<Text>
<Box component="span">
{capitalize(
format(parseISO(courtDate), 'EEEE d. LLLL y', {
locale: localeIS,
}),
).replace('dagur', 'd.')}
</Box>
</Text>
<Text as="span" variant="small">
kl. {format(parseISO(courtDate), 'kk:mm')}
</Text>
</>
)
)
}
export default CourtDate
57 changes: 33 additions & 24 deletions apps/judicial-system/web/src/components/Table/Table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ interface TableProps {
data: CaseListEntry[]
columns: { cell: (row: CaseListEntry) => ReactNode }[]
generateContextMenuItems?: (row: CaseListEntry) => ContextMenuItem[]
onClick?: (row: CaseListEntry) => boolean
}

interface TableWrapperProps {
Expand Down Expand Up @@ -80,7 +81,7 @@ export const useTable = () => {
}

const Table: React.FC<TableProps> = (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()
Expand Down Expand Up @@ -122,7 +123,11 @@ const Table: React.FC<TableProps> = (props) => {
{data.map((theCase: CaseListEntry) => (
<Box marginTop={2} key={theCase.id}>
<MobileCase
onClick={() => handleOpenCase(theCase.id)}
onClick={() => {
if (!onClick?.(theCase)) {
handleOpenCase(theCase.id)
}
}}
theCase={theCase}
isCourtRole={isDistrictCourtUser(user)}
isLoading={isOpeningCaseId === theCase.id && showLoading}
Expand Down Expand Up @@ -185,7 +190,9 @@ const Table: React.FC<TableProps> = (props) => {
aria-disabled={isOpeningCaseId === row.id || isTransitioningCase}
className={styles.tableRowContainer}
onClick={() => {
handleOpenCase(row.id)
if (!onClick?.(row)) {
handleOpenCase(row.id)
}
}}
>
{columns.map((td) => (
Expand All @@ -195,27 +202,29 @@ const Table: React.FC<TableProps> = (props) => {
))}
{generateContextMenuItems && (
<td className={styles.td}>
<AnimatePresence exitBeforeEnter initial={false}>
{isOpeningCaseId === row.id && showLoading ? (
<Box padding={1}>
<LoadingIndicator />
</Box>
) : (
<ContextMenu
menuLabel={`Valmynd fyrir mál ${row.courtCaseNumber}`}
items={generateContextMenuItems(row)}
disclosure={
<IconButton
icon="ellipsisVertical"
colorScheme="transparent"
onClick={(evt) => {
evt.stopPropagation()
}}
/>
}
/>
)}
</AnimatePresence>
{generateContextMenuItems(row).length > 0 && (
<AnimatePresence exitBeforeEnter initial={false}>
{isOpeningCaseId === row.id && showLoading ? (
<Box padding={1}>
<LoadingIndicator />
</Box>
) : (
<ContextMenu
menuLabel={`Valmynd fyrir mál ${row.courtCaseNumber}`}
items={generateContextMenuItems(row)}
disclosure={
<IconButton
icon="ellipsisVertical"
colorScheme="transparent"
onClick={(evt) => {
evt.stopPropagation()
}}
/>
}
/>
)}
</AnimatePresence>
)}
</td>
)}
</tr>
Expand Down
1 change: 1 addition & 0 deletions apps/judicial-system/web/src/components/Table/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Original file line number Diff line number Diff line change
@@ -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.',
},
})
Loading

0 comments on commit 6b940d9

Please sign in to comment.