From 2a8c48a18445588dcfbbdaa02ab2b52cebc2a658 Mon Sep 17 00:00:00 2001 From: Caitlin Roach Date: Tue, 16 Jun 2026 16:14:41 +0100 Subject: [PATCH 01/31] Add empty state for no pharmacies --- app/routes/prototype-admin.js | 14 +++ .../includes/_preset-scenarios-table.html | 8 ++ app/views/pharmacies/index.html | 116 +++++++++--------- 3 files changed, 81 insertions(+), 57 deletions(-) diff --git a/app/routes/prototype-admin.js b/app/routes/prototype-admin.js index b2401748..2bd6777f 100644 --- a/app/routes/prototype-admin.js +++ b/app/routes/prototype-admin.js @@ -564,6 +564,20 @@ module.exports = (router) => { res.redirect('/home') }) + // ---------------------------------------------------------------- + // Preset: Pharmacy HQ, no data (Amanda White, P15951) + // ---------------------------------------------------------------- + + router.get('/prototype-setup/preset/pharmacy-hq-no-data', (req, res) => { + resetSession(req) + const data = req.session.data + data.currentUserId = '6424325235325' + data.currentOrganisationId = 'P15951' + // Remove all pharmacies belonging to P15951 to start with a clean slate + data.organisations = data.organisations.filter(org => org.companyId !== 'P15951' || org.type === 'Pharmacy HQ') + res.redirect('/home') + }) + // ---------------------------------------------------------------- // Preset: Recorder, single organisation (Ocean Merritt, FR4V56) // ---------------------------------------------------------------- diff --git a/app/views/includes/_preset-scenarios-table.html b/app/views/includes/_preset-scenarios-table.html index 3d9bd63b..05a98cf7 100644 --- a/app/views/includes/_preset-scenarios-table.html +++ b/app/views/includes/_preset-scenarios-table.html @@ -71,6 +71,14 @@ role: "Group administrator", scenarioDetails: "Group admin for a large pharmacy chain (same-name pharmacies)." }, + { + presetLabel: "Group admin, pharmacy HQ (no data)", + presetPath: "/prototype-setup/preset/pharmacy-hq-no-data", + userName: "Amanda White", + userEmail: "amanda.white@nhs.net", + role: "Group administrator", + scenarioDetails: "Group admin for a pharmacy HQ with no pre-loaded data, pharmacies or users." + }, { presetLabel: "Regional lead", presetPath: "/prototype-setup/preset/regions", diff --git a/app/views/pharmacies/index.html b/app/views/pharmacies/index.html index b033a9bf..ac9ab6ff 100644 --- a/app/views/pharmacies/index.html +++ b/app/views/pharmacies/index.html @@ -43,65 +43,67 @@

Pharmacies

href: "/pharmacies/select" }) }} - - -
Pharmacies added ({{ organisations | length }})
- {% if (organisations | length) > 10 %} -
- - -
- {% endif %} - - - - - - - - - - - - {% for organisation in organisations %} - - - - - - + {% if (organisations | length) > 0 %} +
- Name - - Vaccines - - Users - - Status - - Actions -
- {{ organisation.name }} ({{ organisation.id}}) - - {% set vaccinesEnabled = [] %} - {% for vaccine in organisation.vaccines %} - {% if vaccine.status == "enabled" %} - {% set vaccinesEnabled = (vaccinesEnabled.push(vaccine.name), vaccinesEnabled) %} - {% endif %} - {% endfor %} - - {{ (vaccinesEnabled | sort | join(", ")) | capitaliseFirstLetter }} - - {{ organisationUserCounts[organisation.id] }} - - {{ organisation.status }} - - Manage -
+ +
Pharmacies added ({{ organisations | length }})
+ {% if (organisations | length) > 10 %} +
+ + +
+ {% endif %} + + + + + + + + - {% endfor %} + + + {% for organisation in organisations %} + + + + + + + + {% endfor %} - -
+ Name + + Vaccines + + Users + + Status + + Actions +
+ {{ organisation.name }} ({{ organisation.id}}) + + {% set vaccinesEnabled = [] %} + {% for vaccine in organisation.vaccines %} + {% if vaccine.status == "enabled" %} + {% set vaccinesEnabled = (vaccinesEnabled.push(vaccine.name), vaccinesEnabled) %} + {% endif %} + {% endfor %} + + {{ (vaccinesEnabled | sort | join(", ")) | capitaliseFirstLetter }} + + {{ organisationUserCounts[organisation.id] }} + + {{ organisation.status }} + + Manage +
+ + + {% endif %} {% if closedOrganisations.length > 0 %}
From a4cdaf808f0028398c9ec832fb6b18cd982a0f75 Mon Sep 17 00:00:00 2001 From: Caitlin Roach Date: Tue, 21 Jul 2026 16:30:23 +0100 Subject: [PATCH 02/31] Add ability to change vaccs --- app/assets/sass/components/_summary-list.scss | 11 ++++ app/routes/pharmacies.js | 56 +++++++++++++++++++ app/views/pharmacies/edit-vaccines.html | 45 +++++++++++++++ app/views/pharmacies/pharmacy.html | 46 ++++++++++++++- 4 files changed, 156 insertions(+), 2 deletions(-) create mode 100644 app/views/pharmacies/edit-vaccines.html diff --git a/app/assets/sass/components/_summary-list.scss b/app/assets/sass/components/_summary-list.scss index 14a7467f..e9ca4304 100644 --- a/app/assets/sass/components/_summary-list.scss +++ b/app/assets/sass/components/_summary-list.scss @@ -2,3 +2,14 @@ margin-top: nhsuk-spacing(2); color: $nhsuk-secondary-text-colour; } + +@include nhsuk-media-query($from: tablet) { + .app-pharmacy-summary-list .nhsuk-summary-list__value { + width: 35%; + } + + .app-pharmacy-summary-list__actions { + width: 35%; + white-space: nowrap; + } +} diff --git a/app/routes/pharmacies.js b/app/routes/pharmacies.js index 20638aa4..c0e41cac 100644 --- a/app/routes/pharmacies.js +++ b/app/routes/pharmacies.js @@ -1236,6 +1236,60 @@ module.exports = router => { } }) + router.get('/pharmacies/:id/edit-vaccines', (req, res) => { + const data = req.session.data + const { id } = req.params + const organisation = data.organisations.find((org) => org.id === id) + + if (!organisation) { + return res.redirect('/pharmacies') + } + + const enabledVaccineNames = (organisation.vaccines || []) + .filter((vaccine) => vaccine.status === 'enabled') + .map((vaccine) => vaccine.name) + + res.render('pharmacies/edit-vaccines', { + organisation, + allVaccines: data.vaccines || [], + enabledVaccineNames + }) + }) + + router.post('/pharmacies/:id/update-vaccines', (req, res) => { + const data = req.session.data + const { id } = req.params + const organisation = data.organisations.find((org) => org.id === id) + + if (!organisation) { + return res.redirect('/pharmacies') + } + + const selectedVaccinesRaw = req.body.vaccinesEnabled + const selectedVaccines = Array.isArray(selectedVaccinesRaw) + ? selectedVaccinesRaw + : (selectedVaccinesRaw ? [selectedVaccinesRaw] : []) + + organisation.vaccines ||= [] + const allVaccineNames = (data.vaccines || []).map((vaccine) => vaccine.name) + + for (const vaccineName of allVaccineNames) { + const existingVaccine = organisation.vaccines.find((vaccine) => vaccine.name === vaccineName) + const isSelected = selectedVaccines.includes(vaccineName) + + if (existingVaccine) { + existingVaccine.status = isSelected ? 'enabled' : 'disabled' + } else if (isSelected) { + organisation.vaccines.push({ + name: vaccineName, + status: 'enabled' + }) + } + } + + return res.redirect(`/pharmacies/${id}?vaccinesUpdated=true`) + }) + router.get('/pharmacies/:id', async (req, res) => { const data = req.session.data @@ -1247,6 +1301,7 @@ module.exports = router => { const deactivatedFromPharmacyId = req.query.deactivatedFromPharmacyId const reactivatedUserId = req.query.reactivatedUserId const reactivatedFromPharmacyId = req.query.reactivatedFromPharmacyId + const vaccinesUpdated = req.query.vaccinesUpdated const tab = (req.query.tab || 'active').toLowerCase() @@ -1329,6 +1384,7 @@ module.exports = router => { deactivatedFromPharmacyId, reactivatedUser, reactivatedFromPharmacyId, + vaccinesUpdated, canDeletePharmacy }) }) diff --git a/app/views/pharmacies/edit-vaccines.html b/app/views/pharmacies/edit-vaccines.html new file mode 100644 index 00000000..1a9a9903 --- /dev/null +++ b/app/views/pharmacies/edit-vaccines.html @@ -0,0 +1,45 @@ +{% extends 'layout.html' %} + +{% set currentSection = "pharmacies" %} +{% set pageName = "Edit vaccines for " + organisation.name %} + +{% block beforeContent %} + {{ backLink({ + href: "/pharmacies/" + organisation.id, + text: "Back" + }) }} +{% endblock %} + +{% block content %} +
+
+
+ {% set items = [] %} + + {% for vaccine in (allVaccines | sort(false, false, "name")) %} + {% set items = (items.push({ + value: vaccine.name, + text: (vaccine.name | capitaliseFirstLetter) + }), items) %} + {% endfor %} + + {{ checkboxes({ + name: "vaccinesEnabled", + fieldset: { + legend: { + text: "Which vaccines can this pharmacy record?", + size: "l", + isPageHeading: true + } + }, + items: items, + values: enabledVaccineNames + }) }} + + {{ button({ + text: "Save changes" + }) }} +
+
+
+{% endblock %} diff --git a/app/views/pharmacies/pharmacy.html b/app/views/pharmacies/pharmacy.html index 3e2f7268..b1f00c0a 100644 --- a/app/views/pharmacies/pharmacy.html +++ b/app/views/pharmacies/pharmacy.html @@ -70,6 +70,20 @@

}) }} {% endif %} + {% if vaccinesUpdated == "true" %} + {% set html %} +

+ Vaccines changed +

+

The vaccines for {{ organisation.name }} have been updated.

+ {% endset %} + + {{ notificationBanner({ + html: html, + type: "success" + }) }} + {% endif %} +

{{ pageName }}

{% set addressParts = [] %} @@ -83,7 +97,25 @@

{{ pageName }}

