diff --git a/integration_tests/e2e/login.cy.ts b/integration_tests/e2e/login.cy.ts index 4e9ae8c4d..6a3bbe533 100644 --- a/integration_tests/e2e/login.cy.ts +++ b/integration_tests/e2e/login.cy.ts @@ -25,6 +25,7 @@ context('SignIn', () => { }) it('User name visible in header', () => { + cy.setupUserAuth() cy.signIn() cy.visit('/prisoner/G6123VU') const indexPage = Page.verifyOnPage(IndexPage) @@ -32,7 +33,7 @@ context('SignIn', () => { }) it('User with prison role has access', () => { - cy.task('stubSignIn', ['ROLE_PRISON']) + cy.setupUserAuth({ roles: ['ROLE_PRISON'] }) cy.signIn() cy.visit('/prisoner/G6123VU') @@ -40,21 +41,21 @@ context('SignIn', () => { }) it('User with Global Search role has access', () => { - cy.task('stubSignIn', ['ROLE_GLOBAL_SEARCH']) - + cy.setupUserAuth({ roles: ['ROLE_GLOBAL_SEARCH'] }) cy.signIn() cy.visit('/prisoner/G6123VU') Page.verifyOnPage(IndexPage) }) it('User with neither prison or global search role denied access', () => { - cy.task('stubSignIn', ['ROLE_SOMETHING_ELSE']) + cy.setupUserAuth({ roles: ['ROLE_SOMETHING_ELSE'] }) cy.signIn({ failOnStatusCode: false, redirectPath: '/prisoner/G6123VU' }) Page.verifyOnPage(AuthErrorPage) }) it('User can log out', () => { + cy.setupUserAuth({ roles: ['ROLE_PRISON'] }) cy.signIn() cy.visit('/prisoner/G6123VU') const indexPage = Page.verifyOnPage(IndexPage) @@ -63,6 +64,7 @@ context('SignIn', () => { }) it('User can manage their details', () => { + cy.setupUserAuth({ roles: ['ROLE_PRISON'] }) cy.signIn() cy.visit('/prisoner/G6123VU') const indexPage = Page.verifyOnPage(IndexPage) @@ -73,6 +75,7 @@ context('SignIn', () => { }) it('Token verification failure takes user to sign in page', () => { + cy.setupUserAuth({ roles: ['ROLE_PRISON'] }) cy.signIn() cy.visit('/prisoner/G6123VU') Page.verifyOnPage(IndexPage) @@ -83,6 +86,7 @@ context('SignIn', () => { }) it('Token verification failure clears user session', () => { + cy.setupUserAuth({ roles: ['ROLE_PRISON'] }) cy.signIn() cy.visit('/prisoner/G6123VU') const indexPage = Page.verifyOnPage(IndexPage) diff --git a/integration_tests/e2e/overviewPage.cy.ts b/integration_tests/e2e/overviewPage.cy.ts index aea5555b5..85f32a09c 100644 --- a/integration_tests/e2e/overviewPage.cy.ts +++ b/integration_tests/e2e/overviewPage.cy.ts @@ -7,174 +7,203 @@ const visitOverviewPage = (): OverviewPage => { } context('Overview Page', () => { - beforeEach(() => { - cy.task('reset') - cy.task('stubSignIn') - cy.task('stubAuthUser') - cy.setupOverviewPageStubs({ prisonerNumber: 'G6123VU', bookingId: '1102484' }) - }) - - it('Overview page is displayed', () => { - visitOverviewPage() - cy.request('/prisoner/G6123VU').its('body').should('contain', 'Overview') - }) - - it('Displays the overview tab as active', () => { - const overviewPage = visitOverviewPage() - overviewPage.activeTab().should('contain', 'Overview') - }) - - context('Mini Summary A', () => { - it('Mini summary list is displayed', () => { - const overviewPage = visitOverviewPage() - overviewPage.miniSummaryGroupA().should('exist') - }) - - it('Mini summary Group A should display the macro header', () => { - const overviewPage = visitOverviewPage() - overviewPage.miniSummaryGroupA_MacroHeader().should('exist') - }) - - it('Mini summary Group A should contain Money card with correct data', () => { - const overviewPage = visitOverviewPage() - overviewPage.moneyCard().contains('h2', 'Money') - overviewPage.moneyCard().contains('p', 'Spends') - overviewPage.moneyCard().contains('p', '£240.51') - overviewPage.moneyCard().contains('p', 'Private cash') - overviewPage.moneyCard().contains('p', '£0.00') - overviewPage.moneyCard().contains('a', 'Transactions and savings') - }) - - it('Mini summary Group A should contain Adjudications card with correct data', () => { - const overviewPage = visitOverviewPage() - overviewPage.adjudicationsCard().contains('h2', 'Adjudications') - overviewPage.adjudicationsCard().contains('p', 'Proven in last 3 months') - overviewPage.adjudicationsCard().contains('p', '4') - overviewPage.adjudicationsCard().contains('p', 'Active') - overviewPage.adjudicationsCard().contains('p', 'No active punishments') - overviewPage.adjudicationsCard().contains('a', 'Adjudications history') - }) - - it('Mini summary Group A should contain Visits card with correct data', () => { - const overviewPage = visitOverviewPage() - overviewPage.visitsCard().contains('h2', 'Visits') - overviewPage.visitsCard().contains('p', 'Next visit date') - overviewPage.visitsCard().contains('p', '15/09/2023') - overviewPage.visitsCard().contains('p', 'Remaining visits') - overviewPage.visitsCard().contains('p', '6') - overviewPage.visitsCard().contains('p', 'Including 2 privileged visits') - overviewPage.visitsCard().contains('a', 'Visits details') - }) - }) - - context('Mini Summary B', () => { - it('Mini summary list is displayed', () => { - const overviewPage = visitOverviewPage() - overviewPage.miniSummaryGroupB().should('exist') - }) - - it('Mini summary Group B should hide the macro header', () => { - const overviewPage = visitOverviewPage() - overviewPage.miniSummaryGroupB_MacroHeader().should('not.exist') - }) - - it('Mini summary Group B should contain Category card with correct data', () => { - const overviewPage = visitOverviewPage() - overviewPage.categoryCard().contains('p', 'Category') - overviewPage.categoryCard().contains('p', 'B') - overviewPage.categoryCard().contains('p', 'Next review: 19/02/2023') - overviewPage.categoryCard().contains('a', 'Manage category') - }) - - it('Mini summary Group B should contain Incentives card with correct data', () => { - const overviewPage = visitOverviewPage() - overviewPage.incentivesCard().contains('p', 'Incentives: since last review') - overviewPage.incentivesCard().contains('p', 'Positive behaviours: 1') - overviewPage.incentivesCard().contains('p', 'Negative behaviours: 1') - overviewPage.incentivesCard().contains('p', 'Next review by: 01/01/2024') - overviewPage.incentivesCard().contains('a', 'Incentive level details') - }) - - it('Mini summary Group B should contain CSRA card with correct data', () => { - const overviewPage = visitOverviewPage() - overviewPage.csraCard().contains('p', 'CSRA') - overviewPage.csraCard().contains('p', 'Standard') - overviewPage.csraCard().contains('p', 'Last review: 19/02/2021') - overviewPage.csraCard().contains('a', 'CSRA history') - }) - }) - - it('Should hide the change location link', () => { - const overviewPage = visitOverviewPage() - // The link text label is change location but the functionality is change caseload - overviewPage.headerChangeLocation().should('not.exist') - }) - - context('Non-associations', () => { - it('Displays the non associations on the page', () => { - const overviewPage = visitOverviewPage() - overviewPage.nonAssociations().table().should('exist') - overviewPage.nonAssociations().rows().should('have.length', 3) - overviewPage.nonAssociations().row(1).prisonerName().should('have.text', 'John Doe') - overviewPage.nonAssociations().row(1).prisonNumber().should('have.text', 'ABC123') - overviewPage.nonAssociations().row(1).location().should('have.text', 'NMI-RECP') - overviewPage.nonAssociations().row(1).reciprocalReason().should('have.text', 'Victim') - overviewPage.nonAssociations().row(2).prisonerName().should('have.text', 'Guy Incognito') - overviewPage.nonAssociations().row(2).prisonNumber().should('have.text', 'DEF321') - overviewPage.nonAssociations().row(2).location().should('have.text', 'NMI-RECP') - overviewPage.nonAssociations().row(2).reciprocalReason().should('have.text', 'Rival Gang') - }) - }) - - context('Personal details', () => { - it('Displays the prisoner presonal details', () => { - const overviewPage = visitOverviewPage() - overviewPage.personalDetails().should('exist') + context('Given the prisoner is not within the users caseload', () => { + context('Given the user has the GLOBAL_SEARCH role', () => { + beforeEach(() => { + cy.task('reset') + cy.setupUserAuth({ + roles: ['ROLE_GLOBAL_SEARCH'], + caseLoads: [{ caseloadFunction: '', caseLoadId: '123', currentlyActive: true, description: '', type: '' }], + }) + cy.setupOverviewPageStubs({ prisonerNumber: 'G6123VU', bookingId: '1102484' }) + }) + + it('Does not display the sidebar', () => { + visitOverviewPage() + cy.getDataQa('hidden-overview-side-bar').should('exist') + }) + + it('Does not display the schedule', () => { + visitOverviewPage() + cy.getDataQa('hidden-overview-schedule').should('exist') + }) + + it('Does not display the non-associations', () => { + visitOverviewPage() + cy.getDataQa('hidden-overview-non-associations').should('exist') + }) }) }) - context('Schedule', () => { - it('Displays the schedule on the page', () => { - const overviewPage = visitOverviewPage() - overviewPage.schedule().morning().column().should('exist') - overviewPage.schedule().afternoon().column().should('exist') - overviewPage.schedule().evening().column().should('exist') - - overviewPage.schedule().morning().item(0).should('include.text', 'Joinery AM') - overviewPage.schedule().afternoon().item(0).should('include.text', 'Joinery PM') - overviewPage.schedule().evening().item(0).should('include.text', 'Gym - Football') - overviewPage.schedule().evening().item(1).should('include.text', 'VLB - Test') - }) - }) - - context('Staff contacts', () => { - it('Displays the offender staff contact details', () => { - const overviewPage = visitOverviewPage() - overviewPage.staffContacts().should('exist') - }) - }) - - it('Click the prisoner profile and go to the stand alone photo page', () => { - const overviewPage = visitOverviewPage() - cy.url().should('eq', 'http://localhost:3007/prisoner/G6123VU') - overviewPage.prisonerPhotoLink().should('exist') - overviewPage.prisonerPhotoLink().click({ force: true }) - cy.url().should('eq', 'http://localhost:3007/prisoner/G6123VU/image') - }) - - context('Statuses', () => { - it('Displays the status list', () => { - const overviewPage = visitOverviewPage() - overviewPage.statusList().should('exist') - overviewPage.statusList().contains('li > p', 'In Moorland (HMP & YOI)') - }) - }) - - context('Click work and skills button', () => { - it('Displays the status list', () => { - const overviewPage = visitOverviewPage() - overviewPage.statusList().should('exist') - overviewPage.statusList().contains('li > p', 'In Moorland (HMP & YOI)') + context('Given prisoner is within the users case load', () => { + beforeEach(() => { + cy.task('reset') + cy.setupUserAuth() + cy.setupOverviewPageStubs({ prisonerNumber: 'G6123VU', bookingId: '1102484' }) + }) + + it('Overview page is displayed', () => { + visitOverviewPage() + cy.request('/prisoner/G6123VU').its('body').should('contain', 'Overview') + }) + + it('Displays the overview tab as active', () => { + const overviewPage = visitOverviewPage() + overviewPage.activeTab().should('contain', 'Overview') + }) + + context('Mini Summary A', () => { + it('Mini summary list is displayed', () => { + const overviewPage = visitOverviewPage() + overviewPage.miniSummaryGroupA().should('exist') + }) + + it('Mini summary Group A should display the macro header', () => { + const overviewPage = visitOverviewPage() + overviewPage.miniSummaryGroupA_MacroHeader().should('exist') + }) + + it('Mini summary Group A should contain Money card with correct data', () => { + const overviewPage = visitOverviewPage() + overviewPage.moneyCard().contains('h2', 'Money') + overviewPage.moneyCard().contains('p', 'Spends') + overviewPage.moneyCard().contains('p', '£240.51') + overviewPage.moneyCard().contains('p', 'Private cash') + overviewPage.moneyCard().contains('p', '£0.00') + overviewPage.moneyCard().contains('a', 'Transactions and savings') + }) + + it('Mini summary Group A should contain Adjudications card with correct data', () => { + const overviewPage = visitOverviewPage() + overviewPage.adjudicationsCard().contains('h2', 'Adjudications') + overviewPage.adjudicationsCard().contains('p', 'Proven in last 3 months') + overviewPage.adjudicationsCard().contains('p', '4') + overviewPage.adjudicationsCard().contains('p', 'Active') + overviewPage.adjudicationsCard().contains('p', 'No active punishments') + overviewPage.adjudicationsCard().contains('a', 'Adjudications history') + }) + + it('Mini summary Group A should contain Visits card with correct data', () => { + const overviewPage = visitOverviewPage() + overviewPage.visitsCard().contains('h2', 'Visits') + overviewPage.visitsCard().contains('p', 'Next visit date') + overviewPage.visitsCard().contains('p', '15/09/2023') + overviewPage.visitsCard().contains('p', 'Remaining visits') + overviewPage.visitsCard().contains('p', '6') + overviewPage.visitsCard().contains('p', 'Including 2 privileged visits') + overviewPage.visitsCard().contains('a', 'Visits details') + }) + }) + + context('Mini Summary B', () => { + it('Mini summary list is displayed', () => { + const overviewPage = visitOverviewPage() + overviewPage.miniSummaryGroupB().should('exist') + }) + + it('Mini summary Group B should hide the macro header', () => { + const overviewPage = visitOverviewPage() + overviewPage.miniSummaryGroupB_MacroHeader().should('not.exist') + }) + + it('Mini summary Group B should contain Category card with correct data', () => { + const overviewPage = visitOverviewPage() + overviewPage.categoryCard().contains('p', 'Category') + overviewPage.categoryCard().contains('p', 'B') + overviewPage.categoryCard().contains('p', 'Next review: 19/02/2023') + overviewPage.categoryCard().contains('a', 'Manage category') + }) + + it('Mini summary Group B should contain Incentives card with correct data', () => { + const overviewPage = visitOverviewPage() + overviewPage.incentivesCard().contains('p', 'Incentives: since last review') + overviewPage.incentivesCard().contains('p', 'Positive behaviours: 1') + overviewPage.incentivesCard().contains('p', 'Negative behaviours: 1') + overviewPage.incentivesCard().contains('p', 'Next review by: 01/01/2024') + overviewPage.incentivesCard().contains('a', 'Incentive level details') + }) + + it('Mini summary Group B should contain CSRA card with correct data', () => { + const overviewPage = visitOverviewPage() + overviewPage.csraCard().contains('p', 'CSRA') + overviewPage.csraCard().contains('p', 'Standard') + overviewPage.csraCard().contains('p', 'Last review: 19/02/2021') + overviewPage.csraCard().contains('a', 'CSRA history') + }) + }) + + it('Should hide the change location link', () => { + const overviewPage = visitOverviewPage() + // The link text label is change location but the functionality is change caseload + overviewPage.headerChangeLocation().should('not.exist') + }) + + context('Non-associations', () => { + it('Displays the non associations on the page', () => { + const overviewPage = visitOverviewPage() + overviewPage.nonAssociations().table().should('exist') + overviewPage.nonAssociations().rows().should('have.length', 3) + overviewPage.nonAssociations().row(1).prisonerName().should('have.text', 'John Doe') + overviewPage.nonAssociations().row(1).prisonNumber().should('have.text', 'ABC123') + overviewPage.nonAssociations().row(1).location().should('have.text', 'NMI-RECP') + overviewPage.nonAssociations().row(1).reciprocalReason().should('have.text', 'Victim') + overviewPage.nonAssociations().row(2).prisonerName().should('have.text', 'Guy Incognito') + overviewPage.nonAssociations().row(2).prisonNumber().should('have.text', 'DEF321') + overviewPage.nonAssociations().row(2).location().should('have.text', 'NMI-RECP') + overviewPage.nonAssociations().row(2).reciprocalReason().should('have.text', 'Rival Gang') + }) + }) + + context('Personal details', () => { + it('Displays the prisoner presonal details', () => { + const overviewPage = visitOverviewPage() + overviewPage.personalDetails().should('exist') + }) + }) + + context('Schedule', () => { + it('Displays the schedule on the page', () => { + const overviewPage = visitOverviewPage() + overviewPage.schedule().morning().column().should('exist') + overviewPage.schedule().afternoon().column().should('exist') + overviewPage.schedule().evening().column().should('exist') + + overviewPage.schedule().morning().item(0).should('include.text', 'Joinery AM') + overviewPage.schedule().afternoon().item(0).should('include.text', 'Joinery PM') + overviewPage.schedule().evening().item(0).should('include.text', 'Gym - Football') + overviewPage.schedule().evening().item(1).should('include.text', 'VLB - Test') + }) + }) + + context('Staff contacts', () => { + it('Displays the offender staff contact details', () => { + const overviewPage = visitOverviewPage() + overviewPage.staffContacts().should('exist') + }) + }) + + it('Click the prisoner profile and go to the stand alone photo page', () => { + const overviewPage = visitOverviewPage() + cy.url().should('eq', 'http://localhost:3007/prisoner/G6123VU') + overviewPage.prisonerPhotoLink().should('exist') + overviewPage.prisonerPhotoLink().click({ force: true }) + cy.url().should('eq', 'http://localhost:3007/prisoner/G6123VU/image') + }) + + context('Statuses', () => { + it('Displays the status list', () => { + const overviewPage = visitOverviewPage() + overviewPage.statusList().should('exist') + overviewPage.statusList().contains('li > p', 'In Moorland (HMP & YOI)') + }) + }) + + context('Click work and skills button', () => { + it('Displays the status list', () => { + const overviewPage = visitOverviewPage() + overviewPage.statusList().should('exist') + overviewPage.statusList().contains('li > p', 'In Moorland (HMP & YOI)') + }) }) }) }) diff --git a/integration_tests/index.d.ts b/integration_tests/index.d.ts index 97989f023..6f4cab8d3 100644 --- a/integration_tests/index.d.ts +++ b/integration_tests/index.d.ts @@ -13,7 +13,7 @@ declare global { setupAlertsPageStubs(options: { prisonerNumber: string; bookingId: number }): Chainable setupWorkAndSkillsPageStubs(options: { prisonerNumber: string; emptyStates: boolean }): Chainable setupOffencesPageStubs(options: { prisonerNumber: string; bookingId: number }): Chainable - setupUserAuth(options: { + setupUserAuth(options?: { roles?: string[] caseLoads?: CaseLoad[] activeCaseLoadId?: string diff --git a/integration_tests/support/commands.ts b/integration_tests/support/commands.ts index 00592d87a..1ff78bd9a 100644 --- a/integration_tests/support/commands.ts +++ b/integration_tests/support/commands.ts @@ -64,7 +64,7 @@ Cypress.Commands.add('setupOffencesPageStubs', ({ prisonerNumber, bookingId }) = cy.task('stubGetPrisonerSentenceDetails', prisonerNumber) }) -Cypress.Commands.add('setupUserAuth', ({ roles, caseLoads, activeCaseLoadId = 'MDI' }) => { +Cypress.Commands.add('setupUserAuth', ({ roles, caseLoads, activeCaseLoadId = 'MDI' } = {}) => { cy.task('stubSignIn', roles) cy.task('stubUserCaseLoads', caseLoads) cy.task('stubAuthUser', { activeCaseLoadId }) diff --git a/server/services/overviewPageService.test.ts b/server/services/overviewPageService.test.ts index 63be05497..136d46947 100644 --- a/server/services/overviewPageService.test.ts +++ b/server/services/overviewPageService.test.ts @@ -44,6 +44,7 @@ import { convertToTitleCase } from '../utils/utils' import { IncentivesApiClient } from '../data/interfaces/incentivesApiClient' import { incentiveReviewsMock } from '../data/localMockData/incentiveReviewsMock' import { caseNoteCountMock } from '../data/localMockData/caseNoteCountMock' +import { CaseLoadsDummyDataA } from '../data/localMockData/caseLoad' describe('OverviewPageService', () => { let prisonApiClient: PrisonApiClient @@ -78,6 +79,7 @@ describe('OverviewPageService', () => { prisonApiClient.getVisitBalances = jest.fn(async () => visitBalancesMock) prisonApiClient.getVisitSummary = jest.fn(async () => visitSummaryMock) prisonApiClient.getCaseNoteCount = jest.fn(async () => caseNoteCountMock) + prisonApiClient.getUserCaseLoads = jest.fn(async () => CaseLoadsDummyDataA) }) describe('Non-associations', () => { @@ -130,7 +132,7 @@ describe('OverviewPageService', () => { const bookingId = 123456 const overviewPageService = overviewPageServiceConstruct() - await overviewPageService.get({ prisonerNumber, bookingId } as Prisoner) + await overviewPageService.get({ prisonerNumber, bookingId, prisonId: 'MDI' } as Prisoner) expect(prisonApiClient.getAccountBalances).toHaveBeenCalledWith(bookingId) expect(prisonApiClient.getAdjudications).toHaveBeenCalledWith(bookingId) expect(prisonApiClient.getVisitSummary).toHaveBeenCalledWith(bookingId) @@ -142,10 +144,37 @@ describe('OverviewPageService', () => { const bookingId = 123456 const overviewPageService = overviewPageServiceConstruct() - const res = await overviewPageService.get({ prisonerNumber, bookingId } as Prisoner) + const res = await overviewPageService.get({ prisonerNumber, bookingId, prisonId: 'MDI' } as Prisoner) expect(res.miniSummaryGroupA).toEqual(miniSummaryGroupAMock) }) + + describe('When the prisoner is not part of the users case loads', () => { + it('should return empty when the user has no specific roles', async () => { + const prisonerNumber = 'A1234BC' + const bookingId = 123456 + + const overviewPageService = overviewPageServiceConstruct() + const res = await overviewPageService.get({ prisonerNumber, bookingId, prisonId: '123' } as Prisoner) + + expect(res.miniSummaryGroupA).toEqual([]) + }) + + it.each(['POM_USER', 'RECEPTION_USER'])( + 'should return the adjudications when the user has a specific role', + async userRole => { + const prisonerNumber = 'A1234BC' + const bookingId = 123456 + + const overviewPageService = overviewPageServiceConstruct() + const res = await overviewPageService.get({ prisonerNumber, bookingId, prisonId: '123' } as Prisoner, [ + userRole, + ]) + + expect(res.miniSummaryGroupA).toEqual([miniSummaryGroupAMock[1]]) + }, + ) + }) }) describe('getMiniSummaryGroupB', () => { @@ -154,7 +183,7 @@ describe('OverviewPageService', () => { const bookingId = 123456 const overviewPageService = overviewPageServiceConstruct() - await overviewPageService.get({ ...PrisonerMockDataA, prisonerNumber, bookingId } as Prisoner) + await overviewPageService.get({ ...PrisonerMockDataA, prisonerNumber, bookingId, prisonId: 'MDI' } as Prisoner) expect(prisonApiClient.getAssessments).toHaveBeenCalledWith(bookingId) }) @@ -163,10 +192,72 @@ describe('OverviewPageService', () => { const bookingId = 123456 const overviewPageService = overviewPageServiceConstruct() - const res = await overviewPageService.get({ ...PrisonerMockDataA, prisonerNumber, bookingId } as Prisoner) + const res = await overviewPageService.get({ + ...PrisonerMockDataA, + prisonerNumber, + bookingId, + prisonId: 'MDI', + } as Prisoner) expect(res.miniSummaryGroupB).toEqual(miniSummaryGroupBMock) }) + describe('When the prisoner is not part of the users case loads', () => { + it('should not return the incentives data', async () => { + const prisonerNumber = 'A1234BC' + const bookingId = 123456 + + const overviewPageService = overviewPageServiceConstruct() + const res = await overviewPageService.get({ + ...PrisonerMockDataA, + prisonerNumber, + bookingId, + prisonId: '123', + } as Prisoner) + + expect(res.miniSummaryGroupB).toEqual([ + { + classes: miniSummaryGroupBMock[0].classes, + data: { ...miniSummaryGroupBMock[0].data, linkHref: undefined, linkLabel: undefined }, + }, + { + classes: miniSummaryGroupBMock[2].classes, + data: { ...miniSummaryGroupBMock[2].data, linkHref: undefined, linkLabel: undefined }, + }, + ]) + }) + + it('should not return have the links on the category card', async () => { + const prisonerNumber = 'A1234BC' + const bookingId = 123456 + + const overviewPageService = overviewPageServiceConstruct() + const res = await overviewPageService.get({ + ...PrisonerMockDataA, + prisonerNumber, + bookingId, + prisonId: '123', + } as Prisoner) + + expect(res.miniSummaryGroupB[0].data.linkLabel).toBeUndefined() + expect(res.miniSummaryGroupB[0].data.linkHref).toBeUndefined() + }) + + it('should not return have the links on the CSRA card', async () => { + const prisonerNumber = 'A1234BC' + const bookingId = 123456 + + const overviewPageService = overviewPageServiceConstruct() + const res = await overviewPageService.get({ + ...PrisonerMockDataA, + prisonerNumber, + bookingId, + prisonId: '123', + } as Prisoner) + + expect(res.miniSummaryGroupB[1].data.linkLabel).toBeUndefined() + expect(res.miniSummaryGroupB[1].data.linkHref).toBeUndefined() + }) + }) }) describe('getPersonalDetails', () => { diff --git a/server/services/overviewPageService.ts b/server/services/overviewPageService.ts index ed7d380cc..e665e1c3f 100644 --- a/server/services/overviewPageService.ts +++ b/server/services/overviewPageService.ts @@ -7,7 +7,14 @@ import { OverviewScheduleItem, } from '../interfaces/overviewPage' import { PrisonApiClient } from '../data/interfaces/prisonApiClient' -import { convertToTitleCase, formatMoney, formatPrivilegedVisitsSummary, getNamesFromString } from '../utils/utils' +import { + convertToTitleCase, + formatMoney, + formatPrivilegedVisitsSummary, + getNamesFromString, + prisonerBelongsToUsersCaseLoad, + userHasRoles, +} from '../utils/utils' import { Assessment } from '../interfaces/prisonApi/assessment' import { AssessmentCode } from '../data/enums/assessmentCode' import { Prisoner } from '../interfaces/prisoner' @@ -51,15 +58,15 @@ export default class OverviewPageService { this.incentivesApiClient = incentivesApiClient } - public async get(prisonerData: Prisoner): Promise { + public async get(prisonerData: Prisoner, userRoles: string[] = []): Promise { const { bookingId, prisonerNumber } = prisonerData const nonAssociations = await this.getNonAssociations(prisonerNumber) - const miniSummaryGroupA = await this.getMiniSummaryGroupA(prisonerNumber, bookingId) - const miniSummaryGroupB = await this.getMiniSummaryGroupB(bookingId) + const miniSummaryGroupA = await this.getMiniSummaryGroupA(prisonerData, userRoles) + const miniSummaryGroupB = await this.getMiniSummaryGroupB(prisonerData) const personalDetails = await this.getPersonalDetails(prisonerData) const staffContacts = await this.getStaffContacts(prisonerData) - const schedule = await this.getSchedule(prisonerData.bookingId) + const schedule = await this.getSchedule(bookingId) const statuses = await this.getStatuses(prisonerData) return { @@ -202,12 +209,14 @@ export default class OverviewPageService { return { personalDetailsMain, personalDetailsSide } } - private async getMiniSummaryGroupA(prisonerNumber: string, bookingId: number): Promise { - const [accountBalances, adjudicationSummary, visitSummary, visitBalances] = await Promise.all([ + private async getMiniSummaryGroupA(prisonerData: Prisoner, userRoles: string[]): Promise { + const { prisonerNumber, bookingId, prisonId } = prisonerData + const [accountBalances, adjudicationSummary, visitSummary, visitBalances, userCaseLoads] = await Promise.all([ this.prisonApiClient.getAccountBalances(bookingId), this.prisonApiClient.getAdjudications(bookingId), this.prisonApiClient.getVisitSummary(bookingId), this.prisonApiClient.getVisitBalances(prisonerNumber), + this.prisonApiClient.getUserCaseLoads(), ]) let privilegedVisitsDescription = '' @@ -257,24 +266,28 @@ export default class OverviewPageService { linkHref: '#', } - return [ - { - data: moneySummaryData, - classes: 'govuk-grid-row card-body', - }, - { - data: adjudicationsSummaryData, - classes: 'govuk-grid-row card-body', - }, - { - data: visitsSummaryData, - classes: 'govuk-grid-row card-body', - }, - ] + const summaryData = [] + const belongsToCaseLoad = prisonerBelongsToUsersCaseLoad(prisonId, userCaseLoads) + + if (belongsToCaseLoad) { + summaryData.push({ data: moneySummaryData, classes: 'govuk-grid-row card-body' }) + } + + if (belongsToCaseLoad || userHasRoles(['POM_USER', 'RECEPTION_USER'], userRoles)) { + summaryData.push({ data: adjudicationsSummaryData, classes: 'govuk-grid-row card-body' }) + } + + if (belongsToCaseLoad) { + summaryData.push({ data: visitsSummaryData, classes: 'govuk-grid-row card-body' }) + } + + return summaryData } - private async getMiniSummaryGroupB(bookingId: number): Promise { + private async getMiniSummaryGroupB(prisonerData: Prisoner): Promise { + const { bookingId, prisonId } = prisonerData const assessments = await this.prisonApiClient.getAssessments(bookingId) + const userCaseLoads = await this.prisonApiClient.getUserCaseLoads() const incentiveReviews: IncentiveReviews = await this.incentivesApiClient.getReviews(bookingId) @@ -303,13 +316,20 @@ export default class OverviewPageService { const csra: Assessment = assessments?.find((assessment: Assessment) => assessment.assessmentCode === AssessmentCode.csra) || null + const belongsToCaseLoad = prisonerBelongsToUsersCaseLoad(prisonId, userCaseLoads) + const categorySummaryData: MiniSummaryData = { bottomLabel: 'Category', bottomContentLine1: category ? category.classificationCode : 'Not entered', bottomContentLine3: category ? `Next review: ${formatDate(category.nextReviewDate, 'short')}` : '', bottomClass: 'small', - linkLabel: 'Manage category', - linkHref: '#', + linkLabel: undefined, + linkHref: undefined, + } + + if (belongsToCaseLoad) { + categorySummaryData.linkLabel = 'Manage category' + categorySummaryData.linkHref = '#' } const incentiveSummaryData: MiniSummaryData = { @@ -330,24 +350,26 @@ export default class OverviewPageService { bottomContentLine1: csra ? csra.classification : 'Not entered', bottomContentLine3: csra ? `Last review: ${formatDate(csra.assessmentDate, 'short')}` : '', bottomClass: 'small', - linkLabel: 'CSRA history', - linkHref: '#', + linkLabel: undefined, + linkHref: undefined, } - return [ - { - data: categorySummaryData, - classes: 'govuk-grid-row card-body', - }, - { - data: incentiveSummaryData, - classes: 'govuk-grid-row card-body', - }, - { - data: csraSummaryData, - classes: 'govuk-grid-row card-body', - }, - ] + if (belongsToCaseLoad) { + csraSummaryData.linkLabel = 'CSRA history' + csraSummaryData.linkHref = '#' + } + + const summaryData = [] + + summaryData.push({ data: categorySummaryData, classes: 'govuk-grid-row card-body' }) + + if (belongsToCaseLoad) { + summaryData.push({ data: incentiveSummaryData, classes: 'govuk-grid-row card-body' }) + } + + summaryData.push({ data: csraSummaryData, classes: 'govuk-grid-row card-body' }) + + return summaryData } private async getSchedule(bookingId: number): Promise { diff --git a/server/utils/utils.test.ts b/server/utils/utils.test.ts index 2eefcce0f..b4d6a525f 100644 --- a/server/utils/utils.test.ts +++ b/server/utils/utils.test.ts @@ -305,6 +305,8 @@ describe('findError', () => { { roles: ['GLOBAL_SEARCH'], userRoles: [], result: false }, { roles: [], userRoles: ['GLOBAL_SEARCH'], result: false }, { roles: ['GLOBAL_SEARCH', 'SOME_ROLE'], userRoles: ['SOME_ROLE'], result: true }, + { roles: ['GLOBAL_SEARCH'], userRoles: ['ROLE_GLOBAL_SEARCH'], result: true }, + { roles: ['ROLE_GLOBAL_SEARCH'], userRoles: ['GLOBAL_SEARCH'], result: true }, ])('Should return the correct result when checking user roles', ({ roles, userRoles, result }) => { expect(userHasRoles(roles, userRoles)).toEqual(result) }) diff --git a/server/utils/utils.ts b/server/utils/utils.ts index 908fdc5e9..b5921bdea 100644 --- a/server/utils/utils.ts +++ b/server/utils/utils.ts @@ -329,6 +329,7 @@ export const findError = (errors: HmppsError[], formFieldId: string) => { * @param userCaseLoads */ export const prisonerBelongsToUsersCaseLoad = (prisonerAgencyId: string, userCaseLoads: CaseLoad[]): boolean => { + console.log(prisonerAgencyId, userCaseLoads) return userCaseLoads.some(caseLoad => caseLoad.caseLoadId === prisonerAgencyId) } @@ -340,5 +341,6 @@ export const prisonerBelongsToUsersCaseLoad = (prisonerAgencyId: string, userCas */ export const userHasRoles = (rolesToCheck: string[], userRoles: string[]): boolean => { - return rolesToCheck.some(role => userRoles.includes(role)) + const normaliseRoleText = (role: string): string => role.replace(/ROLE_/, '') + return rolesToCheck.map(normaliseRoleText).some(role => userRoles.map(normaliseRoleText).includes(role)) } diff --git a/server/views/pages/overviewPage.njk b/server/views/pages/overviewPage.njk index fe07e141c..7b0404301 100644 --- a/server/views/pages/overviewPage.njk +++ b/server/views/pages/overviewPage.njk @@ -1,4 +1,5 @@ {% extends "./index.njk" %} +{% from "../macros/conditionallyShow.njk" import conditionallyShow %} {% block body %}
@@ -11,7 +12,9 @@ {% include "../partials/overviewPage/mainBody.njk" %}
- {% include "../partials/overviewPage/sideBar.njk" %} + {%- call conditionallyShow({condition: prisonerBelongsToUsersCaseLoad(prisonId, user.caseLoads), id: 'overview-side-bar'}) -%} + {% include "../partials/overviewPage/sideBar.njk" %} + {%- endcall -%}
{% endblock %} diff --git a/server/views/partials/overviewPage/mainBody.njk b/server/views/partials/overviewPage/mainBody.njk index 551af2cfc..49eab5dc5 100644 --- a/server/views/partials/overviewPage/mainBody.njk +++ b/server/views/partials/overviewPage/mainBody.njk @@ -28,11 +28,15 @@
- {% include "./schedule/schedule.njk" %} + {%- call conditionallyShow({condition: prisonerBelongsToUsersCaseLoad(prisonId, user.caseLoads), id: 'overview-schedule'}) -%} + {% include "./schedule/schedule.njk" %} + {%- endcall -%}
- {% include "./nonAssociations/nonAssociations.njk" %} + {%- call conditionallyShow({condition: prisonerBelongsToUsersCaseLoad(prisonId, user.caseLoads), id: 'overview-non-associations'}) -%} + {% include "./nonAssociations/nonAssociations.njk" %} + {%- endcall -%}