From 2f45d2bba04e54f9c8cec247bdd40ca6dfc3c54f Mon Sep 17 00:00:00 2001 From: rivalee Date: Mon, 17 Aug 2026 09:43:23 +0100 Subject: [PATCH 01/11] first iteration --- .../appointments/medical-information.js | 31 ++++++++++++++ .../forms/breast-density-factors.njk | 12 ++---- .../pregnancy-and-breastfeeding.html | 40 +++++++++++++++++++ 3 files changed, 75 insertions(+), 8 deletions(-) create mode 100644 app/views/appointments/medical-information/pregnancy-and-breastfeeding.html diff --git a/app/routes/appointments/medical-information.js b/app/routes/appointments/medical-information.js index 11dd646d..143c06b1 100644 --- a/app/routes/appointments/medical-information.js +++ b/app/routes/appointments/medical-information.js @@ -67,6 +67,37 @@ module.exports = (router) => { } ) + // Save pregnancy/breastfeeding from modal form + router.post( + '/clinics/:clinicId/appointments/:appointmentId/medical-information/pregnancy-and-breastfeeding-save', + (req, res) => { + const { clinicId, appointmentId } = req.params + const data = req.session.data + + const postedFactors = req.body?.breastDensityFactors + const factors = ( + Array.isArray(postedFactors) + ? postedFactors + : postedFactors + ? [postedFactors] + : [] + ).filter((factor) => factor && factor !== '_unchecked') + + if (data.appointment?.id !== appointmentId) { + res.status(409).send() + return + } + + const medicalInformation = data.appointment.medicalInformation || {} + medicalInformation.breastDensityFactors = factors + data.appointment.medicalInformation = medicalInformation + + delete data.breastDensityFactors + + res.redirect(modalBreakout(`/clinics/${clinicId}/appointments/${appointmentId}/review-medical-information`)) + } + ) + // Save breast features (includes converting JSON string to structured data) router.post( '/clinics/:clinicId/appointments/:appointmentId/medical-information/record-breast-features/save', diff --git a/app/views/_includes/forms/breast-density-factors.njk b/app/views/_includes/forms/breast-density-factors.njk index a8a211e2..ad9f40ad 100644 --- a/app/views/_includes/forms/breast-density-factors.njk +++ b/app/views/_includes/forms/breast-density-factors.njk @@ -105,15 +105,11 @@ value: { html: hrtInputHtml if allowEdits else hrtSummaryHtml } - }, - { - key: { - text: "Pregnant or breastfeeding" - }, - value: { - html: pregnantOrBreastfeedingInputHtml if allowEdits else pregnantOrBreastfeedingSummaryHtml - } } ] } | removeLastRowBorder ) }} + +

+ {{ appLink({ text: "Pregnancy and breastfeeding", href: contextUrl + "/medical-information/pregnancy-and-breastfeeding" } | openInModal) }} +

diff --git a/app/views/appointments/medical-information/pregnancy-and-breastfeeding.html b/app/views/appointments/medical-information/pregnancy-and-breastfeeding.html new file mode 100644 index 00000000..584735f1 --- /dev/null +++ b/app/views/appointments/medical-information/pregnancy-and-breastfeeding.html @@ -0,0 +1,40 @@ +{# app/views/appointments/medical-information/pregnancy-and-breastfeeding.html #} + +{% extends parentLayout or 'layout-appointment.html' %} + +{% set pageHeading = "Pregnancy and breastfeeding" %} +{% set formAction = "./pregnancy-and-breastfeeding-save" %} + +{% block pageContent %} + + {% set breastDensityFactors = appointment.medicalInformation | getBreastDensityFactors %} + +

{{ pageHeading }}

+ + {{ checkboxes({ + name: "breastDensityFactors", + values: breastDensityFactors.factors, + classes: "nhsuk-checkboxes--small", + fieldset: { + legend: { + text: "Is " + participant.demographicInformation.firstName + " pregnant or breastfeeding?", + classes: "nhsuk-fieldset__legend--s" + } + }, + items: [ + { + value: "pregnant", + text: "Pregnant" + }, + { + value: "breastfeeding", + text: "Breastfeeding" + } + ] + }) }} + + {{ button({ + text: "Save" + }) }} + +{% endblock %} From 7c9d1f6d4b7de6c12fc1ca1e4f52441d0cf54ac1 Mon Sep 17 00:00:00 2001 From: rivalee Date: Mon, 17 Aug 2026 12:31:36 +0100 Subject: [PATCH 02/11] Replace link with button --- app/views/_includes/forms/breast-density-factors.njk | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/app/views/_includes/forms/breast-density-factors.njk b/app/views/_includes/forms/breast-density-factors.njk index ad9f40ad..6439655f 100644 --- a/app/views/_includes/forms/breast-density-factors.njk +++ b/app/views/_includes/forms/breast-density-factors.njk @@ -110,6 +110,11 @@ } | removeLastRowBorder ) }}

- {{ appLink({ text: "Pregnancy and breastfeeding", href: contextUrl + "/medical-information/pregnancy-and-breastfeeding" } | openInModal) }} + {{ button({ + text: "Add pregnancy and breastfeeding", + href: contextUrl + "/medical-information/pregnancy-and-breastfeeding", + variant: "secondary", + small: true + } | openInModal) }}