{% set addressParts = (addressParts.push(organisation.address.postcode), addressParts) %} {% endif %} + {% set addressHtml = addressParts | join(", ") %} + {% if organisation.address.line1 and organisation.address.town %} + {% set addressHtml = addressHtml | replace(", ", ",
") %} + {% endif %} + + {% set vaccinesEnabled = [] %} + {% for vaccine in (organisation.vaccines or []) %} + {% if vaccine.status == "enabled" %} + {% set vaccinesEnabled = (vaccinesEnabled.push(vaccine.name), vaccinesEnabled) %} + {% endif %} + {% endfor %} + + {% set vaccinesText = "None" %} + {% if (vaccinesEnabled | length) > 0 %} + {% set vaccinesText = (vaccinesEnabled | sort | join(", ")) | capitaliseFirstLetter %} + {% endif %} + {{ summaryList({ + classes: "app-pharmacy-summary-list", rows: [ { key: { @@ -98,7 +130,7 @@

{{ pageName }}

text: "Address" }, value: { - text: addressParts | join(", ") + html: addressHtml } }, { @@ -106,7 +138,17 @@

{{ pageName }}

text: "Vaccines" }, value: { - text: "COVID-19, flu" + text: vaccinesText + }, + actions: { + classes: "app-pharmacy-summary-list__actions", + items: [ + { + href: "/pharmacies/" + organisation.id + "/edit-vaccines", + text: "Edit vaccines", + visuallyHiddenText: "vaccines for " + organisation.name + } + ] } } ] From 661fa754d6fbbeaf21ba11144bd4ecbcef42702d Mon Sep 17 00:00:00 2001 From: Caitlin Roach Date: Thu, 23 Jul 2026 12:45:50 +0100 Subject: [PATCH 03/31] page layout --- app/assets/sass/components/_related-nav.scss | 1 + app/assets/sass/components/_summary-list.scss | 11 - app/assets/sass/main.scss | 96 ++++++ .../_secondary-navigation.scss | 29 ++ .../x-govuk-secondary-navigation/macro.njk | 3 + .../x-govuk-secondary-navigation/template.njk | 16 + .../x-govuk-sub-navigation/macro.njk | 3 + .../x-govuk-sub-navigation/template.njk | 33 ++ app/routes/pharmacies.js | 22 +- app/views/layout.html | 2 + app/views/pharmacies/pharmacy.html | 291 +++++++++++------- package-lock.json | 151 ++++++++- package.json | 1 + 13 files changed, 528 insertions(+), 131 deletions(-) create mode 100644 app/components/x-govuk-secondary-navigation/macro.njk create mode 100644 app/components/x-govuk-secondary-navigation/template.njk create mode 100644 app/components/x-govuk-sub-navigation/macro.njk create mode 100644 app/components/x-govuk-sub-navigation/template.njk diff --git a/app/assets/sass/components/_related-nav.scss b/app/assets/sass/components/_related-nav.scss index 77deba5e..bf6dc5d1 100755 --- a/app/assets/sass/components/_related-nav.scss +++ b/app/assets/sass/components/_related-nav.scss @@ -23,3 +23,4 @@ list-style: none; padding-left: 0; } + diff --git a/app/assets/sass/components/_summary-list.scss b/app/assets/sass/components/_summary-list.scss index e9ca4304..14a7467f 100644 --- a/app/assets/sass/components/_summary-list.scss +++ b/app/assets/sass/components/_summary-list.scss @@ -2,14 +2,3 @@ margin-top: nhsuk-spacing(2); color: $nhsuk-secondary-text-colour; } - -@include nhsuk-media-query($from: tablet) { - .app-pharmacy-summary-list .nhsuk-summary-list__value { - width: 35%; - } - - .app-pharmacy-summary-list__actions { - width: 35%; - white-space: nowrap; - } -} diff --git a/app/assets/sass/main.scss b/app/assets/sass/main.scss index 974636a5..66c4e7d1 100755 --- a/app/assets/sass/main.scss +++ b/app/assets/sass/main.scss @@ -1,5 +1,6 @@ // Import NHS.UK frontend library @import "nhsuk-frontend/dist/nhsuk"; +@import "../../../node_modules/@x-govuk/govuk-prototype-components/src/x-govuk"; // Local override classes @import 'overrides'; @@ -149,3 +150,98 @@ border-radius: 3px; .nhsuk-checkboxes__item[hidden] { display: none; } + +.x-govuk-sub-navigation__section-item--current { + background-color: transparent; +} + +.app-pharmacy-back-link { + margin-bottom: 24px; +} + +.app-pharmacy-page-title { + margin-bottom: nhsuk-spacing(6); +} + +@include nhsuk-media-query($from: tablet) { + .app-pharmacy-back-link { + margin-bottom: 48px; + } +} + +.app-section-navigation { + margin-bottom: nhsuk-spacing(4); +} + +.app-section-navigation__list { + @include nhsuk-font(19); + + display: flex; + flex-flow: row nowrap; + gap: nhsuk-spacing(1) nhsuk-spacing(2); + list-style: none; + margin: 0; + padding: 0; + box-shadow: inset 0 -1px $nhsuk-border-colour; + overflow-x: auto; +} + +.app-section-navigation__item { + margin: 0; +} + +.app-section-navigation__link { + @include nhsuk-link-style-default; + @include nhsuk-link-style-no-visited-state; + + display: block; + padding: nhsuk-spacing(2) 2px; + text-decoration: none; + white-space: nowrap; +} + +.app-section-navigation__link[aria-current="page"] { + box-shadow: inset 0 -4px $nhsuk-link-colour; +} + +.app-section-navigation__link[aria-current="page"]:focus { + box-shadow: inset 0 -4px $nhsuk-text-colour; +} + +.app-section-navigation__current { + font-weight: 700; +} + +@include nhsuk-media-query($from: tablet) { + .app-section-navigation--vertical { + margin-right: -#{nhsuk-spacing(2)}; + margin-left: -#{nhsuk-spacing(2)}; + } + + .app-section-navigation--vertical .app-section-navigation__list { + flex-flow: column; + gap: 0; + box-shadow: none; + overflow: visible; + } + + .app-section-navigation--vertical .app-section-navigation__item { + border-left: 4px solid transparent; + } + + .app-section-navigation--vertical .app-section-navigation__item--current { + border-left-color: $nhsuk-link-colour; + } + + .app-section-navigation--vertical .app-section-navigation__link { + padding: nhsuk-spacing(1) nhsuk-spacing(2) nhsuk-spacing(1) calc(#{nhsuk-spacing(2)} + 4px); + } + + .app-section-navigation--vertical .app-section-navigation__link[aria-current="page"] { + box-shadow: none; + } + + .app-section-navigation--vertical .app-section-navigation__link[aria-current="page"]:focus { + box-shadow: inset 0 -4px $nhsuk-text-colour; + } +} diff --git a/app/components/secondary-navigation/_secondary-navigation.scss b/app/components/secondary-navigation/_secondary-navigation.scss index f89d0389..5c623916 100644 --- a/app/components/secondary-navigation/_secondary-navigation.scss +++ b/app/components/secondary-navigation/_secondary-navigation.scss @@ -62,3 +62,32 @@ padding-bottom: nhsuk-spacing(4) - $_current-link-border-width; } } + + .app-secondary-navigation--side { + border-bottom: 0; + border-left: 4px solid $nhsuk-border-colour; + margin-bottom: nhsuk-spacing(6); + padding-left: nhsuk-spacing(3); + } + + .app-secondary-navigation--side .app-secondary-navigation__list { + @include nhsuk-font(19); + + display: block; + margin-bottom: 0; + } + + .app-secondary-navigation--side .app-secondary-navigation__list-item { + margin: 0 0 nhsuk-spacing(2); + padding: 0; + } + + .app-secondary-navigation--side .app-secondary-navigation__list-item:not(:last-child) { + margin-right: 0; + } + + .app-secondary-navigation--side .app-secondary-navigation__list-item--current { + border-left-width: $_current-link-border-width; + margin-left: ((nhsuk-spacing(2) + $_current-link-border-width) * -1); + padding-left: nhsuk-spacing(2); + } diff --git a/app/components/x-govuk-secondary-navigation/macro.njk b/app/components/x-govuk-secondary-navigation/macro.njk new file mode 100644 index 00000000..d2b639cc --- /dev/null +++ b/app/components/x-govuk-secondary-navigation/macro.njk @@ -0,0 +1,3 @@ +{% macro xGovukSecondaryNavigation(params) %} + {%- include "./template.njk" -%} +{% endmacro %} diff --git a/app/components/x-govuk-secondary-navigation/template.njk b/app/components/x-govuk-secondary-navigation/template.njk new file mode 100644 index 00000000..dd4fc4f6 --- /dev/null +++ b/app/components/x-govuk-secondary-navigation/template.njk @@ -0,0 +1,16 @@ +{% from "../../../node_modules/nhsuk-frontend/dist/nhsuk/macros/attributes.njk" import nhsukAttributes %} + + diff --git a/app/components/x-govuk-sub-navigation/macro.njk b/app/components/x-govuk-sub-navigation/macro.njk new file mode 100644 index 00000000..d35b4300 --- /dev/null +++ b/app/components/x-govuk-sub-navigation/macro.njk @@ -0,0 +1,3 @@ +{% macro xGovukSubNavigation(params) %} + {%- include "./template.njk" -%} +{% endmacro %} diff --git a/app/components/x-govuk-sub-navigation/template.njk b/app/components/x-govuk-sub-navigation/template.njk new file mode 100644 index 00000000..7fa95c7d --- /dev/null +++ b/app/components/x-govuk-sub-navigation/template.njk @@ -0,0 +1,33 @@ +{% from "../../../node_modules/nhsuk-frontend/dist/nhsuk/macros/attributes.njk" import nhsukAttributes -%} + + diff --git a/app/routes/pharmacies.js b/app/routes/pharmacies.js index c0e41cac..9e3539f9 100644 --- a/app/routes/pharmacies.js +++ b/app/routes/pharmacies.js @@ -846,7 +846,7 @@ module.exports = router => { req.session.data.permissionLevel = '' req.session.data.vaccinator = '' - res.redirect(`/pharmacies/${organisation.id}?added=true&addedUserId=${addedUserId}&tab=${existingUser ? 'active' : 'invited'}`) + res.redirect(`/pharmacies/${organisation.id}?section=users&added=true&addedUserId=${addedUserId}&tab=${existingUser ? 'active' : 'invited'}`) }) @@ -905,7 +905,7 @@ module.exports = router => { return res.redirect(`/pharmacies/users/${user.id}?deactivatedFromPharmacyId=${pharmacy.id}`) } - res.redirect(`/pharmacies/${pharmacy.id}?tab=deactivated&deactivatedUserId=${user.id}&deactivatedFromPharmacyId=${pharmacy.id}`) + res.redirect(`/pharmacies/${pharmacy.id}?section=users&tab=deactivated&deactivatedUserId=${user.id}&deactivatedFromPharmacyId=${pharmacy.id}`) }) @@ -934,7 +934,7 @@ module.exports = router => { } if (!user) { - return res.redirect(`/pharmacies/${pharmacyId}?tab=invited`) + return res.redirect(`/pharmacies/${pharmacyId}?section=users&tab=invited`) } res.render('pharmacies/users/resend-invite', { @@ -958,12 +958,12 @@ module.exports = router => { const role = (user.organisations || []).find((item) => item.id === pharmacyId) if (!role) { - return res.redirect(`/pharmacies/${pharmacyId}?tab=invited`) + return res.redirect(`/pharmacies/${pharmacyId}?section=users&tab=invited`) } role.inviteSent = new Date().toISOString() - res.redirect(`/pharmacies/${pharmacyId}?tab=invited`) + res.redirect(`/pharmacies/${pharmacyId}?section=users&tab=invited`) }) router.get('/pharmacies/:pharmacyId/users/:userId/reactivate', (req, res) => { @@ -992,13 +992,13 @@ module.exports = router => { } if (!user) { - return res.redirect(`/pharmacies/${pharmacyId}?tab=deactivated`) + return res.redirect(`/pharmacies/${pharmacyId}?section=users&tab=deactivated`) } const role = (user.organisations || []).find((item) => item.id === pharmacyId) if (!role) { - return res.redirect(`/pharmacies/${pharmacyId}?tab=deactivated`) + return res.redirect(`/pharmacies/${pharmacyId}?section=users&tab=deactivated`) } role.status = 'Active' @@ -1006,7 +1006,7 @@ module.exports = router => { user.lastLogIn = new Date().toISOString().split('T')[0] } - res.redirect(`/pharmacies/${pharmacyId}?tab=active&reactivatedUserId=${userId}&reactivatedFromPharmacyId=${pharmacyId}`) + res.redirect(`/pharmacies/${pharmacyId}?section=users&tab=active&reactivatedUserId=${userId}&reactivatedFromPharmacyId=${pharmacyId}`) }) router.get('/pharmacies/users/:userId/deactivate-from-all-pharmacies', (req, res) => { @@ -1303,6 +1303,7 @@ module.exports = router => { const reactivatedFromPharmacyId = req.query.reactivatedFromPharmacyId const vaccinesUpdated = req.query.vaccinesUpdated const tab = (req.query.tab || 'active').toLowerCase() + const section = (req.query.section || 'overview').toLowerCase() const organisation = data.organisations.find((organisation) => organisation.id === id) @@ -1369,6 +1370,8 @@ module.exports = router => { const validTabs = ['invited', 'active', 'deactivated'] const currentTab = validTabs.includes(tab) ? tab : 'active' + const validSections = ['overview', 'users', 'vaccines', 'action'] + const currentPageSection = validSections.includes(section) ? section : 'overview' const usersForTab = usersByStatus[currentTab] res.render('pharmacies/pharmacy', { @@ -1385,7 +1388,8 @@ module.exports = router => { reactivatedUser, reactivatedFromPharmacyId, vaccinesUpdated, - canDeletePharmacy + canDeletePharmacy, + currentPageSection }) }) diff --git a/app/views/layout.html b/app/views/layout.html index 37250045..81bd06d5 100755 --- a/app/views/layout.html +++ b/app/views/layout.html @@ -8,6 +8,8 @@ {% extends "prototype-kit-template.njk" %} {% from '../components/secondary-navigation/macro.njk' import appSecondaryNavigation %} +{% from '../components/x-govuk-secondary-navigation/macro.njk' import xGovukSecondaryNavigation %} +{% from '../components/x-govuk-sub-navigation/macro.njk' import xGovukSubNavigation %} {% block head %} diff --git a/app/views/pharmacies/pharmacy.html b/app/views/pharmacies/pharmacy.html index b1f00c0a..e42fb5d5 100644 --- a/app/views/pharmacies/pharmacy.html +++ b/app/views/pharmacies/pharmacy.html @@ -3,17 +3,20 @@ {% set currentSection = "pharmacies" %} {% set pageName = organisation.name %} +{% set mainClasses = "nhsuk-u-padding-top-0" %} {% block beforeContent %} - {{ backLink({ - href: "/pharmacies" - }) }} {% endblock %} {% block content %}
+ {{ backLink({ + href: "/pharmacies", + classes: "app-pharmacy-back-link" + }) }} + {% if added %} {% set html %}

@@ -84,7 +87,7 @@

}) }} {% endif %} -

{{ pageName }}

+

{{ pageName }} ({{ organisation.id }})

{% set addressParts = [] %} {% if organisation.address.line1 %} @@ -97,10 +100,7 @@

{{ pageName }}

