Skip to content

Commit

Permalink
CDPS-710 add spurs and landings to establishment-roll page
Browse files Browse the repository at this point in the history
  • Loading branch information
whitfield-mj committed May 2, 2024
1 parent 967afbf commit 5027571
Show file tree
Hide file tree
Showing 20 changed files with 521 additions and 74 deletions.
49 changes: 49 additions & 0 deletions assets/js/establishment-roll.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
const landingRows = document.querySelectorAll('.establishment-roll__table__landing-row')
const spurRows = document.querySelectorAll('.establishment-roll__table__spur-row')
const wingRows = document.querySelectorAll('.establishment-roll__table__wing-row')
const totalsRow = document.querySelector('#roll-table-totals-row')

function init() {
;[...landingRows, ...spurRows].forEach(row => {
row.setAttribute('hidden', 'hidden')
})

wingRows.forEach((wingRow, index) => {
const wingId = wingRow.getAttribute('id')
const wingNameCell = wingRow.getElementsByTagName('td')[0]
const wingNameText = wingNameCell.innerText
const childRows = document.querySelectorAll('[data-wing-id="' + wingId + '"]')
const childrenIds = [...childRows].map(row => row.getAttribute('id'))

const wingLink = document.createElement('a')
wingLink.setAttribute('href', '#')
wingLink.setAttribute('class', 'govuk-details__summary govuk-link--no-visited-state')
wingLink.setAttribute('aria-controls', childrenIds.join(' '))
wingLink.innerHTML = wingNameText

wingLink.addEventListener('click', function (event) {
event.preventDefault()
const nextRow = wingRows[index + 1] ? wingRows[index + 1] : totalsRow

childRows.forEach(row => {
const isOpen = !row.getAttribute('hidden')

if (isOpen) {
row.setAttribute('hidden', 'hidden')
wingLink.setAttribute('aria-expanded', 'false')
wingRow.classList.remove('open')
nextRow.classList.remove('next-wing-to-open')
} else {
row.removeAttribute('hidden')
wingLink.setAttribute('aria-expanded', 'true')
wingRow.classList.add('open')
nextRow.classList.add('next-wing-to-open')
}
})
})

wingNameCell.replaceChildren(wingLink)
})
}

init()
76 changes: 76 additions & 0 deletions assets/scss/pages/_establishment-roll.scss
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,88 @@
}

&__table {
border-collapse: separate;
tbody {
tr:last-child {
* {
border-bottom: none;
}
}
}

&__wing-row {
td {
padding: 13px 51px 7px 0;
}

td:first-of-type {
a[aria-expanded='true']:before {
display: block;
width: 0;
height: 0;
-webkit-clip-path: polygon(0 0, 50% 100%, 100% 0);
clip-path: polygon(0 0, 50% 100%, 100% 0);
border-color: transparent;
border-style: solid;
border-width: 12.124px 7px 0;
border-top-color: inherit;
}
}
&.open {
td {
border-bottom: none;
}
}


}

&__landing-row {
font-size: 16px;

td:first-of-type {
display: block;
margin-left: 46px;
border-collapse: separate;

a {
color: govuk-colour('blue');
}
}

&.last-in-group {
td {
border-bottom: none;
margin-bottom: 10px;
}
}

}

&__spur-row {
font-size: 16px;

td:first-of-type {
display: block;
margin-left: 30px;
border-collapse: separate;
font-weight: bold;
padding-left: 15px;
font-size: 19px;
padding-top: 8px;
}

td {
background-color: govuk-colour('light-grey');
border-bottom: none;
padding-top: 10px;
}
}

tr.next-wing-to-open {
td {
border-top: 1px solid govuk-colour('mid-grey');
}
}
}
}
65 changes: 46 additions & 19 deletions integration_tests/e2e/establishmentRoll.cy.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import Page from '../pages/page'
import EstablishmentRollPage from '../pages/EstablishmentRoll'
import { Role } from '../../server/enums/role'
import { assignedRollCountWithSpursMock } from '../../server/mocks/rollCountMock'

