Skip to content

Commit

Permalink
RA-249: create confirm details njk template (#18)
Browse files Browse the repository at this point in the history
* create confirm details njk template

* fix default session value

* add session helper module

* remove extra space
  • Loading branch information
madebyzak authored Feb 6, 2025
1 parent c11e0d6 commit 23b45b3
Show file tree
Hide file tree
Showing 10 changed files with 231 additions and 19 deletions.
12 changes: 0 additions & 12 deletions server/@types/express/express-session.d.ts

This file was deleted.

20 changes: 19 additions & 1 deletion server/@types/express/index.d.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,28 @@
import { HmppsUser } from '../../interfaces/hmppsUser'

export declare module 'express-session' {
// Declare that the session will potentially contain these additional fields
interface SessionData {
returnTo: string
nowInMinutes: number
applicationData?: ApplicationData
}

interface ApplicationData {
type?: ApplicationType
prisonerName?: string
date?: Date
additionalData?: AdditionalApplicationData
}

interface ApplicationType {
value: string
name: string
}

type AdditionalApplicationData = SwapVOsForPinCreditDetails

interface SwapVOsForPinCreditDetails {
swapVOsToPinCreditDetails: string
}
}

Expand Down
5 changes: 2 additions & 3 deletions server/routes/applications/applicationTypeRoutes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Request, Response, Router } from 'express'
import { APPLICATION_TYPES } from '../../constants/applicationTypes'
import asyncMiddleware from '../../middleware/asyncMiddleware'
import AuditService, { Page } from '../../services/auditService'
import { updateSessionData } from '../../utils/session'

export default function applicationTypeRoutes({ auditService }: { auditService: AuditService }): Router {
const router = Router()
Expand Down Expand Up @@ -36,9 +37,7 @@ export default function applicationTypeRoutes({ auditService }: { auditService:
return
}

req.session.applicationData = {
type: selectedAppType,
}
updateSessionData(req, { type: selectedAppType })

res.redirect(`/log/prisoner-details`)
}),
Expand Down
11 changes: 11 additions & 0 deletions server/routes/applications/prisonerDetailsRoutes.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Request, Response, Router } from 'express'
import asyncMiddleware from '../../middleware/asyncMiddleware'
import AuditService, { Page } from '../../services/auditService'
import { updateSessionData } from '../../utils/session'