{% set addressParts = (addressParts.push(organisation.address.postcode), addressParts) %} {% endif %} - {% set addressHtml = addressParts | join(", ") %} - {% if organisation.address.line1 and organisation.address.town %} - {% set addressHtml = addressHtml | replace(", ", ",
") %} - {% endif %} + {% set addressText = addressParts | join(", ") %} {% set vaccinesEnabled = [] %} {% for vaccine in (organisation.vaccines or []) %} @@ -113,104 +113,116 @@

{{ pageName }}

{% if (vaccinesEnabled | length) > 0 %} {% set vaccinesText = (vaccinesEnabled | sort | join(", ")) | capitaliseFirstLetter %} {% endif %} - - {{ summaryList({ - classes: "app-pharmacy-summary-list", - rows: [ - { - key: { - text: "ODS code" - }, - value: { - text: organisation.id - } - }, - { - key: { - text: "Address" - }, - value: { - html: addressHtml - } - }, - { - key: { - text: "Vaccines" - }, - value: { - text: vaccinesText - }, - actions: { - classes: "app-pharmacy-summary-list__actions", - items: [ - { - href: "/pharmacies/" + organisation.id + "/edit-vaccines", - text: "Edit vaccines", - visuallyHiddenText: "vaccines for " + organisation.name - } - ] - } - } - ] - }) }} - - {% if organisation.status != 'Deactivated' %} - {{ button({ - href: "/pharmacies/" + organisation.id + "/view-as", - text: "Access this pharmacy", - classes: "nhsuk-button--secondary" - }) }} - {% endif %} - - {% if organisation.status == 'Deactivated' %} -

This pharmacy has been deactivated.

- -

It will be closed in 90 days.

- {% elif canDeletePharmacy %} -

This pharmacy has not yet recorded any vaccinations. You can delete it if you added it by mistake.

-

Delete this pharmacy

- {% else %} -

If a pharmacy is no longer using Record a vaccination, you should deactivate it.

- -

Deactivate this pharmacy

- - {% endif %} - -

Users

- - {% if organisation.status != 'Deactivated' %} - {{ button({ - href: "/pharmacies/" + organisation.id + "/add-user", - text: "Add user" - }) }} - {% endif %} - - {% set totalUsers = (usersByStatus.invited | length) + (usersByStatus.active | length) + (usersByStatus.deactivated | length) %} - - {% if totalUsers > 0 %} - - {{ appSecondaryNavigation({ - visuallyHiddenTitle: "Users by status", - items: [{ - text: "Invited (" + (usersByStatus.invited | length) + ")", - href: "/pharmacies/" + organisation.id + "?tab=invited", - current: (currentTab == "invited") - }, { - text: "Active (" + (usersByStatus.active | length) + ")", - href: "/pharmacies/" + organisation.id + "?tab=active", - current: (currentTab == "active") - }, { - text: "Deactivated (" + (usersByStatus.deactivated | length) + ")", - href: "/pharmacies/" + organisation.id + "?tab=deactivated", - current: (currentTab == "deactivated") - }] - }) }}
-
-
- {% if (users | length) > 0 %} +
+
+ {% set actionNavText = "Overview" %} + {% if canDeletePharmacy %} + {% set actionNavText = "Delete pharmacy" %} + {% elif organisation.status != 'Deactivated' %} + {% set actionNavText = "Deactivate pharmacy" %} + {% endif %} + + +
+
+
+
+ + {% if currentPageSection == "overview" %} + +

Overview

+ + {{ summaryList({ + rows: [ + { + key: { + text: "ODS code" + }, + value: { + text: organisation.id + } + }, + { + key: { + text: "Address" + }, + value: { + text: addressText + } + }, + { + key: { + text: "Vaccines" + }, + value: { + text: vaccinesText + } + } + ] + }) }} + + {% if organisation.status != 'Deactivated' %} + {{ button({ + href: "/pharmacies/" + organisation.id + "/view-as", + text: "Access this pharmacy", + classes: "nhsuk-button--secondary" + }) }} + {% endif %} + + {% elif currentPageSection == "users" %} + +

Users

+ + {% if organisation.status != 'Deactivated' %} + {{ button({ + href: "/pharmacies/" + organisation.id + "/add-user", + text: "Add user" + }) }} + {% endif %} + + {% set totalUsers = (usersByStatus.invited | length) + (usersByStatus.active | length) + (usersByStatus.deactivated | length) %} + + {% if totalUsers > 0 %} + + {{ appSecondaryNavigation({ + visuallyHiddenTitle: "Users by status", + items: [{ + text: "Invited (" + (usersByStatus.invited | length) + ")", + href: "/pharmacies/" + organisation.id + "?section=users&tab=invited", + current: (currentTab == "invited") + }, { + text: "Active (" + (usersByStatus.active | length) + ")", + href: "/pharmacies/" + organisation.id + "?section=users&tab=active", + current: (currentTab == "active") + }, { + text: "Deactivated (" + (usersByStatus.deactivated | length) + ")", + href: "/pharmacies/" + organisation.id + "?section=users&tab=deactivated", + current: (currentTab == "deactivated") + }] + }) }} + + {% if (users | length) > 0 %} @@ -332,10 +344,79 @@

Users

{% else %}

No active users.

{% endif %} - {% endif %} + {% endif %} - {% endif %} + {% endif %} + + {% elif currentPageSection == "vaccines" %} + + {% set activeVaccines = [] %} + {% for vaccine in (organisation.vaccines or []) %} + {% if vaccine.status == "enabled" %} + {% set activeVaccines = (activeVaccines.push(vaccine.name), activeVaccines) %} + {% endif %} + {% endfor %} + +

Vaccine programmes

+ + {{ button({ + href: "/pharmacies/" + organisation.id + "/edit-vaccines", + text: "Add vaccines" + }) }} + +
+ + + + + + + + {% for vaccineName in (activeVaccines | sort) %} + + + + + {% endfor %} + {% if (activeVaccines | length) == 0 %} + + + + {% endif %} + +
+ Vaccine + + Actions +
+ {{ vaccineName | capitaliseFirstLetter }} + + Remove {{ vaccineName | capitaliseFirstLetter }} +
+ No active vaccines. +
+ + {% else %} + +
+ {% if organisation.status == 'Deactivated' %} +

This pharmacy has been deactivated.

+ +

It will be closed in 90 days.

+ {% elif canDeletePharmacy %} +

This pharmacy has not yet recorded any vaccinations. You can delete it if you added it by mistake.

+

Delete this pharmacy

+ {% else %} +

If a pharmacy is no longer using Record a vaccination, you should deactivate it.

+ +

Deactivate this pharmacy

+ + {% endif %} +
+ {% endif %} +
+
diff --git a/package-lock.json b/package-lock.json index e2027dc3..7432eaa0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,7 @@ "name": "record-a-vaccination-prototype", "license": "MIT", "dependencies": { + "@x-govuk/govuk-prototype-components": "^6.0.0", "@x-govuk/govuk-prototype-filters": "^2.1.0", "accessible-autocomplete": "^3.0.1", "nhsuk-frontend": "github:nhsuk/nhsuk-frontend#0e310c29a", @@ -1792,6 +1793,24 @@ "dev": true, "license": "ISC" }, + "node_modules/@x-govuk/govuk-prototype-components": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@x-govuk/govuk-prototype-components/-/govuk-prototype-components-6.0.0.tgz", + "integrity": "sha512-yTa1rU1ePcBszPs5jWIdwuByS8OQ/4LHrTndt7HaEBJ7bj0Nh+eStobXqmUzbAAHhc1dekE99SH6rVOddZqOjg==", + "license": "MIT", + "dependencies": { + "accessible-autocomplete": "^3.0.0", + "eventslibjs": "^1.2.0", + "gray-matter": "^4.0.3", + "nunjucks": "^3.2.4" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24" + }, + "peerDependencies": { + "govuk-frontend": "^6.0.0" + } + }, "node_modules/@x-govuk/govuk-prototype-filters": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/@x-govuk/govuk-prototype-filters/-/govuk-prototype-filters-2.1.0.tgz", @@ -1814,8 +1833,7 @@ "node_modules/a-sync-waterfall": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/a-sync-waterfall/-/a-sync-waterfall-1.0.1.tgz", - "integrity": "sha512-RYTOHHdWipFUliRFMCS4X2Yn2X8M87V/OpSqWzKKOGhzqyUxzyVmhHDH9sAvG+ZuQf/TAOFsLCpMw09I1ufUnA==", - "peer": true + "integrity": "sha512-RYTOHHdWipFUliRFMCS4X2Yn2X8M87V/OpSqWzKKOGhzqyUxzyVmhHDH9sAvG+ZuQf/TAOFsLCpMw09I1ufUnA==" }, "node_modules/accepts": { "version": "1.3.8", @@ -2061,8 +2079,7 @@ "node_modules/asap": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", - "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", - "peer": true + "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==" }, "node_modules/async": { "version": "2.6.4", @@ -3678,6 +3695,19 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/esquery": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", @@ -3736,6 +3766,12 @@ "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" }, + "node_modules/eventslibjs": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/eventslibjs/-/eventslibjs-1.2.0.tgz", + "integrity": "sha512-nui7FHXHeeZjWkQ1dZ4R3RchkT+164+y1/puiOY1Zc3CPU9W8XzAzdhqvuVQ4EJt7F/W94O5U26/oVFpBOPY3w==", + "license": "MIT" + }, "node_modules/express": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz", @@ -3994,6 +4030,18 @@ "node": ">= 18" } }, + "node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "license": "MIT", + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -4506,6 +4554,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/govuk-frontend": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/govuk-frontend/-/govuk-frontend-6.4.0.tgz", + "integrity": "sha512-jU3oaVFXqK1yDVIdZs1YZ6JD7YDB4PFUHF3rFMWJye9ArImp42F9wCsFzzB1+udjuzGCryJGcHHbBQ5HY+8rqQ==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 4.2.0" + } + }, "node_modules/govuk-markdown": { "version": "0.8.0", "resolved": "https://registry.npmjs.org/govuk-markdown/-/govuk-markdown-0.8.0.tgz", @@ -8757,6 +8815,43 @@ "dev": true, "license": "MIT" }, + "node_modules/gray-matter": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/gray-matter/-/gray-matter-4.0.3.tgz", + "integrity": "sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==", + "license": "MIT", + "dependencies": { + "js-yaml": "^3.13.1", + "kind-of": "^6.0.2", + "section-matter": "^1.0.0", + "strip-bom-string": "^1.0.0" + }, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/gray-matter/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "license": "MIT", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/gray-matter/node_modules/js-yaml": { + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.15.0.tgz", + "integrity": "sha512-ttBQIIQPDeLjpPOohtUdXuXUVoA2uIB6fEH9HyJ7234s5mBJ5wTx20njxplLZQgLaOfpmPQA7X2t5AX6tIPbog==", + "license": "MIT", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, "node_modules/has-bigints": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz", @@ -9161,6 +9256,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -9559,6 +9663,15 @@ "json-buffer": "3.0.1" } }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -9944,7 +10057,6 @@ "version": "3.2.4", "resolved": "https://registry.npmjs.org/nunjucks/-/nunjucks-3.2.4.tgz", "integrity": "sha512-26XRV6BhkgK0VOxfbU5cQI+ICFUtMLixv1noZn1tGU38kQH5A5nmmbk/O45xdyBhD1esk47nKrY0mvQpZIhRjQ==", - "peer": true, "dependencies": { "a-sync-waterfall": "^1.0.0", "asap": "^2.0.3", @@ -9969,7 +10081,6 @@ "version": "5.1.0", "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz", "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==", - "peer": true, "engines": { "node": ">= 6" } @@ -11232,6 +11343,19 @@ "url": "https://paulmillr.com/funding/" } }, + "node_modules/section-matter": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/section-matter/-/section-matter-1.0.0.tgz", + "integrity": "sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==", + "license": "MIT", + "dependencies": { + "extend-shallow": "^2.0.1", + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", @@ -11732,6 +11856,12 @@ "dev": true, "license": "CC0-1.0" }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "license": "BSD-3-Clause" + }, "node_modules/statuses": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", @@ -11864,6 +11994,15 @@ "node": ">=4" } }, + "node_modules/strip-bom-string": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-bom-string/-/strip-bom-string-1.0.0.tgz", + "integrity": "sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", diff --git a/package.json b/package.json index cfffd3fa..3f42dc6b 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ "author": "NHS England", "license": "MIT", "dependencies": { + "@x-govuk/govuk-prototype-components": "^6.0.0", "@x-govuk/govuk-prototype-filters": "^2.1.0", "accessible-autocomplete": "^3.0.1", "nhsuk-frontend": "github:nhsuk/nhsuk-frontend#0e310c29a", From 05f3d0eb4f6f56693314372fdc33dd3b2da27fcc Mon Sep 17 00:00:00 2001 From: Caitlin Roach Date: Thu, 23 Jul 2026 12:47:41 +0100 Subject: [PATCH 04/31] max width change --- app/assets/sass/_overrides.scss | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/assets/sass/_overrides.scss b/app/assets/sass/_overrides.scss index 546b6b08..44191723 100644 --- a/app/assets/sass/_overrides.scss +++ b/app/assets/sass/_overrides.scss @@ -5,6 +5,10 @@ } } +.nhsuk-width-container { + max-width: 1100px; +} + .app-pre-footer-banner { border-top: 1px solid #b1b4b6; } From 36ce0ac2a35e744ecb2c8051258cabe7443173e4 Mon Sep 17 00:00:00 2001 From: Caitlin Roach Date: Thu, 23 Jul 2026 13:41:47 +0100 Subject: [PATCH 05/31] small tweaks to flow --- app/routes/pharmacies.js | 64 +++++++++++++++++++++---- app/views/pharmacies/edit-vaccines.html | 7 ++- app/views/pharmacies/pharmacy.html | 26 ++++++++-- 3 files changed, 79 insertions(+), 18 deletions(-) diff --git a/app/routes/pharmacies.js b/app/routes/pharmacies.js index 9e3539f9..d6cc6347 100644 --- a/app/routes/pharmacies.js +++ b/app/routes/pharmacies.js @@ -16,6 +16,11 @@ const hasVaccinationRecords = (data, organisationId) => { } const scenarioCompanyIds = ['P0191N', 'P15951'] +const allowedPharmacyVaccineNames = ['flu', 'COVID-19', 'MenB'] + +const displayPharmacyVaccineName = (vaccineName) => { + return vaccineName === 'MenB' ? 'Men-B' : vaccineName +} const isoDaysAgo = (daysAgo) => { const date = new Date() @@ -1247,12 +1252,16 @@ module.exports = router => { const enabledVaccineNames = (organisation.vaccines || []) .filter((vaccine) => vaccine.status === 'enabled') + .filter((vaccine) => allowedPharmacyVaccineNames.includes(vaccine.name)) .map((vaccine) => vaccine.name) + const availableVaccines = (data.vaccines || []) + .filter((vaccine) => allowedPharmacyVaccineNames.includes(vaccine.name)) + .filter((vaccine) => !enabledVaccineNames.includes(vaccine.name)) + res.render('pharmacies/edit-vaccines', { organisation, - allVaccines: data.vaccines || [], - enabledVaccineNames + allVaccines: availableVaccines }) }) @@ -1271,15 +1280,16 @@ module.exports = router => { : (selectedVaccinesRaw ? [selectedVaccinesRaw] : []) organisation.vaccines ||= [] - const allVaccineNames = (data.vaccines || []).map((vaccine) => vaccine.name) + for (const vaccineName of selectedVaccines) { + if (!allowedPharmacyVaccineNames.includes(vaccineName)) { + continue + } - for (const vaccineName of allVaccineNames) { const existingVaccine = organisation.vaccines.find((vaccine) => vaccine.name === vaccineName) - const isSelected = selectedVaccines.includes(vaccineName) if (existingVaccine) { - existingVaccine.status = isSelected ? 'enabled' : 'disabled' - } else if (isSelected) { + existingVaccine.status = 'enabled' + } else { organisation.vaccines.push({ name: vaccineName, status: 'enabled' @@ -1287,7 +1297,32 @@ module.exports = router => { } } - return res.redirect(`/pharmacies/${id}?vaccinesUpdated=true`) + return res.redirect(`/pharmacies/${id}?section=vaccines&vaccinesUpdated=true`) + }) + + router.get('/pharmacies/:id/remove-vaccine', (req, res) => { + const data = req.session.data + const { id } = req.params + const vaccineName = req.query.vaccineName + const organisation = data.organisations.find((org) => org.id === id) + + if (!organisation) { + return res.redirect('/pharmacies') + } + + if (!allowedPharmacyVaccineNames.includes(vaccineName)) { + return res.redirect(`/pharmacies/${id}?section=vaccines`) + } + + organisation.vaccines ||= [] + + const existingVaccine = organisation.vaccines.find((vaccine) => vaccine.name === vaccineName) + + if (existingVaccine) { + existingVaccine.status = 'disabled' + } + + return res.redirect(`/pharmacies/${id}?section=vaccines&removedVaccine=${encodeURIComponent(vaccineName)}`) }) @@ -1302,6 +1337,7 @@ module.exports = router => { const reactivatedUserId = req.query.reactivatedUserId const reactivatedFromPharmacyId = req.query.reactivatedFromPharmacyId const vaccinesUpdated = req.query.vaccinesUpdated + const removedVaccine = req.query.removedVaccine const tab = (req.query.tab || 'active').toLowerCase() const section = (req.query.section || 'overview').toLowerCase() @@ -1326,6 +1362,13 @@ module.exports = router => { const deactivatedUser = data.users.find((user) => user.id === deactivatedUserId) const reactivatedUser = data.users.find((user) => user.id === reactivatedUserId) const canDeletePharmacy = !hasVaccinationRecords(data, id) + const enabledAllowedVaccineNames = (organisation.vaccines || []) + .filter((vaccine) => vaccine.status === 'enabled') + .filter((vaccine) => allowedPharmacyVaccineNames.includes(vaccine.name)) + .map((vaccine) => vaccine.name) + const hasAvailableVaccinesToAdd = allowedPharmacyVaccineNames.some((vaccineName) => { + return !enabledAllowedVaccineNames.includes(vaccineName) + }) const userOrganisationPermissions = {} @@ -1388,8 +1431,11 @@ module.exports = router => { reactivatedUser, reactivatedFromPharmacyId, vaccinesUpdated, + removedVaccine, + removedVaccineDisplayName: displayPharmacyVaccineName(removedVaccine), canDeletePharmacy, - currentPageSection + currentPageSection, + hasAvailableVaccinesToAdd }) }) diff --git a/app/views/pharmacies/edit-vaccines.html b/app/views/pharmacies/edit-vaccines.html index 1a9a9903..2a2d8880 100644 --- a/app/views/pharmacies/edit-vaccines.html +++ b/app/views/pharmacies/edit-vaccines.html @@ -19,7 +19,7 @@ {% for vaccine in (allVaccines | sort(false, false, "name")) %} {% set items = (items.push({ value: vaccine.name, - text: (vaccine.name | capitaliseFirstLetter) + text: "Men-B" if vaccine.name == "MenB" else (vaccine.name | capitaliseFirstLetter) }), items) %} {% endfor %} @@ -27,13 +27,12 @@ name: "vaccinesEnabled", fieldset: { legend: { - text: "Which vaccines can this pharmacy record?", + text: "Which vaccines would you like to add for " + organisation.name + " (" + organisation.id + ")?", size: "l", isPageHeading: true } }, - items: items, - values: enabledVaccineNames + items: items }) }} {{ button({ diff --git a/app/views/pharmacies/pharmacy.html b/app/views/pharmacies/pharmacy.html index e42fb5d5..555e638b 100644 --- a/app/views/pharmacies/pharmacy.html +++ b/app/views/pharmacies/pharmacy.html @@ -87,6 +87,20 @@

}) }} {% endif %} + {% if removedVaccine %} + {% set html %} +

