From e4be84b74f79faed26092e3bc2a5e461760b3dce Mon Sep 17 00:00:00 2001 From: Caitlin Roach Date: Tue, 9 Jun 2026 13:59:11 +0100 Subject: [PATCH 01/29] Added users pages and logic back --- app/data/users.js | 82 +++++++++++ app/routes/pharmacies.js | 137 ++++++++++++++++-- app/views/includes/header.html | 6 + app/views/pharmacies/pharmacy.html | 6 +- app/views/pharmacies/users/add-to-check.html | 10 +- .../users/add-to-permission-level.html | 52 +++---- app/views/pharmacies/users/add-to.html | 49 +++++-- .../users/deactivate-from-group.html | 36 +++++ .../users/deactivate-from-pharmacy.html | 2 +- app/views/pharmacies/users/index.html | 125 ++++++++++++++++ .../users/manage-select-pharmacy.html | 110 ++++++++++++++ 11 files changed, 552 insertions(+), 63 deletions(-) create mode 100644 app/views/pharmacies/users/deactivate-from-group.html create mode 100644 app/views/pharmacies/users/index.html create mode 100644 app/views/pharmacies/users/manage-select-pharmacy.html diff --git a/app/data/users.js b/app/data/users.js index f0a34580..27d8578c 100644 --- a/app/data/users.js +++ b/app/data/users.js @@ -98,6 +98,19 @@ module.exports = [ "firstName": "Paulina", "lastName": "Sloan" }, + { + "id": "7301948572610", + "email": "michael.reid@nhs.net", + "organisations": [ + { + "id": "P0191N", + "permissionLevel": "Group administrator", + "status": "Active" + } + ], + "firstName": "Michael", + "lastName": "Reid" + }, // Each pharmacy in Paulina Sloan’s chain has its own vaccinator, some of whom are also admins { "id": "46436346", @@ -155,6 +168,34 @@ module.exports = [ "firstName": "Samantha", "lastName": "Black" }, + { + "id": "2195407736418", + "email": "nina.hunt@nhs.net", + "organisations": [ + { + "id": "FA424", + "permissionLevel": "Administrator", + "status": "Active", + "vaccinator": true + } + ], + "firstName": "Nina", + "lastName": "Hunt" + }, + { + "id": "8701294465302", + "email": "liam.byrne@nhs.net", + "organisations": [ + { + "id": "FA02S", + "permissionLevel": "Recorder", + "status": "Active", + "vaccinator": false + } + ], + "firstName": "Liam", + "lastName": "Byrne" + }, // Amanda White is a group administrator for the // MediCare Health Ltd chain of pharmacies { @@ -170,6 +211,47 @@ module.exports = [ } ] }, + { + "firstName": "Farah", + "lastName": "Iqbal", + "id": "6015872204914", + "email": "farah.iqbal@nhs.net", + "organisations": [ + { + "id": "P15951", + "permissionLevel": "Group administrator", + "status": "Active" + } + ] + }, + { + "id": "3041597862150", + "email": "kyle.mason@nhs.net", + "organisations": [ + { + "id": "FX9141", + "permissionLevel": "Administrator", + "status": "Active", + "vaccinator": true + } + ], + "firstName": "Kyle", + "lastName": "Mason" + }, + { + "id": "4586231970421", + "email": "elise.turner@nhs.net", + "organisations": [ + { + "id": "FX4825", + "permissionLevel": "Recorder", + "status": "Active", + "vaccinator": true + } + ], + "firstName": "Elise", + "lastName": "Turner" + }, { "id": "34634617277", "email": "peter.orange@nhs.net", diff --git a/app/routes/pharmacies.js b/app/routes/pharmacies.js index 682c27e9..dfc72dcb 100644 --- a/app/routes/pharmacies.js +++ b/app/routes/pharmacies.js @@ -103,6 +103,9 @@ module.exports = router => { router.get('/pharmacies/users',(req, res) => { const data = req.session.data const companyId = res.locals.currentOrganisation.id + const deactivatedGroupAdminId = req.query.deactivatedGroupAdminId + const deactivatedUserId = req.query.deactivatedUserId + const deactivatedFromPharmacyId = req.query.deactivatedFromPharmacyId const pharmacies = data.organisations.filter((organisation) => organisation.companyId === companyId) const pharmacyIds = pharmacies.map(pharmacy => pharmacy.id) @@ -119,18 +122,96 @@ module.exports = router => { }) const groupAdministrators = users.filter(function(user) { - return user.organisations.find(org => org.permissionLevel === "Group administrator") + return user.organisations.find(org => org.permissionLevel === "Group administrator" && org.status !== 'Deactivated') + }) + + const deactivatedGroupAdmin = deactivatedGroupAdminId + ? data.users.find((user) => user.id === deactivatedGroupAdminId) + : undefined + + const deactivatedUser = deactivatedUserId + ? data.users.find((user) => user.id === deactivatedUserId) + : undefined + + const deactivatedFromPharmacy = deactivatedFromPharmacyId + ? data.organisations.find((organisation) => organisation.id === deactivatedFromPharmacyId) + : undefined + + // Show only active users added to individual pharmacies in the general user list. + users = users.filter((user) => { + if (groupAdministrators.includes(user)) { + return false + } + + return (user.organisations || []).some((organisation) => { + return pharmacyIds.includes(organisation.id) && organisation.status !== 'Deactivated' + }) }) - // Filter out group admins from the general user list - users = users.filter((user) => !groupAdministrators.includes(user)) + const userPharmacyCounts = {} + + for (const user of users) { + userPharmacyCounts[user.id] = (user.organisations || []).filter((organisation) => { + return pharmacyIds.includes(organisation.id) && organisation.status !== 'Deactivated' + }).length + } res.render('pharmacies/users/index', { users, - groupAdministrators + groupAdministrators, + deactivatedGroupAdmin, + deactivatedUser, + deactivatedFromPharmacy, + userPharmacyCounts }) }) + router.get('/pharmacies/:groupId/users/:userId/deactivate-from-group',(req, res) => { + const data = req.session.data + const groupId = req.params.groupId + const userId = req.params.userId + + const user = data.users.find((item) => item.id === userId) + + if (!user) { + return res.redirect('/pharmacies/users') + } + + const groupRole = (user.organisations || []).find((org) => org.id === groupId && org.permissionLevel === 'Group administrator') + + if (!groupRole) { + return res.redirect('/pharmacies/users') + } + + res.render('pharmacies/users/deactivate-from-group', { + user, + groupId, + groupName: (res.locals.currentOrganisation && res.locals.currentOrganisation.name) || 'this pharmacy group' + }) + }) + + router.post('/pharmacies/:groupId/users/:userId/deactivate-from-group-answer',(req, res) => { + const data = req.session.data + const groupId = req.params.groupId + const userId = req.params.userId + + const user = data.users.find((item) => item.id === userId) + + if (!user) { + return res.redirect('/pharmacies/users') + } + + const groupRole = (user.organisations || []).find((org) => org.id === groupId && org.permissionLevel === 'Group administrator') + + if (!groupRole) { + return res.redirect('/pharmacies/users') + } + + groupRole.status = 'Deactivated' + + res.redirect(`/pharmacies/users?deactivatedGroupAdminId=${user.id}`) + }) + router.get('/pharmacies/users/new',(req, res) => { res.render('pharmacies/users/new') @@ -412,7 +493,7 @@ module.exports = router => { role.status = 'Deactivated' - res.redirect(`/pharmacies/users/${user.id}?deactivatedFromPharmacyId=${pharmacy.id}`) + res.redirect(`/pharmacies/users?deactivatedUserId=${user.id}&deactivatedFromPharmacyId=${pharmacy.id}`) }) @@ -463,6 +544,9 @@ module.exports = router => { const pharmacy = data.organisations.find(organisation => organisation.id === data.pharmacyId) + if (!pharmacy) { + return res.redirect(`/pharmacies/users/${userId}/add-to`) + } res.render('pharmacies/users/add-to-permission-level', { user, @@ -477,6 +561,9 @@ module.exports = router => { const pharmacy = data.organisations.find(organisation => organisation.id === data.pharmacyId) + if (!pharmacy) { + return res.redirect(`/pharmacies/users/${userId}/add-to`) + } res.render('pharmacies/users/add-to-check', { user, @@ -488,14 +575,23 @@ module.exports = router => { const data = req.session.data const id = req.params.id const user = data.users.find(user => user.id === id) + const pharmacy = data.organisations.find(organisation => organisation.id === data.pharmacyId) - user.organisations.push({ - id: pharmacy.id, - status: 'Active', - permissionLevel: data.permissionLevel, - vaccinator: (data.vaccinator === 'yes') - }) + if (!pharmacy) { + return res.redirect(`/pharmacies/users/${id}/add-to`) + } + + const existingOrganisationIds = (user.organisations || []).map(organisation => organisation.id) + + if (!existingOrganisationIds.includes(pharmacy.id)) { + user.organisations.push({ + id: pharmacy.id, + status: 'Active', + permissionLevel: data.permissionLevel, + vaccinator: (data.vaccinator === 'yes') + }) + } // Reset answers data.permissionLevel = '' @@ -543,6 +639,10 @@ module.exports = router => { const user = data.users.find((user) => user.id === id) const companyId = res.locals.currentOrganisation.id + if (!user) { + return res.redirect('/pharmacies/users') + } + const addedToPharmacyId = req.query.addedToPharmacyId const deactivatedFromPharmacyId = req.query.deactivatedFromPharmacyId @@ -557,9 +657,20 @@ module.exports = router => { const totalPharmaciesAtOrganisation = data.organisations.filter(organisation => organisation.companyId === companyId).length - const pharmacyRoles = (user.organisations || []).filter(role => role.permissionLevel !== "Group administrator") + const pharmacyRoles = (user.organisations || []) + .filter((role) => role.permissionLevel !== 'Group administrator') + .filter((role) => role.status !== 'Deactivated') + .map((role) => { + const pharmacy = data.organisations.find((organisation) => organisation.id === role.id) + + return { + ...role, + pharmacy + } + }) + .filter((role) => role.pharmacy && role.pharmacy.companyId === companyId) - res.render('pharmacies/users/user', { + res.render('pharmacies/users/manage-select-pharmacy', { user, pharmacyRoles, addedToPharmacy, diff --git a/app/views/includes/header.html b/app/views/includes/header.html index cf52f5c6..72ce5266 100644 --- a/app/views/includes/header.html +++ b/app/views/includes/header.html @@ -19,6 +19,12 @@ active: (currentSection == "pharmacies") }), navigationItems) %} + {% set navigationItems = (navigationItems.push({ + href: "/pharmacies/users", + text: "Users", + active: (currentSection == "pharmacies-users") + }), navigationItems) %} + {% endif %} diff --git a/app/views/pharmacies/pharmacy.html b/app/views/pharmacies/pharmacy.html index e27a2889..8684d2bc 100644 --- a/app/views/pharmacies/pharmacy.html +++ b/app/views/pharmacies/pharmacy.html @@ -118,8 +118,12 @@

Users

{{ userOrganisationPermissions[user.id].status }} - + Changepermission level for {{ user.firstName }} {{ user.lastName }} + {% if userOrganisationPermissions[user.id].status != 'Deactivated' %} +   + Deactivate {{ user.firstName }} {{ user.lastName }} + {% endif %} {% endfor %} diff --git a/app/views/pharmacies/users/add-to-check.html b/app/views/pharmacies/users/add-to-check.html index 254d626f..c05f1bc3 100644 --- a/app/views/pharmacies/users/add-to-check.html +++ b/app/views/pharmacies/users/add-to-check.html @@ -4,7 +4,7 @@ {% block beforeContent %} {{ backLink({ - href: "/pharmacies/users/new", + href: "/pharmacies/users/" + user.id + "/add-to-permission-level", text: "Back" }) }} {% endblock %} @@ -15,14 +15,6 @@

Check and add user to pharmacy

