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

Display category text instead of category code in certain circumstances #254

Merged
merged 3 commits into from
Aug 18, 2023
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
1 change: 1 addition & 0 deletions integration_tests/support/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ Cypress.Commands.add(
cy.task('stubGetSocNominal404')
cy.task('stubGetStaffRoles', staffRoles)
cy.task('stubGetLearnerNeurodivergence', prisonerNumber)
cy.task('stubInmateDetail', bookingId)
},
)

Expand Down
21 changes: 11 additions & 10 deletions server/controllers/alertsController.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@ import { CaseLoadsDummyDataA } from '../data/localMockData/caseLoad'
import { Role } from '../data/enums/role'
import PrisonerSearchService from '../services/prisonerSearch'
import AlertsPageService from '../services/alertsPageService'
import { inmateDetailMock } from '../data/localMockData/inmateDetailMock'

let req: any
let res: any
let controller: any
let controller: AlertsController

jest.mock('../services/prisonerSearch.ts')
jest.mock('../services/alertsPageService.ts')
Expand Down Expand Up @@ -41,7 +42,7 @@ describe('Alerts Controller', () => {
.mockResolvedValue(pagedActiveAlertsMock)
const mapSpy = jest.spyOn(headerMappers, 'mapHeaderData')

await controller.displayAlerts(req, res, PrisonerMockDataA)
await controller.displayAlerts(req, res, PrisonerMockDataA, inmateDetailMock)

expect(getAlertsSpy).toHaveBeenCalledWith(
res.locals.clientToken,
Expand All @@ -56,7 +57,7 @@ describe('Alerts Controller', () => {
},
true,
)
expect(mapSpy).toHaveBeenCalledWith(PrisonerMockDataA, res.locals.user, 'alerts')
expect(mapSpy).toHaveBeenCalledWith(PrisonerMockDataA, inmateDetailMock, res.locals.user, 'alerts')
})

it('should get inactive alerts', async () => {
Expand All @@ -68,7 +69,7 @@ describe('Alerts Controller', () => {
.mockResolvedValue(pagedInactiveAlertsMock)
const mapSpy = jest.spyOn(headerMappers, 'mapHeaderData')

await controller.displayAlerts(req, res, PrisonerMockDataA)
await controller.displayAlerts(req, res, PrisonerMockDataA, inmateDetailMock)

expect(getAlertsSpy).toHaveBeenCalledWith(
res.locals.clientToken,
Expand All @@ -83,7 +84,7 @@ describe('Alerts Controller', () => {
},
true,
)
expect(mapSpy).toHaveBeenCalledWith(PrisonerMockDataA, res.locals.user, 'alerts')
expect(mapSpy).toHaveBeenCalledWith(PrisonerMockDataA, inmateDetailMock, res.locals.user, 'alerts')
})

it('should set canUpdateAlert to true if user has role and caseload', async () => {
Expand All @@ -92,7 +93,7 @@ describe('Alerts Controller', () => {
.mockResolvedValue(pagedActiveAlertsMock)
jest.spyOn(headerMappers, 'mapHeaderData')

await controller.displayAlerts(req, res, PrisonerMockDataA)
await controller.displayAlerts(req, res, PrisonerMockDataA, inmateDetailMock)

expect(getAlertsSpy).toHaveBeenCalledWith(
res.locals.clientToken,
Expand All @@ -117,7 +118,7 @@ describe('Alerts Controller', () => {

res.locals.user.userRoles = ['ROLE_OTHER']

await controller.displayAlerts(req, res, PrisonerMockDataA)
await controller.displayAlerts(req, res, PrisonerMockDataA, inmateDetailMock)

expect(getAlertsSpy).toHaveBeenCalledWith(
res.locals.clientToken,
Expand All @@ -140,7 +141,7 @@ describe('Alerts Controller', () => {
.mockResolvedValue(pagedActiveAlertsMock)
jest.spyOn(headerMappers, 'mapHeaderData')

await controller.displayAlerts(req, res, { ...PrisonerMockDataA, prisonId: 'XYZ' })
await controller.displayAlerts(req, res, { ...PrisonerMockDataA, prisonId: 'XYZ' }, inmateDetailMock)

expect(getAlertsSpy).toHaveBeenCalledWith(
res.locals.clientToken,
Expand All @@ -164,7 +165,7 @@ describe('Alerts Controller', () => {
.mockResolvedValue(pagedActiveAlertsMock)
jest.spyOn(headerMappers, 'mapHeaderData')

await controller.displayAlerts(req, res, { ...PrisonerMockDataA, prisonId: 'OUT' })
await controller.displayAlerts(req, res, { ...PrisonerMockDataA, prisonId: 'OUT' }, inmateDetailMock)

expect(getAlertsSpy).toHaveBeenCalledWith(
res.locals.clientToken,
Expand All @@ -188,7 +189,7 @@ describe('Alerts Controller', () => {
.mockResolvedValue(pagedActiveAlertsMock)
jest.spyOn(headerMappers, 'mapHeaderData')

await controller.displayAlerts(req, res, { ...PrisonerMockDataA, prisonId: 'TRN' })
await controller.displayAlerts(req, res, { ...PrisonerMockDataA, prisonId: 'TRN' }, inmateDetailMock)

expect(getAlertsSpy).toHaveBeenCalledWith(
res.locals.clientToken,
Expand Down
5 changes: 3 additions & 2 deletions server/controllers/alertsController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { Role } from '../data/enums/role'
import config from '../config'
import { userCanEdit, userHasRoles } from '../utils/utils'
import { Prisoner } from '../interfaces/prisoner'
import { InmateDetail } from '../interfaces/prisonApi/inmateDetail'

/**
* Parse request for alerts page and orchestrate response
Expand All @@ -22,7 +23,7 @@ export default class AlertsController {
this.isActive = isActive
}

public async displayAlerts(req: Request, res: Response, prisonerData: Prisoner) {
public async displayAlerts(req: Request, res: Response, prisonerData: Prisoner, inmateDetail: InmateDetail) {
// Parse query params for paging, sorting and filtering data
const { clientToken } = res.locals
const queryParams: PagedListQueryParams = {}
Expand Down Expand Up @@ -51,7 +52,7 @@ export default class AlertsController {
// Render page
return res.render('pages/alertsPage', {
pageTitle: 'Alerts',
...mapHeaderData(prisonerData, res.locals.user, 'alerts'),
...mapHeaderData(prisonerData, inmateDetail, res.locals.user, 'alerts'),
...alertsPageData,
showingAll,
addAlertLinkUrl,
Expand Down
4 changes: 3 additions & 1 deletion server/controllers/caseNotesController.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import CaseNotesService from '../services/caseNotesService'
import { caseNoteTypesMock } from '../data/localMockData/caseNoteTypesMock'
import { formatDate } from '../utils/dateHelpers'
import config from '../config'
import { inmateDetailMock } from '../data/localMockData/inmateDetailMock'

let req: any
let res: any
Expand Down Expand Up @@ -78,6 +79,7 @@ describe('Case Notes Controller', () => {
fullName: 'John Middle Names Saunders',
})
const mapSpy = jest.spyOn(headerMappers, 'mapHeaderData')
prisonApiClient.getInmateDetail = jest.fn(async () => inmateDetailMock)

await controller.displayCaseNotes()(req, res)

Expand All @@ -97,7 +99,7 @@ describe('Case Notes Controller', () => {
true,
{ displayName: 'A Name' },
)
expect(mapSpy).toHaveBeenCalledWith(PrisonerMockDataA, res.locals.user, 'case-notes')
expect(mapSpy).toHaveBeenCalledWith(PrisonerMockDataA, inmateDetailMock, res.locals.user, 'case-notes')
})

it('should display add case note page', async () => {
Expand Down
9 changes: 6 additions & 3 deletions server/controllers/caseNotesController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,15 +58,18 @@ export default class CaseNotesController {

// Get total count of case notes ignoring filters
// Get case notes based on given query params
const [caseNotesUsage, caseNotesPageData] = await Promise.all([
this.prisonApiClientBuilder(clientToken).getCaseNotesUsage(req.params.prisonerNumber),
// Get inmate detail for header
const prisonApiClient = this.prisonApiClientBuilder(clientToken)
const [caseNotesUsage, caseNotesPageData, inmateDetail] = await Promise.all([
prisonApiClient.getCaseNotesUsage(req.params.prisonerNumber),
this.caseNotesService.get(
userToken,
prisonerData,
queryParams,
canDeleteSensitiveCaseNotes,
req.session.userDetails,
),
prisonApiClient.getInmateDetail(prisonerData.bookingId),
])

const hasCaseNotes = Array.isArray(caseNotesUsage) && caseNotesUsage.length
Expand All @@ -82,7 +85,7 @@ export default class CaseNotesController {
// Render page
return res.render('pages/caseNotes/caseNotesPage', {
pageTitle: 'Case notes',
...mapHeaderData(prisonerData, res.locals.user, 'case-notes'),
...mapHeaderData(prisonerData, inmateDetail, res.locals.user, 'case-notes'),
...caseNotesPageData,
types,
subTypes,
Expand Down
5 changes: 3 additions & 2 deletions server/controllers/overviewController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { Nominal } from '../interfaces/pathfinderApi/nominal'
import { PathfinderApiClient } from '../data/interfaces/pathfinderApiClient'
import { ManageSocCasesApiClient } from '../data/interfaces/manageSocCasesApiClient'
import { RestClientBuilder } from '../data'
import { InmateDetail } from '../interfaces/prisonApi/inmateDetail'

/**
* Parse request for overview page and orchestrate response
Expand All @@ -30,7 +31,7 @@ export default class OverviewController {
private readonly manageSocCasesApiClientBuilder: RestClientBuilder<ManageSocCasesApiClient>,
) {}

public async displayOverview(req: Request, res: Response, prisonerData: Prisoner) {
public async displayOverview(req: Request, res: Response, prisonerData: Prisoner, inmateDetail: InmateDetail) {
const { clientToken } = res.locals
this.pathfinderApiClient = this.pathfinderApiClientBuilder(clientToken)
this.manageSocCasesApiClient = this.manageSocCasesApiClientBuilder(clientToken)
Expand Down Expand Up @@ -63,7 +64,7 @@ export default class OverviewController {

res.render('pages/overviewPage', {
pageTitle: 'Overview',
...mapHeaderData(prisonerData, res.locals.user, 'overview'),
...mapHeaderData(prisonerData, inmateDetail, res.locals.user, 'overview'),
...overviewPageData,
overviewActions,
overviewInfoLinks,
Expand Down
7 changes: 4 additions & 3 deletions server/mappers/headerMapper.test.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,25 @@
import { PrisonerMockDataA, PrisonerMockDataB } from '../data/localMockData/prisoner'
import { mapHeaderData, mapProfileBannerTopLinks } from './headerMappers'
import { userMock } from '../data/localMockData/user'
import { inmateDetailMock } from '../data/localMockData/inmateDetailMock'

describe('HeaderMapping', () => {
describe('Header data', () => {
describe('If the prisoner is part of the users case loads', () => {
it('Contains the location', () => {
const topLinks = mapProfileBannerTopLinks(PrisonerMockDataA, userMock)
const topLinks = mapProfileBannerTopLinks(PrisonerMockDataA, inmateDetailMock, userMock)
expect(topLinks.length).toEqual(4)
expect(topLinks[0].heading).toEqual('Location')
})
})
})
describe('Category A prisoner', () => {
it('Photo type should be photoWithheld for security purposes', async () => {
const headerData = mapHeaderData(PrisonerMockDataA, userMock)
const headerData = mapHeaderData(PrisonerMockDataA, inmateDetailMock, userMock)
expect(headerData.photoType).toBe('photoWithheld')
})
it('Photo type should return as placeholder if the category is not A', async () => {
const headerData = mapHeaderData(PrisonerMockDataB, userMock)
const headerData = mapHeaderData(PrisonerMockDataB, inmateDetailMock, userMock)
expect(headerData.photoType).toBe('placeholder')
})
})
Expand Down
15 changes: 11 additions & 4 deletions server/mappers/headerMappers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,11 @@ import config from '../config'
import { Role } from '../data/enums/role'
import { canViewCaseNotes } from '../utils/roleHelpers'
import { User } from '../data/hmppsAuthClient'
import { InmateDetail } from '../interfaces/prisonApi/inmateDetail'

export const placeHolderImagePath = '/assets/images/prisoner-profile-photo.png'

export function mapProfileBannerTopLinks(prisonerData: Prisoner, user: User) {
export function mapProfileBannerTopLinks(prisonerData: Prisoner, inmateDetail: InmateDetail, user: User) {
const { userRoles, caseLoads } = user
const profileBannerTopLinks = []

Expand Down Expand Up @@ -41,7 +42,7 @@ export function mapProfileBannerTopLinks(prisonerData: Prisoner, user: User) {
? 'Manage category'
: 'View category',
// eslint-disable-next-line no-nested-ternary
info: formatCategoryCodeDescription(prisonerData.category),
info: formatCategoryCodeDescription(prisonerData.category, inmateDetail.category),
classes: '',
url: `${config.serviceUrls.offenderCategorisation}/${prisonerData.bookingId}`,
})
Expand Down Expand Up @@ -78,7 +79,13 @@ export function mapAlerts(prisonerData: Prisoner, alertFlags: AlertFlagLabel[])
return [...new Set(alerts)].sort((a, b) => a.label.localeCompare(b.label))
}

export function mapHeaderData(prisonerData: Prisoner, user?: User, pageId?: string, hideBanner?: boolean) {
export function mapHeaderData(
prisonerData: Prisoner,
inmateDetail: InmateDetail,
user?: User,
pageId?: string,
hideBanner?: boolean,
) {
const photoType = prisonerData.category === 'A' ? 'photoWithheld' : 'placeholder'
const tabs = tabLinks(prisonerData.prisonerNumber, canViewCaseNotes(user, prisonerData))

Expand All @@ -92,7 +99,7 @@ export function mapHeaderData(prisonerData: Prisoner, user?: User, pageId?: stri
style: NameFormatStyle.lastCommaFirst,
}),
prisonerNumber: prisonerData.prisonerNumber,
profileBannerTopLinks: mapProfileBannerTopLinks(prisonerData, user),
profileBannerTopLinks: mapProfileBannerTopLinks(prisonerData, inmateDetail, user),
alerts: mapAlerts(prisonerData, alertFlagLabels),
tabLinks: tabs,
photoType,
Expand Down
Loading