Skip to content

Commit

Permalink
Merge branch 'main' into fix/error-handling-delegation-actor
Browse files Browse the repository at this point in the history
  • Loading branch information
magnearun authored Oct 16, 2024
2 parents 52cbdad + a74f1fd commit 185e0ff
Show file tree
Hide file tree
Showing 51 changed files with 647 additions and 426 deletions.
149 changes: 149 additions & 0 deletions apps/contentful-apps/pages/fields/project-subpage-slug-field.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
import { useEffect, useRef, useState } from 'react'
import { useDebounce } from 'react-use'
import type { EntryProps } from 'contentful-management'
import { FieldExtensionSDK } from '@contentful/app-sdk'
import { Stack, Text, TextInput } from '@contentful/f36-components'
import { useCMA, useSDK } from '@contentful/react-apps-toolkit'
import slugify from '@sindresorhus/slugify'

const DEBOUNCE_TIME = 100

const ProjectSubpageSlugField = () => {
const sdk = useSDK<FieldExtensionSDK>()
const cma = useCMA()
const [value, setValue] = useState(sdk.field?.getValue() ?? '')
const [isValid, setIsValid] = useState(true)
const [projectPage, setProjectPage] = useState<EntryProps | null>(null)
const initialTitleChange = useRef(true)
const [hasEntryBeenPublished, setHasEntryBeenPublished] = useState(
Boolean(sdk.entry.getSys()?.firstPublishedAt),
)

const defaultLocale = sdk.locales.default

useEffect(() => {
const fetchProjectPage = async () => {
const response = await cma.entry.getMany({
query: {
links_to_entry: sdk.entry.getSys().id,
content_type: 'projectPage',
'sys.archivedVersion[exists]': false,
limit: 1,
},
})
if (response.items.length > 0) {
setProjectPage(response.items[0])
}
}
fetchProjectPage()
}, [cma.entry, sdk.entry])

useEffect(() => {
sdk.entry.onSysChanged((newSys) => {
setHasEntryBeenPublished(Boolean(newSys?.firstPublishedAt))
})
}, [sdk.entry])

// Update slug field if the title field changes
useEffect(() => {
return sdk.entry.fields.title
.getForLocale(sdk.field.locale)
.onValueChanged((newTitle) => {
if (hasEntryBeenPublished) {
return
}

// Callback gets called on initial render, so we want to ignore that
if (initialTitleChange.current) {
initialTitleChange.current = false
return
}

if (newTitle) {
setValue(slugify(String(newTitle)))
}
})
}, [hasEntryBeenPublished, sdk.entry.fields.title, sdk.field.locale])

useEffect(() => {
sdk.window.startAutoResizer()
}, [sdk.window])

// Validate the user input
useDebounce(
async () => {
if (!projectPage) {
setIsValid(true)
return
}

const subpageIds: string[] =
projectPage?.fields?.projectSubpages?.[defaultLocale]?.map(
(subpage) => subpage.sys.id,
) ?? []

const subpagesWithSameSlug = (
await cma.entry.getMany({
query: {
locale: sdk.field.locale,
content_type: 'projectSubpage',
'fields.slug': value,
'sys.id[ne]': sdk.entry.getSys().id,
'sys.archivedVersion[exists]': false,
limit: 1000,
select: 'sys',
},
})
).items

const subpageExistsWithSameSlug = subpagesWithSameSlug.some((subpage) =>
subpageIds.includes(subpage.sys.id),
)

if (subpageExistsWithSameSlug) {
setIsValid(false)
return
}
setIsValid(true)
},
DEBOUNCE_TIME,
[value, projectPage],
)

useDebounce(
() => {
if (isValid) {
sdk.field.setValue(value)
} else {
sdk.field.setValue(null) // Set to null to prevent entry publish
}
sdk.field.setInvalid(!isValid)
},
DEBOUNCE_TIME,
[isValid, value],
)

const isInvalid = value.length === 0 || !isValid

return (
<Stack spacing="spacingXs" flexDirection="column" alignItems="flex-start">
<TextInput
value={value}
onChange={(ev) => {
setValue(ev.target.value)
}}
isInvalid={isInvalid}
/>
{value.length === 0 && sdk.field.locale === defaultLocale && (
<Text fontColor="red400">Invalid slug</Text>
)}
{value.length > 0 && isInvalid && (
<Text fontColor="red400">
Project subpage already exists with this slug
</Text>
)}
</Stack>
)
}