+ Vaccine removed +

+

{{ removedVaccineDisplayName }} has been removed from {{ organisation.name }}.

+ {% endset %} + + {{ notificationBanner({ + html: html, + type: "success" + }) }} + {% endif %} +

{{ pageName }} ({{ organisation.id }})

{% set addressParts = [] %} @@ -359,10 +373,12 @@

Users

Vaccine programmes

- {{ button({ - href: "/pharmacies/" + organisation.id + "/edit-vaccines", - text: "Add vaccines" - }) }} + {% if hasAvailableVaccinesToAdd %} + {{ button({ + href: "/pharmacies/" + organisation.id + "/edit-vaccines", + text: "Add vaccines" + }) }} + {% endif %} @@ -382,7 +398,7 @@

Vaccine programmes

{{ vaccineName | capitaliseFirstLetter }} {% endfor %} From 8dc64ab364308abe28349797804508135222f39d Mon Sep 17 00:00:00 2001 From: Caitlin Roach Date: Mon, 27 Jul 2026 16:08:27 +0100 Subject: [PATCH 06/31] Updates based on convo with Anna and Ileri --- app/assets/sass/main.scss | 124 ++++++++-- app/routes/pharmacies.js | 25 +- app/routes/regions.js | 94 +++++++- app/views/layout.html | 18 +- app/views/pharmacies/pharmacy.html | 61 ++--- app/views/regions/organisation.html | 322 +++++++++++++++++--------- app/views/regions/remove-vaccine.html | 38 +++ 7 files changed, 478 insertions(+), 204 deletions(-) create mode 100644 app/views/regions/remove-vaccine.html diff --git a/app/assets/sass/main.scss b/app/assets/sass/main.scss index 66c4e7d1..7f86571e 100755 --- a/app/assets/sass/main.scss +++ b/app/assets/sass/main.scss @@ -212,36 +212,122 @@ border-radius: 3px; font-weight: 700; } -@include nhsuk-media-query($from: tablet) { - .app-section-navigation--vertical { - margin-right: -#{nhsuk-spacing(2)}; - margin-left: -#{nhsuk-spacing(2)}; +.app-section-navigation--vertical .app-section-navigation__list { + flex-flow: column; + gap: 0; + box-shadow: none; + overflow: visible; +} + +.app-section-navigation--vertical .app-section-navigation__item { + border-left: 4px solid transparent; +} + +.app-section-navigation--vertical .app-section-navigation__item--current { + border-left-color: $nhsuk-link-colour; +} + +.app-section-navigation--vertical .app-section-navigation__link { + padding: nhsuk-spacing(1) nhsuk-spacing(2) nhsuk-spacing(1) calc(#{nhsuk-spacing(2)} + 4px); +} + +.app-section-navigation--vertical .app-section-navigation__link[aria-current="page"] { + box-shadow: none; +} + +.app-section-navigation--vertical .app-section-navigation__link[aria-current="page"]:focus { + box-shadow: inset 0 -4px $nhsuk-text-colour; +} + +.app-pharmacy-users-table-responsive { + container-name: pharmacy-users-table; + container-type: inline-size; + max-width: 100%; +} + +.app-pharmacy-users-table { + width: 100%; +} + +.app-pharmacy-users-table .app-pharmacy-users-vaccinator { + white-space: nowrap; + width: 1%; +} + +.app-pharmacy-users-actions a { + display: block; +} + +.app-pharmacy-users-actions a + a { + margin-top: nhsuk-spacing(1); +} + +@media (max-width: 1200px) { + .app-pharmacy-layout-nav, + .app-pharmacy-layout-content { + float: none; + width: 100%; + } + + .app-pharmacy-layout-nav { + margin-bottom: nhsuk-spacing(4); + } +} + +@container pharmacy-users-table (max-width: 700px) { + .app-pharmacy-users-table { + min-width: 0; } - .app-section-navigation--vertical .app-section-navigation__list { - flex-flow: column; - gap: 0; - box-shadow: none; - overflow: visible; + .app-pharmacy-users-table thead { + display: none; } - .app-section-navigation--vertical .app-section-navigation__item { - border-left: 4px solid transparent; + .app-pharmacy-users-table, + .app-pharmacy-users-table tbody, + .app-pharmacy-users-table tr, + .app-pharmacy-users-table td { + display: block; + width: 100%; } - .app-section-navigation--vertical .app-section-navigation__item--current { - border-left-color: $nhsuk-link-colour; + .app-pharmacy-users-table tr { + box-sizing: border-box; + border-bottom: 1px solid $nhsuk-border-colour; + margin-bottom: nhsuk-spacing(3); + padding-bottom: nhsuk-spacing(2); } - .app-section-navigation--vertical .app-section-navigation__link { - padding: nhsuk-spacing(1) nhsuk-spacing(2) nhsuk-spacing(1) calc(#{nhsuk-spacing(2)} + 4px); + .app-pharmacy-users-table td { + border-bottom: 0; + min-width: 0; + padding: nhsuk-spacing(1) 0; } - .app-section-navigation--vertical .app-section-navigation__link[aria-current="page"] { - box-shadow: none; + .app-pharmacy-users-table td::before { + content: attr(data-label); + display: block; + font-weight: 700; + margin-bottom: 2px; } - .app-section-navigation--vertical .app-section-navigation__link[aria-current="page"]:focus { - box-shadow: inset 0 -4px $nhsuk-text-colour; + .app-pharmacy-users-actions a { + display: inline; + margin-right: nhsuk-spacing(3); + } + + .app-pharmacy-users-actions a + a { + margin-top: 0; + } +} + +@include nhsuk-media-query($from: tablet) { + .app-pharmacy-users-table { + min-width: 760px; + } + + .app-section-navigation--vertical { + margin-right: -#{nhsuk-spacing(2)}; + margin-left: -#{nhsuk-spacing(2)}; } } diff --git a/app/routes/pharmacies.js b/app/routes/pharmacies.js index d6cc6347..25cca265 100644 --- a/app/routes/pharmacies.js +++ b/app/routes/pharmacies.js @@ -1301,28 +1301,10 @@ module.exports = router => { }) router.get('/pharmacies/:id/remove-vaccine', (req, res) => { - const data = req.session.data const { id } = req.params - const vaccineName = req.query.vaccineName - const organisation = data.organisations.find((org) => org.id === id) - - if (!organisation) { - return res.redirect('/pharmacies') - } - - if (!allowedPharmacyVaccineNames.includes(vaccineName)) { - return res.redirect(`/pharmacies/${id}?section=vaccines`) - } - - organisation.vaccines ||= [] - - const existingVaccine = organisation.vaccines.find((vaccine) => vaccine.name === vaccineName) - - if (existingVaccine) { - existingVaccine.status = 'disabled' - } - return res.redirect(`/pharmacies/${id}?section=vaccines&removedVaccine=${encodeURIComponent(vaccineName)}`) + // Group admins can no longer remove vaccines from pharmacies. + return res.redirect(`/pharmacies/${id}?section=vaccines`) }) @@ -1337,7 +1319,6 @@ module.exports = router => { const reactivatedUserId = req.query.reactivatedUserId const reactivatedFromPharmacyId = req.query.reactivatedFromPharmacyId const vaccinesUpdated = req.query.vaccinesUpdated - const removedVaccine = req.query.removedVaccine const tab = (req.query.tab || 'active').toLowerCase() const section = (req.query.section || 'overview').toLowerCase() @@ -1431,8 +1412,6 @@ module.exports = router => { reactivatedUser, reactivatedFromPharmacyId, vaccinesUpdated, - removedVaccine, - removedVaccineDisplayName: displayPharmacyVaccineName(removedVaccine), canDeletePharmacy, currentPageSection, hasAvailableVaccinesToAdd diff --git a/app/routes/regions.js b/app/routes/regions.js index 6fdefc3d..92e07de7 100644 --- a/app/routes/regions.js +++ b/app/routes/regions.js @@ -164,24 +164,109 @@ module.exports = router => { router.get('/regions/organisations/:id', (req, res) => { const data = req.session.data const id = req.params.id + const section = (req.query.section || 'overview').toLowerCase() + const tab = (req.query.tab || 'active').toLowerCase() + const removedVaccine = req.query.removedVaccine + const vaccinesAdded = req.query.vaccinesAdded const organisation = data.organisations.find((org) => org.id === id) if (!organisation) { res.redirect('/regions/'); return } const users = data.users.filter((user) => (user.organisations || []).find((organisation) => organisation.id === id)) + const usersByStatus = { + invited: [], + active: [], + deactivated: [] + } + + for (const user of users) { + const userOrganisationSettings = (user.organisations || []).find((userOrganisation) => userOrganisation.id === id) + const status = (userOrganisationSettings && userOrganisationSettings.status || 'Active').toLowerCase() + + if (status === 'invited') { + usersByStatus.invited.push(user) + } else if (status === 'deactivated') { + usersByStatus.deactivated.push(user) + } else { + usersByStatus.active.push(user) + } + } + + const validTabs = ['invited', 'active', 'deactivated'] + const currentTab = validTabs.includes(tab) ? tab : 'active' + const validSections = ['overview', 'users', 'vaccines', 'action'] + const currentPageSection = validSections.includes(section) ? section : 'overview' + const usersForTab = usersByStatus[currentTab] const vaccines = organisation.vaccines || [] const vaccinesEnabled = vaccines.filter((vaccine) => vaccine.status === "enabled") + const canAddVaccines = vaccinesEnabled.length < (data.vaccines || []).length const messages = (res.locals.currentOrganisation.inbox || []).filter((message) => message.fromOrganisationId === id) res.render('regions/organisation', { organisation, - users, + users: usersForTab, + usersByStatus, + currentTab, + currentPageSection, vaccinesEnabled, + canAddVaccines, + removedVaccine, + vaccinesAdded, messages }) }) + router.get('/regions/organisations/:id/remove-vaccine', (req, res) => { + const data = req.session.data + const id = req.params.id + const vaccineName = req.query.vaccineName + const organisation = data.organisations.find((org) => org.id === id) + if (!organisation) { res.redirect('/regions/'); return } + + if (!vaccineName) { + res.redirect(`/regions/organisations/${id}?section=vaccines`) + return + } + + const existingEnabledVaccine = (organisation.vaccines || []).find((vaccine) => vaccine.name === vaccineName && vaccine.status === 'enabled') + + if (!existingEnabledVaccine) { + res.redirect(`/regions/organisations/${id}?section=vaccines`) + return + } + + res.render('regions/remove-vaccine', { + organisation, + vaccineName + }) + }) + + router.post('/regions/organisations/:id/remove-vaccine', (req, res) => { + const data = req.session.data + const id = req.params.id + const vaccineName = req.body.vaccineName + const organisation = data.organisations.find((org) => org.id === id) + if (!organisation) { res.redirect('/regions/'); return } + + if (!vaccineName) { + res.redirect(`/regions/organisations/${id}?section=vaccines`) + return + } + + organisation.vaccines ||= [] + + const existingVaccine = organisation.vaccines.find((vaccine) => vaccine.name === vaccineName && vaccine.status === 'enabled') + + if (existingVaccine) { + existingVaccine.status = 'disabled' + res.redirect(`/regions/organisations/${id}?section=vaccines&removedVaccine=${encodeURIComponent(vaccineName)}`) + return + } + + res.redirect(`/regions/organisations/${id}?section=vaccines`) + }) + // Viewing the page to set vaccines per organisation router.get('/regions/organisations/:id/add-vaccines', (req, res) => { const data = req.session.data @@ -209,7 +294,10 @@ module.exports = router => { const organisation = data.organisations.find((org) => org.id === id) if (!organisation) { res.redirect('/regions/'); return } - const vaccinesToAdd = data.vaccinesToAdd + const vaccinesToAddRaw = data.vaccinesToAdd + const vaccinesToAdd = Array.isArray(vaccinesToAddRaw) + ? vaccinesToAddRaw + : (vaccinesToAddRaw ? [vaccinesToAddRaw] : []) const vaccines = organisation.vaccines || [] @@ -229,7 +317,7 @@ module.exports = router => { } - res.redirect(`/regions/organisations/${id}`) + res.redirect(`/regions/organisations/${id}?section=vaccines&vaccinesAdded=true`) }) diff --git a/app/views/layout.html b/app/views/layout.html index 81bd06d5..0913025c 100755 --- a/app/views/layout.html +++ b/app/views/layout.html @@ -30,14 +30,16 @@ {% block footer %} {{ footer({ diff --git a/app/views/pharmacies/pharmacy.html b/app/views/pharmacies/pharmacy.html index 555e638b..d345f0ad 100644 --- a/app/views/pharmacies/pharmacy.html +++ b/app/views/pharmacies/pharmacy.html @@ -14,6 +14,7 @@ {{ backLink({ href: "/pharmacies", + text: "Back to all pharmacies", classes: "app-pharmacy-back-link" }) }} @@ -87,20 +88,6 @@

}) }} {% endif %} - {% if removedVaccine %} - {% set html %} -