context('Establishment Roll Page', () => {
beforeEach(() => {
Expand All @@ -11,7 +12,7 @@ context('Establishment Roll Page', () => {
{ caseloadFunction: '', caseLoadId: 'LEI', currentlyActive: true, description: 'Leeds (HMP)', type: '' },
],
})
cy.task('stubRollCount')
cy.task('stubRollCount', { payload: assignedRollCountWithSpursMock, query: '?wingOnly=false' })
cy.task('stubRollCountUnassigned')
cy.task('stubMovements')
cy.task('stubEnrouteRollCount')
Expand All @@ -28,38 +29,64 @@ context('Establishment Roll Page', () => {
context('Outage Banner', () => {
it('should display todays stats', () => {
const page = Page.verifyOnPage(EstablishmentRollPage)
page.todaysStats().unlockRoll().should('contain.text', '1015')
page.todaysStats().currentPopulation().should('contain.text', '1023')
page.todaysStats().unlockRoll().should('contain.text', '1815')
page.todaysStats().currentPopulation().should('contain.text', '1823')
page.todaysStats().arrivedToday().should('contain.text', '17')
page.todaysStats().inReception().should('contain.text', '23')
page.todaysStats().stillToArrive().should('contain.text', '1')
page.todaysStats().outToday().should('contain.text', '9')
page.todaysStats().noCellAllocated().should('contain.text', '31')
})

it('should display a table row for each assignedRollCount', () => {
it('should display a table row for each wing level assignedRollCount', () => {
const page = Page.verifyOnPage(EstablishmentRollPage)
page.assignedRollCountFirstRow().should('have.length', 6)
page.assignedRollCountRows().should('have.length', 6)

page.assignedRollCountFirstRow().first().find('td').eq(0).should('contain.text', 'A')
page.assignedRollCountFirstRow().first().find('td').eq(1).should('contain.text', '76')
page.assignedRollCountFirstRow().first().find('td').eq(2).should('contain.text', '900')
page.assignedRollCountFirstRow().first().find('td').eq(3).should('contain.text', '5')
page.assignedRollCountFirstRow().first().find('td').eq(4).should('contain.text', '60')
page.assignedRollCountFirstRow().first().find('td').eq(5).should('contain.text', '-16')
page.assignedRollCountFirstRow().first().find('td').eq(6).should('contain.text', '0')
page.assignedRollCountRows().first().find('td').eq(0).should('contain.text', 'A')
page.assignedRollCountRows().first().find('td').eq(1).should('contain.text', '76')
page.assignedRollCountRows().first().find('td').eq(2).should('contain.text', '900')
page.assignedRollCountRows().first().find('td').eq(3).should('contain.text', '5')
page.assignedRollCountRows().first().find('td').eq(4).should('contain.text', '60')
page.assignedRollCountRows().first().find('td').eq(5).should('contain.text', '-16')
page.assignedRollCountRows().first().find('td').eq(6).should('contain.text', '0')
})

it('should display a table row for totals', () => {
const page = Page.verifyOnPage(EstablishmentRollPage)

page.assignedRollCountFirstRow().last().find('td').eq(0).should('contain.text', 'Totals')
page.assignedRollCountFirstRow().last().find('td').eq(1).should('contain.text', '332')
page.assignedRollCountFirstRow().last().find('td').eq(2).should('contain.text', '1000')
page.assignedRollCountFirstRow().last().find('td').eq(3).should('contain.text', '5')
page.assignedRollCountFirstRow().last().find('td').eq(4).should('contain.text', '312')
page.assignedRollCountFirstRow().last().find('td').eq(5).should('contain.text', '-20')
page.assignedRollCountFirstRow().last().find('td').eq(6).should('contain.text', '0')
page.assignedRollCountRows().last().find('td').eq(0).should('contain.text', 'Totals')
page.assignedRollCountRows().last().find('td').eq(1).should('contain.text', '152')
page.assignedRollCountRows().last().find('td').eq(2).should('contain.text', '1800')
page.assignedRollCountRows().last().find('td').eq(3).should('contain.text', '10')
page.assignedRollCountRows().last().find('td').eq(4).should('contain.text', '120')
page.assignedRollCountRows().last().find('td').eq(5).should('contain.text', '-32')
page.assignedRollCountRows().last().find('td').eq(6).should('contain.text', '0')
})

it('should reveal spurs and landings when click on link', () => {
const page = Page.verifyOnPage(EstablishmentRollPage)

page.assignedRollCountRows().eq(0).find('td').eq(0).should('contain.text', 'A').should('be.visible')
page.assignedRollCountRows().eq(1).find('td').eq(0).should('contain.text', 'Spur A1').should('not.be.visible')
page.assignedRollCountRows().eq(2).find('td').eq(0).should('contain.text', 'Landing A1X').should('not.be.visible')
page.assignedRollCountRows().eq(3).find('td').eq(0).should('contain.text', 'B').should('be.visible')
page.assignedRollCountRows().eq(4).find('td').eq(0).should('contain.text', 'LANDING BY').should('not.be.visible')

const wing1Reveal = page.assignedRollCountRows().eq(0).find('td').eq(0).find('a')
wing1Reveal.click()
page.assignedRollCountRows().eq(1).find('td').eq(0).should('be.visible')
page.assignedRollCountRows().eq(2).find('td').eq(0).should('be.visible')

wing1Reveal.click()
page.assignedRollCountRows().eq(1).find('td').eq(0).should('not.be.visible')
page.assignedRollCountRows().eq(2).find('td').eq(0).should('not.be.visible')

const wing2Reveal = page.assignedRollCountRows().eq(3).find('td').eq(0).find('a')
wing2Reveal.click()
page.assignedRollCountRows().eq(4).find('td').eq(0).should('be.visible')

wing2Reveal.click()
page.assignedRollCountRows().eq(4).find('td').eq(0).should('not.be.visible')
})
})
})
2 changes: 1 addition & 1 deletion integration_tests/e2e/homepage.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ context('Homepage - no active caseload', () => {
{ caseloadFunction: '', caseLoadId: 'MOR', currentlyActive: false, description: 'Moorland', type: '' },
],
})
cy.task('stubRollCount', 'MOR')
cy.task('stubRollCount', { prisonCode: 'MOR' })
cy.task('stubRollCountUnassigned', 'MOR')
cy.task('stubMovements', 'MOR')
cy.task('stubWhatsNewPosts')
Expand Down
6 changes: 3 additions & 3 deletions integration_tests/mockApis/prison.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,18 +39,18 @@ export default {
})
},

stubRollCount: (prisonCode = 'LEI') => {
stubRollCount: ({ prisonCode = 'LEI', payload = assignedRollCountMock, query = '' } = {}) => {
return stubFor({
request: {
method: 'GET',
url: `/prison/api/movements/rollcount/${prisonCode}`,
url: `/prison/api/movements/rollcount/${prisonCode}${query}`,
},
response: {
status: 200,
headers: {
'Content-Type': 'application/json;charset=UTF-8',
},
jsonBody: assignedRollCountMock,
jsonBody: payload,
},
})
},
Expand Down
2 changes: 1 addition & 1 deletion integration_tests/pages/EstablishmentRoll.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,5 @@ export default class EstablishmentRollPage extends Page {
noCellAllocated: (): PageElement => cy.get('[data-qa=no-cell-allocated]'),
})

assignedRollCountFirstRow = (): PageElement => cy.get('table.establishment-roll__table tbody tr')
assignedRollCountRows = (): PageElement => cy.get('table.establishment-roll__table tbody tr')
}
2 changes: 1 addition & 1 deletion server/data/interfaces/prisonApiClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { OffenderCell } from './offenderCell'
export interface PrisonApiClient {
getUserCaseLoads(): Promise<CaseLoad[]>
getUserLocations(): Promise<Location[]>
getRollCount(options: { prisonId: string; unassigned?: boolean }): Promise<BlockRollCount[]>
getRollCount(prisonId: string, options?: { unassigned?: boolean; wingOnly?: boolean }): Promise<BlockRollCount[]>
getEnrouteRollCount(prisonId: string): Promise<number>
getLocationsForPrison(prisonId: string): Promise<Location[]>
getAttributesForLocation(locationId: number): Promise<OffenderCell>
Expand Down
8 changes: 6 additions & 2 deletions server/data/prisonApiClient.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import * as querystring from 'querystring'
import RestClient from './restClient'
import { PrisonApiClient } from './interfaces/prisonApiClient'
import { CaseLoad } from './interfaces/caseLoad'
Expand Down Expand Up @@ -26,10 +27,13 @@ export default class PrisonApiRestClient implements PrisonApiClient {
return this.get<Location[]>({ path: '/api/users/me/locations' })
}

getRollCount({ prisonId, unassigned }: { prisonId: string; unassigned?: boolean }): Promise<BlockRollCount[]> {
getRollCount(
prisonId: string,
queryOptions: { unassigned?: boolean; wingOnly?: boolean } = {},
): Promise<BlockRollCount[]> {
return this.get<BlockRollCount[]>({
path: `/api/movements/rollcount/${prisonId}`,
query: unassigned ? 'unassigned=true' : '',
query: querystring.stringify(queryOptions),
})
}

Expand Down
79 changes: 79 additions & 0 deletions server/mocks/rollCountMock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,3 +119,82 @@ export const unassignedRollCountMock: BlockRollCount[] = [
outOfOrder: 0,
},
]

export const assignedRollCountWithSpursMock: BlockRollCount[] = [
{
currentlyInCell: 900,
outOfLivingUnits: 0,
livingUnitId: 1,
fullLocationPath: 'CKI-A',
locationCode: 'A',
livingUnitDesc: 'A',
bedsInUse: 76,
currentlyOut: 5,
operationalCapacity: 60,
netVacancies: -16,
maximumCapacity: 97,
availablePhysical: 21,
outOfOrder: 0,
},
{
currentlyInCell: 900,
outOfLivingUnits: 0,
livingUnitId: 2,
parentLocationId: 1,
fullLocationPath: 'CKI-A-1',
locationCode: 'A1',
livingUnitDesc: 'Spur A1',
bedsInUse: 76,
currentlyOut: 5,
operationalCapacity: 60,
netVacancies: -16,
maximumCapacity: 97,
availablePhysical: 21,
outOfOrder: 0,
},
{
currentlyInCell: 900,
outOfLivingUnits: 0,
livingUnitId: 3,
parentLocationId: 2,
fullLocationPath: 'CKI-A-1-x',
locationCode: 'A1X',
livingUnitDesc: 'Landing A1X',
bedsInUse: 76,
currentlyOut: 5,
operationalCapacity: 60,
netVacancies: -16,
maximumCapacity: 97,
availablePhysical: 21,
outOfOrder: 0,
},
{
currentlyInCell: 900,
outOfLivingUnits: 0,
livingUnitId: 4,
fullLocationPath: 'CKI-B',
locationCode: 'B',
livingUnitDesc: 'B',
bedsInUse: 76,
currentlyOut: 5,
operationalCapacity: 60,
netVacancies: -16,
maximumCapacity: 97,
availablePhysical: 21,
outOfOrder: 0,
},
{
currentlyInCell: 900,
outOfLivingUnits: 0,
livingUnitId: 5,
parentLocationId: 4,
fullLocationPath: 'CKI-Y',
locationCode: 'BY',
livingUnitDesc: 'LANDING BY',
bedsInUse: 76,
currentlyOut: 5,
maximumCapacity: 97,
availablePhysical: 21,
outOfOrder: 0,
},
]
Loading

0 comments on commit 5027571

Please sign in to comment.