Skip to content

Commit 9bce9f3

Browse files
committed
Create all appointment models in advance for clinic bookings
This commit is the start of work to support iteration through multiple children (or appointments) in the parents' clinic booking journey. It will allow us to map out the full wizard journey but still needs to be supported by dynamic generation of the appointment journey pages for each of the appointments we create (as well as dynamic generation of the health question pages for each of those appointments).
1 parent c76abbc commit 9bce9f3

4 files changed

Lines changed: 58 additions & 63 deletions

File tree

app/controllers/book-into-a-clinic.js

Lines changed: 45 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -2,27 +2,26 @@ import { fakerEN_GB as faker } from '@faker-js/faker'
22
import wizard from '@x-govuk/govuk-prototype-wizard'
33
import _ from 'lodash'
44

5-
import allProgrammesData from '../datasets/programmes.js'
65
import { ParentalRelationship, SessionPresets } from '../enums.js'
7-
import { ClinicAppointment, ClinicBooking, Programme } from '../models.js'
6+
import { ClinicAppointment, ClinicBooking } from '../models.js'
87
import { kebabToCamelCase } from '../utils/string.js'
98

109
export const bookIntoClinicController = {
11-
// Load the preset into locals
10+
/**
11+
* Record the session preset
12+
* @param {*} request
13+
* @param {*} response
14+
* @param {*} next
15+
* @param {*} session_preset_slug
16+
*/
1217
read(request, response, next, session_preset_slug) {
1318
// Record both the session preset (aka "primary programme" to the parent) and the programme types that comprises
1419
const sessionPreset =
1520
SessionPresets.find((preset) => preset.slug === session_preset_slug) ??
1621
SessionPresets[0]
1722
response.locals.sessionPreset = sessionPreset
1823

19-
// Allow us to list the programmes for which the parent's been invited to book an appointment
20-
const programmes = sessionPreset.programmeTypes.map((pt) =>
21-
Programme.findOne(allProgrammesData[pt].id, request.session.data)
22-
)
23-
response.locals.programmes = programmes
24-
25-
// Allow us to offer a phone booking if not wanting online
24+
// Allow us to offer a phone booking if not wanting online (start.njk)
2625
response.locals.bookingPhoneNumber =
2726
request.session.data.teams[0]?.tel ??
2827
faker.helpers.replaceSymbols('01### ######')
@@ -52,11 +51,6 @@ export const bookIntoClinicController = {
5251
const { data } = request.session
5352
const { sessionPreset } = response.locals
5453

55-
// TODO:
56-
// [X] Add a SessionPreset property to the ClinicBooking model, so that we know what type of session the children have been invited to.
57-
// [ ] Update the generators to make sure things are created right
58-
// [ ] Create enough different clinic sessions of the right types to cover the different presets?
59-
6054
// Create a new clinic booking in the wizard context
6155
const booking = ClinicBooking.createInContext(
6256
{
@@ -128,6 +122,9 @@ export const bookIntoClinicController = {
128122
data
129123
)
130124
response.locals.appointment = appointment
125+
response.locals.childNumber =
126+
booking.appointments_ids.indexOf(appointment.uuid) + 1
127+
response.locals.childCount = booking.appointments_ids.length
131128
response.locals.firstName =
132129
appointment.unmatchedFirstName || 'your child'
133130
response.locals.fullName = appointment.fullName || undefined
@@ -172,7 +169,7 @@ export const bookIntoClinicController = {
172169
}
173170
},
174171
[`/${session_preset_slug}/${booking_uuid}/new/${appointment_uuid}/parental-relationship`]:
175-
{}, // allow the *booking* to continue, but stress that someone with responsibility must *attend*
172+
{}, // TODO: allow the *booking* to continue, but stress that someone with responsibility must *attend*
176173
[`/${session_preset_slug}/${booking_uuid}/new/${appointment_uuid}/vaccination-choice`]:
177174
{},
178175
[`/${session_preset_slug}/${booking_uuid}/new/${appointment_uuid}/extra-time`]:
@@ -278,7 +275,7 @@ export const bookIntoClinicController = {
278275
let key
279276
if (view.startsWith('health-question-')) {
280277
key = kebabToCamelCase(view.replace('health-question-', ''))
281-
view = 'health-question' // TODO: reintroduce
278+
view = 'health-question'
282279
}
283280

284281
// Only ask for details if question does not have sub-questions
@@ -299,10 +296,7 @@ export const bookIntoClinicController = {
299296
const { data } = request.session
300297
const { paths } = response.locals
301298

302-
// console.log("data.wizard: " + JSON.stringify(data.wizard, null, 2));
303-
// console.log("request.body: " + JSON.stringify(request.body, null, 2));
304-
305-
// Harvest and store values from forms
299+
// Store values from the posted form
306300
if (request.body.booking) {
307301
ClinicBooking.update(booking_uuid, request.body.booking, data.wizard)
308302
}
@@ -319,26 +313,39 @@ export const bookIntoClinicController = {
319313
_.merge(data.wizard.transaction, request.body.transaction)
320314
}
321315

322-
let redirectUrl = paths.next
323-
324-
// If we've just set the child count, create the appointment to start the sub-journey and
325-
// put its uuid into the routes from this point on
326-
// TODO: but what about iterating to subsequent children? Can't help feeling the whole ask-up-front pattern is flawed.
316+
// If we've just set the child count, create the appointments to start the sub-journey and
317+
// put the first uuid into the routes from this point on
327318
if (request.originalUrl.endsWith('/new/child-count')) {
328-
const booking = new ClinicBooking(
329-
ClinicBooking.findOne(booking_uuid, data.wizard),
330-
data
331-
)
332-
const appointment = ClinicAppointment.createInContext(
333-
{ primary_programme_ids: booking.primaryProgrammeIDs },
334-
data.wizard
335-
)
319+
const booking = ClinicBooking.findOne(booking_uuid, data.wizard)
320+
321+
let desiredCount = Number(data.wizard.transaction.childCount)
322+
desiredCount = isNaN(desiredCount) || desiredCount < 1 ? 1 : desiredCount
323+
const existingCount = booking.appointments_ids.length
324+
325+
const childrenToAdd = Math.max(0, desiredCount - existingCount)
326+
const childrenToRemove = Math.max(0, existingCount - desiredCount)
327+
for (let index = 0; index < childrenToAdd; index++) {
328+
const appointment = ClinicAppointment.createInContext(
329+
{ primary_programme_ids: booking.primaryProgrammeIDs },
330+
data.wizard
331+
)
336332

337-
const bookingUri = booking.bookingUri
338-
redirectUrl = `${request.baseUrl}/${bookingUri}/new/${appointment.appointmentUri}/child`
339-
}
333+
booking.addAppointment(appointment)
334+
}
335+
for (let index = 0; index < childrenToRemove; index++) {
336+
const appointment_uuid = booking.removeLastAppointment()
337+
ClinicAppointment.delete(appointment_uuid, data.wizard)
338+
}
340339

341-
response.redirect(redirectUrl)
340+
// Start the appointment journey for the first child
341+
const firstAppointment = booking.appointments[0]
342+
response.redirect(
343+
`${request.baseUrl}/${booking.bookingUri}/new/${firstAppointment.appointmentUri}/child`
344+
)
345+
} else {
346+
// Continue to the next page in the journey
347+
response.redirect(paths.next)
348+
}
342349
},
343350

344351
/**

app/locales/en.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,7 @@ export const en = {
287287
},
288288
child: {
289289
title: 'What is your child’s name?',
290+
caption: 'Appointment for your %s child',
290291
summary: 'About your child',
291292
description:
292293
'Give the name on your child’s birth certificate. If it’s changed, give the name held by your child’s GP.',

app/models/clinic-booking.js

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,14 +86,23 @@ export class ClinicBooking {
8686
}
8787

8888
/**
89-
* Add a child's appointment to this booking, setting up parent details and relationship in the process
89+
* Add a child's appointment to this booking
9090
*
9191
* @param {ClinicAppointment} appointment - An appointment to make part of this booking
9292
*/
9393
addAppointment(appointment) {
9494
this.appointments_ids.push(appointment.uuid)
9595
}
9696

97+
/**
98+
* Remove the last appointment added to this booking
99+
*
100+
* @returns {string} the uuid of the removed appointment
101+
*/
102+
removeLastAppointment() {
103+
return this.appointments_ids.pop()
104+
}
105+
97106
/**
98107
* Get appointments
99108
*

app/views/book-into-a-clinic/form/child.njk

Lines changed: 2 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44

55
{% block form %}
66
{{ appHeading({
7-
title: title
7+
title: title,
8+
caption: __("clinicBooking.child.caption", childNumber | ordinal) if childCount > 1
89
}) }}
910

1011
{{ __("clinicBooking.child.description") | nhsukMarkdown }}
@@ -20,27 +21,4 @@
2021
hint: { text: __("clinicBooking.child.lastName.hint") },
2122
decorate: "appointment.unmatchedLastName"
2223
}) }}
23-
24-
{#
25-
{{ radios({
26-
fieldset: {
27-
legend: { text: __("clinicBooking.child.hasPreferredName.label") }
28-
},
29-
items: [{
30-
text: __("clinicBooking.child.hasPreferredName.yes"),
31-
conditional: {
32-
html: input({
33-
label: { text: __("clinicBooking.child.preferredFirstName.label") + " (optional)" },
34-
decorate: "clinicBooking.appointments[child_index].preferredFirstName"
35-
}) + input({
36-
label: { text: __("clinicBooking.child.preferredLastName.label") + " (optional)" },
37-
decorate: "clinicBooking.appointments[child_index].preferredLastName"
38-
})
39-
}
40-
}, {
41-
text: __("clinicBooking.child.hasPreferredName.no")
42-
}],
43-
decorate: "child.preferred-name-choice"
44-
}) }}
45-
#}
4624
{% endblock %}

0 commit comments

Comments
 (0)