- Vaccine removed -

-

{{ removedVaccineDisplayName }} has been removed from {{ organisation.name }}.

- {% endset %} - - {{ notificationBanner({ - html: html, - type: "success" - }) }} - {% endif %} -

{{ pageName }} ({{ organisation.id }})

{% set addressParts = [] %} @@ -131,7 +118,7 @@

{{ pageName }}
-
+
{% set actionNavText = "Overview" %} {% if canDeletePharmacy %} {% set actionNavText = "Delete pharmacy" %} @@ -159,7 +146,7 @@

{{ pageName }}

-
+
@@ -238,17 +225,15 @@

Users

{% if (users | length) > 0 %} -

- Remove {{ vaccineName | capitaliseFirstLetter }} + Remove {{ vaccineName | capitaliseFirstLetter }}
+
+
- {% if currentTab == "invited" %} - {% elif currentTab == "deactivated" %} - {% else %} - - - - - {% if currentTab == "invited" %} - {% elif currentTab == "deactivated" %} - {% else %} - {% endif %} - @@ -350,6 +332,7 @@

Users

{% endfor %}
- Name - - Email + Name and email + Vaccinator @@ -258,7 +243,7 @@

Users

Invite sent
+ Vaccinator @@ -268,7 +253,7 @@

Users

Reason deactivated
+ Vaccinator @@ -288,20 +273,18 @@

Users

{% set inviteAgeDays = userOrganisationPermissions[user.id].inviteSent | daysSince %} {% set daysSinceLastLogIn = user.lastLogIn | daysSince %}
+ {{ user.firstName }} {{ user.lastName }} +
{{ user.email }}
- {{ user.email }} - + {{ "Yes" if userOrganisationPermissions[user.id].vaccinator else "No" }} + {{ userOrganisationPermissions[user.id].permissionLevel }} + {% if inviteAgeDays == 0 %} Today {% elif inviteAgeDays %} @@ -311,7 +294,7 @@

Users

{% endif %}
+ {% if userOrganisationPermissions[user.id].deactivatedReason == "Deactivated by user" %} By {{ userOrganisationPermissions[user.id].deactivatedBy or ((currentUser.firstName + " " + currentUser.lastName) if currentUser else "User") }} {% elif userOrganisationPermissions[user.id].deactivatedReason %} @@ -323,7 +306,7 @@

Users

{% endif %}
+ {% if daysSinceLastLogIn == 0 %} Today {% elif daysSinceLastLogIn %} @@ -333,7 +316,7 @@

Users

{% endif %}
+ {% if currentTab == "invited" %} {% if inviteAgeDays > 7 %} Resend invite to {{ user.firstName }} {{ user.lastName }} @@ -342,7 +325,6 @@

Users

Reactivate {{ user.firstName }} {{ user.lastName }} {% else %} Change permission level for {{ user.firstName }} {{ user.lastName }} -   Deactivate {{ user.firstName }} {{ user.lastName }} {% endif %}
+
{% else %} {% if currentTab == "invited" %}

No invited users.

@@ -386,9 +369,6 @@

Vaccine programmes

Vaccine - - Actions - @@ -397,14 +377,11 @@

Vaccine programmes

{{ vaccineName | capitaliseFirstLetter }} - - Remove {{ vaccineName | capitaliseFirstLetter }} - {% endfor %} {% if (activeVaccines | length) == 0 %} - + No active vaccines. diff --git a/app/views/regions/organisation.html b/app/views/regions/organisation.html index 4d752177..a5b4aa45 100644 --- a/app/views/regions/organisation.html +++ b/app/views/regions/organisation.html @@ -11,131 +11,235 @@ {% endblock %} {% block content %} -
-
-

{{ organisation.name }}

- - {% if organisation.status == 'Invited' %} -

You have invited this organisation to create an NHS Record a vaccination service account.

- - {% elseif organisation.status == "Deactivated" %} + {% set addressParts = [] %} + {% if organisation.address and organisation.address.line1 %} + {% set addressParts = (addressParts.push(organisation.address.line1), addressParts) %} + {% endif %} + {% if organisation.address and organisation.address.town %} + {% set addressParts = (addressParts.push(organisation.address.town), addressParts) %} + {% endif %} + {% if organisation.address and organisation.address.postcode %} + {% set addressParts = (addressParts.push(organisation.address.postcode), addressParts) %} + {% endif %} -

This organisation has been deactivated.

It will be closed in 90 days.

+ {% set addressText = addressParts | join(", ") %} + {% set vaccinesText = "None" %} + {% if (vaccinesEnabled | length) > 0 %} + {% set vaccinesText = (vaccinesEnabled | sort(false, false, "name") | pluck("name") | formatList) %} + {% endif %} -

Reactivate organisation

+
+
+ {% if vaccinesAdded == "true" %} + {% set html %} +

+ Vaccines added +

+

Vaccines have been added to {{ organisation.name }}.

+ {% endset %} + {{ notificationBanner({ + html: html, + type: "success" + }) }} {% endif %} - -

They can record - {% if (vaccinesEnabled | length) == (data.vaccines | length) %} - all - {% else %} - {{ vaccinesEnabled | sort(false, false, "name") | pluck("name") | formatList }} - {% endif %} - vaccinations. - - {% if (vaccinesEnabled | length) < (data.vaccines | length) %} - Add vaccines - {% endif %} -

- - {% if (messages | length) > 0 %} - {% set message = (messages | first) %} - - {% set messageHtml %} -

Access to record {{ message.vaccineRequested }} requested on {{ message.sentOn | govukDate }}. View request

+ {% if removedVaccine %} + {% set html %} +

+ Vaccine removed +

+

{{ removedVaccine }} has been removed from {{ organisation.name }}.

