Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

CAS 994: Add overlap offenders name, gender and link to referral #1158

Merged
merged 3 commits into from
Dec 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions assets/sass/components/_overlap-details.scss
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@
display: inline;
}

.overlap-details__value--bold {
font-weight: bold;
}

.overlap-details__row--inline {
display: inline;
}
16 changes: 5 additions & 11 deletions cypress_shared/components/bedspaceSearchResult.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,26 +57,20 @@ export default class BedspaceSearchResult extends Component {
cy.get('ul[data-cy-overlaps] > li')
.eq(i)
.within(() => {
cy.root().contains(`Name: ${overlap.name}`)
cy.root().contains(`Sex: ${overlap.sex},`)
cy.root().contains(`CRN: ${overlap.crn}`)
cy.root().contains(overlap.days === 1 ? '1 day overlap' : `${overlap.days} days overlap`)
cy.get('a')
.contains('View booking')
.should(
'have.attr',
'href',
paths.bookings.show({
premisesId: this.result.premises.id,
roomId: overlap.roomId,
bookingId: overlap.bookingId,
}),
)
.contains(`View referral for ${overlap.name}`)
.should('have.attr', 'href', paths.assessments.summary({ id: overlap.assessmentId }))
})
})
})
}

clickOverlapLink(crn: string) {
cy.get('summary').contains('Other people staying').click()
cy.get('ul[data-cy-overlaps] > li').find('dd.overlap-details__value').contains(crn).parents('li').find('a').click()
cy.get('ul[data-cy-overlaps]').find('dd.overlap-details__value').contains(crn).parents('li').find('a').click()
}
}
1 change: 1 addition & 0 deletions cypress_shared/fixtures/person-local.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,6 @@
"nationality": "",
"ethnicity": "",
"sex": "Male",
"type": "FullPerson",
"genderIdentity": "Prefer not to say"
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import Page from '../../../../cypress_shared/pages/page'
import DashboardPage from '../../../../cypress_shared/pages/temporary-accommodation/dashboardPage'
import AssessmentSummaryPage from '../../../../cypress_shared/pages/assess/summary'
import BedspaceSearchPage from '../../../../cypress_shared/pages/temporary-accommodation/manage/bedspaceSearch'
import BedspaceShowPage from '../../../../cypress_shared/pages/temporary-accommodation/manage/bedspaceShow'
import BookingShowPage from '../../../../cypress_shared/pages/temporary-accommodation/manage/bookingShow'
import { setupTestUser } from '../../../../cypress_shared/utils/setupTestUser'
import {
assessmentFactory,
bedSearchParametersFactory,
bedSearchResultFactory,
bedSearchResultsFactory,
bookingFactory,
overlapFactory,
personFactory,
placeContextFactory,
Expand Down Expand Up @@ -148,7 +148,7 @@ context('Bedspace Search', () => {
Page.verifyOnPage(BedspaceShowPage, premises, room)
})

it('allows me to view an overlapping booking', () => {
it("allows me to view an overlapping offender's referral", () => {
// Given I am signed in
cy.signIn()

Expand All @@ -163,19 +163,20 @@ context('Bedspace Search', () => {
const premises = premisesFactory.build()
const room = roomFactory.build()

const booking = bookingFactory.build({
person,
})
const assessment = assessmentFactory.build({ status: 'closed' })

const results = bedSearchResultsFactory.build({
results: [
bedSearchResultFactory.forBedspace(premises, room).build({
overlaps: [
overlapFactory.build({
name: person.name,
crn: person.crn,
personType: person.type,
roomId: room.id,
bookingId: booking.id,
assessmentId: assessment.id,
days: 5,
sex: person.sex,
}),
],
}),
Expand All @@ -185,7 +186,7 @@ context('Bedspace Search', () => {
cy.task('stubBedSearch', results)
cy.task('stubSinglePremises', premises)
cy.task('stubSingleRoom', { premisesId: premises.id, room })
cy.task('stubBooking', { premisesId: premises.id, booking })
cy.task('stubFindAssessment', { ...assessment, status: 'closed' })

// And when I fill out the form
const searchParameters = bedSearchParametersFactory.build()
Expand All @@ -196,7 +197,7 @@ context('Bedspace Search', () => {
const postSearchPage = Page.verifyOnPage(BedspaceSearchPage, results)
postSearchPage.clickOverlapLink(room, person.crn)

Page.verifyOnPage(BookingShowPage, premises, room, booking)
Page.verifyOnPage(AssessmentSummaryPage, assessment)
})

it('shows errors when the API returns an error', () => {
Expand Down
3 changes: 3 additions & 0 deletions server/testutils/factories/overlap.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
import { fakerEN_GB as faker } from '@faker-js/faker'
import { Factory } from 'fishery'
import { TemporaryAccommodationBedSearchResultOverlap as Overlap } from '../../@types/shared'
import assessmentFactory from './assessment'
import { fullPersonFactory } from './person'

export default Factory.define<Overlap>(() => ({
crn: fullPersonFactory.build().crn,
name: fullPersonFactory.build().name,
sex: fullPersonFactory.build().sex,
roomId: faker.string.uuid(),
personType: fullPersonFactory.build().type,
bookingId: faker.string.uuid(),
assessmentId: assessmentFactory.build().id,
days: faker.number.int({ min: 1, max: 100 }),
}))
2 changes: 1 addition & 1 deletion server/testutils/factories/person.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export const fullPersonFactory = Factory.define<FullPerson>(() => ({
crn: `C${faker.number.int({ min: 100000, max: 999999 })}`,
name: faker.person.fullName(),
dateOfBirth: DateFormats.dateObjToIsoDate(faker.date.past()),
sex: faker.helpers.arrayElement(['Male', 'Female', 'Other', 'Prefer not to say']),
sex: faker.helpers.arrayElement(['Male', 'Female']),
status: faker.helpers.arrayElement(['InCustody', 'InCommunity']),
nomsNumber: `NOMS${faker.number.int({ min: 100, max: 999 })}`,
nationality: faker.location.country(),
Expand Down
62 changes: 54 additions & 8 deletions server/utils/bedspaceSearchResultUtils.test.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
import { TemporaryAccommodationBedSearchResultOverlap } from '@approved-premises/api'
import { FullPerson, RestrictedPerson, TemporaryAccommodationBedSearchResultOverlap } from '@approved-premises/api'
import {
assessmentFactory,
bedSearchResultFactory,
bookingFactory,
characteristicFactory,
personFactory,
premisesFactory,
restrictedPersonFactory,
roomFactory,
} from '../testutils/factories'
import {
bedspaceKeyCharacteristics,
bedspaceOverlapResult,
premisesKeyCharacteristics,
} from './bedspaceSearchResultUtils'
import { fullPersonFactory } from '../testutils/factories/person'

describe('BedspaceSearchResultUtils', () => {
describe('bedspaceKeyCharacteristics', () => {
Expand Down Expand Up @@ -65,41 +66,86 @@ describe('BedspaceSearchResultUtils', () => {

describe('bedspaceOverlapResult', () => {
let overLapDays: TemporaryAccommodationBedSearchResultOverlap['days']
let overlapResult: Omit<TemporaryAccommodationBedSearchResultOverlap, 'name' | 'sex' | 'assesmentId'>
let overlapResult: TemporaryAccommodationBedSearchResultOverlap
let overLapAssessmentId: TemporaryAccommodationBedSearchResultOverlap['assessmentId']
let person: FullPerson | RestrictedPerson

const createOverLapResult = () => {
return {
crn: personFactory.build().crn,
crn: person.crn,
days: overLapDays,
personType: personFactory.build().type,
personType: person.type,
roomId: roomFactory.build().id,
bookingId: bookingFactory.build().id,
bookingId: '123456789',
assessmentId: overLapAssessmentId,
name: person.type === 'FullPerson' ? (person as FullPerson).name : 'Limited access offender',
sex: person.type === 'FullPerson' ? (person as FullPerson).sex : undefined,
}
}

beforeEach(() => {
overLapDays = 8
overLapAssessmentId = assessmentFactory.build().id
person = fullPersonFactory.build()
overlapResult = createOverLapResult()
})

it('returns object of key/value pairs', () => {
expect(bedspaceOverlapResult(overlapResult)).toEqual({
crn: overlapResult.crn,
overlapDays: '8 days overlap',
personType: 'FullPerson',
roomId: overlapResult.roomId,
bookingId: overlapResult.bookingId,
assessmentId: overlapResult.assessmentId,
displayName: overlapResult.name,
referralNameOrCrn: overlapResult.name,
sex: overlapResult.sex,
})
})

describe('when overlap by 1 day', () => {
beforeEach(() => {
overLapDays = 1
overLapAssessmentId = assessmentFactory.build().id
overlapResult = createOverLapResult()
})

it('returns the correct overlap message for single day', () => {
expect(bedspaceOverlapResult(overlapResult).overlapDays).toEqual('1 day overlap')
})
})

describe('when offender is "Limited access offender', () => {
beforeEach(() => {
overLapDays = 8
person = restrictedPersonFactory.build()
overLapAssessmentId = assessmentFactory.build().id
overlapResult = createOverLapResult()
})

it('returns object of key/value pairs', () => {
expect(bedspaceOverlapResult(overlapResult)).toEqual({
crn: overlapResult.crn,
overlapDays: '8 days overlap',
personType: 'RestrictedPerson',
roomId: overlapResult.roomId,
referralNameOrCrn: overlapResult.crn,
assessmentId: overlapResult.assessmentId,
displayName: 'Limited access offender',
})
})
})

describe('when no assessment is assigned', () => {
beforeEach(() => {
overLapDays = 1
overLapAssessmentId = undefined
overlapResult = createOverLapResult()
})

it('returns undefined for assessment ID', () => {
expect(bedspaceOverlapResult(overlapResult).assessmentId).toBeUndefined()
})
})
})
})
16 changes: 11 additions & 5 deletions server/utils/bedspaceSearchResultUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,22 @@ export function bedspaceKeyCharacteristics(result: BedSearchResult): Array<strin
.map(characteristic => characteristic.name)
}

export function bedspaceOverlapResult(
overlapResult: Omit<TemporaryAccommodationBedSearchResultOverlap, 'name' | 'sex' | 'assesmentId' | 'personType'>,
) {
const { crn, days, roomId, bookingId } = overlapResult
export function bedspaceOverlapResult(overlapResult: TemporaryAccommodationBedSearchResultOverlap) {
const { crn, days, roomId, personType, assessmentId } = overlapResult
const overlapDays = `${days} ${days === 1 ? 'day' : 'days'} overlap`

const displayName = personType === 'FullPerson' ? overlapResult.name : 'Limited access offender'
const referralNameOrCrn = personType === 'FullPerson' ? overlapResult.name : overlapResult.crn
const sex = personType === 'FullPerson' ? overlapResult.sex : undefined

return {
crn,
overlapDays,
roomId,
bookingId,
personType,
displayName,
referralNameOrCrn,
sex,
assessmentId,
}
}
42 changes: 25 additions & 17 deletions server/views/components/overlap-details/macro.njk
Original file line number Diff line number Diff line change
@@ -1,20 +1,28 @@
{% macro overlapDetails(params) %}
<dl class="overlap-details">
<div class="overlap-details__row">
<dt class="overlap-details__key">
CRN:
</dt>
<dd class="overlap-details__value">{{ params.overlap.crn }}</dd>
</div>
<div class="overlap-details__row overlap-details__row--inline">
<dt class="overlap-details__key govuk-visually-hidden">
Overlap:
</dt>
<dd class="overlap-details__value">{{ params.overlap.overlapDays }}</dd>
</div>
</dl>
<a class="govuk-link"
href="{{ addPlaceContext(paths.bookings.show({premisesId: params.premisesId, roomId: params.overlap.roomId, bookingId: params.overlap.bookingId})) }}">
View booking
<dl class="overlap-details">
<div class="overlap-details__row">
<dt class="overlap-details__key govuk-visually-hidden">Name:</dt>
<dd class="overlap-details__value overlap-details__value--bold">{{ params.overlap.displayName }}</dd>
</div>
<div class="overlap-details__row">
<dt class="overlap-details__key">CRN:</dt>
<dd class="overlap-details__value">{{ params.overlap.crn }}</dd>
</div>
<div class="overlap-details__row overlap-details__row--inline">
{% if params.overlap.sex %}
<dt class="overlap-details__key govuk-visually-hidden">Sex:</dt>
<dd class="overlap-details__value">{{ params.overlap.sex }},</dd>
{% endif %}
<dt class="overlap-details__key govuk-visually-hidden">Overlap:</dt>
<dd class="overlap-details__value">{{ params.overlap.overlapDays }}</dd>
</div>
</dl>

{% if params.overlap.assessmentId %}
<a class="govuk-link" href="{{ addPlaceContext(paths.assessments.summary({ id: params.overlap.assessmentId })) }}">
View referral<span class="govuk-visually-hidden"> for {{ params.overlap.referralNameOrCrn }}</span>
</a>
{% else %}
<p class="govuk-body">No referral found.</p>
{% endif %}
{% endmacro %}
Loading