export default ProjectSubpageSlugField
Original file line number Diff line number Diff line change
Expand Up @@ -147,9 +147,10 @@ export const getIndictmentInfo = (

const verdictInfo = defendants?.map<[boolean, Date | undefined]>(
(defendant) => [
rulingDecision === CaseIndictmentRulingDecision.RULING &&
defendant.serviceRequirement !== ServiceRequirement.NOT_REQUIRED,
defendant.verdictViewDate
rulingDecision === CaseIndictmentRulingDecision.RULING,
defendant.serviceRequirement === ServiceRequirement.NOT_REQUIRED
? new Date()
: defendant.verdictViewDate
? new Date(defendant.verdictViewDate)
: undefined,
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,15 @@ export class Defendant {
@Field(() => DefenderChoice, { nullable: true })
readonly defenderChoice?: DefenderChoice

@Field(() => DefenderChoice, { nullable: true })
readonly requestedDefenderChoice?: DefenderChoice

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

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

@Field(() => SubpoenaType, { nullable: true })
readonly subpoenaType?: SubpoenaType

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
module.exports = {
up: (queryInterface, Sequelize) => {
return queryInterface.sequelize.transaction(async (t) => {
await queryInterface.addColumn(
'defendant',
'requested_defender_choice',
{
type: Sequelize.STRING,
allowNull: true,
},
{ transaction: t },
)
await queryInterface.addColumn(
'defendant',
'requested_defender_national_id',
{
type: Sequelize.STRING,
allowNull: true,
},
{ transaction: t },
)
await queryInterface.addColumn(
'defendant',
'requested_defender_name',
{
type: Sequelize.STRING,
allowNull: true,
},
{ transaction: t },
)

await queryInterface.sequelize.query(
`UPDATE "defendant" SET requested_defender_choice = defender_choice`,
{ transaction: t },
)

await queryInterface.sequelize.query(
`UPDATE "defendant" SET requested_defender_national_id = defender_national_id`,
{ transaction: t },
)

await queryInterface.sequelize.query(
`UPDATE "defendant" SET requested_defender_name = defender_name`,
{ transaction: t },
)
})
},
down: (queryInterface) => {
return queryInterface.sequelize.transaction(async (t) => {
await queryInterface.removeColumn(
'defendant',
'requested_defender_choice',
{
transaction: t,
},
)
await queryInterface.removeColumn(
'defendant',
'requested_defender_national_id',
{
transaction: t,
},
)
await queryInterface.removeColumn(
'defendant',
'requested_defender_name',
{
transaction: t,
},
)
})
},
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ import {
isRequestCase,
isRestrictionCase,
RequestSharedWithDefender,
ServiceRequirement,
UserRole,
} from '@island.is/judicial-system/types'

Expand Down Expand Up @@ -289,21 +288,19 @@ const canPrisonAdminUserAccessCase = (
) {
return false
}
}

// Check defendant verdict appeal deadline access
const verdictInfo = theCase.defendants?.map<[boolean, Date | undefined]>(
(defendant) => [
defendant.serviceRequirement !== ServiceRequirement.NOT_REQUIRED,
defendant.verdictViewDate,
],
)
// Check defendant verdict appeal deadline access
const canAppealVerdict = true
const verdictInfo = (theCase.defendants || []).map<
[boolean, Date | undefined]
>((defendant) => [canAppealVerdict, defendant.verdictViewDate])

const [_, indictmentVerdictAppealDeadlineExpired] =
getIndictmentVerdictAppealDeadlineStatus(verdictInfo)
const [_, indictmentVerdictAppealDeadlineExpired] =
getIndictmentVerdictAppealDeadlineStatus(verdictInfo)

if (!indictmentVerdictAppealDeadlineExpired) {
return false
}
if (!indictmentVerdictAppealDeadlineExpired) {
return false
}

return true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -214,8 +214,7 @@ const getPrisonAdminUserCasesQueryFilter = (): WhereOptions => {
[Op.notIn]: Sequelize.literal(`
(SELECT case_id
FROM defendant
WHERE service_requirement <> 'NOT_REQUIRED'
AND (verdict_view_date IS NULL OR verdict_view_date > NOW() - INTERVAL '28 days'))
WHERE (verdict_view_date IS NULL OR verdict_view_date > NOW() - INTERVAL '28 days'))
`),
},
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -389,8 +389,7 @@ describe('getCasesQueryFilter', () => {
[Op.notIn]: Sequelize.literal(`
(SELECT case_id
FROM defendant
WHERE service_requirement <> 'NOT_REQUIRED'
AND (verdict_view_date IS NULL OR verdict_view_date > NOW() - INTERVAL '28 days'))
WHERE (verdict_view_date IS NULL OR verdict_view_date > NOW() - INTERVAL '28 days'))
`),
},
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,4 +93,19 @@ export class UpdateDefendantDto {
@IsEnum(SubpoenaType)
@ApiPropertyOptional({ enum: SubpoenaType })
readonly subpoenaType?: SubpoenaType

@IsOptional()
@IsEnum(DefenderChoice)
@ApiPropertyOptional({ enum: DefenderChoice })
readonly requestedDefenderChoice?: DefenderChoice

@IsOptional()
@IsString()
@ApiPropertyOptional({ type: String })
readonly requestedDefenderNationalId?: string

@IsOptional()
@IsString()
@ApiPropertyOptional({ type: String })
readonly requestedDefenderName?: string
}
Original file line number Diff line number Diff line change
Expand Up @@ -137,4 +137,20 @@ export class Defendant extends Model {
@HasMany(() => Subpoena, { foreignKey: 'defendantId' })
@ApiPropertyOptional({ type: () => Subpoena, isArray: true })
subpoenas?: Subpoena[]

@Column({
type: DataType.ENUM,
allowNull: true,
values: Object.values(DefenderChoice),
})
@ApiPropertyOptional({ enum: DefenderChoice })
requestedDefenderChoice?: DefenderChoice

@Column({ type: DataType.STRING, allowNull: true })
@ApiPropertyOptional({ type: String })
requestedDefenderNationalId?: string

@Column({ type: DataType.STRING, allowNull: true })
@ApiPropertyOptional({ type: String })
requestedDefenderName?: string
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,4 +49,19 @@ export class UpdateSubpoenaDto {
@IsString()
@ApiPropertyOptional({ type: String })
readonly defenderPhoneNumber?: string

@IsOptional()
@IsEnum(DefenderChoice)
@ApiPropertyOptional({ enum: DefenderChoice })
readonly requestedDefenderChoice?: DefenderChoice

@IsOptional()
@IsString()
@ApiPropertyOptional({ type: String })
readonly requestedDefenderNationalId?: string

@IsOptional()
@IsString()
@ApiPropertyOptional({ type: String })
readonly requestedDefenderName?: string
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import {
Header,
Inject,
Param,
Query,
Res,
UseGuards,
} from '@nestjs/common'
Expand Down
Loading

0 comments on commit 185e0ff

Please sign in to comment.