{% endset %} - {{ insetText({ - html: messageHtml, - classes: "nhsuk-u-margin-top-0 nhsuk-u-padding-top-1 nhsuk-u-padding-bottom-1" + {{ notificationBanner({ + html: html, + type: "success" }) }} {% endif %} +

{{ organisation.name }} ({{ organisation.id }})

- {% if organisation.status != 'Invited' %} -

Deactivate organisation

+
+
+ + - {% if organisation.status == 'Invited' or organisation.status == 'Active' %} - -
-
- - {% if (users | length) > 0 %} - - - - - - - - - - - - {% for leadUser in users %} - - {% set userOrganisationSettings = (leadUser.organisations | findById(organisation.id)) %} - - - - - - - - {% endfor %} - -
Users
- Name - - Email address - - Status - - -
- {{ leadUser.firstName }} {{ leadUser.lastName }} - - {{ leadUser.email }} - - {{ userOrganisationSettings.status }} - - {% if userOrganisationSettings.status == 'Invited' %} - Uninvite - {% endif %} -
- {% endif %} - - - {% if (users | length) > 3 %} - {{ pagination({ - next: { - href: "#" - }, - items: [ - { - number: 1, - href: "#", - current: true - }, - { - number: 2, - href: "#" - } - ] - }) }} - {% endif %} - - {% set buttonText = "Add another user" if (organisation.leadUsers | length) > 0 else "Add user" %} - - {{ button({ text: buttonText, href: "/regions/organisations/" + organisation.id + "/add-email"}) }} +
+
+
+ {% if currentPageSection == "overview" %} +

Overview

+ + {% if organisation.status == 'Invited' %} +

You have invited this organisation to create an NHS Record a vaccination service account.

+ {% endif %} + + {{ summaryList({ + rows: [ + { + key: { text: "ODS code" }, + value: { text: organisation.id } + }, + { + key: { text: "Address" }, + value: { text: addressText or "Not provided" } + }, + { + key: { text: "Status" }, + value: { text: organisation.status } + }, + { + key: { text: "Vaccines" }, + value: { text: vaccinesText } + } + ] + }) }} + + {% if (messages | length) > 0 %} + {% set message = (messages | first) %} + + {% set messageHtml %} +

Access to record {{ message.vaccineRequested }} requested on {{ message.sentOn | govukDate }}. View request

+ {% endset %} + + {{ insetText({ + html: messageHtml, + classes: "nhsuk-u-margin-top-0 nhsuk-u-padding-top-1 nhsuk-u-padding-bottom-1" + }) }} + {% endif %} + + {% elif currentPageSection == "users" %} +

Users

+ + {% if organisation.status == 'Invited' or organisation.status == 'Active' %} + {% set totalUsers = (usersByStatus.invited | length) + (usersByStatus.active | length) + (usersByStatus.deactivated | length) %} + {% set buttonText = "Add user" if totalUsers > 0 else "Add user" %} + {{ button({ text: buttonText, href: "/regions/organisations/" + organisation.id + "/add-email"}) }} + + {{ appSecondaryNavigation({ + visuallyHiddenTitle: "Users by status", + items: [{ + text: "Invited (" + (usersByStatus.invited | length) + ")", + href: "/regions/organisations/" + organisation.id + "?section=users&tab=invited", + current: (currentTab == "invited") + }, { + text: "Active (" + (usersByStatus.active | length) + ")", + href: "/regions/organisations/" + organisation.id + "?section=users&tab=active", + current: (currentTab == "active") + }, { + text: "Deactivated (" + (usersByStatus.deactivated | length) + ")", + href: "/regions/organisations/" + organisation.id + "?section=users&tab=deactivated", + current: (currentTab == "deactivated") + }] + }) }} + + {% if (users | length) > 0 %} +
+ + + + + + + + + + {% for leadUser in users %} + {% set userOrganisationSettings = (leadUser.organisations | findById(organisation.id)) %} + + + + + + {% endfor %} + +
Name and emailStatusActions
+ {{ leadUser.firstName }} {{ leadUser.lastName }} +
{{ leadUser.email }}
+
{{ userOrganisationSettings.status }} + {% if userOrganisationSettings.status == 'Invited' %} + Uninvite + {% endif %} +
+
+ {% else %} +

No users in this status.

+ {% endif %} + {% else %} +

This organisation is deactivated. Reactivate it to manage users.

+ {% endif %} + + {% elif currentPageSection == "vaccines" %} +

Vaccines

+ + {% if canAddVaccines %} + {{ button({ text: "Add vaccines", href: "/regions/organisations/" + organisation.id + "/add-vaccines"}) }} + {% endif %} + + {% if (vaccinesEnabled | length) > 0 %} + + + + + + + + + {% for vaccine in (vaccinesEnabled | sort(false, false, "name")) %} + + + + + {% endfor %} + +
VaccineActions
{{ vaccine.name | capitaliseFirstLetter }} + Remove {{ vaccine.name | capitaliseFirstLetter }} +
+ {% else %} +

No vaccines enabled yet.

+ {% endif %} + + {% else %} +

Deactivate organisation

+ + {% if organisation.status == "Deactivated" %} +

This organisation has been deactivated.

+

It will be closed in 90 days.

+

Reactivate organisation

+ {% elseif organisation.status == 'Invited' %} +

This organisation has been invited and is waiting to set up access.

+ {% else %} +

If an organisation is no longer using Record a vaccination, you should deactivate it.

+

Deactivate organisation

+ {% endif %} + {% endif %} +
- {% endif %} +
{% endblock %} diff --git a/app/views/regions/remove-vaccine.html b/app/views/regions/remove-vaccine.html new file mode 100644 index 00000000..2e72c1b1 --- /dev/null +++ b/app/views/regions/remove-vaccine.html @@ -0,0 +1,38 @@ +{% extends 'layout.html' %} + +{% set pageName = "Remove " + vaccineName + " from " + organisation.name %} +{% set currentSection = "organisations" %} + +{% block beforeContent %} + {{ backLink({ + href: "/regions/organisations/" + organisation.id + "?section=vaccines", + text: "Back" + }) }} +{% endblock %} + +{% block content %} +
+
+

{{ pageName }}

+ +

Removing this vaccine means users in this organisation can no longer record new {{ vaccineName }} vaccinations, including those in the past, edit existing records or add additional batches.

+ +

Existing vaccination records for {{ vaccineName }} will still be available to view and report on.

+ +

You can add {{ vaccineName }} again later if needed.

+ +
+ + +
+ {{ button({ + text: "Yes, remove vaccine", + classes: "nhsuk-button--warning" + }) }} + + Cancel +
+
+
+
+{% endblock %} From 3684523357c6bee163d18e4971c73c0b9e56560a Mon Sep 17 00:00:00 2001 From: Caitlin Roach Date: Mon, 27 Jul 2026 16:26:48 +0100 Subject: [PATCH 07/31] Added "vaccine no longer available" error page --- .../record-vaccination-check-and-confirm.html | 148 ++++++++++++++++++ app/views/index.html | 1 + 2 files changed, 149 insertions(+) create mode 100644 app/views/errors/record-vaccination-check-and-confirm.html diff --git a/app/views/errors/record-vaccination-check-and-confirm.html b/app/views/errors/record-vaccination-check-and-confirm.html new file mode 100644 index 00000000..8acb1826 --- /dev/null +++ b/app/views/errors/record-vaccination-check-and-confirm.html @@ -0,0 +1,148 @@ +{% extends 'layout.html' %} + +{% set pageName = "Check and confirm" %} + +{% from "warning-callout/macro.njk" import warningCallout %} + +{% block beforeContent %} + {{ backLink({ href: "/record-vaccinations/injection-site" }) }} +{% endblock %} + +{% block content %} +
+
+

{{ pageName }}

+ + {{ warningCallout({ + heading: "Vaccine no longer available", + html: "

The vaccine you are recording has been removed from the system by a regional administrator and is no longer available.

You cannot record this vaccination at this time. If this vaccination has already been administered, record by hand and contact your regional administrator.

" + }) }} + +

Patient

+ + {{ summaryList({ + rows: [ + { + key: { + text: "Name" + }, + value: { + text: "Emma Johnson" + } + }, + { + key: { + text: "Date of birth" + }, + value: { + html: "14 March 1990
(36 years old)" + } + }, + { + key: { + text: "Address" + }, + value: { + html: "12 King Street
Leeds
LS1 4AB" + } + }, + { + key: { + text: "NHS number" + }, + value: { + text: "943 476 5919" + } + } + ] + }) }} + +

Vaccination

+ + {{ summaryList({ + rows: [ + { + key: { + text: "Date" + }, + value: { + text: "Today" + } + }, + { + key: { + text: "Site" + }, + value: { + text: "Leeds City Vaccination Site" + } + }, + { + key: { + text: "Vaccinator" + }, + value: { + text: "Sam Carter" + } + }, + { + key: { + text: "Vaccine" + }, + value: { + html: "Flu
aQIV" + } + }, + { + key: { + text: "Batch" + }, + value: { + html: "AB1234
Expires 31 December 2026" + } + }, + { + key: { + text: "Dose sequence" + }, + value: { + text: "1" + } + }, + { + key: { + text: "Eligibility" + }, + value: { + text: "Aged 65 years or over" + } + }, + { + key: { + text: "Consent given by" + }, + value: { + text: "Patient" + } + }, + { + key: { + text: "Injection site" + }, + value: { + text: "Left upper arm" + } + }, + { + key: { + text: "Optional note" + }, + value: { + text: "Patient attended with carer." + } + } + ] + }) }} +
+
+{% endblock %} diff --git a/app/views/index.html b/app/views/index.html index 1c88c480..70374024 100755 --- a/app/views/index.html +++ b/app/views/index.html @@ -123,6 +123,7 @@

Error pages

  • Sorry, there is a problem with the service (500 error)
  • Sorry, the service is unavailable (503 error)
  • Rate limited (429 error)
  • +
  • The vaccine you are recording is no longer available (Regional admin has removed vaccines mid-recording)
  • Sorry there is a problem with your account (user deactivated)
  • We cannot find a user with this email (after a successful 3rd party login)
  • You previously logged in a different way (Keycloak error)
  • From c6abf07a804fa76f505a14dca3ffde4cee303518 Mon Sep 17 00:00:00 2001 From: Caitlin Roach Date: Mon, 27 Jul 2026 16:28:07 +0100 Subject: [PATCH 08/31] code style fixes --- app/routes/pharmacies.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/app/routes/pharmacies.js b/app/routes/pharmacies.js index 25cca265..df2563c4 100644 --- a/app/routes/pharmacies.js +++ b/app/routes/pharmacies.js @@ -18,10 +18,6 @@ const hasVaccinationRecords = (data, organisationId) => { const scenarioCompanyIds = ['P0191N', 'P15951'] const allowedPharmacyVaccineNames = ['flu', 'COVID-19', 'MenB'] -const displayPharmacyVaccineName = (vaccineName) => { - return vaccineName === 'MenB' ? 'Men-B' : vaccineName -} - const isoDaysAgo = (daysAgo) => { const date = new Date() date.setDate(date.getDate() - daysAgo) From 6263a3964b2d34fa7d17461d195ceb744bb476f0 Mon Sep 17 00:00:00 2001 From: Caitlin Roach Date: Mon, 27 Jul 2026 16:36:15 +0100 Subject: [PATCH 09/31] vaccine added notification --- app/views/index.html | 1 + .../messaging/new-vaccine-notification.html | 91 +++++++++++++++++++ 2 files changed, 92 insertions(+) create mode 100644 app/views/messaging/new-vaccine-notification.html diff --git a/app/views/index.html b/app/views/index.html index 70374024..8cb12dd3 100755 --- a/app/views/index.html +++ b/app/views/index.html @@ -137,6 +137,7 @@

    Error pages

    Messaging

      +
    • New vaccine notification
    • Notification (Reports)
    • Notification (Vaccines)
    • Feedback
    • diff --git a/app/views/messaging/new-vaccine-notification.html b/app/views/messaging/new-vaccine-notification.html new file mode 100644 index 00000000..867c2d01 --- /dev/null +++ b/app/views/messaging/new-vaccine-notification.html @@ -0,0 +1,91 @@ +{% extends 'layout.html' %} + +{% set pageName = "New vaccine notification" %} + +{% set currentSection = "vaccinate" %} + +{% block content %} +
      +
      + + {% set notificationHtml %} +

      + [Vaccine name] has been added by your organisation. Do x, y, and z to use it. +

      + {% endset %} + + {{ notificationBanner({ + html: notificationHtml + }) }} + + + {% if (errorList | length) > 0 %} + {{ errorSummary({ + titleText: "There is a problem", + errorList: errorList + }) }} + {% endif %} + +
      + + {% set nhsNumberHtml %} + + {{ input({ + id: "nhs-number", + name: "nhsNumber", + classes: "nhsuk-input--width-10", + inputmode: "numeric", + errorMessage: nhsNumberError, + label: { + text: "NHS number", + classes: "nhsuk-label--s" + }, + value: data.nhsNumber, + hint: { + text: "For example, 485 777 3456" + } + }) }} + {% endset %} + + + {{ radios({ + idPrefix: "nhs-number-known", + name: "nhsNumberKnown", + fieldset: { + legend: { + html: "Do you have the patient’s NHS number?", + classes: "nhsuk-fieldset__legend--l", + isPageHeading: "true" + } + }, + value: data.nhsNumberKnown, + errorMessage: nhsNumberKnownError if nhsNumberKnownError, + items: [ + { + value: "yes", + text: "Yes", + conditional: { + html: nhsNumberHtml + } + }, + { + value: "no", + text: "No" + } + ] + }) }} + + {# This is to make sure the right options are shown on the 'Done' page. #} + + + + + {{ button({ + text: "Continue" + })}} +
      + +
      +
      + +{% endblock %} From 040cd1a5e98dc00b817a00f134713c50d7319d27 Mon Sep 17 00:00:00 2001 From: Anna-Sutton Date: Tue, 28 Jul 2026 10:52:06 +0100 Subject: [PATCH 10/31] Updated vaccine removal message --- app/views/regions/remove-vaccine.html | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/app/views/regions/remove-vaccine.html b/app/views/regions/remove-vaccine.html index 2e72c1b1..2e812064 100644 --- a/app/views/regions/remove-vaccine.html +++ b/app/views/regions/remove-vaccine.html @@ -1,6 +1,6 @@ {% extends 'layout.html' %} -{% set pageName = "Remove " + vaccineName + " from " + organisation.name %} +{% set pageName = "Remove " + vaccineName %} {% set currentSection = "organisations" %} {% block beforeContent %} @@ -15,18 +15,16 @@

      {{ pageName }}

      -

      Removing this vaccine means users in this organisation can no longer record new {{ vaccineName }} vaccinations, including those in the past, edit existing records or add additional batches.

      - -

      Existing vaccination records for {{ vaccineName }} will still be available to view and report on.

      - -

      You can add {{ vaccineName }} again later if needed.

      +

      Once you remove this vaccine, users at {{ organisation.name }} will not be able to record any {{ vaccineName }} vaccinations or edit {{ vaccineName }} vaccination records. + +

      You can add this vaccine back at any time.

      {{ button({ - text: "Yes, remove vaccine", + text: "Remove vaccine", classes: "nhsuk-button--warning" }) }} From 4e33649386e8744cc3ea83403c56b333c6cc74cb Mon Sep 17 00:00:00 2001 From: Anna-Sutton Date: Tue, 28 Jul 2026 11:02:22 +0100 Subject: [PATCH 11/31] Update notification message for vaccines added --- app/views/pharmacies/pharmacy.html | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/views/pharmacies/pharmacy.html b/app/views/pharmacies/pharmacy.html index d345f0ad..4167a34e 100644 --- a/app/views/pharmacies/pharmacy.html +++ b/app/views/pharmacies/pharmacy.html @@ -77,9 +77,8 @@

      {% if vaccinesUpdated == "true" %} {% set html %}

      - Vaccines changed + Vaccines added

      -

      The vaccines for {{ organisation.name }} have been updated.

      {% endset %} {{ notificationBanner({ From 8408bbe75d9513985be49bc077fc9e13467192c4 Mon Sep 17 00:00:00 2001 From: Anna-Sutton Date: Tue, 28 Jul 2026 11:06:41 +0100 Subject: [PATCH 12/31] Simplify vaccine notification messages Removed notification messages for added and removed vaccines. --- app/views/regions/organisation.html | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/app/views/regions/organisation.html b/app/views/regions/organisation.html index a5b4aa45..ac5ba64c 100644 --- a/app/views/regions/organisation.html +++ b/app/views/regions/organisation.html @@ -34,8 +34,6 @@ {% set html %}

      Vaccines added -

      -

      Vaccines have been added to {{ organisation.name }}.

      {% endset %} {{ notificationBanner({ @@ -47,9 +45,7 @@

      {% if removedVaccine %} {% set html %}

      - Vaccine removed -

      -

      {{ removedVaccine }} has been removed from {{ organisation.name }}.

      + {{ removedVaccine }} removed {% endset %} {{ notificationBanner({ From 3bd48c57f7972c2fbb9a1f24530baad2d11922d6 Mon Sep 17 00:00:00 2001 From: Anna-Sutton Date: Tue, 28 Jul 2026 12:50:28 +0100 Subject: [PATCH 13/31] Update vaccination warning and patient details --- .../errors/record-vaccination-check-and-confirm.html | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/app/views/errors/record-vaccination-check-and-confirm.html b/app/views/errors/record-vaccination-check-and-confirm.html index 8acb1826..26c65a3e 100644 --- a/app/views/errors/record-vaccination-check-and-confirm.html +++ b/app/views/errors/record-vaccination-check-and-confirm.html @@ -14,8 +14,9 @@

      {{ pageName }}

      {{ warningCallout({ - heading: "Vaccine no longer available", - html: "

      The vaccine you are recording has been removed from the system by a regional administrator and is no longer available.

      You cannot record this vaccination at this time. If this vaccination has already been administered, record by hand and contact your regional administrator.

      " + heading: "Vaccination no longer available", + html: "

      You cannot record this vaccination because a regional lead has removed flu vaccines for your organisation.

      +

      If you have already vaccinated the patient, record it on paper and contact your regional lead.

      " }) }}

      Patient

      @@ -35,7 +36,7 @@

      Patient

      text: "Date of birth" }, value: { - html: "14 March 1990
      (36 years old)" + html: "14 March 1960
      (66 years old)" } }, { @@ -90,7 +91,7 @@

      Vaccination

      text: "Vaccine" }, value: { - html: "Flu
      aQIV" + html: "Flu
      Adjuvanted Trivalent Influenza Vaccine (aTIV)" } }, { From 331633a60efb264a660c4f0b7c8933f5f3926d3a Mon Sep 17 00:00:00 2001 From: Anna-Sutton Date: Tue, 28 Jul 2026 13:32:54 +0100 Subject: [PATCH 14/31] Revise vaccine added message for users who've just logged in --- app/views/messaging/new-vaccine-notification.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/messaging/new-vaccine-notification.html b/app/views/messaging/new-vaccine-notification.html index 867c2d01..9b619f6c 100644 --- a/app/views/messaging/new-vaccine-notification.html +++ b/app/views/messaging/new-vaccine-notification.html @@ -10,7 +10,7 @@ {% set notificationHtml %}

      - [Vaccine name] has been added by your organisation. Do x, y, and z to use it. + You can now use Record a vaccination for [vaccine name] vaccinations. Make sure an administrator has added batches before you start recording.

      {% endset %} From ac33cffdefe1165a496ae7f31f2986293876e2c0 Mon Sep 17 00:00:00 2001 From: Anna-Sutton Date: Tue, 28 Jul 2026 13:41:15 +0100 Subject: [PATCH 15/31] Create vaccine-removed-notification.html --- app/views/vaccine-removed-notification.html | 1 + 1 file changed, 1 insertion(+) create mode 100644 app/views/vaccine-removed-notification.html diff --git a/app/views/vaccine-removed-notification.html b/app/views/vaccine-removed-notification.html new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/app/views/vaccine-removed-notification.html @@ -0,0 +1 @@ + From c5c9ba3103f2f63b6ead0d778099d16d7ae25bb0 Mon Sep 17 00:00:00 2001 From: Anna-Sutton Date: Tue, 28 Jul 2026 13:42:18 +0100 Subject: [PATCH 16/31] Delete app/views/vaccine-removed-notification.html --- app/views/vaccine-removed-notification.html | 1 - 1 file changed, 1 deletion(-) delete mode 100644 app/views/vaccine-removed-notification.html diff --git a/app/views/vaccine-removed-notification.html b/app/views/vaccine-removed-notification.html deleted file mode 100644 index 8b137891..00000000 --- a/app/views/vaccine-removed-notification.html +++ /dev/null @@ -1 +0,0 @@ - From a6f12d564a4788f0a62490402b42e5c952790bc7 Mon Sep 17 00:00:00 2001 From: Anna-Sutton Date: Tue, 28 Jul 2026 13:47:11 +0100 Subject: [PATCH 17/31] Vaccine removed notification --- .../vaccine-removed-notification.html | 91 +++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 app/views/messaging/vaccine-removed-notification.html diff --git a/app/views/messaging/vaccine-removed-notification.html b/app/views/messaging/vaccine-removed-notification.html new file mode 100644 index 00000000..e940bf2c --- /dev/null +++ b/app/views/messaging/vaccine-removed-notification.html @@ -0,0 +1,91 @@ +{% extends 'layout.html' %} + +{% set pageName = "Vaccine removed notification" %} + +{% set currentSection = "vaccinate" %} + +{% block content %} +
      +
      + + {% set notificationHtml %} +

      + You can no longer record or edit [vaccine name] vaccinations at [organisation name].

      +

      If you still need to access [vaccine name] vaccinations, contact your regional lead.

      + {% endset %} + + {{ notificationBanner({ + html: notificationHtml + }) }} + + + {% if (errorList | length) > 0 %} + {{ errorSummary({ + titleText: "There is a problem", + errorList: errorList + }) }} + {% endif %} + + + + {% set nhsNumberHtml %} + + {{ input({ + id: "nhs-number", + name: "nhsNumber", + classes: "nhsuk-input--width-10", + inputmode: "numeric", + errorMessage: nhsNumberError, + label: { + text: "NHS number", + classes: "nhsuk-label--s" + }, + value: data.nhsNumber, + hint: { + text: "For example, 485 777 3456" + } + }) }} + {% endset %} + + + {{ radios({ + idPrefix: "nhs-number-known", + name: "nhsNumberKnown", + fieldset: { + legend: { + html: "Do you have the patient’s NHS number?", + classes: "nhsuk-fieldset__legend--l", + isPageHeading: "true" + } + }, + value: data.nhsNumberKnown, + errorMessage: nhsNumberKnownError if nhsNumberKnownError, + items: [ + { + value: "yes", + text: "Yes", + conditional: { + html: nhsNumberHtml + } + }, + { + value: "no", + text: "No" + } + ] + }) }} + + {# This is to make sure the right options are shown on the 'Done' page. #} + + + + + {{ button({ + text: "Continue" + })}} + + +
      +
      + +{% endblock %} From 0fceeafbe9be4635716af5d5511334a353dc2ed7 Mon Sep 17 00:00:00 2001 From: Anna-Sutton Date: Tue, 28 Jul 2026 13:56:42 +0100 Subject: [PATCH 18/31] Updated vaccine notification message --- app/views/messaging/new-vaccine-notification.html | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/views/messaging/new-vaccine-notification.html b/app/views/messaging/new-vaccine-notification.html index 9b619f6c..40d86c36 100644 --- a/app/views/messaging/new-vaccine-notification.html +++ b/app/views/messaging/new-vaccine-notification.html @@ -10,7 +10,8 @@ {% set notificationHtml %}

      - You can now use Record a vaccination for [vaccine name] vaccinations. Make sure an administrator has added batches before you start recording. + You can now use Record a vaccination for [vaccine name] vaccinations.

      +

      Make sure an administrator has added batches before you start recording.

      {% endset %} From 2ffb8db0f140995d04d559577bd4fa56ec8bcfd2 Mon Sep 17 00:00:00 2001 From: Anna-Sutton Date: Tue, 28 Jul 2026 14:00:26 +0100 Subject: [PATCH 19/31] Update warning message for unavailable vaccine --- app/views/errors/record-vaccination-check-and-confirm.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/errors/record-vaccination-check-and-confirm.html b/app/views/errors/record-vaccination-check-and-confirm.html index 26c65a3e..23d629eb 100644 --- a/app/views/errors/record-vaccination-check-and-confirm.html +++ b/app/views/errors/record-vaccination-check-and-confirm.html @@ -14,8 +14,8 @@

      {{ pageName }}

      {{ warningCallout({ - heading: "Vaccination no longer available", - html: "

      You cannot record this vaccination because a regional lead has removed flu vaccines for your organisation.

      + heading: "Vaccine no longer available", + html: "

      You cannot record this vaccination because a regional lead has removed access to [vaccine name] vaccines.

      If you have already vaccinated the patient, record it on paper and contact your regional lead.

      " }) }} From ce55238b302c5122a8063a678d0c8aa3a8b8f294 Mon Sep 17 00:00:00 2001 From: Anna-Sutton Date: Tue, 28 Jul 2026 14:03:57 +0100 Subject: [PATCH 20/31] Fix wording in vaccine removal notification --- app/views/messaging/vaccine-removed-notification.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/messaging/vaccine-removed-notification.html b/app/views/messaging/vaccine-removed-notification.html index e940bf2c..be1661e9 100644 --- a/app/views/messaging/vaccine-removed-notification.html +++ b/app/views/messaging/vaccine-removed-notification.html @@ -11,7 +11,7 @@ {% set notificationHtml %}

      You can no longer record or edit [vaccine name] vaccinations at [organisation name].

      -

      If you still need to access [vaccine name] vaccinations, contact your regional lead.

      +

      If you still need access to [vaccine name] vaccinations, contact your regional lead.

      {% endset %} {{ notificationBanner({ From 28f2d3cc9f36bd114fbbef1eafee2dfb49f4f7ca Mon Sep 17 00:00:00 2001 From: Caitlin Roach Date: Tue, 28 Jul 2026 14:44:01 +0100 Subject: [PATCH 21/31] Fix capitalisation issue and set up logic for plural/singular "vaccine/s added" --- app/routes/pharmacies.js | 10 +++++++++- app/routes/regions.js | 9 ++++++++- app/views/index.html | 1 + app/views/pharmacies/pharmacy.html | 2 +- app/views/regions/add-vaccines.html | 2 +- app/views/regions/organisation.html | 3 ++- 6 files changed, 22 insertions(+), 5 deletions(-) diff --git a/app/routes/pharmacies.js b/app/routes/pharmacies.js index df2563c4..aadf3db1 100644 --- a/app/routes/pharmacies.js +++ b/app/routes/pharmacies.js @@ -1276,6 +1276,8 @@ module.exports = router => { : (selectedVaccinesRaw ? [selectedVaccinesRaw] : []) organisation.vaccines ||= [] + let vaccinesUpdatedCount = 0 + for (const vaccineName of selectedVaccines) { if (!allowedPharmacyVaccineNames.includes(vaccineName)) { continue @@ -1284,8 +1286,12 @@ module.exports = router => { const existingVaccine = organisation.vaccines.find((vaccine) => vaccine.name === vaccineName) if (existingVaccine) { + if (existingVaccine.status !== 'enabled') { + vaccinesUpdatedCount += 1 + } existingVaccine.status = 'enabled' } else { + vaccinesUpdatedCount += 1 organisation.vaccines.push({ name: vaccineName, status: 'enabled' @@ -1293,7 +1299,7 @@ module.exports = router => { } } - return res.redirect(`/pharmacies/${id}?section=vaccines&vaccinesUpdated=true`) + return res.redirect(`/pharmacies/${id}?section=vaccines&vaccinesUpdated=true&vaccinesUpdatedCount=${vaccinesUpdatedCount}`) }) router.get('/pharmacies/:id/remove-vaccine', (req, res) => { @@ -1315,6 +1321,7 @@ module.exports = router => { const reactivatedUserId = req.query.reactivatedUserId const reactivatedFromPharmacyId = req.query.reactivatedFromPharmacyId const vaccinesUpdated = req.query.vaccinesUpdated + const vaccinesUpdatedCount = Number.parseInt(req.query.vaccinesUpdatedCount, 10) || 0 const tab = (req.query.tab || 'active').toLowerCase() const section = (req.query.section || 'overview').toLowerCase() @@ -1408,6 +1415,7 @@ module.exports = router => { reactivatedUser, reactivatedFromPharmacyId, vaccinesUpdated, + vaccinesUpdatedCount, canDeletePharmacy, currentPageSection, hasAvailableVaccinesToAdd diff --git a/app/routes/regions.js b/app/routes/regions.js index 92e07de7..98410604 100644 --- a/app/routes/regions.js +++ b/app/routes/regions.js @@ -168,6 +168,7 @@ module.exports = router => { const tab = (req.query.tab || 'active').toLowerCase() const removedVaccine = req.query.removedVaccine const vaccinesAdded = req.query.vaccinesAdded + const vaccinesAddedCount = Number.parseInt(req.query.vaccinesAddedCount, 10) || 0 const organisation = data.organisations.find((org) => org.id === id) if (!organisation) { res.redirect('/regions/'); return } @@ -213,6 +214,7 @@ module.exports = router => { canAddVaccines, removedVaccine, vaccinesAdded, + vaccinesAddedCount, messages }) }) @@ -300,14 +302,19 @@ module.exports = router => { : (vaccinesToAddRaw ? [vaccinesToAddRaw] : []) const vaccines = organisation.vaccines || [] + let vaccinesAddedCount = 0 for (let vaccineToAdd of vaccinesToAdd) { const existingVaccine = vaccines.find((vaccine) => vaccine.name === vaccineToAdd) if (existingVaccine) { + if (existingVaccine.status !== 'enabled') { + vaccinesAddedCount += 1 + } existingVaccine.status = "enabled" } else { + vaccinesAddedCount += 1 vaccines.push({ name: vaccineToAdd, @@ -317,7 +324,7 @@ module.exports = router => { } - res.redirect(`/regions/organisations/${id}?section=vaccines&vaccinesAdded=true`) + res.redirect(`/regions/organisations/${id}?section=vaccines&vaccinesAdded=true&vaccinesAddedCount=${vaccinesAddedCount}`) }) diff --git a/app/views/index.html b/app/views/index.html index 8cb12dd3..c0b75de1 100755 --- a/app/views/index.html +++ b/app/views/index.html @@ -138,6 +138,7 @@

      Messaging

      • New vaccine notification
      • +
      • Vaccine removed notification
      • Notification (Reports)
      • Notification (Vaccines)
      • Feedback
      • diff --git a/app/views/pharmacies/pharmacy.html b/app/views/pharmacies/pharmacy.html index 4167a34e..45ef2b68 100644 --- a/app/views/pharmacies/pharmacy.html +++ b/app/views/pharmacies/pharmacy.html @@ -77,7 +77,7 @@

        {% if vaccinesUpdated == "true" %} {% set html %}

        - Vaccines added + {{ "Vaccine" if vaccinesUpdatedCount == 1 else "Vaccines" }} added

        {% endset %} diff --git a/app/views/regions/add-vaccines.html b/app/views/regions/add-vaccines.html index ac8b8b75..76065140 100644 --- a/app/views/regions/add-vaccines.html +++ b/app/views/regions/add-vaccines.html @@ -23,7 +23,7 @@ {% for vaccine in (vaccinesNotYetAdded | sort(false, false, "name")) %} {% set items = (items.push({ value: vaccine.name, - text: (vaccine.name ) + text: (vaccine.name | capitaliseFirstLetter) }), items) %} {% endfor %} diff --git a/app/views/regions/organisation.html b/app/views/regions/organisation.html index ac5ba64c..54945a54 100644 --- a/app/views/regions/organisation.html +++ b/app/views/regions/organisation.html @@ -33,7 +33,8 @@ {% if vaccinesAdded == "true" %} {% set html %}

        - Vaccines added + {{ "Vaccine" if vaccinesAddedCount == 1 else "Vaccines" }} added +

        {% endset %} {{ notificationBanner({ From 4fec17edde0a7aefedad98ee226b514bc6013044 Mon Sep 17 00:00:00 2001 From: Caitlin Roach Date: Tue, 28 Jul 2026 15:21:48 +0100 Subject: [PATCH 22/31] Made add user and add vaccine pages consistent between regions and pharmacies --- app/assets/sass/_overrides.scss | 2 +- app/data/organisations.js | 10 +++++----- app/views/pharmacies/add-user-check.html | 6 ++++-- .../pharmacies/add-user-permission-level.html | 19 +++++++------------ app/views/pharmacies/add-user.html | 6 ++++-- app/views/pharmacies/edit-vaccines.html | 6 ++++-- .../regions/add-another-email-check.html | 2 ++ app/views/regions/add-another-email.html | 2 ++ app/views/regions/add-email.html | 5 +++-- app/views/regions/check-and-send.html | 2 ++ 10 files changed, 34 insertions(+), 26 deletions(-) diff --git a/app/assets/sass/_overrides.scss b/app/assets/sass/_overrides.scss index 44191723..589aa38e 100644 --- a/app/assets/sass/_overrides.scss +++ b/app/assets/sass/_overrides.scss @@ -15,7 +15,7 @@ .app-pre-footer-banner .govuk-phase-banner__content { display: flex; - flex-wrap: nowrap; + flex-wrap: wrap; align-items: baseline; @include nhsuk-font(16); margin-top: 24px; diff --git a/app/data/organisations.js b/app/data/organisations.js index bfe3b7bd..2412317c 100644 --- a/app/data/organisations.js +++ b/app/data/organisations.js @@ -186,9 +186,9 @@ module.exports = [ }, { id: "RVL", - name: "Barnet and chase farm Hospitals NHS Trust", + name: "Barnet and Chase Farm Hospitals NHS Trust", address: { - line1: "Barnet General hospital", + line1: "Barnet General Hospital", town: "Barnet", postcode: "EN5 3DJ" }, @@ -222,7 +222,7 @@ module.exports = [ }, { id: "RRP", - name: "Barnet, enfield and haringey mental Health NHS Trust", + name: "Barnet, Enfield and Haringey Mental Health NHS Trust", address: { line1: "Trust headquarters block b2", town: "London", @@ -240,7 +240,7 @@ module.exports = [ }, { id: "RCN", - name: "Barnsley Community and priority services NHS Trust", + name: "Barnsley Community and Priority Services NHS Trust", address: { line1: "Kendray hospital", town: "Barnsley", @@ -7694,7 +7694,7 @@ module.exports = [ id: "RDC", name: "Wellhouse NHS Trust", address: { - line1: "Barnet hospital", + line1: "Barnet Hospital", town: "Barnet", postcode: "EN5 3DJ" }, diff --git a/app/views/pharmacies/add-user-check.html b/app/views/pharmacies/add-user-check.html index 2ee30845..8794745f 100644 --- a/app/views/pharmacies/add-user-check.html +++ b/app/views/pharmacies/add-user-check.html @@ -1,6 +1,6 @@ {% extends 'layout.html' %} -{% set pageName = "Check" %} +{% set pageName = "Check and add user" %} {% set currentSection = "pharmacies" %} @@ -15,7 +15,9 @@
        -

        Check and {% if existingUserWithSameEmail %}reactivate{% else %}add{% endif %} user to {{ organisation.name }} ({{ organisation.id }})

        +
        {{ organisation.name }} ({{ organisation.id }})
        + +

        Check and add user

        {% set nameText %} {% if existingUser %} diff --git a/app/views/pharmacies/add-user-permission-level.html b/app/views/pharmacies/add-user-permission-level.html index 3a8f2b6e..4924fee1 100644 --- a/app/views/pharmacies/add-user-permission-level.html +++ b/app/views/pharmacies/add-user-permission-level.html @@ -2,12 +2,13 @@ {% set currentSection = "pharmacies" %} {% if existingUser %} - {% set pageName = existingUser.firstName + " " + existingUser.lastName + "'s role at " + organisation.name + " (" + organisation.id + ")" %} + {% set roleHeading = existingUser.firstName + " " + existingUser.lastName + "'s role" %} {% elseif data.firstName or data.lastName %} - {% set pageName = (data.firstName + " " + data.lastName) + "'s role at " + organisation.name + " (" + organisation.id + ")" %} + {% set roleHeading = (data.firstName + " " + data.lastName) + "'s role" %} {% else %} - {% set pageName = "New user's role at " + organisation.name + " (" + organisation.id + ")" %} + {% set roleHeading = "New user's role" %} {% endif %} +{% set pageName = roleHeading %} {% block beforeContent %} {{ backLink({ @@ -46,15 +47,9 @@ }) }} {% endif %} -

        - {% if existingUser %} - {{ existingUser.firstName }} {{ existingUser.lastName }}'s role at {{ organisation.name }} ({{ organisation.id }}) - {% elseif data.firstName or data.lastName %} - {{ data.firstName }} {{ data.lastName }}'s role at {{ organisation.name }} ({{ organisation.id }}) - {% else %} - Add a new user to {{ organisation.name }} ({{ organisation.id }}) - {% endif %} -

        +
        {{ organisation.name }} ({{ organisation.id }})
        + +

        {{ roleHeading }}

        diff --git a/app/views/pharmacies/add-user.html b/app/views/pharmacies/add-user.html index c05d68db..37a8d8e0 100644 --- a/app/views/pharmacies/add-user.html +++ b/app/views/pharmacies/add-user.html @@ -1,7 +1,7 @@ {% extends 'layout.html' %} {% set currentSection = "pharmacies" %} -{% set pageName = "Add a user to " + organisation.name + " (" + organisation.id + ")" %} +{% set pageName = "Which user would you like to add?" %} {% block beforeContent %} {{ backLink({ @@ -24,7 +24,9 @@ }) }} {% endif %} -

        {{ pageName }}

        +
        {{ organisation.name }} ({{ organisation.id }})
        + +

        Which user would you like to add?

        You can add an existing user to the pharmacy, or invite a new user.

        diff --git a/app/views/pharmacies/edit-vaccines.html b/app/views/pharmacies/edit-vaccines.html index 2a2d8880..22cad92f 100644 --- a/app/views/pharmacies/edit-vaccines.html +++ b/app/views/pharmacies/edit-vaccines.html @@ -23,11 +23,13 @@ }), items) %} {% endfor %} +
        {{ organisation.name }} ({{ organisation.id }})
        + {{ checkboxes({ name: "vaccinesEnabled", fieldset: { legend: { - text: "Which vaccines would you like to add for " + organisation.name + " (" + organisation.id + ")?", + text: "Which vaccines do you want to add?", size: "l", isPageHeading: true } @@ -36,7 +38,7 @@ }) }} {{ button({ - text: "Save changes" + text: "Confirm" }) }}
        diff --git a/app/views/regions/add-another-email-check.html b/app/views/regions/add-another-email-check.html index 779a0639..02403bde 100644 --- a/app/views/regions/add-another-email-check.html +++ b/app/views/regions/add-another-email-check.html @@ -13,6 +13,8 @@ {% block content %}
        +
        {{ organisation.name }} ({{ organisation.id }})
        +

        {{ pageName }}

        This email will be sent to {{ data["email"] }}:

        diff --git a/app/views/regions/add-another-email.html b/app/views/regions/add-another-email.html index 593e9f4b..90fde8e7 100644 --- a/app/views/regions/add-another-email.html +++ b/app/views/regions/add-another-email.html @@ -14,6 +14,8 @@
        +
        {{ organisation.name }} ({{ organisation.id }})
        +

        {{ pageName }}

        Choose a user at {{ organisation.name }}.

        diff --git a/app/views/regions/add-email.html b/app/views/regions/add-email.html index 4eacfdd8..4c0ee1f6 100644 --- a/app/views/regions/add-email.html +++ b/app/views/regions/add-email.html @@ -1,6 +1,6 @@ {% extends 'layout.html' %} -{% set pageName = "Add a user" %} +{% set pageName = "Add another user" %} {% set currentSection = "organisations" %} {% block beforeContent %} @@ -14,8 +14,9 @@
        +
        {{ organisation.name }} ({{ organisation.id }})
        -

        {{ pageName }}

        +

        Add another user

        Choose a user at {{ organisation.name }}.

        diff --git a/app/views/regions/check-and-send.html b/app/views/regions/check-and-send.html index 86125f07..ee9b0f92 100644 --- a/app/views/regions/check-and-send.html +++ b/app/views/regions/check-and-send.html @@ -14,6 +14,8 @@
        +
        {{ organisation.name }} ({{ organisation.id }})
        +

        {{ pageName }}

        {{ summaryList({ From 4d359a4ec8501b580cca37842bd375d7d42d04c9 Mon Sep 17 00:00:00 2001 From: Anna-Sutton Date: Wed, 29 Jul 2026 12:06:07 +0100 Subject: [PATCH 23/31] Create vaccine-disabled.html New error page if user tries to save a vaccination when the vaccine has just been disabled by a regional lead. --- app/views/errors/vaccine-disabled.html | 1 + 1 file changed, 1 insertion(+) create mode 100644 app/views/errors/vaccine-disabled.html diff --git a/app/views/errors/vaccine-disabled.html b/app/views/errors/vaccine-disabled.html new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/app/views/errors/vaccine-disabled.html @@ -0,0 +1 @@ + From 9eddee640d13b3c71526e49415e2c36cef306d54 Mon Sep 17 00:00:00 2001 From: Anna-Sutton Date: Wed, 29 Jul 2026 12:13:18 +0100 Subject: [PATCH 24/31] Create vaccine-disabled error page Add error message for disabled vaccination recording. --- app/views/errors/vaccine-disabled.html | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/app/views/errors/vaccine-disabled.html b/app/views/errors/vaccine-disabled.html index 8b137891..4a01b246 100644 --- a/app/views/errors/vaccine-disabled.html +++ b/app/views/errors/vaccine-disabled.html @@ -1 +1,21 @@ +{% extends 'layout.html' %} +{% set pageName = "There is a problem with recording this vaccination" %} + +{% block content %} +
        +
        +

        {{ pageName }}

        + +

        You cannot record this vaccination because a regional lead has removed your access to [vaccine name] vaccines.

        + +

        If If you have already vaccinated the patient, record it on paper and contact your regional lead.

        + +

        a href="https://guide.ravs.england.nhs.uk/service-unavailable/">Download our paper form.

        + + +
        +
        + + +{% endblock %} From b463fadc325f5d01406f89ff786b1056f3aa318c Mon Sep 17 00:00:00 2001 From: Anna-Sutton Date: Wed, 29 Jul 2026 12:15:48 +0100 Subject: [PATCH 25/31] Fix HTML formatting in vaccine-disabled error page --- app/views/errors/vaccine-disabled.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/errors/vaccine-disabled.html b/app/views/errors/vaccine-disabled.html index 4a01b246..076719aa 100644 --- a/app/views/errors/vaccine-disabled.html +++ b/app/views/errors/vaccine-disabled.html @@ -9,9 +9,9 @@

        {{ pageName }}

        You cannot record this vaccination because a regional lead has removed your access to [vaccine name] vaccines.

        -

        If If you have already vaccinated the patient, record it on paper and contact your regional lead.

        +

        If you have already vaccinated the patient, record it on paper and contact your regional lead.

        -

        a href="https://guide.ravs.england.nhs.uk/service-unavailable/">Download our paper form.

        +

        Download our paper form.

        From 25503c6f889bfdeaf81e958baa2efcc32ea131c6 Mon Sep 17 00:00:00 2001 From: Anna-Sutton Date: Wed, 29 Jul 2026 13:49:16 +0100 Subject: [PATCH 26/31] Update error message for vaccination saving issue --- app/views/errors/vaccine-disabled.html | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/app/views/errors/vaccine-disabled.html b/app/views/errors/vaccine-disabled.html index 076719aa..8772f299 100644 --- a/app/views/errors/vaccine-disabled.html +++ b/app/views/errors/vaccine-disabled.html @@ -1,17 +1,18 @@ {% extends 'layout.html' %} -{% set pageName = "There is a problem with recording this vaccination" %} +{% set pageName = "There is a problem saving this vaccination" %} {% block content %}

        {{ pageName }}

        -

        You cannot record this vaccination because a regional lead has removed your access to [vaccine name] vaccines.

        +

        You cannot save this vaccination because a regional lead has removed your access to [vaccine name] vaccines.

        If you have already vaccinated the patient, record it on paper and contact your regional lead.

        - -

        Download our paper form.

        + +

        Go back to the Check and confirm page.

        +

        Download our paper form (opens in new tab).

        From d98a02a10eb60f09937e7a039a3b0ec972a72c04 Mon Sep 17 00:00:00 2001 From: Anna-Sutton Date: Wed, 29 Jul 2026 13:51:50 +0100 Subject: [PATCH 27/31] Fix HTML structure for vaccine-disabled error page --- app/views/errors/vaccine-disabled.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/errors/vaccine-disabled.html b/app/views/errors/vaccine-disabled.html index 8772f299..a16cdc42 100644 --- a/app/views/errors/vaccine-disabled.html +++ b/app/views/errors/vaccine-disabled.html @@ -11,8 +11,8 @@

        {{ pageName }}

        If you have already vaccinated the patient, record it on paper and contact your regional lead.

        -

        Go back to the Check and confirm page.

        -

        Download our paper form (opens in new tab).

        +

        Go back to the Check and confirm page

        +

        Download our paper form (opens in new tab)

        From 0230203f228d079fc7ae80b69a95fecdf443bfa8 Mon Sep 17 00:00:00 2001 From: Anna-Sutton Date: Wed, 29 Jul 2026 13:56:32 +0100 Subject: [PATCH 28/31] Enhance message for vaccine-disabled page Added additional context to the link for returning to the Check and confirm page. --- app/views/errors/vaccine-disabled.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/errors/vaccine-disabled.html b/app/views/errors/vaccine-disabled.html index a16cdc42..39ac1704 100644 --- a/app/views/errors/vaccine-disabled.html +++ b/app/views/errors/vaccine-disabled.html @@ -11,7 +11,7 @@

        {{ pageName }}

        If you have already vaccinated the patient, record it on paper and contact your regional lead.

        -

        Go back to the Check and confirm page

        +

        Go back to the Check and confirm page to see details of the vaccination.

        Download our paper form (opens in new tab)

        From 3a6efea605518ec688309591a7e913fabf5b6fb2 Mon Sep 17 00:00:00 2001 From: Caitlin Roach Date: Wed, 29 Jul 2026 14:36:50 +0100 Subject: [PATCH 29/31] removed links to pages with notifications for vaccine add/removal --- app/views/index.html | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/views/index.html b/app/views/index.html index c0b75de1..70374024 100755 --- a/app/views/index.html +++ b/app/views/index.html @@ -137,8 +137,6 @@

        Error pages

        Messaging

          -
        • New vaccine notification
        • -
        • Vaccine removed notification
        • Notification (Reports)
        • Notification (Vaccines)
        • Feedback
        • From 31d08267f6ce082c327dfa4de794a13181b38ea4 Mon Sep 17 00:00:00 2001 From: Caitlin Roach Date: Wed, 29 Jul 2026 14:40:20 +0100 Subject: [PATCH 30/31] add new link to index for error and removed warning message version --- .../record-vaccination-check-and-confirm.html | 149 ------------------ app/views/index.html | 2 +- 2 files changed, 1 insertion(+), 150 deletions(-) delete mode 100644 app/views/errors/record-vaccination-check-and-confirm.html diff --git a/app/views/errors/record-vaccination-check-and-confirm.html b/app/views/errors/record-vaccination-check-and-confirm.html deleted file mode 100644 index 23d629eb..00000000 --- a/app/views/errors/record-vaccination-check-and-confirm.html +++ /dev/null @@ -1,149 +0,0 @@ -{% extends 'layout.html' %} - -{% set pageName = "Check and confirm" %} - -{% from "warning-callout/macro.njk" import warningCallout %} - -{% block beforeContent %} - {{ backLink({ href: "/record-vaccinations/injection-site" }) }} -{% endblock %} - -{% block content %} -
          -
          -

          {{ pageName }}

          - - {{ warningCallout({ - heading: "Vaccine no longer available", - html: "

          You cannot record this vaccination because a regional lead has removed access to [vaccine name] vaccines.

          -

          If you have already vaccinated the patient, record it on paper and contact your regional lead.

          " - }) }} - -

          Patient

          - - {{ summaryList({ - rows: [ - { - key: { - text: "Name" - }, - value: { - text: "Emma Johnson" - } - }, - { - key: { - text: "Date of birth" - }, - value: { - html: "14 March 1960
          (66 years old)" - } - }, - { - key: { - text: "Address" - }, - value: { - html: "12 King Street
          Leeds
          LS1 4AB" - } - }, - { - key: { - text: "NHS number" - }, - value: { - text: "943 476 5919" - } - } - ] - }) }} - -

          Vaccination

          - - {{ summaryList({ - rows: [ - { - key: { - text: "Date" - }, - value: { - text: "Today" - } - }, - { - key: { - text: "Site" - }, - value: { - text: "Leeds City Vaccination Site" - } - }, - { - key: { - text: "Vaccinator" - }, - value: { - text: "Sam Carter" - } - }, - { - key: { - text: "Vaccine" - }, - value: { - html: "Flu
          Adjuvanted Trivalent Influenza Vaccine (aTIV)" - } - }, - { - key: { - text: "Batch" - }, - value: { - html: "AB1234
          Expires 31 December 2026" - } - }, - { - key: { - text: "Dose sequence" - }, - value: { - text: "1" - } - }, - { - key: { - text: "Eligibility" - }, - value: { - text: "Aged 65 years or over" - } - }, - { - key: { - text: "Consent given by" - }, - value: { - text: "Patient" - } - }, - { - key: { - text: "Injection site" - }, - value: { - text: "Left upper arm" - } - }, - { - key: { - text: "Optional note" - }, - value: { - text: "Patient attended with carer." - } - } - ] - }) }} -
          -
          -{% endblock %} diff --git a/app/views/index.html b/app/views/index.html index 70374024..fa25b97b 100755 --- a/app/views/index.html +++ b/app/views/index.html @@ -123,7 +123,7 @@

          Error pages

        • Sorry, there is a problem with the service (500 error)
        • Sorry, the service is unavailable (503 error)
        • Rate limited (429 error)
        • -
        • The vaccine you are recording is no longer available (Regional admin has removed vaccines mid-recording)
        • +
        • Problem saving the vaccination (Regional admin has removed vaccines mid-recording)
        • Sorry there is a problem with your account (user deactivated)
        • We cannot find a user with this email (after a successful 3rd party login)
        • You previously logged in a different way (Keycloak error)
        • From 8df7e180ebe5d38b0a8d7029915981035b09023b Mon Sep 17 00:00:00 2001 From: Caitlin Roach Date: Wed, 29 Jul 2026 15:17:12 +0100 Subject: [PATCH 31/31] Updates to content on vaccines for pharmas and orgs --- app/views/pharmacies/pharmacy.html | 4 ++-- app/views/regions/organisation.html | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/views/pharmacies/pharmacy.html b/app/views/pharmacies/pharmacy.html index 45ef2b68..9e00092d 100644 --- a/app/views/pharmacies/pharmacy.html +++ b/app/views/pharmacies/pharmacy.html @@ -353,7 +353,7 @@

          Users

          {% endif %} {% endfor %} -

          Vaccine programmes

          +

          Vaccines

          {% if hasAvailableVaccinesToAdd %} {{ button({ @@ -366,7 +366,7 @@

          Vaccine programmes

          - Vaccine + Vaccines this pharmacy can record diff --git a/app/views/regions/organisation.html b/app/views/regions/organisation.html index 54945a54..773c59dc 100644 --- a/app/views/regions/organisation.html +++ b/app/views/regions/organisation.html @@ -201,7 +201,7 @@

          Vaccines

          - +
          VaccineVaccines this organisation can record Actions