- {% set pharmaciesHtml %} - - {% endset %} - {{ summaryList({ rows: [ { diff --git a/app/views/pharmacies/users/add-to-permission-level.html b/app/views/pharmacies/users/add-to-permission-level.html index 971049f7..d700c19f 100644 --- a/app/views/pharmacies/users/add-to-permission-level.html +++ b/app/views/pharmacies/users/add-to-permission-level.html @@ -15,7 +15,32 @@
-

What should {{ user.firstName }} {{ user.lastName}}'s role at {{ pharmacy.name }} be?

+

What should {{ user.firstName }} {{ user.lastName}}'s role at {{ pharmacy.name }} ({{ pharmacy.id }}) be?

+ + {{ radios({ + name: "vaccinator", + fieldset: { + legend: { + text: "Are they a vaccinator?", + size: "s" + } + }, + hint: { + text: "Vaccination records include the name of the person who gave the vaccination" + }, + value: data.vaccinator, + items: [ + { + value: "yes", + text: "Yes", + id: "vaccinator" + }, + { + value: "no", + text: "No" + } + ] + }) }} {{ radios({ name: "permissionLevel", @@ -52,31 +77,6 @@

What should {{ user.firstName }} {{ user.lastName}}' ] }) }} - {{ radios({ - name: "vaccinator", - fieldset: { - legend: { - text: "Are they a vaccinator?", - size: "s" - } - }, - hint: { - text: "Vaccination records include the name of the person who gave the vaccination" - }, - value: data.vaccinator, - items: [ - { - value: "yes", - text: "Yes", - id: "vaccinator" - }, - { - value: "no", - text: "No" - } - ] - }) }} - {{ button({ text: "Continue" }) }} diff --git a/app/views/pharmacies/users/add-to.html b/app/views/pharmacies/users/add-to.html index b14ecbbb..071dcac0 100644 --- a/app/views/pharmacies/users/add-to.html +++ b/app/views/pharmacies/users/add-to.html @@ -12,7 +12,7 @@ {% block content %}
-
+
{% set items = [] %} @@ -24,18 +24,41 @@ }), items) %} {% endfor %} - {{ radios({ - id: "pharmacy-id", - name: "pharmacyId", - value: data.pharmacyId, - fieldset: { - legend: { - text: "Which pharmacy would you like to add " + user.firstName + " " + user.lastName + " to?", - size: "l" - } - }, - items: items - }) }} + {% call fieldset({ + legend: { + text: "Which pharmacy would you like to add " + user.firstName + " " + user.lastName + " to?", + size: "l" + } + }) %} + + {% if (pharmacies | length) > 10 %} + {{ input({ + id: "pharmacy-search", + name: "pharmacySearch", + type: "search", + label: { + text: "Search" + }, + classes: "nhsuk-input--width-20", + attributes: { + "data-module": "app-radios-filter" + }, + formGroup: { + classes: "nhsuk-u-margin-bottom-4" + } + }) }} + {% endif %} + +
+ {{ radios({ + id: "pharmacy-id", + name: "pharmacyId", + value: data.pharmacyId, + items: items + }) }} +
+ + {% endcall %} {{ button({ text: "Continue" diff --git a/app/views/pharmacies/users/deactivate-from-group.html b/app/views/pharmacies/users/deactivate-from-group.html new file mode 100644 index 00000000..5a85a2fe --- /dev/null +++ b/app/views/pharmacies/users/deactivate-from-group.html @@ -0,0 +1,36 @@ +{% extends 'layout.html' %} + +{% set pageName = "Deactivate account" %} + +{% set currentSection = "pharmacies-users" %} + +{% block beforeContent %} + {{ backLink({ + href: "/pharmacies/users", + text: "Back" + }) }} +{% endblock %} + +{% block content %} +
+
+ +

Deactivate {{ user.firstName }} {{ user.lastName }} from {{ groupName }}

+ +

Once you deactivate {{ user.firstName }} {{ user.lastName }} ({{ user.email }}), they cannot sign in and use NHS Record a vaccination for this pharmacy group. They’ll receive an email to confirm their account has been deactivated.

+ +

Their Okta account will remain active, so they can continue to access other services.

+ +

You can reactivate their account anytime.

+ + + {{ button({ + "text": "Deactivate", + classes: "nhsuk-button--warning" + }) }} + + +
+
+ +{% endblock %} diff --git a/app/views/pharmacies/users/deactivate-from-pharmacy.html b/app/views/pharmacies/users/deactivate-from-pharmacy.html index 8f0c5461..b25c0e11 100644 --- a/app/views/pharmacies/users/deactivate-from-pharmacy.html +++ b/app/views/pharmacies/users/deactivate-from-pharmacy.html @@ -16,7 +16,7 @@
-

Deactivate {{ user.firstName }} {{ user.lastName }} from {{ pharmacy.name }}

+

Deactivate {{ user.firstName }} {{ user.lastName }} from {{ pharmacy.name }} ({{ pharmacy.id }})

Once you deactivate {{ user.firstName }} {{ user.lastName }} ({{ user.email}}), they cannot sign in and use NHS Record a vaccination at this pharmacy. They’ll receive an email to confirm their account has been deactivated.

diff --git a/app/views/pharmacies/users/index.html b/app/views/pharmacies/users/index.html new file mode 100644 index 00000000..e80de7b1 --- /dev/null +++ b/app/views/pharmacies/users/index.html @@ -0,0 +1,125 @@ +{% extends 'layout.html' %} + +{% set pageName = "Users" %} +{% set currentSection = "pharmacies-users" %} + +{% block content %} +
+
+ {% if req.query.added == "true" %} + {{ notificationBanner({ + titleText: "Success", + html: "User added" + }) }} + {% endif %} + {% if deactivatedGroupAdmin %} + {% set html %} +

+ User deactivated +

+

{{ deactivatedGroupAdmin.firstName }} {{ deactivatedGroupAdmin.lastName }} has been successfully deactivated from the pharmacy group

+ {% endset %} + + {{ notificationBanner({ + html: html, + type: "success" + }) }} + {% endif %} + {% if deactivatedUser and deactivatedFromPharmacy %} + {% set html %} +

+ User deactivated +

+

{{ deactivatedUser.firstName }} {{ deactivatedUser.lastName }} has been successfully deactivated from {{ deactivatedFromPharmacy.name }} ({{ deactivatedFromPharmacy.id }})

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

Users

+ +

Add a new user or change the permissions of an existing user.

+ + {{ button({ + text: "Add user", + href: "/pharmacies/users/new" + }) }} + +

Group administrators

+ + {% if groupAdministrators and (groupAdministrators | length) > 0 %} + + + + + + {% if (groupAdministrators | length) >= 2 %} + + {% endif %} + + + + {% for user in groupAdministrators %} + + + + {% if (groupAdministrators | length) >= 2 %} + + {% endif %} + + {% endfor %} + +
NameEmail
{{ user.firstName }} {{ user.lastName }}{{ user.email }} + Deactivate {{ user.firstName }} {{ user.lastName }} +
+ {% else %} +

No group administrators added yet.

+ {% endif %} + +

Users at individual pharmacies

+ + {% if users and (users | length) > 0 %} + {% if (users | length) > 10 %} + {{ input({ + id: "pharmacy-search", + name: "pharmacySearch", + type: "search", + label: { + text: "Search" + }, + classes: "nhsuk-input--width-20", + formGroup: { + classes: "nhsuk-u-margin-bottom-4" + } + }) }} + {% endif %} + + + + + + + + + + + + {% for user in users %} + + + + + + + {% endfor %} + +
NameEmailPharmaciesActions
{{ user.firstName }} {{ user.lastName }}{{ user.email }}{{ userPharmacyCounts[user.id] or 0 }}Manage {{ user.firstName }} {{ user.lastName }}
+ {% else %} +

No users added to individual pharmacies yet.

+ {% endif %} +
+
+{% endblock %} diff --git a/app/views/pharmacies/users/manage-select-pharmacy.html b/app/views/pharmacies/users/manage-select-pharmacy.html new file mode 100644 index 00000000..95edb1d6 --- /dev/null +++ b/app/views/pharmacies/users/manage-select-pharmacy.html @@ -0,0 +1,110 @@ +{% extends 'layout.html' %} + +{% set currentSection = "pharmacies-users" %} +{% set pageName = user.firstName + " " + user.lastName %} + +{% block beforeContent %} + {{ backLink({ + href: "/pharmacies/users" + }) }} +{% endblock %} + +{% block content %} +
+
+ {% if addedToPharmacy %} + {% set html %} +

+ User updated +

+

{{ user.firstName }} {{ user.lastName }} has been added to {{ addedToPharmacy.name }}

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

+ User updated +

+

{{ user.firstName }} {{ user.lastName }} has been deactivated from {{ deactivatedFromPharmacy.name }}

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

{{ user.firstName }} {{ user.lastName }}

+ + {{ summaryList({ + rows: [ + { + key: { + text: "Email" + }, + value: { + text: user.email + } + } + ] + }) }} +
+
+ +
+
+

Access and permission levels

+ + {% if pharmacyRoles and (pharmacyRoles | length) > 0 %} + + + + + + + + + + + + {% for role in pharmacyRoles %} + + + + + + + + {% endfor %} + +
PharmacyPermission levelVaccinatorStatusActions
{{ role.pharmacy.name }}{{ role.permissionLevel }}{{ "Yes" if role.vaccinator else "No" }}{{ role.status }} + Change permission level at {{ role.pharmacy.name }} + {% if role.status != 'Deactivated' %} +   + Deactivate from {{ role.pharmacy.name }} + {% endif %} +
+ + {{ button({ + text: "Add to another pharmacy", + href: "/pharmacies/users/" + user.id + "/add-to", + classes: "nhsuk-button--secondary" + }) }} + {% else %} +

This user is not currently added to any individual pharmacies.

+ + {{ button({ + text: "Add to a pharmacy", + href: "/pharmacies/users/" + user.id + "/add-to", + classes: "nhsuk-button--secondary" + }) }} + {% endif %} +
+
+{% endblock %} From 29faf5bbb3c0d98e885a38bac6086bd72eeb4699 Mon Sep 17 00:00:00 2001 From: Caitlin Roach Date: Tue, 9 Jun 2026 15:21:56 +0100 Subject: [PATCH 02/29] Add ODS codes to pharmacy table on ind user page --- app/views/pharmacies/users/manage-select-pharmacy.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/pharmacies/users/manage-select-pharmacy.html b/app/views/pharmacies/users/manage-select-pharmacy.html index 95edb1d6..587fac64 100644 --- a/app/views/pharmacies/users/manage-select-pharmacy.html +++ b/app/views/pharmacies/users/manage-select-pharmacy.html @@ -75,7 +75,7 @@

Access and permission levels

{% for role in pharmacyRoles %} - {{ role.pharmacy.name }} + {{ role.pharmacy.name }} ({{ role.pharmacy.id }}) {{ role.permissionLevel }} {{ "Yes" if role.vaccinator else "No" }} {{ role.status }} From e4b2fae0b22c00917cab4e2a57a494330e8654ae Mon Sep 17 00:00:00 2001 From: Caitlin Roach Date: Tue, 9 Jun 2026 15:29:57 +0100 Subject: [PATCH 03/29] added full stops to success messages --- app/views/pharmacies/users/index.html | 4 ++-- app/views/pharmacies/users/manage-select-pharmacy.html | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/views/pharmacies/users/index.html b/app/views/pharmacies/users/index.html index e80de7b1..e52cd8d5 100644 --- a/app/views/pharmacies/users/index.html +++ b/app/views/pharmacies/users/index.html @@ -17,7 +17,7 @@

User deactivated

-

{{ deactivatedGroupAdmin.firstName }} {{ deactivatedGroupAdmin.lastName }} has been successfully deactivated from the pharmacy group

+

{{ deactivatedGroupAdmin.firstName }} {{ deactivatedGroupAdmin.lastName }} has been successfully deactivated from the pharmacy group.

{% endset %} {{ notificationBanner({ @@ -30,7 +30,7 @@

User deactivated

-

{{ deactivatedUser.firstName }} {{ deactivatedUser.lastName }} has been successfully deactivated from {{ deactivatedFromPharmacy.name }} ({{ deactivatedFromPharmacy.id }})

+

{{ deactivatedUser.firstName }} {{ deactivatedUser.lastName }} has been successfully deactivated from {{ deactivatedFromPharmacy.name }} ({{ deactivatedFromPharmacy.id }}).

{% endset %} {{ notificationBanner({ diff --git a/app/views/pharmacies/users/manage-select-pharmacy.html b/app/views/pharmacies/users/manage-select-pharmacy.html index 587fac64..74779931 100644 --- a/app/views/pharmacies/users/manage-select-pharmacy.html +++ b/app/views/pharmacies/users/manage-select-pharmacy.html @@ -31,7 +31,7 @@

User updated

-

{{ user.firstName }} {{ user.lastName }} has been deactivated from {{ deactivatedFromPharmacy.name }}

+

{{ user.firstName }} {{ user.lastName }} has been deactivated from {{ deactivatedFromPharmacy.name }}.

{% endset %} {{ notificationBanner({ From 2ea6ac77a45786a84c9b02ac00567235c65fac2c Mon Sep 17 00:00:00 2001 From: Caitlin Roach Date: Tue, 9 Jun 2026 15:40:27 +0100 Subject: [PATCH 04/29] added email variants folder --- app/routes/pharmacies.js | 6 ++++-- .../variants/reactivation-email.html} | 0 .../variants}/welcome-email-group-admin.html | 0 .../variants/welcome-email.html} | 0 app/views/pharmacies/add-user-check.html | 4 ++-- app/views/pharmacies/pharmacy.html | 14 ++++++++++++++ app/views/pharmacies/users/add-to-check.html | 2 +- app/views/pharmacies/users/check.html | 2 +- app/views/user-admin/check.html | 4 ++-- 9 files changed, 24 insertions(+), 8 deletions(-) rename app/views/{user-admin/_reactivation-email.html => emails/variants/reactivation-email.html} (100%) rename app/views/{pharmacies/users => emails/variants}/welcome-email-group-admin.html (100%) rename app/views/{user-admin/_welcome-email.html => emails/variants/welcome-email.html} (100%) diff --git a/app/routes/pharmacies.js b/app/routes/pharmacies.js index dfc72dcb..d25ee47e 100644 --- a/app/routes/pharmacies.js +++ b/app/routes/pharmacies.js @@ -350,7 +350,7 @@ module.exports = router => { pharmacy.status = 'Deactivated' - res.redirect(`/pharmacies/${id}`) + res.redirect(`/pharmacies/${id}?deactivated=true`) }) router.get('/pharmacies/:id/add-user',(req, res) => { @@ -607,6 +607,7 @@ module.exports = router => { const id = req.params.id const added = req.query.added const addedUserId = req.query.addedUserId + const deactivated = req.query.deactivated const organisation = data.organisations.find((organisation) => organisation.id === id) @@ -628,7 +629,8 @@ module.exports = router => { users, userOrganisationPermissions, added, - addedUser + addedUser, + deactivated }) }) diff --git a/app/views/user-admin/_reactivation-email.html b/app/views/emails/variants/reactivation-email.html similarity index 100% rename from app/views/user-admin/_reactivation-email.html rename to app/views/emails/variants/reactivation-email.html diff --git a/app/views/pharmacies/users/welcome-email-group-admin.html b/app/views/emails/variants/welcome-email-group-admin.html similarity index 100% rename from app/views/pharmacies/users/welcome-email-group-admin.html rename to app/views/emails/variants/welcome-email-group-admin.html diff --git a/app/views/user-admin/_welcome-email.html b/app/views/emails/variants/welcome-email.html similarity index 100% rename from app/views/user-admin/_welcome-email.html rename to app/views/emails/variants/welcome-email.html diff --git a/app/views/pharmacies/add-user-check.html b/app/views/pharmacies/add-user-check.html index 04f041a3..b43aaf5e 100644 --- a/app/views/pharmacies/add-user-check.html +++ b/app/views/pharmacies/add-user-check.html @@ -107,9 +107,9 @@

Check and {% if existingUserWithSameEmail %}reactiva
{% if existingUserWithSameEmail %} - {% include "user-admin/_reactivation-email.html" %} + {% include "emails/variants/reactivation-email.html" %} {% else %} - {% include "user-admin/_welcome-email.html" %} + {% include "emails/variants/welcome-email.html" %} {% endif %}
diff --git a/app/views/pharmacies/pharmacy.html b/app/views/pharmacies/pharmacy.html index 8684d2bc..e4f4a352 100644 --- a/app/views/pharmacies/pharmacy.html +++ b/app/views/pharmacies/pharmacy.html @@ -28,6 +28,20 @@

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

+ Pharmacy deactivated +

+

{{ organisation.name }} ({{ organisation.id }}) has been successfully deactivated.

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

{{ pageName }}

{{ summaryList({ diff --git a/app/views/pharmacies/users/add-to-check.html b/app/views/pharmacies/users/add-to-check.html index c05f1bc3..2cf74803 100644 --- a/app/views/pharmacies/users/add-to-check.html +++ b/app/views/pharmacies/users/add-to-check.html @@ -82,7 +82,7 @@

Check and add user to pharmacy

{{ user.firstName }} will receive this email telling them they now have access to the pharmacy:

- {% include "user-admin/_welcome-email.html" %} + {% include "emails/variants/welcome-email.html" %}
diff --git a/app/views/pharmacies/users/check.html b/app/views/pharmacies/users/check.html index d914dcbe..decffe7c 100644 --- a/app/views/pharmacies/users/check.html +++ b/app/views/pharmacies/users/check.html @@ -116,7 +116,7 @@

Check and add {{ "group administrator" if data.permi

{{ data.firstName }} will receive this welcome email telling them how to access the service:

- {% include "user-admin/_welcome-email.html" %} + {% include "emails/variants/welcome-email.html" %}
diff --git a/app/views/user-admin/check.html b/app/views/user-admin/check.html index 4f4c0d0c..9e76d1cc 100644 --- a/app/views/user-admin/check.html +++ b/app/views/user-admin/check.html @@ -101,9 +101,9 @@

Check and {% if existingUserWithSameEmail %}reactiva
{% if existingUserWithSameEmail %} - {% include "user-admin/_reactivation-email.html" %} + {% include "emails/variants/reactivation-email.html" %} {% else %} - {% include "user-admin/_welcome-email.html" %} + {% include "emails/variants/welcome-email.html" %} {% endif %}
From b66f71ea0704b9f072e8d3b50ec613e7a1f7749b Mon Sep 17 00:00:00 2001 From: Caitlin Roach Date: Tue, 9 Jun 2026 15:42:25 +0100 Subject: [PATCH 05/29] flattened email structure --- app/views/emails/{variants => }/reactivation-email.html | 0 .../emails/{variants => }/welcome-email-group-admin.html | 0 app/views/emails/{variants => }/welcome-email.html | 0 app/views/pharmacies/add-user-check.html | 4 ++-- app/views/pharmacies/users/add-to-check.html | 2 +- app/views/pharmacies/users/check.html | 2 +- app/views/pharmacies/users/manage-select-pharmacy.html | 2 +- app/views/user-admin/check.html | 4 ++-- 8 files changed, 7 insertions(+), 7 deletions(-) rename app/views/emails/{variants => }/reactivation-email.html (100%) rename app/views/emails/{variants => }/welcome-email-group-admin.html (100%) rename app/views/emails/{variants => }/welcome-email.html (100%) diff --git a/app/views/emails/variants/reactivation-email.html b/app/views/emails/reactivation-email.html similarity index 100% rename from app/views/emails/variants/reactivation-email.html rename to app/views/emails/reactivation-email.html diff --git a/app/views/emails/variants/welcome-email-group-admin.html b/app/views/emails/welcome-email-group-admin.html similarity index 100% rename from app/views/emails/variants/welcome-email-group-admin.html rename to app/views/emails/welcome-email-group-admin.html diff --git a/app/views/emails/variants/welcome-email.html b/app/views/emails/welcome-email.html similarity index 100% rename from app/views/emails/variants/welcome-email.html rename to app/views/emails/welcome-email.html diff --git a/app/views/pharmacies/add-user-check.html b/app/views/pharmacies/add-user-check.html index b43aaf5e..ba1aa837 100644 --- a/app/views/pharmacies/add-user-check.html +++ b/app/views/pharmacies/add-user-check.html @@ -107,9 +107,9 @@

Check and {% if existingUserWithSameEmail %}reactiva
{% if existingUserWithSameEmail %} - {% include "emails/variants/reactivation-email.html" %} + {% include "emails/reactivation-email.html" %} {% else %} - {% include "emails/variants/welcome-email.html" %} + {% include "emails/welcome-email.html" %} {% endif %}
diff --git a/app/views/pharmacies/users/add-to-check.html b/app/views/pharmacies/users/add-to-check.html index 2cf74803..901ae60a 100644 --- a/app/views/pharmacies/users/add-to-check.html +++ b/app/views/pharmacies/users/add-to-check.html @@ -82,7 +82,7 @@

Check and add user to pharmacy

{{ user.firstName }} will receive this email telling them they now have access to the pharmacy:

- {% include "emails/variants/welcome-email.html" %} + {% include "emails/welcome-email.html" %}
diff --git a/app/views/pharmacies/users/check.html b/app/views/pharmacies/users/check.html index decffe7c..bfadb9e4 100644 --- a/app/views/pharmacies/users/check.html +++ b/app/views/pharmacies/users/check.html @@ -116,7 +116,7 @@

Check and add {{ "group administrator" if data.permi

{{ data.firstName }} will receive this welcome email telling them how to access the service:

- {% include "emails/variants/welcome-email.html" %} + {% include "emails/welcome-email.html" %}
diff --git a/app/views/pharmacies/users/manage-select-pharmacy.html b/app/views/pharmacies/users/manage-select-pharmacy.html index 74779931..72d254e7 100644 --- a/app/views/pharmacies/users/manage-select-pharmacy.html +++ b/app/views/pharmacies/users/manage-select-pharmacy.html @@ -17,7 +17,7 @@

User updated

-

{{ user.firstName }} {{ user.lastName }} has been added to {{ addedToPharmacy.name }}

+

{{ user.firstName }} {{ user.lastName }} has been added to {{ addedToPharmacy.name }}.

{% endset %} {{ notificationBanner({ diff --git a/app/views/user-admin/check.html b/app/views/user-admin/check.html index 9e76d1cc..16cd7704 100644 --- a/app/views/user-admin/check.html +++ b/app/views/user-admin/check.html @@ -101,9 +101,9 @@

Check and {% if existingUserWithSameEmail %}reactiva
{% if existingUserWithSameEmail %} - {% include "emails/variants/reactivation-email.html" %} + {% include "emails/reactivation-email.html" %} {% else %} - {% include "emails/variants/welcome-email.html" %} + {% include "emails/welcome-email.html" %} {% endif %}
From 21399a35f5a734e2bb3fe67b9e509db145c9e3a2 Mon Sep 17 00:00:00 2001 From: Caitlin Roach Date: Tue, 9 Jun 2026 15:49:21 +0100 Subject: [PATCH 06/29] pharmacy table updates --- app/views/pharmacies/index.html | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/app/views/pharmacies/index.html b/app/views/pharmacies/index.html index 1d181147..c5729741 100644 --- a/app/views/pharmacies/index.html +++ b/app/views/pharmacies/index.html @@ -4,7 +4,7 @@ {% block content %}
-
+
{% if added %} {% set html %} @@ -51,7 +51,10 @@

Pharmacies

Users - Actions + Status + + + Actions @@ -74,6 +77,9 @@

Pharmacies

{{ organisationUserCounts[organisation.id] }} + + {{ organisation.status }} + Manage From a41f4c14511e49aa74ecc059ad1a4153eda396bd Mon Sep 17 00:00:00 2001 From: Caitlin Roach Date: Tue, 9 Jun 2026 16:39:09 +0100 Subject: [PATCH 07/29] added example of closed pharmacy --- app/data/organisations.js | 83 +++++++++++++++++++++++++++++++++ app/routes/pharmacies.js | 9 +++- app/views/pharmacies/index.html | 56 ++++++++++++++++++++++ 3 files changed, 146 insertions(+), 2 deletions(-) diff --git a/app/data/organisations.js b/app/data/organisations.js index 6546f175..bfe3b7bd 100644 --- a/app/data/organisations.js +++ b/app/data/organisations.js @@ -9157,5 +9157,88 @@ module.exports = [ type: 'Pharmacy HQ', status: 'Active', region: "Y56" + }, + { + id: "FCX831", + name: "Riverside Community Pharmacy", + address: { + line1: "42 River Street", + town: "Bristol", + postcode: "BS2 8NT" + }, + type: "Community Pharmacy", + status: "Closed", + region: "Y56", + companyId: "P0191N", + vaccines: [ + {name: "COVID-19", status: "enabled"}, + {name: "flu", status: "enabled"} + ], + sites: [ + { + id: "FCX831-01", + name: "Riverside Community Pharmacy", + address: { + line1: "42 River Street", + town: "Bristol", + postcode: "BS2 8NT" + } + } + ] + }, + { + id: "FDX942", + name: "Central Health Pharmacy", + address: { + line1: "78 Main Street", + town: "Oxford", + postcode: "OX1 3HR" + }, + type: "Community Pharmacy", + status: "Closed", + region: "Y56", + companyId: "P0191N", + vaccines: [ + {name: "COVID-19", status: "enabled"} + ], + sites: [ + { + id: "FDX942-01", + name: "Central Health Pharmacy", + address: { + line1: "78 Main Street", + town: "Oxford", + postcode: "OX1 3HR" + } + } + ] + }, + { + id: "FEY153", + name: "Wellcare Pharmacy", + address: { + line1: "156 High Street", + town: "Edinburgh", + postcode: "EH8 8DH" + }, + type: "Community Pharmacy", + status: "Closed", + region: "Y56", + companyId: "P15951", + vaccines: [ + {name: "COVID-19", status: "enabled"}, + {name: "MMR", status: "enabled"} + ], + sites: [ + { + id: "FEY153-01", + name: "Wellcare Pharmacy", + address: { + line1: "156 High Street", + town: "Edinburgh", + postcode: "EH8 8DH" + } + } + ] } ] diff --git a/app/routes/pharmacies.js b/app/routes/pharmacies.js index d25ee47e..a4a3e981 100644 --- a/app/routes/pharmacies.js +++ b/app/routes/pharmacies.js @@ -19,11 +19,15 @@ module.exports = router => { const companyId = res.locals.currentOrganisation.id - const organisations = data.organisations.filter((organisation) => organisation.companyId === companyId).sort(sortByNameThenPostcode()) + const allOrganisations = data.organisations.filter((organisation) => organisation.companyId === companyId).sort(sortByNameThenPostcode()) + + // Separate active/deactivated pharmacies from closed ones + const organisations = allOrganisations.filter((org) => org.status !== 'Closed') + const closedOrganisations = allOrganisations.filter((org) => org.status === 'Closed') let organisationUserCounts = {} - for (const organisation of organisations) { + for (const organisation of allOrganisations) { organisationUserCounts[organisation.id] = data.users .filter((user) => (user.organisations || []) .find((orgPermission) => orgPermission.id === organisation.id) @@ -33,6 +37,7 @@ module.exports = router => { res.render('pharmacies/index', { organisations, + closedOrganisations, organisationUserCounts, added }) diff --git a/app/views/pharmacies/index.html b/app/views/pharmacies/index.html index c5729741..05fe1c10 100644 --- a/app/views/pharmacies/index.html +++ b/app/views/pharmacies/index.html @@ -88,6 +88,62 @@

Pharmacies

+ + {% if closedOrganisations.length > 0 %} +
+ + + Closed pharmacies ({{ closedOrganisations | length }}) + + +
+

The following pharmacies have been closed.

+ + + + + + + + + + + {% for organisation in closedOrganisations %} + + + + + + + {% endfor %} + +
+ Name + + Vaccines + + Users + + Status +
+ {{ 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 }} +
+
+
+ {% endif %}
From 24a275d4ed5d360740176768d2bd7f68122e7c94 Mon Sep 17 00:00:00 2001 From: Anna-Sutton Date: Tue, 9 Jun 2026 21:06:35 +0100 Subject: [PATCH 08/29] Update line that introduced the email on check.html --- app/views/pharmacies/users/check.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/pharmacies/users/check.html b/app/views/pharmacies/users/check.html index bfadb9e4..ecc47246 100644 --- a/app/views/pharmacies/users/check.html +++ b/app/views/pharmacies/users/check.html @@ -113,7 +113,7 @@

Check and add {{ "group administrator" if data.permi ] }) }} -

{{ data.firstName }} will receive this welcome email telling them how to access the service:

+

{{ data.firstName }} {{ data.lastName }} will receive this email telling them how to access the service.

{% include "emails/welcome-email.html" %} From 4f0adb3ba5c7da2012c9816c2f92bffd2a6a76f4 Mon Sep 17 00:00:00 2001 From: Anna-Sutton Date: Wed, 10 Jun 2026 09:07:27 +0100 Subject: [PATCH 09/29] Aligned H1 on this screen with other similar screens --- app/views/pharmacies/users/add-to-permission-level.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/pharmacies/users/add-to-permission-level.html b/app/views/pharmacies/users/add-to-permission-level.html index d700c19f..fda41258 100644 --- a/app/views/pharmacies/users/add-to-permission-level.html +++ b/app/views/pharmacies/users/add-to-permission-level.html @@ -15,7 +15,7 @@
-

What should {{ user.firstName }} {{ user.lastName}}'s role at {{ pharmacy.name }} ({{ pharmacy.id }}) be?

+

{{ user.firstName }} {{ user.lastName}}'s role at {{ pharmacy.name }} ({{ pharmacy.id }})

{{ radios({ name: "vaccinator", From 50e812f2d5d1b8a2dff54f5c9518206427ccb350 Mon Sep 17 00:00:00 2001 From: Caitlin Roach Date: Wed, 10 Jun 2026 09:28:05 +0100 Subject: [PATCH 10/29] Fixed h1 text on user add to pharmacy --- .../pharmacies/add-user-permission-level.html | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/app/views/pharmacies/add-user-permission-level.html b/app/views/pharmacies/add-user-permission-level.html index 0992b1e3..ba7ea424 100644 --- a/app/views/pharmacies/add-user-permission-level.html +++ b/app/views/pharmacies/add-user-permission-level.html @@ -1,7 +1,13 @@ {% extends 'layout.html' %} {% set currentSection = "pharmacies" %} -{% set pageName = "Add a user to " + organisation.name %} +{% if existingUser %} + {% set pageName = existingUser.firstName + " " + existingUser.lastName + "'s role at " + organisation.name %} +{% elseif data.firstName or data.lastName %} + {% set pageName = (data.firstName + " " + data.lastName) + "'s role at " + organisation.name %} +{% else %} + {% set pageName = "New user's role at " + organisation.name %} +{% endif %} {% block beforeContent %} {{ backLink({ @@ -13,13 +19,13 @@

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

From 84f9d3b6e9b07118ca574eae9b8846f05e3ae54b Mon Sep 17 00:00:00 2001 From: Caitlin Roach Date: Wed, 10 Jun 2026 09:31:41 +0100 Subject: [PATCH 11/29] added email file for multiple pharmacies --- .../welcome-email-mulitple-pharmacies.html | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 app/views/emails/welcome-email-mulitple-pharmacies.html diff --git a/app/views/emails/welcome-email-mulitple-pharmacies.html b/app/views/emails/welcome-email-mulitple-pharmacies.html new file mode 100644 index 00000000..bb99042b --- /dev/null +++ b/app/views/emails/welcome-email-mulitple-pharmacies.html @@ -0,0 +1,41 @@ +

From: NHS Record a vaccination service (RAVS)
+ Subject: Start using Record a vaccination at (Pharmacy branch name) +

+
+ +

Dear (Name),

+ +

You’ve been invited to use the NHS Record a vaccination service at (Pharmacy branch name).

+ +

Get started

+ +

We’ve created an Okta account for you to securely access the service.

+ +

Here’s what you need to do:

+ +

1. Activate your Okta account

+

You’ll receive a 'Welcome to Okta' email (from noreply@okta.com).

+ +

Activate the link within 7 days.

+ +

If you cannot find the email, check your spam or junk.

+ +

2. Log in to Record a vaccination

+ +

Once you've activated your Okta account, log in to www.ravs.england.nhs.uk using your Okta username and password.

+ +

You can also access the service through your Okta account by selecting 'RAVS (PROD) app'.

+ +

Training and support

+

To help you get started, you can:

+ +

Kind regards,
+ NHS Record a vaccination

+ + + + From f525666b6f5dd9c27a451348e473890246b3181a Mon Sep 17 00:00:00 2001 From: Caitlin Roach Date: Wed, 10 Jun 2026 09:39:55 +0100 Subject: [PATCH 12/29] change role to permissions --- app/views/pharmacies/users/new-permission-level.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/pharmacies/users/new-permission-level.html b/app/views/pharmacies/users/new-permission-level.html index e01d527d..bb5a11ff 100644 --- a/app/views/pharmacies/users/new-permission-level.html +++ b/app/views/pharmacies/users/new-permission-level.html @@ -16,7 +16,7 @@

{{ data.firstName }} {{ data.lastName }}’s role

-

These roles will apply to the {{ data.pharmacyIds | length }} pharmacies.

+

These permissions will apply to the {{ data.pharmacyIds | length }} pharmacies.

{{ radios({ name: "vaccinator", From 7b68739f6dbc3a9f9b277a04d691d7668c35edb2 Mon Sep 17 00:00:00 2001 From: Anna-Sutton Date: Wed, 10 Jun 2026 10:35:33 +0100 Subject: [PATCH 13/29] Updated email for user added to multiple pharmacies Updated the welcome email to include multiple pharmacy locations. --- app/views/emails/welcome-email.html | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/app/views/emails/welcome-email.html b/app/views/emails/welcome-email.html index bb99042b..a961116f 100644 --- a/app/views/emails/welcome-email.html +++ b/app/views/emails/welcome-email.html @@ -1,11 +1,15 @@

From: NHS Record a vaccination service (RAVS)
- Subject: Start using Record a vaccination at (Pharmacy branch name) + Subject: Start using Record a vaccination


Dear (Name),

-

You’ve been invited to use the NHS Record a vaccination service at (Pharmacy branch name).

+

You’ve been invited to use the NHS Record a vaccination service at these pharmacies:

+ +

(pharmacy 1 and ODS code)

+

(pharmacy 2 and ODS code)

+

(pharmacy 3 and ODS code)

Get started

From f8d7003fc304dcf1909900b1fa76ec566eff3a55 Mon Sep 17 00:00:00 2001 From: Anna-Sutton Date: Wed, 10 Jun 2026 11:46:30 +0100 Subject: [PATCH 14/29] Updated description of Pharmacies page Changed to: Add pharmacies or manage an existing pharmacy. --- app/views/pharmacies/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/pharmacies/index.html b/app/views/pharmacies/index.html index 05fe1c10..9f050bdb 100644 --- a/app/views/pharmacies/index.html +++ b/app/views/pharmacies/index.html @@ -22,7 +22,7 @@

Pharmacies

-

Add pharmacies or manage users at an existing pharmacy.

+

Add pharmacies or manage an existing pharmacy.

{{ button({ text: "Add pharmacies", From 3f220e1bcb640388c774a80d3cc2190d1542ef1c Mon Sep 17 00:00:00 2001 From: Anna-Sutton Date: Wed, 10 Jun 2026 13:25:37 +0100 Subject: [PATCH 15/29] Tweaked deactivation message for user --- app/views/pharmacies/users/deactivate-from-group.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/pharmacies/users/deactivate-from-group.html b/app/views/pharmacies/users/deactivate-from-group.html index 5a85a2fe..0fa87f6f 100644 --- a/app/views/pharmacies/users/deactivate-from-group.html +++ b/app/views/pharmacies/users/deactivate-from-group.html @@ -17,7 +17,7 @@

Deactivate {{ user.firstName }} {{ user.lastName }} from {{ groupName }}

-

Once you deactivate {{ user.firstName }} {{ user.lastName }} ({{ user.email }}), they cannot sign in and use NHS Record a vaccination for this pharmacy group. They’ll receive an email to confirm their account has been deactivated.

+

Once you deactivate {{ user.firstName }} {{ user.lastName }} ({{ user.email }}), they will not be able to sign in and use NHS Record a vaccination for this pharmacy group. They’ll receive an email to confirm their account has been deactivated.

Their Okta account will remain active, so they can continue to access other services.

From df9f2581a2e6458cd93442f20a17aeeb61244d5c Mon Sep 17 00:00:00 2001 From: Caitlin Roach Date: Wed, 10 Jun 2026 13:33:35 +0100 Subject: [PATCH 16/29] Fixed remove action on new pharmas to a user --- app/routes/pharmacies.js | 18 +++++++- .../users/new-select-pharmacies-check.html | 44 +++++++++---------- 2 files changed, 37 insertions(+), 25 deletions(-) diff --git a/app/routes/pharmacies.js b/app/routes/pharmacies.js index a4a3e981..338c1c76 100644 --- a/app/routes/pharmacies.js +++ b/app/routes/pharmacies.js @@ -245,7 +245,7 @@ module.exports = router => { router.get('/pharmacies/users/new-select-pharmacies-check',(req, res) => { const data = req.session.data - const pharmacyIds = data.pharmacyIds + const pharmacyIds = data.pharmacyIds || [] // Get pharmacies selected on previous page const pharmacies = data.organisations.filter((organisation) => pharmacyIds.includes(organisation.id)) @@ -256,6 +256,22 @@ module.exports = router => { }) }) + router.get('/pharmacies/users/new-select-pharmacies-check/remove/:pharmacyId', (req, res) => { + const data = req.session.data + const pharmacyId = req.params.pharmacyId + const pharmacyIds = Array.isArray(data.pharmacyIds) + ? data.pharmacyIds + : (data.pharmacyIds ? [data.pharmacyIds] : []) + + data.pharmacyIds = pharmacyIds.filter((id) => id !== pharmacyId) + + if (data.pharmacyIds.length === 0) { + return res.redirect('/pharmacies/users/new-select-pharmacies') + } + + res.redirect('/pharmacies/users/new-select-pharmacies-check') + }) + router.get('/pharmacies/users/new-permission-level',(req, res) => { const data = req.session.data const pharmacyIds = data.pharmacyIds || [] diff --git a/app/views/pharmacies/users/new-select-pharmacies-check.html b/app/views/pharmacies/users/new-select-pharmacies-check.html index cff3e136..838f6c86 100644 --- a/app/views/pharmacies/users/new-select-pharmacies-check.html +++ b/app/views/pharmacies/users/new-select-pharmacies-check.html @@ -16,38 +16,34 @@

Check pharmacies

These are the pharmacies you will give {{ data.firstName }} {{ data.lastName }} access to.

- - {% set rows = [] %} + {% set rows = [] %} - {% for pharmacy in pharmacies %} + {% for pharmacy in pharmacies %} - {% set removeHtml %} - {{ button({ - text: "Remove", - classes: "nhsuk-button--secondary nhsuk-button--small nhsuk-u-margin-bottom-0" - }) }} - {% endset %} + {% set removeHtml %} + Remove + {% endset %} - {% set rows = (rows.push([ - { text: pharmacy.name + ", " + pharmacy.address.postcode + " (" + pharmacy.id + ")" }, - { html: removeHtml } - ]), rows) %} - {% endfor %} + {% set rows = (rows.push([ + { text: pharmacy.name + ", " + pharmacy.address.postcode + " (" + pharmacy.id + ")" }, + { html: removeHtml } + ]), rows) %} + {% endfor %} - {{ table({ - head: [ - { text: "Pharmacy" }, - { text: "" } - ], - rows: rows - }) }} + {{ table({ + head: [ + { text: "Pharmacy" }, + { text: "" } + ], + rows: rows + }) }} - {{ button({ - "text": "Continue" + {{ button({ + text: "Continue", + href: "/pharmacies/users/new-permission-level" }) }} -
From 766136a332d9f4ba674c6b22842a46275e47b90c Mon Sep 17 00:00:00 2001 From: Caitlin Roach Date: Wed, 10 Jun 2026 13:35:43 +0100 Subject: [PATCH 17/29] fix line on check pharmacies for multi pharma to a user --- app/views/pharmacies/users/new-select-pharmacies-check.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/pharmacies/users/new-select-pharmacies-check.html b/app/views/pharmacies/users/new-select-pharmacies-check.html index 838f6c86..75086f4b 100644 --- a/app/views/pharmacies/users/new-select-pharmacies-check.html +++ b/app/views/pharmacies/users/new-select-pharmacies-check.html @@ -14,7 +14,7 @@

Check pharmacies

-

These are the pharmacies you will give {{ data.firstName }} {{ data.lastName }} access to.

+

You are adding {{ data.firstName }} {{ data.lastName }} to these pharmacies.

{% set rows = [] %} From 55bcc43e031e932e4be5e112a7b20cf1b3e2a593 Mon Sep 17 00:00:00 2001 From: Caitlin Roach Date: Wed, 10 Jun 2026 13:57:43 +0100 Subject: [PATCH 18/29] Changes to make adding to additional pharmacies for multi at once --- app/routes/pharmacies.js | 115 +++++++++++++++--- ...=> welcome-email-multiple-pharmacies.html} | 0 app/views/pharmacies/users/add-to-check.html | 34 ++++-- .../users/add-to-permission-level.html | 15 ++- .../users/add-to-select-pharmacies-check.html | 51 ++++++++ app/views/pharmacies/users/add-to.html | 14 +-- app/views/pharmacies/users/check.html | 12 +- .../users/manage-select-pharmacy.html | 15 ++- .../users/new-permission-level.html | 15 ++- 9 files changed, 229 insertions(+), 42 deletions(-) rename app/views/emails/{welcome-email-mulitple-pharmacies.html => welcome-email-multiple-pharmacies.html} (100%) create mode 100644 app/views/pharmacies/users/add-to-select-pharmacies-check.html diff --git a/app/routes/pharmacies.js b/app/routes/pharmacies.js index 338c1c76..882e8b47 100644 --- a/app/routes/pharmacies.js +++ b/app/routes/pharmacies.js @@ -247,6 +247,14 @@ module.exports = router => { const data = req.session.data const pharmacyIds = data.pharmacyIds || [] + if (pharmacyIds.length === 0) { + return res.redirect('/pharmacies/users/new-select-pharmacies') + } + + if (pharmacyIds.length === 1) { + return res.redirect('/pharmacies/users/new-permission-level') + } + // Get pharmacies selected on previous page const pharmacies = data.organisations.filter((organisation) => pharmacyIds.includes(organisation.id)) @@ -558,20 +566,66 @@ module.exports = router => { }) }) + router.get('/pharmacies/users/:id/add-to-select-pharmacies-check', (req, res) => { + const data = req.session.data + const userId = req.params.id + const user = data.users.find(user => user.id === userId) + + const selectedPharmacyIds = data.addToPharmacyIds + ? (Array.isArray(data.addToPharmacyIds) ? data.addToPharmacyIds : [data.addToPharmacyIds]) + : [] + + if (selectedPharmacyIds.length === 0) { + return res.redirect(`/pharmacies/users/${userId}/add-to`) + } + + if (selectedPharmacyIds.length === 1) { + return res.redirect(`/pharmacies/users/${userId}/add-to-permission-level`) + } + + const pharmacies = data.organisations.filter((organisation) => selectedPharmacyIds.includes(organisation.id)) + + res.render('pharmacies/users/add-to-select-pharmacies-check', { + user, + pharmacies + }) + }) + + router.get('/pharmacies/users/:id/add-to-select-pharmacies-check/remove/:pharmacyId', (req, res) => { + const data = req.session.data + const userId = req.params.id + const pharmacyId = req.params.pharmacyId + + const selectedPharmacyIds = data.addToPharmacyIds + ? (Array.isArray(data.addToPharmacyIds) ? data.addToPharmacyIds : [data.addToPharmacyIds]) + : [] + + data.addToPharmacyIds = selectedPharmacyIds.filter((id) => id !== pharmacyId) + + if (data.addToPharmacyIds.length === 0) { + return res.redirect(`/pharmacies/users/${userId}/add-to`) + } + + res.redirect(`/pharmacies/users/${userId}/add-to-select-pharmacies-check`) + }) + router.get('/pharmacies/users/:id/add-to-permission-level',(req, res) => { const data = req.session.data const userId = req.params.id const user = data.users.find(user => user.id === userId) - const pharmacy = data.organisations.find(organisation => organisation.id === data.pharmacyId) + const selectedPharmacyIds = data.addToPharmacyIds + ? (Array.isArray(data.addToPharmacyIds) ? data.addToPharmacyIds : [data.addToPharmacyIds]) + : [] + const pharmacies = data.organisations.filter((organisation) => selectedPharmacyIds.includes(organisation.id)) - if (!pharmacy) { + if (pharmacies.length === 0) { return res.redirect(`/pharmacies/users/${userId}/add-to`) } res.render('pharmacies/users/add-to-permission-level', { user, - pharmacy + pharmacies }) }) @@ -580,15 +634,18 @@ module.exports = router => { const userId = req.params.id const user = data.users.find(user => user.id === userId) - const pharmacy = data.organisations.find(organisation => organisation.id === data.pharmacyId) + const selectedPharmacyIds = data.addToPharmacyIds + ? (Array.isArray(data.addToPharmacyIds) ? data.addToPharmacyIds : [data.addToPharmacyIds]) + : [] + const pharmacies = data.organisations.filter((organisation) => selectedPharmacyIds.includes(organisation.id)) - if (!pharmacy) { + if (pharmacies.length === 0) { return res.redirect(`/pharmacies/users/${userId}/add-to`) } res.render('pharmacies/users/add-to-check', { user, - pharmacy + pharmacies }) }) @@ -597,29 +654,45 @@ module.exports = router => { const id = req.params.id const user = data.users.find(user => user.id === id) - const pharmacy = data.organisations.find(organisation => organisation.id === data.pharmacyId) + const selectedPharmacyIds = data.addToPharmacyIds + ? (Array.isArray(data.addToPharmacyIds) ? data.addToPharmacyIds : [data.addToPharmacyIds]) + : [] + const pharmacies = data.organisations.filter((organisation) => selectedPharmacyIds.includes(organisation.id)) - if (!pharmacy) { + if (pharmacies.length === 0) { return res.redirect(`/pharmacies/users/${id}/add-to`) } const existingOrganisationIds = (user.organisations || []).map(organisation => organisation.id) - if (!existingOrganisationIds.includes(pharmacy.id)) { - user.organisations.push({ - id: pharmacy.id, - status: 'Active', - permissionLevel: data.permissionLevel, - vaccinator: (data.vaccinator === 'yes') - }) + const addedPharmacyIds = [] + + for (const pharmacy of pharmacies) { + if (!existingOrganisationIds.includes(pharmacy.id)) { + user.organisations.push({ + id: pharmacy.id, + status: 'Active', + permissionLevel: data.permissionLevel, + vaccinator: (data.vaccinator === 'yes') + }) + addedPharmacyIds.push(pharmacy.id) + } } // Reset answers data.permissionLevel = '' data.vaccinator = '' - data.pharmacyId = '' + data.addToPharmacyIds = [] + + if (addedPharmacyIds.length === 0) { + return res.redirect(`/pharmacies/users/${id}`) + } - res.redirect(`/pharmacies/users/${id}?addedToPharmacyId=${pharmacy.id}`) + if (addedPharmacyIds.length > 1) { + res.redirect(`/pharmacies/users/${id}?addedToPharmacyIds=${addedPharmacyIds.join(',')}`) + } else { + res.redirect(`/pharmacies/users/${id}?addedToPharmacyId=${addedPharmacyIds[0]}`) + } }) @@ -667,13 +740,18 @@ module.exports = router => { } const addedToPharmacyId = req.query.addedToPharmacyId + const addedToPharmacyIds = req.query.addedToPharmacyIds const deactivatedFromPharmacyId = req.query.deactivatedFromPharmacyId - let addedToPharmacy, deactivatedFromPharmacy + let addedToPharmacy, addedToPharmacies, deactivatedFromPharmacy if (addedToPharmacyId) { addedToPharmacy = data.organisations.find(organisation => organisation.id === addedToPharmacyId) } + if (addedToPharmacyIds) { + const ids = addedToPharmacyIds.split(',').filter(Boolean) + addedToPharmacies = data.organisations.filter((organisation) => ids.includes(organisation.id)) + } if (deactivatedFromPharmacyId) { deactivatedFromPharmacy = data.organisations.find(organisation => organisation.id === deactivatedFromPharmacyId) } @@ -697,6 +775,7 @@ module.exports = router => { user, pharmacyRoles, addedToPharmacy, + addedToPharmacies, deactivatedFromPharmacy, totalPharmaciesAtOrganisation }) diff --git a/app/views/emails/welcome-email-mulitple-pharmacies.html b/app/views/emails/welcome-email-multiple-pharmacies.html similarity index 100% rename from app/views/emails/welcome-email-mulitple-pharmacies.html rename to app/views/emails/welcome-email-multiple-pharmacies.html diff --git a/app/views/pharmacies/users/add-to-check.html b/app/views/pharmacies/users/add-to-check.html index 901ae60a..67036dbc 100644 --- a/app/views/pharmacies/users/add-to-check.html +++ b/app/views/pharmacies/users/add-to-check.html @@ -13,24 +13,40 @@
-

Check and add user to pharmacy

+

Check and add

+ + {% set pharmaciesHtml %} +
    + {% for pharmacy in pharmacies %} +
  • {{ pharmacy.name }} ({{ pharmacy.id }})
  • + {% endfor %} +
+ {% endset %} {{ summaryList({ rows: [ { key: { - text: "User" + text: "Name" + }, + value: { + text: user.firstName + " " + user.lastName + } + }, + { + key: { + text: "Email address" }, value: { - html: user.firstName + " " + user.lastName + "
" + user.email + text: user.email } }, { key: { - text: "Pharmacy" + text: "Pharmacy" if (pharmacies | length) == 1 else "Pharmacies" }, value: { - html: pharmacy.name + " (" + pharmacy.id + ")" + html: pharmaciesHtml }, actions: { items: [ @@ -79,10 +95,14 @@

Check and add user to pharmacy

] }) }} -

{{ user.firstName }} will receive this email telling them they now have access to the pharmacy:

+

{{ user.firstName }} will receive this email telling them they now have access to the {{ "pharmacy" if (pharmacies | length) == 1 else "pharmacies" }}:

- {% include "emails/welcome-email.html" %} + {% if (pharmacies | length) > 1 %} + {% include "emails/welcome-email-multiple-pharmacies.html" %} + {% else %} + {% include "emails/welcome-email.html" %} + {% endif %}
diff --git a/app/views/pharmacies/users/add-to-permission-level.html b/app/views/pharmacies/users/add-to-permission-level.html index fda41258..07223914 100644 --- a/app/views/pharmacies/users/add-to-permission-level.html +++ b/app/views/pharmacies/users/add-to-permission-level.html @@ -1,12 +1,13 @@ {% extends 'layout.html' %} {% set currentSection = "pharmacies-users" %} +{% set selectedPharmacy = (pharmacies | first) if (pharmacies | length) == 1 %} {% set pageName = "Add pharmacies" %} {% block beforeContent %} {{ backLink({ - href: "/pharmacies/users/" + user.id + "/add-to" + href: "/pharmacies/users/" + user.id + "/add-to-select-pharmacies-check" if (pharmacies | length) > 1 else "/pharmacies/users/" + user.id + "/add-to" }) }} {% endblock %} @@ -15,7 +16,17 @@
-

{{ user.firstName }} {{ user.lastName}}'s role at {{ pharmacy.name }} ({{ pharmacy.id }})

+

+ {% if (pharmacies | length) == 1 and selectedPharmacy %} + {{ user.firstName }} {{ user.lastName }}'s role at {{ selectedPharmacy.name }} ({{ selectedPharmacy.id }}) + {% else %} + {{ user.firstName }} {{ user.lastName }}'s role + {% endif %} +

+ + {% if (pharmacies | length) > 1 %} +

These permissions will apply to the {{ pharmacies | length }} pharmacies.

+ {% endif %} {{ radios({ name: "vaccinator", diff --git a/app/views/pharmacies/users/add-to-select-pharmacies-check.html b/app/views/pharmacies/users/add-to-select-pharmacies-check.html new file mode 100644 index 00000000..99b25756 --- /dev/null +++ b/app/views/pharmacies/users/add-to-select-pharmacies-check.html @@ -0,0 +1,51 @@ +{% extends 'layout.html' %} + +{% set currentSection = "pharmacies-users" %} + +{% block beforeContent %} + {{ backLink({ + href: "/pharmacies/users/" + user.id + "/add-to" + }) }} +{% endblock %} + +{% block content %} +
+
+ +

Check pharmacies

+ +

You are adding {{ user.firstName }} {{ user.lastName }} to these pharmacies.

+ + {% set rows = [] %} + + {% for pharmacy in pharmacies %} + + {% set removeHtml %} + Remove + {% endset %} + + {% set rows = (rows.push([ + { text: pharmacy.name + ", " + pharmacy.address.postcode + " (" + pharmacy.id + ")" }, + { html: removeHtml } + ]), rows) %} + {% endfor %} + + + {{ table({ + head: [ + { text: "Pharmacy" }, + { text: "" } + ], + rows: rows + }) }} + + + {{ button({ + text: "Continue", + href: "/pharmacies/users/" + user.id + "/add-to-permission-level" + }) }} + +
+
+ +{% endblock %} diff --git a/app/views/pharmacies/users/add-to.html b/app/views/pharmacies/users/add-to.html index 071dcac0..9870c9ac 100644 --- a/app/views/pharmacies/users/add-to.html +++ b/app/views/pharmacies/users/add-to.html @@ -13,7 +13,7 @@ {% block content %}
- + {% set items = [] %} @@ -26,7 +26,7 @@ {% call fieldset({ legend: { - text: "Which pharmacy would you like to add " + user.firstName + " " + user.lastName + " to?", + text: "Which pharmacies would you like to add " + user.firstName + " " + user.lastName + " to?", size: "l" } }) %} @@ -41,7 +41,7 @@ }, classes: "nhsuk-input--width-20", attributes: { - "data-module": "app-radios-filter" + "data-module": "app-checkbox-filter" }, formGroup: { classes: "nhsuk-u-margin-bottom-4" @@ -50,10 +50,10 @@ {% endif %}
- {{ radios({ - id: "pharmacy-id", - name: "pharmacyId", - value: data.pharmacyId, + {{ checkboxes({ + id: "pharmacy-ids", + name: "addToPharmacyIds", + values: data.addToPharmacyIds, items: items }) }}
diff --git a/app/views/pharmacies/users/check.html b/app/views/pharmacies/users/check.html index ecc47246..b0762553 100644 --- a/app/views/pharmacies/users/check.html +++ b/app/views/pharmacies/users/check.html @@ -18,7 +18,7 @@

Check and add {{ "group administrator" if data.permi {% set pharmaciesHtml %}
    {% for pharmacy in pharmacies %} -
  • {{ pharmacy.name }}
  • +
  • {{ pharmacy.name }} ({{ pharmacy.id }})
  • {% endfor %}
{% endset %} @@ -95,7 +95,7 @@

Check and add {{ "group administrator" if data.permi }, { key: { - text: "Pharmacies" + text: "Pharmacy" if (pharmacies | length) == 1 else "Pharmacies" }, value: { html: pharmaciesHtml @@ -113,10 +113,14 @@

Check and add {{ "group administrator" if data.permi ] }) }} -

{{ data.firstName }} {{ data.lastName }} will receive this email telling them how to access the service.

+

{{ data.firstName }} {{ data.lastName }} will receive this email.

- {% include "emails/welcome-email.html" %} + {% if (pharmacies | length) > 1 %} + {% include "emails/welcome-email-multiple-pharmacies.html" %} + {% else %} + {% include "emails/welcome-email.html" %} + {% endif %}
diff --git a/app/views/pharmacies/users/manage-select-pharmacy.html b/app/views/pharmacies/users/manage-select-pharmacy.html index 72d254e7..6cb46497 100644 --- a/app/views/pharmacies/users/manage-select-pharmacy.html +++ b/app/views/pharmacies/users/manage-select-pharmacy.html @@ -12,7 +12,20 @@ {% block content %}
- {% if addedToPharmacy %} + {% if addedToPharmacies and (addedToPharmacies | length) > 0 %} + {% set html %} +

+ User updated +

+

{{ user.firstName }} {{ user.lastName }} has been added to {{ (addedToPharmacies | pluck('name') | join(', ')) }}.

+ {% endset %} + + {{ notificationBanner({ + html: html, + type: "success" + }) }} + + {% elseif addedToPharmacy %} {% set html %}

User updated diff --git a/app/views/pharmacies/users/new-permission-level.html b/app/views/pharmacies/users/new-permission-level.html index bb5a11ff..faa0b5b5 100644 --- a/app/views/pharmacies/users/new-permission-level.html +++ b/app/views/pharmacies/users/new-permission-level.html @@ -1,10 +1,11 @@ {% extends 'layout.html' %} {% set currentSection = "pharmacies-users" %} +{% set selectedPharmacy = (pharmacies | first) if (pharmacies | length) == 1 %} {% block beforeContent %} {{ backLink({ - href: "/pharmacies/users/new-select-pharmacies-check" + href: "/pharmacies/users/new-select-pharmacies" if (pharmacies | length) == 1 else "/pharmacies/users/new-select-pharmacies-check" }) }} {% endblock %} @@ -14,9 +15,17 @@ -

{{ data.firstName }} {{ data.lastName }}’s role

+

+ {% if (pharmacies | length) == 1 and selectedPharmacy %} + {{ data.firstName }} {{ data.lastName }}'s role at {{ selectedPharmacy.name }} ({{ selectedPharmacy.id }}) + {% else %} + {{ data.firstName }} {{ data.lastName }}'s role + {% endif %} +

-

These permissions will apply to the {{ data.pharmacyIds | length }} pharmacies.

+ {% if (pharmacies | length) > 1 %} +

These permissions will apply to the {{ pharmacies | length }} pharmacies.

+ {% endif %} {{ radios({ name: "vaccinator", From 2a4fb1c62a50be8f008f670cdaab5c8529fcedfd Mon Sep 17 00:00:00 2001 From: Caitlin Roach Date: Wed, 10 Jun 2026 14:02:14 +0100 Subject: [PATCH 19/29] Success message updates --- app/views/pharmacies/users/add-to-check.html | 2 +- app/views/pharmacies/users/manage-select-pharmacy.html | 9 +++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/app/views/pharmacies/users/add-to-check.html b/app/views/pharmacies/users/add-to-check.html index 67036dbc..1e2441d8 100644 --- a/app/views/pharmacies/users/add-to-check.html +++ b/app/views/pharmacies/users/add-to-check.html @@ -95,7 +95,7 @@

Check and add

] }) }} -

{{ user.firstName }} will receive this email telling them they now have access to the {{ "pharmacy" if (pharmacies | length) == 1 else "pharmacies" }}:

+

{{ user.firstName }} {{ user.lastName }} will receive this email.

{% if (pharmacies | length) > 1 %} diff --git a/app/views/pharmacies/users/manage-select-pharmacy.html b/app/views/pharmacies/users/manage-select-pharmacy.html index 6cb46497..7a0f22e4 100644 --- a/app/views/pharmacies/users/manage-select-pharmacy.html +++ b/app/views/pharmacies/users/manage-select-pharmacy.html @@ -13,11 +13,16 @@
{% if addedToPharmacies and (addedToPharmacies | length) > 0 %} + {% set addedToPharmaciesWithOds = [] %} + {% for pharmacy in addedToPharmacies %} + {% set addedToPharmaciesWithOds = (addedToPharmaciesWithOds.push(pharmacy.name + " (" + pharmacy.id + ")"), addedToPharmaciesWithOds) %} + {% endfor %} + {% set html %}

User updated

-

{{ user.firstName }} {{ user.lastName }} has been added to {{ (addedToPharmacies | pluck('name') | join(', ')) }}.

+

{{ user.firstName }} {{ user.lastName }} has been added to {{ addedToPharmaciesWithOds | formatList }}.

{% endset %} {{ notificationBanner({ @@ -30,7 +35,7 @@

User updated

-

{{ user.firstName }} {{ user.lastName }} has been added to {{ addedToPharmacy.name }}.

+

{{ user.firstName }} {{ user.lastName }} has been added to {{ addedToPharmacy.name }} ({{ addedToPharmacy.id }}).

{% endset %} {{ notificationBanner({ From 3737ce35b8b81ac96fb06fd43ecdf88f61388c9f Mon Sep 17 00:00:00 2001 From: Caitlin Roach Date: Wed, 10 Jun 2026 14:07:50 +0100 Subject: [PATCH 20/29] added ability to deactivate from all pharmacies at once --- app/routes/pharmacies.js | 57 +++++++++++++++++++ .../users/deactivate-from-all-pharmacies.html | 42 ++++++++++++++ .../users/manage-select-pharmacy.html | 29 ++++++++-- 3 files changed, 123 insertions(+), 5 deletions(-) create mode 100644 app/views/pharmacies/users/deactivate-from-all-pharmacies.html diff --git a/app/routes/pharmacies.js b/app/routes/pharmacies.js index 882e8b47..9d226311 100644 --- a/app/routes/pharmacies.js +++ b/app/routes/pharmacies.js @@ -526,6 +526,59 @@ module.exports = router => { }) + router.get('/pharmacies/users/:userId/deactivate-from-all-pharmacies', (req, res) => { + const data = req.session.data + const userId = req.params.userId + const companyId = res.locals.currentOrganisation.id + + const user = data.users.find((item) => item.id === userId) + + if (!user) { + return res.redirect('/pharmacies/users') + } + + const activePharmacyRolesAtCompany = (user.organisations || []) + .map((role) => { + const pharmacy = data.organisations.find((organisation) => organisation.id === role.id) + return { role, pharmacy } + }) + .filter(({ role, pharmacy }) => pharmacy && pharmacy.companyId === companyId && role.permissionLevel !== 'Group administrator' && role.status !== 'Deactivated') + + if (activePharmacyRolesAtCompany.length === 0) { + return res.redirect(`/pharmacies/users/${userId}`) + } + + res.render('pharmacies/users/deactivate-from-all-pharmacies', { + user, + pharmacies: activePharmacyRolesAtCompany.map(({ pharmacy }) => pharmacy) + }) + }) + + router.post('/pharmacies/users/:userId/deactivate-from-all-pharmacies-answer', (req, res) => { + const data = req.session.data + const userId = req.params.userId + const companyId = res.locals.currentOrganisation.id + + const user = data.users.find((item) => item.id === userId) + + if (!user) { + return res.redirect('/pharmacies/users') + } + + let updatedRolesCount = 0 + + for (const role of (user.organisations || [])) { + const pharmacy = data.organisations.find((organisation) => organisation.id === role.id) + + if (pharmacy && pharmacy.companyId === companyId && role.permissionLevel !== 'Group administrator' && role.status !== 'Deactivated') { + role.status = 'Deactivated' + updatedRolesCount++ + } + } + + res.redirect(`/pharmacies/users/${userId}?deactivatedFromAllPharmacies=true&deactivatedFromAllCount=${updatedRolesCount}`) + }) + router.post('/pharmacies/:pharmacyId/users/:userId/change-answer',(req, res) => { const data = req.session.data @@ -742,6 +795,8 @@ module.exports = router => { const addedToPharmacyId = req.query.addedToPharmacyId const addedToPharmacyIds = req.query.addedToPharmacyIds const deactivatedFromPharmacyId = req.query.deactivatedFromPharmacyId + const deactivatedFromAllPharmacies = req.query.deactivatedFromAllPharmacies === 'true' + const deactivatedFromAllCount = parseInt(req.query.deactivatedFromAllCount, 10) || 0 let addedToPharmacy, addedToPharmacies, deactivatedFromPharmacy @@ -777,6 +832,8 @@ module.exports = router => { addedToPharmacy, addedToPharmacies, deactivatedFromPharmacy, + deactivatedFromAllPharmacies, + deactivatedFromAllCount, totalPharmaciesAtOrganisation }) }) diff --git a/app/views/pharmacies/users/deactivate-from-all-pharmacies.html b/app/views/pharmacies/users/deactivate-from-all-pharmacies.html new file mode 100644 index 00000000..7a80d5be --- /dev/null +++ b/app/views/pharmacies/users/deactivate-from-all-pharmacies.html @@ -0,0 +1,42 @@ +{% extends 'layout.html' %} + +{% set pageName = "Deactivate account" %} + +{% set currentSection = "pharmacies-users" %} + +{% block beforeContent %} + {{ backLink({ + href: "/pharmacies/users/" + user.id, + text: "Back" + }) }} +{% endblock %} + +{% block content %} +
+
+ +

Deactivate {{ user.firstName }} {{ user.lastName }} from {{ (pharmacies | length) | plural("pharmacy") }}

+ +

Once you deactivate {{ user.firstName }} {{ user.lastName }} ({{ user.email }}), they will not be able to sign in and use NHS Record a vaccination at any of these pharmacies:

+ +
    + {% for pharmacy in pharmacies %} +
  • {{ pharmacy.name }} ({{ pharmacy.id }})
  • + {% endfor %} +
+ +

Their Okta account will remain active, so they can continue to access other services.

+ +

You can reactivate their account anytime.

+ + + {{ button({ + text: "Deactivate", + classes: "nhsuk-button--warning" + }) }} + + +
+
+ +{% endblock %} diff --git a/app/views/pharmacies/users/manage-select-pharmacy.html b/app/views/pharmacies/users/manage-select-pharmacy.html index 7a0f22e4..62081201 100644 --- a/app/views/pharmacies/users/manage-select-pharmacy.html +++ b/app/views/pharmacies/users/manage-select-pharmacy.html @@ -58,6 +58,20 @@

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

+ User updated +

+

{{ user.firstName }} {{ user.lastName }} has been deactivated from {{ deactivatedFromAllCount }} {{ deactivatedFromAllCount | plural('pharmacy') }}.

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

{{ user.firstName }} {{ user.lastName }}

{{ summaryList({ @@ -109,11 +123,16 @@

Access and permission levels

- {{ button({ - text: "Add to another pharmacy", - href: "/pharmacies/users/" + user.id + "/add-to", - classes: "nhsuk-button--secondary" - }) }} +
+ {{ button({ + text: "Add to another pharmacy", + href: "/pharmacies/users/" + user.id + "/add-to", + classes: "nhsuk-button--secondary" + }) }} + {% if (pharmacyRoles | length) >= 2 %} + Deactivate from all pharmacies + {% endif %} +
{% else %}

This user is not currently added to any individual pharmacies.

From 892e1c1d2f3e81ac5f73f5e82b0c31b2c9fdeaf8 Mon Sep 17 00:00:00 2001 From: Caitlin Roach Date: Wed, 10 Jun 2026 14:21:55 +0100 Subject: [PATCH 21/29] fix to h1 for adding brand new user to a pharmacy --- app/routes/pharmacies.js | 19 ++++++++++++++----- app/views/pharmacies/add-user-check.html | 4 ++-- .../pharmacies/add-user-permission-level.html | 12 ++++++------ app/views/pharmacies/users/index.html | 13 +++++++++++++ ...ect-pharmacy.html => manage-ind-user.html} | 2 +- 5 files changed, 36 insertions(+), 14 deletions(-) rename app/views/pharmacies/users/{manage-select-pharmacy.html => manage-ind-user.html} (98%) diff --git a/app/routes/pharmacies.js b/app/routes/pharmacies.js index 9d226311..6357b52b 100644 --- a/app/routes/pharmacies.js +++ b/app/routes/pharmacies.js @@ -111,6 +111,8 @@ module.exports = router => { const deactivatedGroupAdminId = req.query.deactivatedGroupAdminId const deactivatedUserId = req.query.deactivatedUserId const deactivatedFromPharmacyId = req.query.deactivatedFromPharmacyId + const deactivatedFromAllUserId = req.query.deactivatedFromAllUserId + const deactivatedFromAllCount = parseInt(req.query.deactivatedFromAllCount, 10) || 0 const pharmacies = data.organisations.filter((organisation) => organisation.companyId === companyId) const pharmacyIds = pharmacies.map(pharmacy => pharmacy.id) @@ -142,6 +144,10 @@ module.exports = router => { ? data.organisations.find((organisation) => organisation.id === deactivatedFromPharmacyId) : undefined + const deactivatedFromAllUser = deactivatedFromAllUserId + ? data.users.find((user) => user.id === deactivatedFromAllUserId) + : undefined + // Show only active users added to individual pharmacies in the general user list. users = users.filter((user) => { if (groupAdministrators.includes(user)) { @@ -167,6 +173,8 @@ module.exports = router => { deactivatedGroupAdmin, deactivatedUser, deactivatedFromPharmacy, + deactivatedFromAllUser, + deactivatedFromAllCount, userPharmacyCounts }) }) @@ -565,18 +573,18 @@ module.exports = router => { return res.redirect('/pharmacies/users') } - let updatedRolesCount = 0 + const deactivatedPharmacyIds = [] for (const role of (user.organisations || [])) { const pharmacy = data.organisations.find((organisation) => organisation.id === role.id) if (pharmacy && pharmacy.companyId === companyId && role.permissionLevel !== 'Group administrator' && role.status !== 'Deactivated') { role.status = 'Deactivated' - updatedRolesCount++ + deactivatedPharmacyIds.push(pharmacy.id) } } - res.redirect(`/pharmacies/users/${userId}?deactivatedFromAllPharmacies=true&deactivatedFromAllCount=${updatedRolesCount}`) + res.redirect(`/pharmacies/users?deactivatedFromAllUserId=${userId}&deactivatedFromAllCount=${deactivatedPharmacyIds.length}`) }) @@ -796,7 +804,8 @@ module.exports = router => { const addedToPharmacyIds = req.query.addedToPharmacyIds const deactivatedFromPharmacyId = req.query.deactivatedFromPharmacyId const deactivatedFromAllPharmacies = req.query.deactivatedFromAllPharmacies === 'true' - const deactivatedFromAllCount = parseInt(req.query.deactivatedFromAllCount, 10) || 0 + const deactivatedFromAllPharmacyIds = (req.query.deactivatedFromAllPharmacyIds || '').split(',').filter(Boolean) + const deactivatedFromAllCount = deactivatedFromAllPharmacyIds.length let addedToPharmacy, addedToPharmacies, deactivatedFromPharmacy @@ -826,7 +835,7 @@ module.exports = router => { }) .filter((role) => role.pharmacy && role.pharmacy.companyId === companyId) - res.render('pharmacies/users/manage-select-pharmacy', { + res.render('pharmacies/users/manage-ind-user', { user, pharmacyRoles, addedToPharmacy, diff --git a/app/views/pharmacies/add-user-check.html b/app/views/pharmacies/add-user-check.html index ba1aa837..ea56ce9d 100644 --- a/app/views/pharmacies/add-user-check.html +++ b/app/views/pharmacies/add-user-check.html @@ -100,9 +100,9 @@

Check and {% if existingUserWithSameEmail %}reactiva {% if existingUser %} -

{{ existingUser.firstName }} {{ existingUser.lastName }} will receive this email inviting them to use the service at {{ organisation.name }} ({{ organisation.id }}).

+

{{ existingUser.firstName }} {{ existingUser.lastName }} will receive this email.

{% else %} -

{{ data.firstName }} {{ data.lastName }} will receive this email inviting them to use the service at {{ organisation.name }} ({{ organisation.id }}).

+

{{ data.firstName }} {{ data.lastName }} will receive this email.

{% endif %}
diff --git a/app/views/pharmacies/add-user-permission-level.html b/app/views/pharmacies/add-user-permission-level.html index ba7ea424..37ca1ad0 100644 --- a/app/views/pharmacies/add-user-permission-level.html +++ b/app/views/pharmacies/add-user-permission-level.html @@ -2,11 +2,11 @@ {% set currentSection = "pharmacies" %} {% if existingUser %} - {% set pageName = existingUser.firstName + " " + existingUser.lastName + "'s role at " + organisation.name %} + {% set pageName = existingUser.firstName + " " + existingUser.lastName + "'s role at " + organisation.name + " (" + organisation.id + ")" %} {% elseif data.firstName or data.lastName %} - {% set pageName = (data.firstName + " " + data.lastName) + "'s role at " + organisation.name %} + {% set pageName = (data.firstName + " " + data.lastName) + "'s role at " + organisation.name + " (" + organisation.id + ")" %} {% else %} - {% set pageName = "New user's role at " + organisation.name %} + {% set pageName = "New user's role at " + organisation.name + " (" + organisation.id + ")" %} {% endif %} {% block beforeContent %} @@ -20,11 +20,11 @@

{% if existingUser %} - {{ existingUser.firstName }} {{ existingUser.lastName }}'s role at {{ organisation.name }} + {{ 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 }} + {{ data.firstName }} {{ data.lastName }}'s role at {{ organisation.name }} ({{ organisation.id }}) {% else %} - New user's role at {{ organisation.name }} + Add new user to {{ organisation.name }} ({{ organisation.id }}) {% endif %}

diff --git a/app/views/pharmacies/users/index.html b/app/views/pharmacies/users/index.html index e52cd8d5..9b57c9ad 100644 --- a/app/views/pharmacies/users/index.html +++ b/app/views/pharmacies/users/index.html @@ -38,6 +38,19 @@

type: "success" }) }} {% endif %} + {% if deactivatedFromAllUser %} + {% set html %} +

+ User deactivated +

+

{{ deactivatedFromAllUser.firstName }} {{ deactivatedFromAllUser.lastName }} has been successfully deactivated from {{ deactivatedFromAllCount | plural("pharmacy") }}.

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

Users

diff --git a/app/views/pharmacies/users/manage-select-pharmacy.html b/app/views/pharmacies/users/manage-ind-user.html similarity index 98% rename from app/views/pharmacies/users/manage-select-pharmacy.html rename to app/views/pharmacies/users/manage-ind-user.html index 62081201..fbfaf973 100644 --- a/app/views/pharmacies/users/manage-select-pharmacy.html +++ b/app/views/pharmacies/users/manage-ind-user.html @@ -63,7 +63,7 @@

User updated

-

{{ user.firstName }} {{ user.lastName }} has been deactivated from {{ deactivatedFromAllCount }} {{ deactivatedFromAllCount | plural('pharmacy') }}.

+

{{ user.firstName }} {{ user.lastName }} has been deactivated from {{ deactivatedFromAllCount | plural('pharmacy') }}.

{% endset %} {{ notificationBanner({ From 4e79a937c730799fc4d5f42cd90c6734f90e913a Mon Sep 17 00:00:00 2001 From: Caitlin Roach Date: Wed, 10 Jun 2026 14:28:17 +0100 Subject: [PATCH 22/29] permission expander --- app/views/pharmacies/users/index.html | 58 +++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/app/views/pharmacies/users/index.html b/app/views/pharmacies/users/index.html index 9b57c9ad..52e9c132 100644 --- a/app/views/pharmacies/users/index.html +++ b/app/views/pharmacies/users/index.html @@ -94,6 +94,64 @@

Group administrators

Users at individual pharmacies

+ {% call details({ + summaryText: "What permissions will the user have?", + classes: "nhsuk-expander" + }) %} +

This table shows the permission levels you can assign when you add a user to a pharmacy.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Permission level + + Record vaccinations + + Manage vaccines + + Create reports + + Manage users +
+ Recorder + YesNoNoNo
+ Administrator + YesYesYesNo
+ Lead administrator + YesYesYesYes
+

You should add at least 1 lead administrator per pharmacy, so that person can add further users and manage vaccines at the pharmacy.

+ {% endcall %} + {% if users and (users | length) > 0 %} {% if (users | length) > 10 %} {{ input({ From 0023c1df22cd874c3d2988144101810eab384823 Mon Sep 17 00:00:00 2001 From: Caitlin Roach Date: Wed, 10 Jun 2026 15:28:07 +0100 Subject: [PATCH 23/29] Updates to check pages --- app/routes/pharmacies.js | 71 ++++++++- app/views/pharmacies/pharmacy.html | 70 ++++++++- app/views/pharmacies/users/add-to-check.html | 8 +- app/views/pharmacies/users/check.html | 10 +- .../users/deactivate-from-pharmacy.html | 4 +- app/views/pharmacies/users/index.html | 60 +------ .../pharmacies/users/manage-ind-user.html | 5 +- .../users/manage-select-pharmacy.html | 147 ++++++++++++++++++ 8 files changed, 296 insertions(+), 79 deletions(-) create mode 100644 app/views/pharmacies/users/manage-select-pharmacy.html diff --git a/app/routes/pharmacies.js b/app/routes/pharmacies.js index 6357b52b..cab382f9 100644 --- a/app/routes/pharmacies.js +++ b/app/routes/pharmacies.js @@ -508,13 +508,15 @@ module.exports = router => { const data = req.session.data const pharmacyId = req.params.pharmacyId const userId = req.params.userId + const from = req.query.from === 'pharmacy' ? 'pharmacy' : 'user' const user = data.users.find(user => user.id === userId) const pharmacy = data.organisations.find(organisation => organisation.id === pharmacyId) res.render('pharmacies/users/deactivate-from-pharmacy', { user, - pharmacy + pharmacy, + from }) }) @@ -522,6 +524,7 @@ module.exports = router => { const data = req.session.data const pharmacyId = req.params.pharmacyId const userId = req.params.userId + const from = req.query.from === 'pharmacy' ? 'pharmacy' : 'user' const user = data.users.find(user => user.id === userId) const pharmacy = data.organisations.find(organisation => organisation.id === pharmacyId) @@ -530,8 +533,35 @@ module.exports = router => { role.status = 'Deactivated' - res.redirect(`/pharmacies/users?deactivatedUserId=${user.id}&deactivatedFromPharmacyId=${pharmacy.id}`) + if (from === 'user') { + return res.redirect(`/pharmacies/users/${user.id}?deactivatedFromPharmacyId=${pharmacy.id}`) + } + + res.redirect(`/pharmacies/${pharmacy.id}?tab=deactivated&deactivatedUserId=${user.id}&deactivatedFromPharmacyId=${pharmacy.id}`) + + }) + + router.get('/pharmacies/:pharmacyId/users/:userId/reactivate', (req, res) => { + const data = req.session.data + const pharmacyId = req.params.pharmacyId + const userId = req.params.userId + + const user = data.users.find((item) => item.id === userId) + const pharmacy = data.organisations.find((organisation) => organisation.id === pharmacyId) + + if (!user || !pharmacy) { + return res.redirect('/pharmacies') + } + + const role = (user.organisations || []).find((item) => item.id === pharmacyId) + + if (!role) { + return res.redirect(`/pharmacies/${pharmacyId}?tab=deactivated`) + } + + role.status = 'Active' + res.redirect(`/pharmacies/${pharmacyId}?tab=active&reactivatedUserId=${userId}&reactivatedFromPharmacyId=${pharmacyId}`) }) router.get('/pharmacies/users/:userId/deactivate-from-all-pharmacies', (req, res) => { @@ -763,10 +793,17 @@ module.exports = router => { const added = req.query.added const addedUserId = req.query.addedUserId const deactivated = req.query.deactivated + const deactivatedUserId = req.query.deactivatedUserId + const deactivatedFromPharmacyId = req.query.deactivatedFromPharmacyId + const reactivatedUserId = req.query.reactivatedUserId + const reactivatedFromPharmacyId = req.query.reactivatedFromPharmacyId + const tab = (req.query.tab || 'active').toLowerCase() const organisation = data.organisations.find((organisation) => organisation.id === id) const addedUser = data.users.find((user) => user.id === addedUserId) + const deactivatedUser = data.users.find((user) => user.id === deactivatedUserId) + const reactivatedUser = data.users.find((user) => user.id === reactivatedUserId) const userOrganisationPermissions = {} @@ -775,17 +812,43 @@ module.exports = router => { .find((orgPermission) => orgPermission.id === organisation.id) ) + const usersByStatus = { + invited: [], + active: [], + deactivated: [] + } + for (const user of users) { userOrganisationPermissions[user.id] = user.organisations.find((userOrganisation) => userOrganisation.id === organisation.id) + + const userOrganisationStatus = userOrganisationPermissions[user.id].status + + if (userOrganisationStatus === 'Invited') { + usersByStatus.invited.push(user) + } else if (userOrganisationStatus === 'Deactivated') { + usersByStatus.deactivated.push(user) + } else { + usersByStatus.active.push(user) + } } + const validTabs = ['invited', 'active', 'deactivated'] + const currentTab = validTabs.includes(tab) ? tab : 'active' + const usersForTab = usersByStatus[currentTab] + res.render('pharmacies/pharmacy', { organisation, - users, + users: usersForTab, + usersByStatus, + currentTab, userOrganisationPermissions, added, addedUser, - deactivated + deactivated, + deactivatedUser, + deactivatedFromPharmacyId, + reactivatedUser, + reactivatedFromPharmacyId }) }) diff --git a/app/views/pharmacies/pharmacy.html b/app/views/pharmacies/pharmacy.html index e4f4a352..1c9ce629 100644 --- a/app/views/pharmacies/pharmacy.html +++ b/app/views/pharmacies/pharmacy.html @@ -42,6 +42,34 @@

}) }} {% endif %} + {% if deactivatedUser and deactivatedFromPharmacyId == organisation.id %} + {% set html %} +

+ User deactivated +

+

{{ deactivatedUser.firstName }} {{ deactivatedUser.lastName }} has been successfully deactivated from {{ organisation.name }} ({{ organisation.id }}).

+ {% endset %} + + {{ notificationBanner({ + html: html, + type: "success" + }) }} + {% endif %} + + {% if reactivatedUser and reactivatedFromPharmacyId == organisation.id %} + {% set html %} +

+ User reactivated +

+

{{ reactivatedUser.firstName }} {{ reactivatedUser.lastName }} has been successfully reactivated for {{ organisation.name }} ({{ organisation.id }}).

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

{{ pageName }}

{{ summaryList({ @@ -83,10 +111,6 @@

{{ pageName }}

{% endif %}

Users

-
-
-
-
{% if organisation.status != 'Deactivated' %} {{ button({ @@ -95,6 +119,27 @@

Users

}) }} {% endif %} + {{ 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 %} @@ -133,10 +178,13 @@

Users

{{ userOrganisationPermissions[user.id].status }} @@ -144,7 +192,13 @@

Users

- Changepermission level for {{ user.firstName }} {{ user.lastName }} - {% if userOrganisationPermissions[user.id].status != 'Deactivated' %} + {% if userOrganisationPermissions[user.id].status == 'Invited' %} + {% elif userOrganisationPermissions[user.id].status == 'Deactivated' %} + Reactivate {{ user.firstName }} {{ user.lastName }} + {% else %} + Change permission level for {{ user.firstName }} {{ user.lastName }}   - Deactivate {{ user.firstName }} {{ user.lastName }} + Deactivate {{ user.firstName }} {{ user.lastName }} {% endif %}
{% else %} -

No users added yet.

+ {% if currentTab == "invited" %} +

No invited users.

+ {% elif currentTab == "deactivated" %} +

No deactivated users.

+ {% else %} +

No active users.

+ {% endif %} {% endif %}
diff --git a/app/views/pharmacies/users/add-to-check.html b/app/views/pharmacies/users/add-to-check.html index 1e2441d8..51ce1a52 100644 --- a/app/views/pharmacies/users/add-to-check.html +++ b/app/views/pharmacies/users/add-to-check.html @@ -13,7 +13,13 @@
-

Check and add

+

+ {% if (pharmacies | length) > 1 %} + Check and add user to {{ pharmacies | length }} pharmacies + {% else %} + Check and add user to {{ pharmacies[0].name }} ({{ pharmacies[0].id }}) + {% endif %} +

{% set pharmaciesHtml %}
    diff --git a/app/views/pharmacies/users/check.html b/app/views/pharmacies/users/check.html index b0762553..7f55ff8d 100644 --- a/app/views/pharmacies/users/check.html +++ b/app/views/pharmacies/users/check.html @@ -13,7 +13,15 @@
    -

    Check and add {{ "group administrator" if data.permissionLevel == "Group administrator" else "user" }}

    +

    + {% if data.groupAdministrator == "yes" %} + Check and add group administrator + {% elif (pharmacies | length) > 1 %} + Check and add user to {{ pharmacies | length }} pharmacies + {% else %} + Check and add user to {{ pharmacies[0].name }} ({{ pharmacies[0].id }}) + {% endif %} +

    {% set pharmaciesHtml %}
      diff --git a/app/views/pharmacies/users/deactivate-from-pharmacy.html b/app/views/pharmacies/users/deactivate-from-pharmacy.html index b25c0e11..94d3da74 100644 --- a/app/views/pharmacies/users/deactivate-from-pharmacy.html +++ b/app/views/pharmacies/users/deactivate-from-pharmacy.html @@ -6,7 +6,7 @@ {% block beforeContent %} {{ backLink({ - href: "/pharmacies/users/" + user.id, + href: ("/pharmacies/" + pharmacy.id) if from == "pharmacy" else ("/pharmacies/users/" + user.id), text: "Back" }) }} {% endblock %} @@ -24,7 +24,7 @@

      Deactivate {{ user.firstName }} {{ user.lastName }}

      You can reactivate their account anytime.

      -
      + {{ button({ "text": "Deactivate", classes: "nhsuk-button--warning" diff --git a/app/views/pharmacies/users/index.html b/app/views/pharmacies/users/index.html index 52e9c132..227eb8ae 100644 --- a/app/views/pharmacies/users/index.html +++ b/app/views/pharmacies/users/index.html @@ -92,65 +92,7 @@

      Group administrators

      No group administrators added yet.

      {% endif %} -

      Users at individual pharmacies

      - - {% call details({ - summaryText: "What permissions will the user have?", - classes: "nhsuk-expander" - }) %} -

      This table shows the permission levels you can assign when you add a user to a pharmacy.

      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      - Permission level - - Record vaccinations - - Manage vaccines - - Create reports - - Manage users -
      - Recorder - YesNoNoNo
      - Administrator - YesYesYesNo
      - Lead administrator - YesYesYesYes
      -

      You should add at least 1 lead administrator per pharmacy, so that person can add further users and manage vaccines at the pharmacy.

      - {% endcall %} +

      Active users at individual pharmacies

      {% if users and (users | length) > 0 %} {% if (users | length) > 10 %} diff --git a/app/views/pharmacies/users/manage-ind-user.html b/app/views/pharmacies/users/manage-ind-user.html index fbfaf973..64c0db5a 100644 --- a/app/views/pharmacies/users/manage-ind-user.html +++ b/app/views/pharmacies/users/manage-ind-user.html @@ -115,7 +115,7 @@

      Access and permission levels

      Change permission level at {{ role.pharmacy.name }} {% if role.status != 'Deactivated' %}   - Deactivate from {{ role.pharmacy.name }} + Deactivate from {{ role.pharmacy.name }} {% endif %} @@ -129,9 +129,6 @@

      Access and permission levels

      href: "/pharmacies/users/" + user.id + "/add-to", classes: "nhsuk-button--secondary" }) }} - {% if (pharmacyRoles | length) >= 2 %} - Deactivate from all pharmacies - {% endif %}

    {% else %}

    This user is not currently added to any individual pharmacies.

    diff --git a/app/views/pharmacies/users/manage-select-pharmacy.html b/app/views/pharmacies/users/manage-select-pharmacy.html new file mode 100644 index 00000000..6da91839 --- /dev/null +++ b/app/views/pharmacies/users/manage-select-pharmacy.html @@ -0,0 +1,147 @@ +{% extends 'layout.html' %} + +{% set currentSection = "pharmacies-users" %} +{% set pageName = user.firstName + " " + user.lastName %} + +{% block beforeContent %} + {{ backLink({ + href: "/pharmacies/users" + }) }} +{% endblock %} + +{% block content %} +
    +
    + {% if addedToPharmacies and (addedToPharmacies | length) > 0 %} + {% set addedToPharmaciesWithOds = [] %} + {% for pharmacy in addedToPharmacies %} + {% set addedToPharmaciesWithOds = (addedToPharmaciesWithOds.push(pharmacy.name + " (" + pharmacy.id + ")"), addedToPharmaciesWithOds) %} + {% endfor %} + + {% set html %} +

    + User updated +

    +

    {{ user.firstName }} {{ user.lastName }} has been added to {{ addedToPharmaciesWithOds | formatList }}.

    + {% endset %} + + {{ notificationBanner({ + html: html, + type: "success" + }) }} + + {% elseif addedToPharmacy %} + {% set html %} +

    + User updated +

    +

    {{ user.firstName }} {{ user.lastName }} has been added to {{ addedToPharmacy.name }} ({{ addedToPharmacy.id }}).

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

    + User updated +

    +

    {{ user.firstName }} {{ user.lastName }} has been deactivated from {{ deactivatedFromPharmacy.name }}.

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

    + User updated +

    +

    {{ user.firstName }} {{ user.lastName }} has been deactivated from {{ deactivatedFromAllCount | plural('pharmacy') }}.

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

    {{ user.firstName }} {{ user.lastName }}

    + + {{ summaryList({ + rows: [ + { + key: { + text: "Email" + }, + value: { + text: user.email + } + } + ] + }) }} +
    +
    + +
    +
    +

    Access and permission levels

    + + {% if pharmacyRoles and (pharmacyRoles | length) > 0 %} + + + + + + + + + + + + {% for role in pharmacyRoles %} + + + + + + + + {% endfor %} + +
    PharmacyPermission levelVaccinatorStatusActions
    {{ role.pharmacy.name }} ({{ role.pharmacy.id }}){{ role.permissionLevel }}{{ "Yes" if role.vaccinator else "No" }}{{ role.status }} + Change permission level at {{ role.pharmacy.name }} + {% if role.status != 'Deactivated' %} +   + Deactivate from {{ role.pharmacy.name }} + {% endif %} +
    + +
    + {{ button({ + text: "Add to another pharmacy", + href: "/pharmacies/users/" + user.id + "/add-to", + classes: "nhsuk-button--secondary" + }) }} + {% if (pharmacyRoles | length) >= 2 %} + Deactivate from all pharmacies + {% endif %} +
    + {% else %} +

    This user is not currently added to any individual pharmacies.

    + + {{ button({ + text: "Add to a pharmacy", + href: "/pharmacies/users/" + user.id + "/add-to", + classes: "nhsuk-button--secondary" + }) }} + {% endif %} +
    +
    +{% endblock %} From 571c8cd009a8fefb880abd34ad2f4ad4157fb6ea Mon Sep 17 00:00:00 2001 From: Anna-Sutton Date: Thu, 11 Jun 2026 15:02:09 +0100 Subject: [PATCH 24/29] Update welcome email for user invited to use RAVS for a single pharmacy --- app/views/emails/welcome-email.html | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/app/views/emails/welcome-email.html b/app/views/emails/welcome-email.html index a961116f..477e3c8d 100644 --- a/app/views/emails/welcome-email.html +++ b/app/views/emails/welcome-email.html @@ -1,15 +1,11 @@

    From: NHS Record a vaccination service (RAVS)
    - Subject: Start using Record a vaccination + Subject: Start using Record a vaccination at (pharmacy name)


    Dear (Name),

    -

    You’ve been invited to use the NHS Record a vaccination service at these pharmacies:

    - -

    (pharmacy 1 and ODS code)

    -

    (pharmacy 2 and ODS code)

    -

    (pharmacy 3 and ODS code)

    +

    You’ve been invited to use the NHS Record a vaccination service at (pharmacy name).

    Get started

    @@ -18,6 +14,7 @@

    Here’s what you need to do:

    1. Activate your Okta account

    +

    You’ll receive a 'Welcome to Okta' email (from noreply@okta.com).

    Activate the link within 7 days.

    From bf838957e147bb5fbe8b5e285d1d97ce1eab7966 Mon Sep 17 00:00:00 2001 From: Caitlin Roach Date: Thu, 11 Jun 2026 16:26:59 +0100 Subject: [PATCH 25/29] remove unneeded email tempalte --- app/views/emails/reactivation-email.html | 13 ------------- app/views/pharmacies/add-user-check.html | 6 +----- app/views/user-admin/check.html | 12 ++---------- 3 files changed, 3 insertions(+), 28 deletions(-) delete mode 100644 app/views/emails/reactivation-email.html diff --git a/app/views/emails/reactivation-email.html b/app/views/emails/reactivation-email.html deleted file mode 100644 index 2a0a0c7e..00000000 --- a/app/views/emails/reactivation-email.html +++ /dev/null @@ -1,13 +0,0 @@ -

    From: ravs@england.nhs.uk
    -Subject: Reactivated account: NHS Record a vaccination service (RAVS) -

    -
    - -

    Hi {{ firstName}} {{ lastName}},

    - -

    We’ve reactivated your NHS Record a vaccination account. You can sign in using your Okta account.

    - -

    Reset your Okta password if you need to.

    - -

    Many thanks,
    -NHS Record a vaccination

    diff --git a/app/views/pharmacies/add-user-check.html b/app/views/pharmacies/add-user-check.html index ea56ce9d..2ee30845 100644 --- a/app/views/pharmacies/add-user-check.html +++ b/app/views/pharmacies/add-user-check.html @@ -106,11 +106,7 @@

    Check and {% if existingUserWithSameEmail %}reactiva {% endif %}
    - {% if existingUserWithSameEmail %} - {% include "emails/reactivation-email.html" %} - {% else %} - {% include "emails/welcome-email.html" %} - {% endif %} + {% include "emails/welcome-email.html" %}
    diff --git a/app/views/user-admin/check.html b/app/views/user-admin/check.html index 16cd7704..099f7ac7 100644 --- a/app/views/user-admin/check.html +++ b/app/views/user-admin/check.html @@ -93,18 +93,10 @@

    Check and {% if existingUserWithSameEmail %}reactiva }) }} - {% if existingUserWithSameEmail %} -

    {{ data.firstName }} will be re-activated and sent this email:

    - {% else %} -

    {{ data.firstName }} will receive this welcome email with information about activating an account:

    - {% endif %} +

    {{ data.firstName }} will receive this welcome email with information about activating an account:

    - {% if existingUserWithSameEmail %} - {% include "emails/reactivation-email.html" %} - {% else %} - {% include "emails/welcome-email.html" %} - {% endif %} + {% include "emails/welcome-email.html" %}
    From 74d0891f55cdab67320e0306ffcf604aca0505df Mon Sep 17 00:00:00 2001 From: Anna-Sutton Date: Thu, 11 Jun 2026 16:30:31 +0100 Subject: [PATCH 26/29] Updated welcome email content for pharmacy company --- app/views/emails/welcome-email.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/emails/welcome-email.html b/app/views/emails/welcome-email.html index 477e3c8d..611ed71b 100644 --- a/app/views/emails/welcome-email.html +++ b/app/views/emails/welcome-email.html @@ -1,11 +1,11 @@

    From: NHS Record a vaccination service (RAVS)
    - Subject: Start using Record a vaccination at (pharmacy name) + Subject: Start using Record a vaccination at (Pharmacy company)


    Dear (Name),

    -

    You’ve been invited to use the NHS Record a vaccination service at (pharmacy name).

    +

    You’ve been invited to use the NHS Record a vaccination service as a group administrator for (Pharmacy company).

    Get started

    From 3ff074d115aeca02e773110de9fb52252102fa80 Mon Sep 17 00:00:00 2001 From: Caitlin Roach Date: Thu, 11 Jun 2026 16:33:23 +0100 Subject: [PATCH 27/29] pharmacy selection text update --- app/views/pharmacies/users/new-select-pharmacies.html | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/views/pharmacies/users/new-select-pharmacies.html b/app/views/pharmacies/users/new-select-pharmacies.html index a1d0156f..c246bf17 100644 --- a/app/views/pharmacies/users/new-select-pharmacies.html +++ b/app/views/pharmacies/users/new-select-pharmacies.html @@ -12,9 +12,8 @@
    -

    Select pharmacies

    +

    Which pharmacies would you like to add {{ data.firstName }} {{ data.lastName }} to?

    -

    You can invite the new user to 1 or more of your pharmacies.

    @@ -29,8 +28,9 @@

    Select pharmacies

    {% call fieldset({ legend: { - text: "Which pharmacies do you want to add " + data.firstName + " " + data.lastName + " to?", - size: "m" + text: "Select pharmacies", + size: "m", + classes: "nhsuk-u-visually-hidden" } }) %} From b121c21f88773bcc2d23cb5e82c8edd92e0d3cf0 Mon Sep 17 00:00:00 2001 From: Anna-Sutton Date: Thu, 11 Jun 2026 16:56:40 +0100 Subject: [PATCH 28/29] Minor tweak to H1 Changed 'Add new user ...' to 'Add a new user' --- app/views/pharmacies/add-user-permission-level.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/pharmacies/add-user-permission-level.html b/app/views/pharmacies/add-user-permission-level.html index 37ca1ad0..0c991cd0 100644 --- a/app/views/pharmacies/add-user-permission-level.html +++ b/app/views/pharmacies/add-user-permission-level.html @@ -24,7 +24,7 @@

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

    From 2865ed6cd7cba667356d28af834462463f3ba68d Mon Sep 17 00:00:00 2001 From: Caitlin Roach Date: Thu, 11 Jun 2026 16:58:49 +0100 Subject: [PATCH 29/29] fix to capitalisation and to how we write vaccine co admins in appts --- app/data/appointments.js | 2 +- app/filters.js | 19 +++++++++++++++++++ app/views/appointments/_cancelled.html | 2 +- app/views/appointments/_completed.html | 2 +- app/views/appointments/_scheduled.html | 2 +- app/views/reports/choose-vaccines.html | 2 +- 6 files changed, 24 insertions(+), 5 deletions(-) diff --git a/app/data/appointments.js b/app/data/appointments.js index 9e999f49..a090e2ce 100644 --- a/app/data/appointments.js +++ b/app/data/appointments.js @@ -62,7 +62,7 @@ module.exports = [ } }, vaccinations: [ - "flu", "RSV" + "COVID-19", "RSV" ] }, { diff --git a/app/filters.js b/app/filters.js index 57aa92fc..f9d9a048 100644 --- a/app/filters.js +++ b/app/filters.js @@ -38,6 +38,25 @@ module.exports = function () { } } + filters.joinWithAnd = function(array) { + if (!Array.isArray(array) || array.length === 0) { + return '' + } + + const items = array.map((item) => String(item)) + items[0] = filters.capitaliseFirstLetter(items[0]) + + if (items.length === 1) { + return items[0] + } + + if (items.length === 2) { + return `${items[0]} and ${items[1]}` + } + + return `${items.slice(0, -1).join(', ')} and ${items[items.length - 1]}` + } + /** * Returns the name of a month, eg 'November', when * given the number of the month, eg 11. diff --git a/app/views/appointments/_cancelled.html b/app/views/appointments/_cancelled.html index 58e90892..b5e5c173 100644 --- a/app/views/appointments/_cancelled.html +++ b/app/views/appointments/_cancelled.html @@ -25,7 +25,7 @@
    {{ appointment.patient.dateOfBirth | age }} old
    - {{ (appointment.vaccinations | join(", ")) | capitaliseFirstLetter }} + {{ appointment.vaccinations | joinWithAnd }} diff --git a/app/views/appointments/_completed.html b/app/views/appointments/_completed.html index 5a838cbf..db279cba 100644 --- a/app/views/appointments/_completed.html +++ b/app/views/appointments/_completed.html @@ -24,7 +24,7 @@
    {{ appointment.patient.dateOfBirth | age }} old
    - {{ (appointment.vaccinations | join("
    ")) | capitaliseFirstLetter | safe }} + {{ appointment.vaccinations | joinWithAnd }} {% if appointment.patient.contactDetails.mobile %} diff --git a/app/views/appointments/_scheduled.html b/app/views/appointments/_scheduled.html index 0da0b9e1..333e12ca 100644 --- a/app/views/appointments/_scheduled.html +++ b/app/views/appointments/_scheduled.html @@ -28,7 +28,7 @@
    {{ appointment.patient.dateOfBirth | age }} old
    - {{ (appointment.vaccinations | join("
    ")) | capitaliseFirstLetter | safe }} + {{ appointment.vaccinations | joinWithAnd }} {% if appointment.patient.contactDetails.mobile %} diff --git a/app/views/reports/choose-vaccines.html b/app/views/reports/choose-vaccines.html index 1eb5ac18..506b89be 100644 --- a/app/views/reports/choose-vaccines.html +++ b/app/views/reports/choose-vaccines.html @@ -37,7 +37,7 @@ {% for vaccine in (enabledVaccines | sort(false, false, "name")) %} {% set items = (items.push({ value: vaccine.name, - text: (vaccine.name ) + text: (vaccine.name | capitaliseFirstLetter) }), items) %} {% endfor %}