export default function prisonerDetailsRoutes({ auditService }: { auditService: AuditService }): Router {
const router = Router()
Expand All @@ -27,6 +28,16 @@ export default function prisonerDetailsRoutes({ auditService }: { auditService:
router.post(
'/log/prisoner-details',
asyncMiddleware(async (req: Request, res: Response) => {
if (!req.session.applicationData) {
res.status(400).send('Application data is missing')
return
}

updateSessionData(req, {
prisonerName: req.body.prisonerName,
date: req.body.date,
})

res.redirect(`/log/swap-vos-pin-credit-details`)
}),
)
Expand Down
11 changes: 10 additions & 1 deletion server/routes/applications/swapVosPinCreditDetailsRoutes.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { Request, Response, Router } from 'express'
import { APPLICATION_TYPES } from '../../constants/applicationTypes'
import asyncMiddleware from '../../middleware/asyncMiddleware'
import AuditService, { Page } from '../../services/auditService'
import { APPLICATION_TYPES } from '../../constants/applicationTypes'
import { updateSessionData } from '../../utils/session'

export default function swapVosPinCreditDetailsRoutes({ auditService }: { auditService: AuditService }): Router {
const router = Router()
Expand Down Expand Up @@ -30,6 +31,13 @@ export default function swapVosPinCreditDetailsRoutes({ auditService }: { auditS
router.post(
'/log/swap-vos-pin-credit-details',
asyncMiddleware(async (req: Request, res: Response) => {
updateSessionData(req, {
additionalData: {
...req.session.applicationData?.additionalData,
swapVOsToPinCreditDetails: req.body.swapVosPinCreditDetails,
},
})

res.redirect(`/log/swap-vos-pin-credit-details/confirm`)
}),
)
Expand All @@ -51,6 +59,7 @@ export default function swapVosPinCreditDetailsRoutes({ auditService }: { auditS
return res.render('pages/log/confirm-swap-vos-pin-credit-details', {
title: 'Check details',
appTypeTitle: 'Swap VOs for PIN credit',
session: req.session,
})
}),
)
Expand Down
71 changes: 71 additions & 0 deletions server/utils/session.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import { Request } from 'express'
import { SessionData } from 'express-session'
import { updateSessionData } from './session'

describe(updateSessionData.name, () => {
let req: Request

beforeEach(() => {
req = {
session: {} as SessionData,
} as Request
})

it('should initialize applicationData if it does not exist', () => {
updateSessionData(req, { prisonerName: 'John Doe' })

expect(req.session.applicationData).toEqual({
prisonerName: 'John Doe',
})
})

it('should update an existing field without removing other fields', () => {
req.session.applicationData = {
type: { name: 'Swap VOs', value: 'swap-vos' },
prisonerName: 'Jane Doe',
}

updateSessionData(req, { prisonerName: 'John Doe' })

expect(req.session.applicationData).toEqual({
type: { name: 'Swap VOs', value: 'swap-vos' },
prisonerName: 'John Doe',
})
})

it('should add new fields while keeping existing ones', () => {
req.session.applicationData = {
type: { name: 'Swap VOs', value: 'swap-vos' },
}

updateSessionData(req, { prisonerName: 'John Doe', date: new Date('2024-02-05') })

expect(req.session.applicationData).toEqual({
type: { name: 'Swap VOs', value: 'swap-vos' },
prisonerName: 'John Doe',
date: new Date('2024-02-05'),
})
})

it('should not overwrite nested objects but merge updates', () => {
req.session.applicationData = {
type: { name: 'Swap VOs', value: 'swap-vos' },
additionalData: { swapVOsToPinCreditDetails: 'Old value' },
}

updateSessionData(req, {
additionalData: { swapVOsToPinCreditDetails: 'New value' },
})

expect(req.session.applicationData).toEqual({
type: { name: 'Swap VOs', value: 'swap-vos' },
additionalData: { swapVOsToPinCreditDetails: 'New value' },
})
})

it('should handle undefined session gracefully', () => {
req.session = undefined

expect(() => updateSessionData(req, { prisonerName: 'John Doe' })).toThrow()
})
})
14 changes: 14 additions & 0 deletions server/utils/session.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { Request } from 'express'
import { SessionData } from 'express-session'

// eslint-disable-next-line import/prefer-default-export
export const updateSessionData = (req: Request, updates: Partial<SessionData['applicationData']>) => {
if (!req.session.applicationData) {
req.session.applicationData = {} as SessionData['applicationData']
}

req.session.applicationData = {
...req.session.applicationData,
...updates,
}
}
102 changes: 101 additions & 1 deletion server/views/pages/log/confirm-swap-vos-pin-credit-details.njk
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
{% from "govuk/components/back-link/macro.njk" import govukBackLink %}
{% from "govuk/components/button/macro.njk" import govukButton %}
{% from "govuk/components/summary-list/macro.njk" import govukSummaryList %}

{% extends "../../partials/layout.njk" %}

Expand All @@ -9,7 +11,105 @@
<div class="govuk-body govuk-width-container">
{{ govukBackLink({
text: "Back",
href: "/log/prisoner-details"
href: "/log/swap-vos-pin-credit-details"
}) }}

<span class="govuk-caption-xl">{{ appTypeTitle }}</span>
<h1 class="govuk-heading-xl govuk-!-margin-top-0">Check details</h1>

{{ govukSummaryList({
classes: "govuk-!-margin-bottom-9",
rows: [
{
key: {
text: "Application Type"
},
value: {
text: "Swap VOs for pin credit"
},
actions: {
items: [
{
href: "#",
text: "Change",
visuallyHiddenText: "application type"
}
]
}
}
]
}) }}

<h2 class="govuk-heading-m">Application details</h2>

{{ govukSummaryList({
classes: "govuk-!-margin-bottom-9",
rows: [
{
key: {
text: "Prisoner"
},
value: {
text: session.applicationData.prisonerName
},
actions: {
items: [
{
href: "#",
text: "Change",
visuallyHiddenText: "prisoner"
}
]
}
},
{
key: {
text: "Submitted on"
},
value: {
text: session.applicationData.date
},
actions: {
items: [
{
href: "#",
text: "Change",
visuallyHiddenText: "submitted on"
}
]
}
}
]
}) }}

<h2 class="govuk-heading-m">VOs to swap</h2>

{{ govukSummaryList({
classes: "govuk-!-margin-bottom-9",
rows: [
{
key: {
text: "Details"
},
value: {
text: session.applicationData.additionalData.swapVOsToPinCreditDetails
},
actions: {
items: [
{
href: "#",
text: "Change",
visuallyHiddenText: "details"
}
]
}
}
]
}) }}

{{ govukButton({
text: "Continue",
classes: "govuk-button--primary"
}) }}
</div>
{% endblock %}
2 changes: 2 additions & 0 deletions server/views/pages/log/prisoner-details.njk
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@
classes: "govuk-!-margin-top-0"
}) }}

<input type="hidden" id="prisonerName" name="prisonerName" value="Patel, Taj">

{{ mojDatePicker({
id: "date",
name: "date",
Expand Down
2 changes: 1 addition & 1 deletion server/views/pages/log/swap-vos-pin-credit-details.njk
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
<input type="hidden" name="_csrf" value="{{ csrfToken }}" />

{{ govukCharacterCount({
name: "swap-vos-pin-credit-details",
name: "swapVosPinCreditDetails",
id: "swap-vos-pin-credit-details",
maxlength: 1000,
threshold: 75,
Expand Down

0 comments on commit 23b45b3

Please sign in to comment.