From 1dfc2319c34e8896284f09f22f27e1be98675b9b Mon Sep 17 00:00:00 2001 From: rivalee Date: Thu, 27 Aug 2026 14:24:05 +0100 Subject: [PATCH 03/11] modify data display on check info page --- app/assets/javascript/main.js | 37 +++++---- app/lib/utils/medical-information.js | 22 ++++-- .../appointments/medical-information.js | 65 +++++++-------- .../forms/breast-density-factors.njk | 79 +++++++++++++++---- .../pregnancy-and-breastfeeding.html | 18 ++++- 5 files changed, 149 insertions(+), 72 deletions(-) diff --git a/app/assets/javascript/main.js b/app/assets/javascript/main.js index bdc7aa2e..9fc8505b 100644 --- a/app/assets/javascript/main.js +++ b/app/assets/javascript/main.js @@ -201,13 +201,13 @@ function setupBreastDensityFactorsAutosave() { return } - const factorsName = 'breastDensityFactors' const hrtName = 'breastDensityFactorsHrt' + const hrtYearStartedName = 'breastDensityFactorsHrtYearStarted' + const hrtYearStoppedName = 'breastDensityFactorsHrtYearStopped' - const checkboxes = container.querySelectorAll(`input[name="${factorsName}"]`) const hrtRadios = container.querySelectorAll(`input[name="${hrtName}"]`) - if (checkboxes.length === 0 && hrtRadios.length === 0) { + if (hrtRadios.length === 0) { return } @@ -223,13 +223,8 @@ function setupBreastDensityFactorsAutosave() { return } - // "No" to HRT is an answer, not a factor - match the count in - // getBreastDensityFactors so the two never disagree - const checkedFactors = container.querySelectorAll( - `input[name="${factorsName}"]:checked` - ).length const hrtYes = container.querySelector(`input[name="${hrtName}"]:checked`)?.value === 'yes' - const count = checkedFactors + (hrtYes ? 1 : 0) + const count = hrtYes ? 1 : 0 if (count === 0) { summary.textContent = 'No breast density factors added' @@ -244,18 +239,24 @@ function setupBreastDensityFactorsAutosave() { // queue - otherwise an earlier response could be the last one to arrive let pendingSave = Promise.resolve() - const saveFactors = () => { + const saveHrt = () => { const formData = new URLSearchParams() - container - .querySelectorAll(`input[name="${factorsName}"]:checked`) - .forEach((checkbox) => formData.append(factorsName, checkbox.value)) - const selectedHrt = container.querySelector(`input[name="${hrtName}"]:checked`) if (selectedHrt) { formData.append(hrtName, selectedHrt.value) } + const yearStartedInput = container.querySelector(`input[name="${hrtYearStartedName}"]`) + if (yearStartedInput) { + formData.append(hrtYearStartedName, yearStartedInput.value) + } + + const yearStoppedInput = container.querySelector(`input[name="${hrtYearStoppedName}"]`) + if (yearStoppedInput) { + formData.append(hrtYearStoppedName, yearStoppedInput.value) + } + updateContentsSummary() pendingSave = pendingSave @@ -279,8 +280,12 @@ function setupBreastDensityFactorsAutosave() { } container - .querySelectorAll(`input[name="${factorsName}"], input[name="${hrtName}"]`) - .forEach((input) => input.addEventListener('change', saveFactors)) + .querySelectorAll(`input[name="${hrtName}"]`) + .forEach((input) => input.addEventListener('change', saveHrt)) + + container + .querySelectorAll(`input[name="${hrtYearStartedName}"], input[name="${hrtYearStoppedName}"]`) + .forEach((input) => input.addEventListener('change', saveHrt)) } // Quick settings modal — press backtick (`) to open settings in a modal overlay. diff --git a/app/lib/utils/medical-information.js b/app/lib/utils/medical-information.js index c7cfead3..4fae3b59 100644 --- a/app/lib/utils/medical-information.js +++ b/app/lib/utils/medical-information.js @@ -464,26 +464,32 @@ const summariseBreastFeatures = (features) => { */ const getBreastDensityFactors = (medicalInformation) => { const rawFactors = medicalInformation?.breastDensityFactors - const factors = Array.isArray(rawFactors) - ? rawFactors.filter(Boolean) + const factors = (Array.isArray(rawFactors) + ? rawFactors : rawFactors ? [rawFactors] : [] + ).filter((f) => f && f !== '_unchecked') const hrt = medicalInformation?.breastDensityFactorsHrt + const hrtYearStarted = medicalInformation?.breastDensityFactorsHrtYearStarted + const hrtYearStopped = medicalInformation?.breastDensityFactorsHrtYearStopped // "Not started HRT" is an answer, but it isn't a density factor - only // count the things that actually affect density const count = (hrt === 'yes' ? 1 : 0) + (factors.includes('pregnant') ? 1 : 0) + - (factors.includes('breastfeeding') ? 1 : 0) + (factors.includes('breastfeeding') ? 1 : 0) + + (factors.includes('stopped-less-than-3-months') ? 1 : 0) const summaries = summariseBreastDensityFactors(medicalInformation) return { factors, hrt, + hrtYearStarted, + hrtYearStopped, count, // Everything worth showing, including a recorded "no" to HRT question - use this // to decide whether to show the row at all, and count for "n added" @@ -507,13 +513,15 @@ const summariseBreastDensityFactors = (medicalInformation) => { : [] const hrt = medicalInformation?.breastDensityFactorsHrt + const hrtYearStarted = medicalInformation?.breastDensityFactorsHrtYearStarted + const hrtYearStopped = medicalInformation?.breastDensityFactorsHrtYearStopped const summaries = [] if (hrt === 'yes') { - summaries.push('Started a course of HRT since last screening appointment') + summaries.push('Currently taking HRT' + (hrtYearStarted ? ` (started: ${hrtYearStarted})` : '')) } else if (hrt === 'no') { - summaries.push('Not started a course of HRT since last screening appointment') + summaries.push('Not currently taking HRT' + (hrtYearStopped ? ` (stopped: ${hrtYearStopped})` : '')) } if (factors.includes('pregnant')) { @@ -524,6 +532,10 @@ const summariseBreastDensityFactors = (medicalInformation) => { summaries.push('Breastfeeding') } + if (factors.includes('stopped-less-than-3-months')) { + summaries.push('Pregnancy or breastfeeding stopped less than 3 months ago') + } + return summaries } diff --git a/app/routes/appointments/medical-information.js b/app/routes/appointments/medical-information.js index 143c06b1..44370294 100644 --- a/app/routes/appointments/medical-information.js +++ b/app/routes/appointments/medical-information.js @@ -29,71 +29,64 @@ module.exports = (router) => { const { appointmentId } = req.params const data = req.session.data - // An unticked checkbox group posts nothing at all, so a missing value - // means "none selected" rather than "unchanged" - const postedFactors = req.body?.breastDensityFactors - const factors = ( - Array.isArray(postedFactors) - ? postedFactors - : postedFactors - ? [postedFactors] - : [] - ).filter((factor) => factor && factor !== '_unchecked') - const postedHrt = req.body?.breastDensityFactorsHrt + const postedHrtYearStarted = req.body?.breastDensityFactorsHrtYearStarted + const postedHrtYearStopped = req.body?.breastDensityFactorsHrtYearStopped - // The appointment context middleware has already made the temp copy, - // so this is only defensive if (data.appointment?.id !== appointmentId) { res.status(409).send() return } const medicalInformation = data.appointment.medicalInformation || {} - medicalInformation.breastDensityFactors = factors if (postedHrt) { medicalInformation.breastDensityFactorsHrt = postedHrt } + if (postedHrtYearStarted !== undefined) { + medicalInformation.breastDensityFactorsHrtYearStarted = postedHrtYearStarted + } + + if (postedHrtYearStopped !== undefined) { + medicalInformation.breastDensityFactorsHrtYearStopped = postedHrtYearStopped + } + data.appointment.medicalInformation = medicalInformation - // These aren't form fields for any other page - don't leave them in - // session data where auto-store-data has put them - delete data.breastDensityFactors delete data.breastDensityFactorsHrt + delete data.breastDensityFactorsHrtYearStarted + delete data.breastDensityFactorsHrtYearStopped res.status(204).send() } ) - // Save pregnancy/breastfeeding from modal form + // Pregnancy/breastfeeding modal form — data is auto-saved by the kit + // via the field name; we just need the modalBreakout redirect. + // Pregnancy/breastfeeding modal — auto-store-data saves the field + // directly to appointment.medicalInformation.breastDensityFactors; + // route only handles the modalBreakout redirect. router.post( '/clinics/:clinicId/appointments/:appointmentId/medical-information/pregnancy-and-breastfeeding-save', (req, res) => { const { clinicId, appointmentId } = req.params - const data = req.session.data + res.redirect(modalBreakout(`/clinics/${clinicId}/appointments/${appointmentId}/review-medical-information`)) + } + ) - const postedFactors = req.body?.breastDensityFactors - const factors = ( - Array.isArray(postedFactors) - ? postedFactors - : postedFactors - ? [postedFactors] - : [] - ).filter((factor) => factor && factor !== '_unchecked') + // Delete pregnancy/breastfeeding + router.get( + '/clinics/:clinicId/appointments/:appointmentId/medical-information/pregnancy-and-breastfeeding-delete', + (req, res) => { + const { clinicId, appointmentId } = req.params + const data = req.session.data - if (data.appointment?.id !== appointmentId) { - res.status(409).send() - return + if (data.appointment?.medicalInformation) { + delete data.appointment.medicalInformation.breastDensityFactors } - const medicalInformation = data.appointment.medicalInformation || {} - medicalInformation.breastDensityFactors = factors - data.appointment.medicalInformation = medicalInformation - - delete data.breastDensityFactors - + req.flash('success', 'Pregnancy and breastfeeding deleted') res.redirect(modalBreakout(`/clinics/${clinicId}/appointments/${appointmentId}/review-medical-information`)) } ) diff --git a/app/views/_includes/forms/breast-density-factors.njk b/app/views/_includes/forms/breast-density-factors.njk index 6439655f..ac128c97 100644 --- a/app/views/_includes/forms/breast-density-factors.njk +++ b/app/views/_includes/forms/breast-density-factors.njk @@ -19,28 +19,55 @@ {% set participantName = participant | getFullName %} -{% set hrtQuestion = "Has " + participant.demographicInformation.firstName + " started a course of HRT since their last screening appointment?" %} +{% set hrtQuestion = "Is " + participant.demographicInformation.firstName + " currently taking HRT?" %} {% set pregnantOrBreastfeedingQuestion = "Is " + participant.demographicInformation.firstName + " pregnant or breastfeeding?" %} +{% set hrtYesConditionalHtml %} +
+ + +
+{% endset %} + +{% set hrtNoConditionalHtml %} +
+ + +
+{% endset %} + {% set hrtInputHtml %} {{ radios({ name: "breastDensityFactorsHrt", value: breastDensityFactors.hrt, - classes: "nhsuk-radios--inline nhsuk-radios--small", + classes: "nhsuk-radios--small", fieldset: { legend: { text: hrtQuestion, classes: "nhsuk-fieldset__legend--s" } }, + hint: { + text: "(optional)" + }, items: [ { value: "yes", - text: "Yes, has started a course of HRT" + text: "Yes", + conditional: { + html: hrtYesConditionalHtml + } }, { value: "no", - text: "No, has not started a course of HRT" + text: "No", + conditional: { + html: hrtNoConditionalHtml + } } ] }) }} @@ -72,9 +99,9 @@ {% set hrtSummaryHtml %} {% if breastDensityFactors.hrt == "yes" %} -

Started a course of HRT since last screening appointment

+

Currently taking HRT{% if breastDensityFactors.hrtYearStarted %} (started: {{ breastDensityFactors.hrtYearStarted }}){% endif %}

{% elseif breastDensityFactors.hrt == "no" %} -

Not started a course of HRT since last screening appointment

+

Not currently taking HRT{% if breastDensityFactors.hrtYearStopped %} (stopped: {{ breastDensityFactors.hrtYearStopped }}){% endif %}

{% else %}

Not answered

{% endif %} @@ -89,6 +116,9 @@ {% if breastDensityFactors.factors | includes("breastfeeding") %}
  • Breastfeeding
  • {% endif %} + {% if breastDensityFactors.factors | includes("stopped-less-than-3-months") %} +
  • Pregnancy or breastfeeding stopped less than 3 months ago
  • + {% endif %} {% else %}

    No

    @@ -109,12 +139,33 @@ ] } | removeLastRowBorder ) }} -

    - {{ button({ - text: "Add pregnancy and breastfeeding", - href: contextUrl + "/medical-information/pregnancy-and-breastfeeding", - variant: "secondary", - small: true - } | openInModal) }} -

    + {% if breastDensityFactors.factors | length %} + {% call card({ + heading: "Pregnancy and breastfeeding", + headingLevel: 4, + headingSize: "s", + classes: "nhsuk-u-margin-bottom-4 nhsuk-u-margin-top-4", + actions: { + items: [ + { + href: contextUrl + "/medical-information/pregnancy-and-breastfeeding", + text: "Change" + } | openInModal + ] + } if allowEdits + }) %} + {{ pregnantOrBreastfeedingSummaryHtml | safe }} + {% endcall %} + {% endif %} + + {% if allowEdits and not breastDensityFactors.factors | length %} +

    + {{ button({ + text: "Add pregnancy and breastfeeding", + href: contextUrl + "/medical-information/pregnancy-and-breastfeeding", + variant: "secondary", + small: true + } | openInModal) }} +

    + {% endif %} diff --git a/app/views/appointments/medical-information/pregnancy-and-breastfeeding.html b/app/views/appointments/medical-information/pregnancy-and-breastfeeding.html index 584735f1..a925bac0 100644 --- a/app/views/appointments/medical-information/pregnancy-and-breastfeeding.html +++ b/app/views/appointments/medical-information/pregnancy-and-breastfeeding.html @@ -12,7 +12,7 @@

    {{ pageHeading }}

    {{ checkboxes({ - name: "breastDensityFactors", + name: "appointment[medicalInformation][breastDensityFactors]", values: breastDensityFactors.factors, classes: "nhsuk-checkboxes--small", fieldset: { @@ -29,6 +29,14 @@

    {{ pageHeading }}

    { value: "breastfeeding", text: "Breastfeeding" + }, + { + divider: "or" + }, + { + value: "stopped-less-than-3-months", + text: "Pregnancy or breastfeeding stopped less than 3 months ago", + exclusive: true } ] }) }} @@ -37,4 +45,12 @@

    {{ pageHeading }}

    text: "Save" }) }} + {% if breastDensityFactors.factors | length %} +

    + + Delete this item + +

    + {% endif %} + {% endblock %} From 8572046225a47c51201bfdc4cb6e5bcc02ba855c Mon Sep 17 00:00:00 2001 From: rivalee Date: Thu, 3 Sep 2026 15:00:36 +0100 Subject: [PATCH 04/11] change pattern to match symptoms, content edits --- app/lib/utils/medical-information.js | 6 +- .../forms/breast-density-factors.njk | 87 +++++++++++++------ 2 files changed, 65 insertions(+), 28 deletions(-) diff --git a/app/lib/utils/medical-information.js b/app/lib/utils/medical-information.js index 4fae3b59..5a0c1e30 100644 --- a/app/lib/utils/medical-information.js +++ b/app/lib/utils/medical-information.js @@ -519,17 +519,17 @@ const summariseBreastDensityFactors = (medicalInformation) => { const summaries = [] if (hrt === 'yes') { - summaries.push('Currently taking HRT' + (hrtYearStarted ? ` (started: ${hrtYearStarted})` : '')) + summaries.push('Currently taking HRT' + (hrtYearStarted ? ` (Approximate year started: ${hrtYearStarted})` : '')) } else if (hrt === 'no') { summaries.push('Not currently taking HRT' + (hrtYearStopped ? ` (stopped: ${hrtYearStopped})` : '')) } if (factors.includes('pregnant')) { - summaries.push('Pregnant') + summaries.push('Currently pregnant') } if (factors.includes('breastfeeding')) { - summaries.push('Breastfeeding') + summaries.push('Currently breastfeeding') } if (factors.includes('stopped-less-than-3-months')) { diff --git a/app/views/_includes/forms/breast-density-factors.njk b/app/views/_includes/forms/breast-density-factors.njk index ac128c97..51be6fab 100644 --- a/app/views/_includes/forms/breast-density-factors.njk +++ b/app/views/_includes/forms/breast-density-factors.njk @@ -25,7 +25,7 @@ {% set hrtYesConditionalHtml %}
    @@ -34,7 +34,7 @@ {% set hrtNoConditionalHtml %}
    @@ -111,10 +111,10 @@ {% if breastDensityFactors.factors | length %}
      {% if breastDensityFactors.factors | includes("pregnant") %} -
    • Pregnant
    • +
    • Currently pregnant
    • {% endif %} {% if breastDensityFactors.factors | includes("breastfeeding") %} -
    • Breastfeeding
    • +
    • Currently breastfeeding
    • {% endif %} {% if breastDensityFactors.factors | includes("stopped-less-than-3-months") %}
    • Pregnancy or breastfeeding stopped less than 3 months ago
    • @@ -126,8 +126,8 @@ {% endset %}
      - {{ summaryList({ - rows: [ + {% if displayFormat == "expander" %} + {% set breastDensityRows = [ { key: { text: "HRT (hormone replacement therapy)" @@ -136,26 +136,63 @@ html: hrtInputHtml if allowEdits else hrtSummaryHtml } } - ] - } | removeLastRowBorder ) }} + ] %} - {% if breastDensityFactors.factors | length %} - {% call card({ - heading: "Pregnancy and breastfeeding", - headingLevel: 4, - headingSize: "s", - classes: "nhsuk-u-margin-bottom-4 nhsuk-u-margin-top-4", - actions: { - items: [ - { - href: contextUrl + "/medical-information/pregnancy-and-breastfeeding", - text: "Change" - } | openInModal - ] - } if allowEdits - }) %} - {{ pregnantOrBreastfeedingSummaryHtml | safe }} - {% endcall %} + {% if breastDensityFactors.factors | length %} + {% set breastDensityRows = breastDensityRows | push({ + key: { + text: "Pregnancy and breastfeeding" + }, + value: { + html: pregnantOrBreastfeedingSummaryHtml + }, + actions: { + items: [ + { + href: contextUrl + "/medical-information/pregnancy-and-breastfeeding", + text: "Change" + } | openInModal + ] + } if allowEdits + }) %} + {% endif %} + + {{ summaryList({ + rows: breastDensityRows, + lastRowBorder: false + }) }} + {% else %} + {{ summaryList({ + rows: [ + { + key: { + text: "HRT (hormone replacement therapy)" + }, + value: { + html: hrtInputHtml if allowEdits else hrtSummaryHtml + } + } + ] + } | removeLastRowBorder ) }} + {% endif %} + + {% if breastDensityFactors.factors | length and displayFormat != "expander" %} + {% call card({ + heading: "Pregnancy and breastfeeding", + headingLevel: 4, + headingSize: "s", + classes: "nhsuk-u-margin-bottom-4 nhsuk-u-margin-top-4", + actions: { + items: [ + { + href: contextUrl + "/medical-information/pregnancy-and-breastfeeding", + text: "Change" + } | openInModal + ] + } if allowEdits + }) %} + {{ pregnantOrBreastfeedingSummaryHtml | safe }} + {% endcall %} {% endif %} {% if allowEdits and not breastDensityFactors.factors | length %} From 7d6f26a54c164827449a225a163c13374e0a653f Mon Sep 17 00:00:00 2001 From: Ed Horsford Date: Fri, 4 Sep 2026 10:24:38 +0100 Subject: [PATCH 05/11] Standardise breast density factors data and forms - Store HRT as medicalInformation.hrt { status, yearStarted, yearStopped } and the pregnancy answers as medicalInformation.pregnancyAndBreastfeeding - Name the form fields against the appointment so auto-store-data saves them, dropping the pregnancy save route and slimming the HRT autosave to a no-op endpoint the fetch can post to - Keep the referrer chain through the pregnancy add, change and delete links so saving returns to the page you came from - Build every summary from one set of labels, so the form and the summaries can't drift apart - Use the input macro for the year fields, and take the expander's factor count from the server so it can't disagree with the stored data --- app/assets/javascript/main.js | 52 ++-- .../breast-density-factors-generator.js | 21 +- app/lib/utils/medical-information.js | 149 ++++++---- .../appointments/medical-information.js | 82 ++---- .../forms/breast-density-factors.njk | 260 ++++++++---------- .../pregnancy-and-breastfeeding.html | 38 ++- docs/MEDICAL-INFORMATION-GENERATOR-GUIDE.md | 21 +- 7 files changed, 297 insertions(+), 326 deletions(-) diff --git a/app/assets/javascript/main.js b/app/assets/javascript/main.js index 9fc8505b..4b68d99c 100644 --- a/app/assets/javascript/main.js +++ b/app/assets/javascript/main.js @@ -188,8 +188,8 @@ document.addEventListener('DOMContentLoaded', () => { } }) -// Breast density factors are edited in place rather than on their own page, -// so there's no submit button to save them - each change posts on its own. +// The HRT answer is edited in place rather than on its own page, so there's no +// submit button to save it - each change posts on its own. function setupBreastDensityFactorsAutosave() { const container = document.querySelector('[data-breast-density-factors-save-url]') if (!container) { @@ -201,19 +201,21 @@ function setupBreastDensityFactorsAutosave() { return } - const hrtName = 'breastDensityFactorsHrt' - const hrtYearStartedName = 'breastDensityFactorsHrtYearStarted' - const hrtYearStoppedName = 'breastDensityFactorsHrtYearStopped' + const statusName = 'appointment[medicalInformation][hrt][status]' + const yearStartedName = 'appointment[medicalInformation][hrt][yearStarted]' + const yearStoppedName = 'appointment[medicalInformation][hrt][yearStopped]' - const hrtRadios = container.querySelectorAll(`input[name="${hrtName}"]`) + const statusRadios = container.querySelectorAll(`input[name="${statusName}"]`) - if (hrtRadios.length === 0) { + if (statusRadios.length === 0) { return } // Keep the expander's "n factors added" line in step with the inputs. // Only the review page wraps these in an expander, so this does nothing - // elsewhere. + // elsewhere. Pregnancy and breastfeeding is edited on its own page, so its + // count comes from the server - match getBreastDensityFactors so the two + // never disagree const updateContentsSummary = () => { const summary = container .closest('.js-expandable-section') @@ -223,8 +225,9 @@ function setupBreastDensityFactorsAutosave() { return } - const hrtYes = container.querySelector(`input[name="${hrtName}"]:checked`)?.value === 'yes' - const count = hrtYes ? 1 : 0 + const factorCount = Number(container.dataset.breastDensityFactorCount) || 0 + const takingHrt = container.querySelector(`input[name="${statusName}"]:checked`)?.value === 'yes' + const count = factorCount + (takingHrt ? 1 : 0) if (count === 0) { summary.textContent = 'No breast density factors added' @@ -242,20 +245,17 @@ function setupBreastDensityFactorsAutosave() { const saveHrt = () => { const formData = new URLSearchParams() - const selectedHrt = container.querySelector(`input[name="${hrtName}"]:checked`) - if (selectedHrt) { - formData.append(hrtName, selectedHrt.value) + const selectedStatus = container.querySelector(`input[name="${statusName}"]:checked`) + if (selectedStatus) { + formData.append(statusName, selectedStatus.value) } - const yearStartedInput = container.querySelector(`input[name="${hrtYearStartedName}"]`) - if (yearStartedInput) { - formData.append(hrtYearStartedName, yearStartedInput.value) - } - - const yearStoppedInput = container.querySelector(`input[name="${hrtYearStoppedName}"]`) - if (yearStoppedInput) { - formData.append(hrtYearStoppedName, yearStoppedInput.value) - } + ;[yearStartedName, yearStoppedName].forEach((name) => { + const input = container.querySelector(`input[name="${name}"]`) + if (input) { + formData.append(name, input.value) + } + }) updateContentsSummary() @@ -280,11 +280,9 @@ function setupBreastDensityFactorsAutosave() { } container - .querySelectorAll(`input[name="${hrtName}"]`) - .forEach((input) => input.addEventListener('change', saveHrt)) - - container - .querySelectorAll(`input[name="${hrtYearStartedName}"], input[name="${hrtYearStoppedName}"]`) + .querySelectorAll( + `input[name="${statusName}"], input[name="${yearStartedName}"], input[name="${yearStoppedName}"]` + ) .forEach((input) => input.addEventListener('change', saveHrt)) } diff --git a/app/lib/generators/medical-information/breast-density-factors-generator.js b/app/lib/generators/medical-information/breast-density-factors-generator.js index 5238e00c..7287eb8b 100644 --- a/app/lib/generators/medical-information/breast-density-factors-generator.js +++ b/app/lib/generators/medical-information/breast-density-factors-generator.js @@ -14,7 +14,7 @@ * @param {number} [options.probabilityOfHrt] - Chance of currently taking HRT (0-1) * @param {number} [options.probabilityOfPregnancyBreastfeeding] - Chance of being pregnant or breastfeeding (0-1) * @param {number} [options.probabilityOfBeingAsked=0.8] - Chance the question was asked at all - * @returns {object} Object with breastDensityFactors and breastDensityFactorsHrt, either may be absent + * @returns {object} Object with hrt and pregnancyAndBreastfeeding, either may be absent */ const generateBreastDensityFactors = (options = {}) => { const { @@ -29,8 +29,17 @@ const generateBreastDensityFactors = (options = {}) => { // keeps "no medical information" a possible outcome, and lets the summaries // distinguish "not answered" from a recorded "no" if (Math.random() < probabilityOfBeingAsked) { - result.breastDensityFactorsHrt = - Math.random() < probabilityOfHrt ? 'yes' : 'no' + const isTakingHrt = Math.random() < probabilityOfHrt + const currentYear = new Date().getFullYear() + + result.hrt = { + status: isTakingHrt ? 'yes' : 'no' + } + + // Years are strings because that's what the form fields post back + if (isTakingHrt) { + result.hrt.yearStarted = String(currentYear - Math.floor(Math.random() * 10)) + } } const factors = [] @@ -38,14 +47,14 @@ const generateBreastDensityFactors = (options = {}) => { if (Math.random() < probabilityOfPregnancyBreastfeeding) { // Breastfeeding is the more likely of the two at screening age if (Math.random() < 0.7) { - factors.push('breastfeeding') + factors.push('currently-breastfeeding') } else { - factors.push('pregnant') + factors.push('currently-pregnant') } } if (factors.length > 0) { - result.breastDensityFactors = factors + result.pregnancyAndBreastfeeding = factors } return result diff --git a/app/lib/utils/medical-information.js b/app/lib/utils/medical-information.js index 5a0c1e30..8364c056 100644 --- a/app/lib/utils/medical-information.js +++ b/app/lib/utils/medical-information.js @@ -451,92 +451,129 @@ const summariseBreastFeatures = (features) => { .filter(Boolean) } +// Pregnancy and breastfeeding options, in display order. The stored value and +// the label shown back to the user come from here, so the form and every +// summary can never drift apart. +const pregnancyAndBreastfeedingOptions = [ + { + value: 'currently-pregnant', + text: 'Currently pregnant' + }, + { + value: 'currently-breastfeeding', + text: 'Currently breastfeeding' + }, + { + divider: 'or' + }, + { + value: 'stopped-less-than-3-months', + text: 'Pregnancy or breastfeeding stopped less than 3 months ago', + behaviour: 'exclusive' + } +] + /** - * Read the breast density factors off an appointment's medical information + * Normalise a checkbox group's stored value to an array * * A checkbox group posts a bare string when one box is ticked and an array - * when several are, so the stored value needs normalising before anything can - * read it. Doing that here means templates get a single shape to work with - * rather than repeating the coercion at every call site. + * when several are, so the stored value needs coercing before anything can + * read it. + * + * @param {*} value - The stored value + * @returns {Array} The value as an array, empty if nothing is stored + */ +const toCheckboxArray = (value) => { + if (Array.isArray(value)) { + return value.filter(Boolean) + } + + return value ? [value] : [] +} + +/** + * Read the breast density factors off an appointment's medical information + * + * Breast density factors are a display grouping rather than a stored object - + * they pull together the separately stored HRT answer and pregnancy and + * breastfeeding answers. Reading them here means templates get a single shape + * to work with rather than repeating the coercion at every call site. * * @param {Object} medicalInformation - The medicalInformation object from appointment - * @returns {{factors: Array, hrt: string|undefined, count: number, answeredCount: number, summaries: Array}} + * @returns {{factors: Array, hrt: Object, count: number, answeredCount: number, summaries: Array, factorSummaries: Array, options: Array}} */ const getBreastDensityFactors = (medicalInformation) => { - const rawFactors = medicalInformation?.breastDensityFactors - const factors = (Array.isArray(rawFactors) - ? rawFactors - : rawFactors - ? [rawFactors] - : [] - ).filter((f) => f && f !== '_unchecked') - - const hrt = medicalInformation?.breastDensityFactorsHrt - const hrtYearStarted = medicalInformation?.breastDensityFactorsHrtYearStarted - const hrtYearStopped = medicalInformation?.breastDensityFactorsHrtYearStopped - - // "Not started HRT" is an answer, but it isn't a density factor - only - // count the things that actually affect density - const count = - (hrt === 'yes' ? 1 : 0) + - (factors.includes('pregnant') ? 1 : 0) + - (factors.includes('breastfeeding') ? 1 : 0) + - (factors.includes('stopped-less-than-3-months') ? 1 : 0) + const factors = toCheckboxArray(medicalInformation?.pregnancyAndBreastfeeding) + const hrt = medicalInformation?.hrt || {} const summaries = summariseBreastDensityFactors(medicalInformation) return { factors, hrt, - hrtYearStarted, - hrtYearStopped, - count, - // Everything worth showing, including a recorded "no" to HRT question - use this - // to decide whether to show the row at all, and count for "n added" + // "Not taking HRT" is an answer, but it isn't a density factor - only + // count the things that actually affect density + count: (hrt.status === 'yes' ? 1 : 0) + factors.length, + // Everything worth showing, including a recorded "no" to the HRT question - + // use this to decide whether to show the row at all answeredCount: summaries.length, - summaries + summaries, + factorSummaries: summarisePregnancyAndBreastfeeding(medicalInformation), + hrtSummary: summariseHrt(medicalInformation), + options: pregnancyAndBreastfeedingOptions } } /** - * Summarise breast density factors into an array of summary strings + * Summarise the pregnancy and breastfeeding answers into an array of labels * * @param {Object} medicalInformation - The medicalInformation object from appointment * @returns {Array} Array of summary strings */ -const summariseBreastDensityFactors = (medicalInformation) => { - const rawFactors = medicalInformation?.breastDensityFactors - const factors = Array.isArray(rawFactors) - ? rawFactors.filter(Boolean) - : rawFactors - ? [rawFactors] - : [] +const summarisePregnancyAndBreastfeeding = (medicalInformation) => { + const factors = toCheckboxArray(medicalInformation?.pregnancyAndBreastfeeding) - const hrt = medicalInformation?.breastDensityFactorsHrt - const hrtYearStarted = medicalInformation?.breastDensityFactorsHrtYearStarted - const hrtYearStopped = medicalInformation?.breastDensityFactorsHrtYearStopped + return pregnancyAndBreastfeedingOptions + .filter((option) => option.value && factors.includes(option.value)) + .map((option) => option.text) +} - const summaries = [] +/** + * Summarise breast density factors into an array of summary strings + * + * @param {Object} medicalInformation - The medicalInformation object from appointment + * @returns {Array} Array of summary strings + */ +const summariseBreastDensityFactors = (medicalInformation) => { + const hrtSummary = summariseHrt(medicalInformation) - if (hrt === 'yes') { - summaries.push('Currently taking HRT' + (hrtYearStarted ? ` (Approximate year started: ${hrtYearStarted})` : '')) - } else if (hrt === 'no') { - summaries.push('Not currently taking HRT' + (hrtYearStopped ? ` (stopped: ${hrtYearStopped})` : '')) - } + return (hrtSummary ? [hrtSummary] : []).concat( + summarisePregnancyAndBreastfeeding(medicalInformation) + ) +} - if (factors.includes('pregnant')) { - summaries.push('Currently pregnant') - } +/** + * Summarise the HRT answer, including the year if one was recorded + * + * @param {Object} medicalInformation - The medicalInformation object from appointment + * @returns {string|null} Summary string, or null if the question wasn't answered + */ +const summariseHrt = (medicalInformation) => { + const hrt = medicalInformation?.hrt || {} - if (factors.includes('breastfeeding')) { - summaries.push('Currently breastfeeding') + if (hrt.status === 'yes') { + return hrt.yearStarted + ? `Currently taking HRT (started ${hrt.yearStarted})` + : 'Currently taking HRT' } - if (factors.includes('stopped-less-than-3-months')) { - summaries.push('Pregnancy or breastfeeding stopped less than 3 months ago') + if (hrt.status === 'no') { + return hrt.yearStopped + ? `Not currently taking HRT (stopped ${hrt.yearStopped})` + : 'Not currently taking HRT' } - return summaries + return null } /** @@ -569,5 +606,7 @@ module.exports = { summariseBreastFeatures, getBreastDensityFactors, summariseBreastDensityFactors, + summarisePregnancyAndBreastfeeding, + summariseHrt, summariseOtherMedicalInformation } diff --git a/app/routes/appointments/medical-information.js b/app/routes/appointments/medical-information.js index 44370294..8896eb4d 100644 --- a/app/routes/appointments/medical-information.js +++ b/app/routes/appointments/medical-information.js @@ -9,85 +9,41 @@ const { } = require('../../lib/utils/referrers') module.exports = (router) => { - // Auto-save breast density factors as they're changed + // Auto-save the HRT answer as it's changed // - // These answers are edited in place on the review page rather than on a - // sub-page with its own submit, so there's no form post to carry them. - // Like the other medical information sections, this writes to the temp - // appointment and is committed when the appointment is completed or paused. - // - // The inputs are named outside the appointment[...] namespace on purpose. - // They render inside other forms, and the kit's unchecked-checkbox script - // adds an "_unchecked" value for every checkbox in whichever form is being - // submitted. Since auto-store-data replaces arrays rather than merging - // them, an appointment-namespaced name would let any other form on the page - // wipe these answers. Keeping them out of that namespace means only this - // route ever writes them. + // HRT is edited in place on the review page rather than on a sub-page with + // its own submit, so there's no form post to carry it. The fields are named + // against the appointment, so auto-store-data has already written them to + // the temp appointment by the time this runs - the route exists only to give + // the fetch something to post to that doesn't render a whole page. Without + // JavaScript the surrounding form's submit saves the same fields the same way. router.post( - '/clinics/:clinicId/appointments/:appointmentId/medical-information/breast-density-factors-save', + '/clinics/:clinicId/appointments/:appointmentId/medical-information/hrt-save', (req, res) => { - const { appointmentId } = req.params - const data = req.session.data - - const postedHrt = req.body?.breastDensityFactorsHrt - const postedHrtYearStarted = req.body?.breastDensityFactorsHrtYearStarted - const postedHrtYearStopped = req.body?.breastDensityFactorsHrtYearStopped - - if (data.appointment?.id !== appointmentId) { - res.status(409).send() - return - } - - const medicalInformation = data.appointment.medicalInformation || {} - - if (postedHrt) { - medicalInformation.breastDensityFactorsHrt = postedHrt - } - - if (postedHrtYearStarted !== undefined) { - medicalInformation.breastDensityFactorsHrtYearStarted = postedHrtYearStarted - } - - if (postedHrtYearStopped !== undefined) { - medicalInformation.breastDensityFactorsHrtYearStopped = postedHrtYearStopped - } - - data.appointment.medicalInformation = medicalInformation - - delete data.breastDensityFactorsHrt - delete data.breastDensityFactorsHrtYearStarted - delete data.breastDensityFactorsHrtYearStopped - res.status(204).send() } ) - // Pregnancy/breastfeeding modal form — data is auto-saved by the kit - // via the field name; we just need the modalBreakout redirect. - // Pregnancy/breastfeeding modal — auto-store-data saves the field - // directly to appointment.medicalInformation.breastDensityFactors; - // route only handles the modalBreakout redirect. - router.post( - '/clinics/:clinicId/appointments/:appointmentId/medical-information/pregnancy-and-breastfeeding-save', - (req, res) => { - const { clinicId, appointmentId } = req.params - res.redirect(modalBreakout(`/clinics/${clinicId}/appointments/${appointmentId}/review-medical-information`)) - } - ) - - // Delete pregnancy/breastfeeding + // Delete pregnancy and breastfeeding router.get( - '/clinics/:clinicId/appointments/:appointmentId/medical-information/pregnancy-and-breastfeeding-delete', + '/clinics/:clinicId/appointments/:appointmentId/medical-information/pregnancy-and-breastfeeding/delete', (req, res) => { const { clinicId, appointmentId } = req.params const data = req.session.data if (data.appointment?.medicalInformation) { - delete data.appointment.medicalInformation.breastDensityFactors + delete data.appointment.medicalInformation.pregnancyAndBreastfeeding } req.flash('success', 'Pregnancy and breastfeeding deleted') - res.redirect(modalBreakout(`/clinics/${clinicId}/appointments/${appointmentId}/review-medical-information`)) + + const returnUrl = getReturnUrl( + `/clinics/${clinicId}/appointments/${appointmentId}/review-medical-information`, + req.query.referrerChain, + req.query.scrollTo + ) + + res.redirect(modalBreakout(returnUrl)) } ) diff --git a/app/views/_includes/forms/breast-density-factors.njk b/app/views/_includes/forms/breast-density-factors.njk index 51be6fab..140a407e 100644 --- a/app/views/_includes/forms/breast-density-factors.njk +++ b/app/views/_includes/forms/breast-density-factors.njk @@ -2,204 +2,172 @@ {# Breast density factors - HRT, pregnancy and breastfeeding. - Shown inline rather than on a sub-page, so when edits are allowed the inputs - render directly and save themselves as they're changed (see the autosave in - main.js). The save URL rides on the wrapper element. - - The inputs are named outside the appointment[...] namespace on purpose. This - section renders inside other forms (the review page wraps everything in a - "complete and continue" form), and the kit's unchecked-checkbox script adds - an "_unchecked" value for every checkbox in whichever form is submitted. - Since auto-store-data replaces arrays rather than merging them, an - appointment-namespaced name would let any other form on the page wipe these - answers. The save route maps these names onto the appointment. + HRT is shown inline rather than on a sub-page, so when edits are allowed the + inputs render directly and save themselves as they're changed (see the + autosave in main.js). The save URL rides on the wrapper element. Without + JavaScript the surrounding form's submit saves the same fields. + + Pregnancy and breastfeeding is a checkbox group, and the kit's + unchecked-checkbox script adds an "_unchecked" value for every checkbox in + whichever form is submitted. Since this section renders inside other forms, + editing it inline would let an unrelated submit wipe the answers - so it + gets its own page instead. + + Set displayFormat to "expander" to fold pregnancy and breastfeeding into the + summary list; otherwise it renders as its own card below. #} {% set breastDensityFactors = appointment.medicalInformation | getBreastDensityFactors %} -{% set participantName = participant | getFullName %} - {% set hrtQuestion = "Is " + participant.demographicInformation.firstName + " currently taking HRT?" %} -{% set pregnantOrBreastfeedingQuestion = "Is " + participant.demographicInformation.firstName + " pregnant or breastfeeding?" %} - -{% set hrtYesConditionalHtml %} -
      - - -
      + +{% set pregnancyAndBreastfeedingUrl = contextUrl + "/medical-information/pregnancy-and-breastfeeding" %} + +{% set hrtYearStartedHtml %} + {{ input({ + id: "hrtYearStarted", + name: "appointment[medicalInformation][hrt][yearStarted]", + label: { + text: "Approximate year started" + }, + classes: "nhsuk-input--width-4", + inputmode: "numeric", + value: breastDensityFactors.hrt.yearStarted + }) }} {% endset %} -{% set hrtNoConditionalHtml %} -
      - - -
      +{% set hrtYearStoppedHtml %} + {{ input({ + id: "hrtYearStopped", + name: "appointment[medicalInformation][hrt][yearStopped]", + label: { + text: "Approximate year stopped, if previously taken" + }, + classes: "nhsuk-input--width-4", + inputmode: "numeric", + value: breastDensityFactors.hrt.yearStopped + }) }} {% endset %} {% set hrtInputHtml %} {{ radios({ - name: "breastDensityFactorsHrt", - value: breastDensityFactors.hrt, + name: "appointment[medicalInformation][hrt][status]", + value: breastDensityFactors.hrt.status, classes: "nhsuk-radios--small", fieldset: { legend: { - text: hrtQuestion, + text: hrtQuestion + " (optional)", classes: "nhsuk-fieldset__legend--s" } }, - hint: { - text: "(optional)" - }, items: [ { value: "yes", text: "Yes", conditional: { - html: hrtYesConditionalHtml + html: hrtYearStartedHtml } }, { value: "no", text: "No", conditional: { - html: hrtNoConditionalHtml + html: hrtYearStoppedHtml } } ] }) }} {% endset %} -{% set pregnantOrBreastfeedingInputHtml %} - {{ checkboxes({ - name: "breastDensityFactors", - values: breastDensityFactors.factors, - classes: "nhsuk-checkboxes--small", - fieldset: { - legend: { - text: pregnantOrBreastfeedingQuestion, - classes: "nhsuk-fieldset__legend--s" - } - }, - items: [ - { - value: "pregnant", - text: "Pregnant" - }, - { - value: "breastfeeding", - text: "Breastfeeding" - } - ] - }) }} -{% endset %} - {% set hrtSummaryHtml %} - {% if breastDensityFactors.hrt == "yes" %} -

      Currently taking HRT{% if breastDensityFactors.hrtYearStarted %} (started: {{ breastDensityFactors.hrtYearStarted }}){% endif %}

      - {% elseif breastDensityFactors.hrt == "no" %} -

      Not currently taking HRT{% if breastDensityFactors.hrtYearStopped %} (stopped: {{ breastDensityFactors.hrtYearStopped }}){% endif %}

      - {% else %} -

      Not answered

      - {% endif %} +

      {{ breastDensityFactors.hrtSummary or "Not answered" }}

      {% endset %} -{% set pregnantOrBreastfeedingSummaryHtml %} - {% if breastDensityFactors.factors | length %} +{% set pregnancyAndBreastfeedingSummaryHtml %} + {% if breastDensityFactors.factorSummaries | length > 1 %}
        - {% if breastDensityFactors.factors | includes("pregnant") %} -
      • Currently pregnant
      • - {% endif %} - {% if breastDensityFactors.factors | includes("breastfeeding") %} -
      • Currently breastfeeding
      • - {% endif %} - {% if breastDensityFactors.factors | includes("stopped-less-than-3-months") %} -
      • Pregnancy or breastfeeding stopped less than 3 months ago
      • - {% endif %} + {% for summary in breastDensityFactors.factorSummaries %} +
      • {{ summary }}
      • + {% endfor %}
      + {% elseif breastDensityFactors.factorSummaries | length %} +

      {{ breastDensityFactors.factorSummaries | first }}

      {% else %}

      No

      {% endif %} {% endset %} -
      - {% if displayFormat == "expander" %} - {% set breastDensityRows = [ - { - key: { - text: "HRT (hormone replacement therapy)" - }, - value: { - html: hrtInputHtml if allowEdits else hrtSummaryHtml - } - } - ] %} - - {% if breastDensityFactors.factors | length %} - {% set breastDensityRows = breastDensityRows | push({ - key: { - text: "Pregnancy and breastfeeding" - }, - value: { - html: pregnantOrBreastfeedingSummaryHtml - }, - actions: { - items: [ - { - href: contextUrl + "/medical-information/pregnancy-and-breastfeeding", - text: "Change" - } | openInModal - ] - } if allowEdits - }) %} - {% endif %} - - {{ summaryList({ - rows: breastDensityRows, - lastRowBorder: false - }) }} - {% else %} - {{ summaryList({ - rows: [ - { - key: { - text: "HRT (hormone replacement therapy)" - }, - value: { - html: hrtInputHtml if allowEdits else hrtSummaryHtml - } - } - ] - } | removeLastRowBorder ) }} - {% endif %} +{# The card macro appends its own heading to the action, so only the summary + list row needs the visually hidden text spelling out #} +{% set changeInCardAction = { + items: [ + { + href: pregnancyAndBreastfeedingUrl | urlWithReferrer(currentUrl), + text: "Change" + } | openInModal + ] +} if allowEdits %} + +{% set changeInRowAction = { + items: [ + { + href: pregnancyAndBreastfeedingUrl | urlWithReferrer(currentUrl), + text: "Change", + visuallyHiddenText: "pregnancy and breastfeeding" + } | openInModal + ] +} if allowEdits %} + +{% set breastDensityRows = [ + { + key: { + text: "HRT (hormone replacement therapy)" + }, + value: { + html: hrtInputHtml if allowEdits else hrtSummaryHtml + } + } +] %} + +{# In the expander the pregnancy answers sit in the same list as HRT; elsewhere + they get their own card below so the change action is easier to spot #} +{% if breastDensityFactors.factors | length and displayFormat == "expander" %} + {% set breastDensityRows = breastDensityRows | push({ + key: { + text: "Pregnancy and breastfeeding" + }, + value: { + html: pregnancyAndBreastfeedingSummaryHtml + }, + actions: changeInRowAction + }) %} +{% endif %} + +
      + + {{ summaryList({ + rows: breastDensityRows, + lastRowBorder: false + }) }} {% if breastDensityFactors.factors | length and displayFormat != "expander" %} - {% call card({ - heading: "Pregnancy and breastfeeding", - headingLevel: 4, - headingSize: "s", - classes: "nhsuk-u-margin-bottom-4 nhsuk-u-margin-top-4", - actions: { - items: [ - { - href: contextUrl + "/medical-information/pregnancy-and-breastfeeding", - text: "Change" - } | openInModal - ] - } if allowEdits - }) %} - {{ pregnantOrBreastfeedingSummaryHtml | safe }} - {% endcall %} + {% call card({ + heading: "Pregnancy and breastfeeding", + headingLevel: 4, + headingSize: "s", + classes: "nhsuk-u-margin-bottom-4 nhsuk-u-margin-top-4", + actions: changeInCardAction + }) %} + {{ pregnancyAndBreastfeedingSummaryHtml | safe }} + {% endcall %} {% endif %} {% if allowEdits and not breastDensityFactors.factors | length %}

      {{ button({ text: "Add pregnancy and breastfeeding", - href: contextUrl + "/medical-information/pregnancy-and-breastfeeding", + href: pregnancyAndBreastfeedingUrl | urlWithReferrer(currentUrl), variant: "secondary", small: true } | openInModal) }} diff --git a/app/views/appointments/medical-information/pregnancy-and-breastfeeding.html b/app/views/appointments/medical-information/pregnancy-and-breastfeeding.html index a925bac0..b155141a 100644 --- a/app/views/appointments/medical-information/pregnancy-and-breastfeeding.html +++ b/app/views/appointments/medical-information/pregnancy-and-breastfeeding.html @@ -3,16 +3,24 @@ {% extends parentLayout or 'layout-appointment.html' %} {% set pageHeading = "Pregnancy and breastfeeding" %} -{% set formAction = "./pregnancy-and-breastfeeding-save" %} + +{% set gridColumn = "nhsuk-grid-column-two-thirds" %} + +{% set formAction = './../review-medical-information' | getReturnUrl(referrerChain, query.scrollTo) %} {% block pageContent %} {% set breastDensityFactors = appointment.medicalInformation | getBreastDensityFactors %} -

      {{ pageHeading }}

      +

      + + {{ participant | getFullName }} + + {{ pageHeading }} +

      {{ checkboxes({ - name: "appointment[medicalInformation][breastDensityFactors]", + name: "appointment[medicalInformation][pregnancyAndBreastfeeding]", values: breastDensityFactors.factors, classes: "nhsuk-checkboxes--small", fieldset: { @@ -21,24 +29,7 @@

      {{ pageHeading }}

      classes: "nhsuk-fieldset__legend--s" } }, - items: [ - { - value: "pregnant", - text: "Pregnant" - }, - { - value: "breastfeeding", - text: "Breastfeeding" - }, - { - divider: "or" - }, - { - value: "stopped-less-than-3-months", - text: "Pregnancy or breastfeeding stopped less than 3 months ago", - exclusive: true - } - ] + items: breastDensityFactors.options }) }} {{ button({ @@ -46,8 +37,11 @@

      {{ pageHeading }}

      }) }} {% if breastDensityFactors.factors | length %} + {% set deleteHref %} + ./pregnancy-and-breastfeeding/delete{{ "" | urlWithReferrer(referrerChain, query.scrollTo) }} + {% endset %}

      - + Delete this item

      diff --git a/docs/MEDICAL-INFORMATION-GENERATOR-GUIDE.md b/docs/MEDICAL-INFORMATION-GENERATOR-GUIDE.md index 7b084e2f..56797a5c 100644 --- a/docs/MEDICAL-INFORMATION-GENERATOR-GUIDE.md +++ b/docs/MEDICAL-INFORMATION-GENERATOR-GUIDE.md @@ -36,8 +36,8 @@ appointment: { participantId: string, medicalInformation: { symptoms: [], // ✅ Array of symptom objects - breastDensityFactorsHrt: string, // ✅ 'yes' or 'no' - absent if not asked - breastDensityFactors: [], // ✅ Any of 'pregnant', 'breastfeeding' - absent if none + hrt: {}, // ✅ status ('yes'/'no') plus optional year - absent if not asked + pregnancyAndBreastfeeding: [], // ✅ Any of the pregnancy/breastfeeding values - absent if none otherMedicalInformation: string, // ✅ Freetext medical info breastFeatures: [], // ✅ Array of breast feature objects medicalHistory: { // Object with arrays for each type @@ -192,7 +192,7 @@ Replaces the separate HRT and pregnancy/breastfeeding generators. The question i **Key features:** - Generates the factors that affect breast density: HRT, pregnancy and breastfeeding -- 80% default probability the question was asked at all — if it wasn't, `breastDensityFactorsHrt` is left unset, so summaries can distinguish “not answered” from a recorded “no” +- 80% default probability the question was asked at all — if it wasn't, `hrt` is left unset, so summaries can distinguish “not answered” from a recorded “no” - 30% default probability of currently taking HRT - 5% default probability of being pregnant or breastfeeding (appropriate for the screening age group), split 70/30 towards breastfeeding - Returns a plain object of keys the umbrella generator merges with `Object.assign`, rather than a nested sub-object @@ -211,10 +211,17 @@ generateBreastDensityFactors({ ```javascript { - // Absent if the question wasn't asked - breastDensityFactorsHrt: 'yes' | 'no', - // Absent if neither applies - breastDensityFactors: ['pregnant' | 'breastfeeding'] + // Absent if the question wasn't asked. yearStarted is only set when taking HRT; + // yearStopped is only ever entered by a user + hrt: { + status: 'yes' | 'no', + yearStarted: string, + yearStopped: string + }, + // Absent if none apply + pregnancyAndBreastfeeding: [ + 'currently-pregnant' | 'currently-breastfeeding' | 'stopped-less-than-3-months' + ] } ``` From 078ef4a4e146084aa7471a2b98b52d0a347b8747 Mon Sep 17 00:00:00 2001 From: Ed Horsford Date: Fri, 4 Sep 2026 10:30:01 +0100 Subject: [PATCH 06/11] Show pregnancy and breastfeeding the same way everywhere The include had two presentations - a summary list row inside the expander, a card everywhere else. Keep the row. --- .../forms/breast-density-factors.njk | 34 ++----------------- 1 file changed, 3 insertions(+), 31 deletions(-) diff --git a/app/views/_includes/forms/breast-density-factors.njk b/app/views/_includes/forms/breast-density-factors.njk index 140a407e..799479a6 100644 --- a/app/views/_includes/forms/breast-density-factors.njk +++ b/app/views/_includes/forms/breast-density-factors.njk @@ -12,9 +12,6 @@ whichever form is submitted. Since this section renders inside other forms, editing it inline would let an unrelated submit wipe the answers - so it gets its own page instead. - - Set displayFormat to "expander" to fold pregnancy and breastfeeding into the - summary list; otherwise it renders as its own card below. #} {% set breastDensityFactors = appointment.medicalInformation | getBreastDensityFactors %} @@ -97,18 +94,7 @@ {% endif %} {% endset %} -{# The card macro appends its own heading to the action, so only the summary - list row needs the visually hidden text spelling out #} -{% set changeInCardAction = { - items: [ - { - href: pregnancyAndBreastfeedingUrl | urlWithReferrer(currentUrl), - text: "Change" - } | openInModal - ] -} if allowEdits %} - -{% set changeInRowAction = { +{% set changePregnancyAndBreastfeedingAction = { items: [ { href: pregnancyAndBreastfeedingUrl | urlWithReferrer(currentUrl), @@ -129,9 +115,7 @@ } ] %} -{# In the expander the pregnancy answers sit in the same list as HRT; elsewhere - they get their own card below so the change action is easier to spot #} -{% if breastDensityFactors.factors | length and displayFormat == "expander" %} +{% if breastDensityFactors.factors | length %} {% set breastDensityRows = breastDensityRows | push({ key: { text: "Pregnancy and breastfeeding" @@ -139,7 +123,7 @@ value: { html: pregnancyAndBreastfeedingSummaryHtml }, - actions: changeInRowAction + actions: changePregnancyAndBreastfeedingAction }) %} {% endif %} @@ -151,18 +135,6 @@ lastRowBorder: false }) }} - {% if breastDensityFactors.factors | length and displayFormat != "expander" %} - {% call card({ - heading: "Pregnancy and breastfeeding", - headingLevel: 4, - headingSize: "s", - classes: "nhsuk-u-margin-bottom-4 nhsuk-u-margin-top-4", - actions: changeInCardAction - }) %} - {{ pregnancyAndBreastfeedingSummaryHtml | safe }} - {% endcall %} - {% endif %} - {% if allowEdits and not breastDensityFactors.factors | length %}

      {{ button({ From 7e50b0d54922d22162fa91967ee86825a08df951 Mon Sep 17 00:00:00 2001 From: Ed Horsford Date: Fri, 4 Sep 2026 10:33:03 +0100 Subject: [PATCH 07/11] Put the autosave hook on the summary list itself The wrapper div existed only to carry the data attributes, and the macro takes attributes. --- .../forms/breast-density-factors.njk | 38 ++++++++++--------- 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/app/views/_includes/forms/breast-density-factors.njk b/app/views/_includes/forms/breast-density-factors.njk index 799479a6..e75d1981 100644 --- a/app/views/_includes/forms/breast-density-factors.njk +++ b/app/views/_includes/forms/breast-density-factors.njk @@ -127,22 +127,24 @@ }) %} {% endif %} -

      - - {{ summaryList({ - rows: breastDensityRows, - lastRowBorder: false - }) }} +{# The autosave finds the list by its save URL, and takes the factor count from + here so it can't disagree with what the server stored #} +{{ summaryList({ + rows: breastDensityRows, + lastRowBorder: false, + attributes: { + "data-breast-density-factors-save-url": contextUrl + "/medical-information/hrt-save", + "data-breast-density-factor-count": breastDensityFactors.factors | length + } +}) }} - {% if allowEdits and not breastDensityFactors.factors | length %} -

      - {{ button({ - text: "Add pregnancy and breastfeeding", - href: pregnancyAndBreastfeedingUrl | urlWithReferrer(currentUrl), - variant: "secondary", - small: true - } | openInModal) }} -

      - {% endif %} -
      +{% if allowEdits and not breastDensityFactors.factors | length %} +

      + {{ button({ + text: "Add pregnancy and breastfeeding", + href: pregnancyAndBreastfeedingUrl | urlWithReferrer(currentUrl), + variant: "secondary", + small: true + } | openInModal) }} +

      +{% endif %} From e91a0419225e42969d51666c55d25d1cabd00ce6 Mon Sep 17 00:00:00 2001 From: Ed Horsford Date: Fri, 4 Sep 2026 10:41:38 +0100 Subject: [PATCH 08/11] Say the HRT year is approximate in summaries The fields only ask for an approximate year, so "started 2017" read as more precise than the answer is. --- app/lib/utils/medical-information.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/app/lib/utils/medical-information.js b/app/lib/utils/medical-information.js index 8364c056..5acbdff6 100644 --- a/app/lib/utils/medical-information.js +++ b/app/lib/utils/medical-information.js @@ -561,15 +561,17 @@ const summariseBreastDensityFactors = (medicalInformation) => { const summariseHrt = (medicalInformation) => { const hrt = medicalInformation?.hrt || {} + // The year fields only ever ask for an approximate year, so the summaries + // say so rather than reading as an exact date if (hrt.status === 'yes') { return hrt.yearStarted - ? `Currently taking HRT (started ${hrt.yearStarted})` + ? `Currently taking HRT (started approximately ${hrt.yearStarted})` : 'Currently taking HRT' } if (hrt.status === 'no') { return hrt.yearStopped - ? `Not currently taking HRT (stopped ${hrt.yearStopped})` + ? `Not currently taking HRT (stopped approximately ${hrt.yearStopped})` : 'Not currently taking HRT' } From 7123d6fd0a0896d1a488418048b8e71dea82e744 Mon Sep 17 00:00:00 2001 From: Ed Horsford Date: Fri, 4 Sep 2026 10:43:35 +0100 Subject: [PATCH 09/11] Reword the HRT year and combine the pregnancy line Years read as "approximate start: 2017". Pregnant and breastfeeding together now summarise as one line rather than two. --- app/lib/utils/medical-information.js | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/app/lib/utils/medical-information.js b/app/lib/utils/medical-information.js index 5acbdff6..5990d1da 100644 --- a/app/lib/utils/medical-information.js +++ b/app/lib/utils/medical-information.js @@ -533,6 +533,14 @@ const getBreastDensityFactors = (medicalInformation) => { const summarisePregnancyAndBreastfeeding = (medicalInformation) => { const factors = toCheckboxArray(medicalInformation?.pregnancyAndBreastfeeding) + // Both at once reads better as one line than as two + if ( + factors.includes('currently-pregnant') && + factors.includes('currently-breastfeeding') + ) { + return ['Currently pregnant and breastfeeding'] + } + return pregnancyAndBreastfeedingOptions .filter((option) => option.value && factors.includes(option.value)) .map((option) => option.text) @@ -565,13 +573,13 @@ const summariseHrt = (medicalInformation) => { // say so rather than reading as an exact date if (hrt.status === 'yes') { return hrt.yearStarted - ? `Currently taking HRT (started approximately ${hrt.yearStarted})` + ? `Currently taking HRT (approximate start: ${hrt.yearStarted})` : 'Currently taking HRT' } if (hrt.status === 'no') { return hrt.yearStopped - ? `Not currently taking HRT (stopped approximately ${hrt.yearStopped})` + ? `Not currently taking HRT (approximate stop: ${hrt.yearStopped})` : 'Not currently taking HRT' } From 1176d78b47af1fcb1a965de38d55e8b535d550dc Mon Sep 17 00:00:00 2001 From: Ed Horsford Date: Fri, 4 Sep 2026 10:58:26 +0100 Subject: [PATCH 10/11] Give pregnancy and breastfeeding its own helper getBreastDensityFactors returned "factors" holding only the pregnancy answers, as though HRT weren't a factor. The pregnancy page now reads its own data rather than reaching through the breast density grouping. --- app/lib/utils/medical-information.js | 39 ++++++++++++++----- .../forms/breast-density-factors.njk | 15 +++---- .../pregnancy-and-breastfeeding.html | 8 ++-- 3 files changed, 41 insertions(+), 21 deletions(-) diff --git a/app/lib/utils/medical-information.js b/app/lib/utils/medical-information.js index 5990d1da..3efefff7 100644 --- a/app/lib/utils/medical-information.js +++ b/app/lib/utils/medical-information.js @@ -491,36 +491,54 @@ const toCheckboxArray = (value) => { return value ? [value] : [] } +/** + * Read the pregnancy and breastfeeding answers off an appointment's medical + * information + * + * A checkbox group stores a bare string when one box is ticked and an array + * when several are, so reading it here means callers get one shape to work + * with rather than repeating the coercion. + * + * @param {Object} medicalInformation - The medicalInformation object from appointment + * @returns {{values: Array, summaries: Array, options: Array}} + */ +const getPregnancyAndBreastfeeding = (medicalInformation) => { + return { + values: toCheckboxArray(medicalInformation?.pregnancyAndBreastfeeding), + summaries: summarisePregnancyAndBreastfeeding(medicalInformation), + options: pregnancyAndBreastfeedingOptions + } +} + /** * Read the breast density factors off an appointment's medical information * * Breast density factors are a display grouping rather than a stored object - * they pull together the separately stored HRT answer and pregnancy and - * breastfeeding answers. Reading them here means templates get a single shape - * to work with rather than repeating the coercion at every call site. + * breastfeeding answers. * * @param {Object} medicalInformation - The medicalInformation object from appointment - * @returns {{factors: Array, hrt: Object, count: number, answeredCount: number, summaries: Array, factorSummaries: Array, options: Array}} + * @returns {{hrt: Object, hrtSummary: string|null, pregnancyAndBreastfeeding: Object, count: number, answeredCount: number, summaries: Array}} */ const getBreastDensityFactors = (medicalInformation) => { - const factors = toCheckboxArray(medicalInformation?.pregnancyAndBreastfeeding) const hrt = medicalInformation?.hrt || {} + const pregnancyAndBreastfeeding = + getPregnancyAndBreastfeeding(medicalInformation) const summaries = summariseBreastDensityFactors(medicalInformation) return { - factors, hrt, + hrtSummary: summariseHrt(medicalInformation), + pregnancyAndBreastfeeding, // "Not taking HRT" is an answer, but it isn't a density factor - only // count the things that actually affect density - count: (hrt.status === 'yes' ? 1 : 0) + factors.length, + count: + (hrt.status === 'yes' ? 1 : 0) + pregnancyAndBreastfeeding.values.length, // Everything worth showing, including a recorded "no" to the HRT question - // use this to decide whether to show the row at all answeredCount: summaries.length, - summaries, - factorSummaries: summarisePregnancyAndBreastfeeding(medicalInformation), - hrtSummary: summariseHrt(medicalInformation), - options: pregnancyAndBreastfeedingOptions + summaries } } @@ -615,6 +633,7 @@ module.exports = { summariseBreastFeature, summariseBreastFeatures, getBreastDensityFactors, + getPregnancyAndBreastfeeding, summariseBreastDensityFactors, summarisePregnancyAndBreastfeeding, summariseHrt, diff --git a/app/views/_includes/forms/breast-density-factors.njk b/app/views/_includes/forms/breast-density-factors.njk index e75d1981..5b572d04 100644 --- a/app/views/_includes/forms/breast-density-factors.njk +++ b/app/views/_includes/forms/breast-density-factors.njk @@ -15,6 +15,7 @@ #} {% set breastDensityFactors = appointment.medicalInformation | getBreastDensityFactors %} +{% set pregnancyAndBreastfeeding = breastDensityFactors.pregnancyAndBreastfeeding %} {% set hrtQuestion = "Is " + participant.demographicInformation.firstName + " currently taking HRT?" %} @@ -81,14 +82,14 @@ {% endset %} {% set pregnancyAndBreastfeedingSummaryHtml %} - {% if breastDensityFactors.factorSummaries | length > 1 %} + {% if pregnancyAndBreastfeeding.summaries | length > 1 %}
        - {% for summary in breastDensityFactors.factorSummaries %} + {% for summary in pregnancyAndBreastfeeding.summaries %}
      • {{ summary }}
      • {% endfor %}
      - {% elseif breastDensityFactors.factorSummaries | length %} -

      {{ breastDensityFactors.factorSummaries | first }}

      + {% elseif pregnancyAndBreastfeeding.summaries | length %} +

      {{ pregnancyAndBreastfeeding.summaries | first }}

      {% else %}

      No

      {% endif %} @@ -115,7 +116,7 @@ } ] %} -{% if breastDensityFactors.factors | length %} +{% if pregnancyAndBreastfeeding.values | length %} {% set breastDensityRows = breastDensityRows | push({ key: { text: "Pregnancy and breastfeeding" @@ -134,11 +135,11 @@ lastRowBorder: false, attributes: { "data-breast-density-factors-save-url": contextUrl + "/medical-information/hrt-save", - "data-breast-density-factor-count": breastDensityFactors.factors | length + "data-breast-density-factor-count": pregnancyAndBreastfeeding.values | length } }) }} -{% if allowEdits and not breastDensityFactors.factors | length %} +{% if allowEdits and not pregnancyAndBreastfeeding.values | length %}

      {{ button({ text: "Add pregnancy and breastfeeding", diff --git a/app/views/appointments/medical-information/pregnancy-and-breastfeeding.html b/app/views/appointments/medical-information/pregnancy-and-breastfeeding.html index b155141a..22523693 100644 --- a/app/views/appointments/medical-information/pregnancy-and-breastfeeding.html +++ b/app/views/appointments/medical-information/pregnancy-and-breastfeeding.html @@ -10,7 +10,7 @@ {% block pageContent %} - {% set breastDensityFactors = appointment.medicalInformation | getBreastDensityFactors %} + {% set pregnancyAndBreastfeeding = appointment.medicalInformation | getPregnancyAndBreastfeeding %}

      @@ -21,7 +21,7 @@

      {{ checkboxes({ name: "appointment[medicalInformation][pregnancyAndBreastfeeding]", - values: breastDensityFactors.factors, + values: pregnancyAndBreastfeeding.values, classes: "nhsuk-checkboxes--small", fieldset: { legend: { @@ -29,14 +29,14 @@

      classes: "nhsuk-fieldset__legend--s" } }, - items: breastDensityFactors.options + items: pregnancyAndBreastfeeding.options }) }} {{ button({ text: "Save" }) }} - {% if breastDensityFactors.factors | length %} + {% if pregnancyAndBreastfeeding.values | length %} {% set deleteHref %} ./pregnancy-and-breastfeeding/delete{{ "" | urlWithReferrer(referrerChain, query.scrollTo) }} {% endset %} From f908677233cf488f552c3f991e4bb2c3b1b11eb5 Mon Sep 17 00:00:00 2001 From: Ed Horsford Date: Fri, 4 Sep 2026 11:01:01 +0100 Subject: [PATCH 11/11] Count a recorded "no" to HRT as a breast density factor Recently stopping HRT matters as much as currently taking it, so every recorded answer counts. That makes count and answeredCount the same number, so there's now just one. --- app/assets/javascript/main.js | 6 +++--- app/lib/utils/medical-information.js | 17 ++++++----------- .../summary-lists/medical-info-summary.njk | 4 ++-- 3 files changed, 11 insertions(+), 16 deletions(-) diff --git a/app/assets/javascript/main.js b/app/assets/javascript/main.js index 6d8c9957..36ab1ee7 100644 --- a/app/assets/javascript/main.js +++ b/app/assets/javascript/main.js @@ -171,7 +171,7 @@ function setupBreastDensityFactorsAutosave() { // Only the review page wraps these in an expander, so this does nothing // elsewhere. Pregnancy and breastfeeding is edited on its own page, so its // count comes from the server - match getBreastDensityFactors so the two - // never disagree + // never disagree, answering "no" to HRT included const updateContentsSummary = () => { const summary = container .closest('.js-expandable-section') @@ -182,8 +182,8 @@ function setupBreastDensityFactorsAutosave() { } const factorCount = Number(container.dataset.breastDensityFactorCount) || 0 - const takingHrt = container.querySelector(`input[name="${statusName}"]:checked`)?.value === 'yes' - const count = factorCount + (takingHrt ? 1 : 0) + const hrtAnswered = !!container.querySelector(`input[name="${statusName}"]:checked`) + const count = factorCount + (hrtAnswered ? 1 : 0) if (count === 0) { summary.textContent = 'No breast density factors added' diff --git a/app/lib/utils/medical-information.js b/app/lib/utils/medical-information.js index 3efefff7..799074fe 100644 --- a/app/lib/utils/medical-information.js +++ b/app/lib/utils/medical-information.js @@ -518,27 +518,22 @@ const getPregnancyAndBreastfeeding = (medicalInformation) => { * breastfeeding answers. * * @param {Object} medicalInformation - The medicalInformation object from appointment - * @returns {{hrt: Object, hrtSummary: string|null, pregnancyAndBreastfeeding: Object, count: number, answeredCount: number, summaries: Array}} + * @returns {{hrt: Object, hrtSummary: string|null, pregnancyAndBreastfeeding: Object, count: number, summaries: Array}} */ const getBreastDensityFactors = (medicalInformation) => { const hrt = medicalInformation?.hrt || {} const pregnancyAndBreastfeeding = getPregnancyAndBreastfeeding(medicalInformation) - const summaries = summariseBreastDensityFactors(medicalInformation) - return { hrt, hrtSummary: summariseHrt(medicalInformation), pregnancyAndBreastfeeding, - // "Not taking HRT" is an answer, but it isn't a density factor - only - // count the things that actually affect density - count: - (hrt.status === 'yes' ? 1 : 0) + pregnancyAndBreastfeeding.values.length, - // Everything worth showing, including a recorded "no" to the HRT question - - // use this to decide whether to show the row at all - answeredCount: summaries.length, - summaries + // Every recorded answer counts, a "no" to HRT included - recently stopping + // matters as much as currently taking it. Use this to decide whether to + // show the section at all, and for the "n added" line + count: (hrt.status ? 1 : 0) + pregnancyAndBreastfeeding.values.length, + summaries: summariseBreastDensityFactors(medicalInformation) } } diff --git a/app/views/_includes/summary-lists/medical-info-summary.njk b/app/views/_includes/summary-lists/medical-info-summary.njk index 6c5cfce7..4ee0624b 100644 --- a/app/views/_includes/summary-lists/medical-info-summary.njk +++ b/app/views/_includes/summary-lists/medical-info-summary.njk @@ -129,8 +129,8 @@ {# Breast density factors summary #} {% set breastDensityFactors = appointment.medicalInformation | getBreastDensityFactors %} -{# Show the row whenever there's an answer to show, including "not started a course of HRT since last screening appointment" #} -{% set breastDensityCount = breastDensityFactors.answeredCount %} +{# Show the row whenever there's an answer to show, a recorded "no" to HRT included #} +{% set breastDensityCount = breastDensityFactors.count %} {% set breastDensityFactorsHtml %} {% if breastDensityFactors.summaries | length %}