Skip to content

Commit d3a8da0

Browse files
Pharmacy chain sign up improvements (#710)
This adds some improvements and bug fixes to the pharmacy chain sign up flow.
1 parent 07b93c6 commit d3a8da0

14 files changed

Lines changed: 161 additions & 53 deletions

app/lib/ods.js

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
const { capitaliseFromOds } = require('./utils/capitalise-from-ods.js')
2+
13

24
// There are 2 different ODS APIs, the old ORD API and the newer FHIR-based API.
35
// The ORD API is officially deprecated and may be retired in the future.
@@ -32,7 +34,7 @@ async function fetchPaginatedOrganisations(queryParams) {
3234
const results = (data.Organisations || []).map(function(org) {
3335
return {
3436
id: org.OrgId,
35-
name: org.Name,
37+
name: capitaliseFromOds(org.Name),
3638
address: {
3739
postcode: org.PostCode
3840
}
@@ -81,10 +83,10 @@ async function getOrganisation(id) {
8183

8284
const organisation = {
8385
id: data.id,
84-
name: data.name,
86+
name: capitaliseFromOds(data.name),
8587
address: {
86-
line1: data.address[0].line[0],
87-
town: data.address[0].city,
88+
line1: capitaliseFromOds(data.address[0].line[0]),
89+
town: capitaliseFromOds(data.address[0].city),
8890
postcode: data.address[0].postalCode
8991
}
9092
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// Words that should remain lowercase (unless at the start)
2+
const lowercaseWords = ['and', 'the', 'of', 'in', 'for', 'on', 'at', 'to', 'by', 'with', 'a', 'an'];
3+
4+
// Acronyms that should remain uppercase
5+
const acronyms = ['NHS', 'GP', 'PCN', 'CCG', 'ICB', 'CIC', 'UK', 'LLP', 'PLC'];
6+
7+
module.exports.capitaliseFromOds = function(input) {
8+
if (!input) return input;
9+
10+
const words = input.toLowerCase().split(/\s+/);
11+
12+
const capitalisedWords = words.map((word, index) => {
13+
// Check if word is initials (e.g. "p.g." or "a.b.c.")
14+
if (/^([a-z]\.)+$/i.test(word)) {
15+
return word.toUpperCase();
16+
}
17+
18+
// Check if word is a single letter (keep uppercase)
19+
if (/^[a-z]$/i.test(word)) {
20+
return word.toUpperCase();
21+
}
22+
23+
// Check if upper-cased word is an acronym
24+
const upperWord = word.toUpperCase();
25+
if (acronyms.includes(upperWord)) {
26+
return upperWord;
27+
}
28+
29+
// Check if word should remain lowercase (but not if it's the first word)
30+
if (index !== 0 && lowercaseWords.includes(word)) {
31+
return word;
32+
}
33+
34+
// Capitalise first letter, rest lowercase
35+
return word.charAt(0).toUpperCase() + word.slice(1);
36+
});
37+
38+
return capitalisedWords.join(' ');
39+
}

app/routes/apply.js

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,17 @@ module.exports = router => {
105105
})
106106
})
107107

108+
// Check list of selected pharmacies
109+
router.post('/apply/pharmacy-chain-check-remove-one', (req, res) => {
110+
const data = req.session.data
111+
const pharmacyIdToRemove = data.pharmacyIdToRemove
112+
113+
data.pharmacyIds = data.pharmacyIds.filter(id => id !== pharmacyIdToRemove)
114+
115+
res.redirect('/apply/pharmacy-chain-check')
116+
})
117+
118+
108119
// Check your answers page
109120
router.get('/apply/check', (req, res) => {
110121
const data = req.session.data
@@ -157,6 +168,51 @@ module.exports = router => {
157168
res.redirect('/apply/check-your-email')
158169
})
159170

171+
// Routing after the final check answers for chains page
172+
router.post('/apply/check-chain-answer', async (req, res) => {
173+
const data = req.session.data
174+
175+
let pharmacies = await getPharmaciesBelongingToOrganisation(data.pharmacyChainId)
176+
177+
pharmacies = pharmacies.filter((pharmacy) => {
178+
return data.pharmacyIds.includes(pharmacy.id)
179+
})
180+
181+
let userOrganisationPermissions = []
182+
183+
for (const pharmacy of pharmacies) {
184+
185+
// Add the pharmacy itself as the single site
186+
pharmacy.sites = [
187+
{
188+
id: pharmacy.id,
189+
name: pharmacy.name,
190+
address: pharmacy.address
191+
}
192+
]
193+
194+
data.organisations.push(pharmacy)
195+
userOrganisationPermissions.push({
196+
id: pharmacy.id,
197+
permissionLevel: 'Lead administrator',
198+
status: 'Active',
199+
vaccinator: false
200+
})
201+
}
202+
203+
const user = {
204+
id: Math.floor(Math.random() * 10000000).toString(),
205+
firstName: data.firstName,
206+
lastName: data.lastName,
207+
email: data.email,
208+
organisations: userOrganisationPermissions
209+
}
210+
211+
data.users.push(user)
212+
213+
res.redirect('/apply/check-your-email-chain')
214+
})
215+
160216
// Welcome email mockup
161217
router.get('/apply/welcome-email', (req, res) => {
162218
const data = req.session.data

app/routes/auth.js

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ module.exports = router => {
4343
req.session.data.currentUserId = user.id;
4444
req.session.data.currentOrganisationId = userOrganisationIds[0]
4545

46-
res.redirect('/survey')
46+
res.redirect('/home')
4747

4848
} else if (userRegionIds.length === 1) {
4949

@@ -55,7 +55,10 @@ module.exports = router => {
5555
} else if (organisationsUserIsAnAdminAt.length > 1) {
5656

5757
req.session.data.currentUserId = user.id
58-
res.redirect('/auth/select-mode')
58+
59+
// Skipping the select mode screen for research purposes
60+
res.redirect('/auth/select-organisation')
61+
// res.redirect('/auth/select-mode')
5962

6063
} else {
6164

@@ -79,7 +82,7 @@ module.exports = router => {
7982
req.session.data.currentUserId = data.userId
8083

8184

82-
res.redirect('/survey')
85+
res.redirect('/home')
8386
} else {
8487
res.redirect('/auth/select-mode')
8588
}
@@ -102,18 +105,12 @@ module.exports = router => {
102105
})
103106

104107
router.post('/select-organisation', (req, res) => {
105-
106-
const data = req.session.data
107-
const email = data.email
108-
const user = data.users.find((user) => user.email === email)
109-
110108
const selectedOrganisationId = req.session.data.organisationId
111109

112110
if (selectedOrganisationId) {
113-
req.session.data.currentUserId = user.id;
114111
req.session.data.currentOrganisationId = selectedOrganisationId;
115112

116-
res.redirect('/survey')
113+
res.redirect('/home')
117114
} else {
118115

119116
res.redirect('/auth/select-organisation')

app/routes/home.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ module.exports = router => {
8585
// organisation
8686
vaccinationsRecorded = allVaccinationsRecorded.filter((vaccination)=> vaccination.organisationId === currentOrganisation.id)
8787

88-
if (sites.length === 0) {
88+
if (!sites.length || sites.length === 0) {
8989
sites = [currentOrganisation]
9090
}
9191

app/routes/vaccines.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,8 @@ module.exports = (router) => {
105105

106106
for (const vaccine of vaccinesAdded) {
107107

108+
currentOrganisation.vaccines ||= []
109+
108110
let vaccineToEnable = currentOrganisation.vaccines.find((vaccine) => vaccine.name === vaccine)
109111

110112
if (vaccineToEnable) {

app/views/apply/check-chain.html

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,16 @@
1515
<h1 class="nhsuk-heading-l">{{ pageName }}</h1>
1616

1717
{% set pharmaciesHtml %}
18-
{% for pharmacy in pharmacies %}
19-
{{ pharmacy.name | capitalize }} ({{ pharmacy.id }})
20-
<br>
21-
{% endfor %}
18+
{% if (pharmacies | length) <= 10 %}
19+
<ul class="nhsuk-list">
20+
{% for pharmacy in pharmacies %}
21+
<li>{{ pharmacy.name }} ({{ pharmacy.id }})</li>
22+
{% endfor %}
23+
</ul>
24+
{% else %}
25+
{{ pharmacies | length }} pharmacies
26+
{% endif %}
27+
2228
{% endset %}
2329

2430
<h2 class="nhsuk-heading-m">Your pharmacies</h2>
@@ -29,7 +35,7 @@ <h2 class="nhsuk-heading-m">Your pharmacies</h2>
2935
text: "Company"
3036
},
3137
value: {
32-
html: (pharmacyChain.name | capitalize)
38+
html: pharmacyChain.name
3339
},
3440
actions: {
3541
items: [
@@ -146,7 +152,7 @@ <h2 class="nhsuk-heading-m">2nd lead administrator</h2>
146152
}) }}
147153
{% endif %}
148154

149-
<form action="/apply/check-your-email-chain" method="post">
155+
<form action="/apply/check-chain-answer" method="post">
150156
{{ button({
151157
text: "Confirm"
152158
}) }}

app/views/apply/check-pharmacy-chain.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ <h1 class="nhsuk-heading-l">{{ pageName }}</h1>
2222
text: "Name"
2323
},
2424
value: {
25-
text: organisation.name | capitalize
25+
text: organisation.name
2626
}
2727
},
2828
{
@@ -46,7 +46,7 @@ <h1 class="nhsuk-heading-l">{{ pageName }}</h1>
4646
text: "Address"
4747
},
4848
value: {
49-
html: (organisation.address.line1 | capitalize) + "<br>" + (organisation.address.town | capitalize) + "<br>" + organisation.address.postcode
49+
html: organisation.address.line1 + "<br>" + organisation.address.town + "<br>" + organisation.address.postcode
5050
}
5151
}
5252
]

app/views/apply/pharmacies.html

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{% extends 'layout.html' %}
22

3-
{% set pageName = "" %}
3+
{% set pageName = "Select the pharmacies where you want to start using RAVS" %}
44

55

66
{% block beforeContent %}
@@ -16,22 +16,23 @@
1616
<div class="nhsuk-grid-row">
1717
<div class="nhsuk-grid-column-two-thirds">
1818

19-
{% set items = [
20-
{
21-
text: "Select all",
22-
value: "",
23-
attributes: {
24-
"data-select-all": "true"
25-
}
26-
},
27-
{
28-
divider: "or"
29-
}
30-
] %}
19+
{% set items = [] %}
20+
{% if pharmacies | length > 1 %}
21+
{% set items = (items.push({
22+
text: "Select all",
23+
value: "",
24+
attributes: {
25+
"data-select-all": "true"
26+
}
27+
}), items) %}
28+
{% set items = (items.push({
29+
divider: "or"
30+
}), items) %}
31+
{% endif %}
3132

3233
{% for pharmacy in pharmacies %}
3334
{% set items = (items.push({
34-
text: (pharmacy.name | capitalize) + ", " + pharmacy.address.postcode + " (" + pharmacy.id + ")",
35+
text: pharmacy.name + ", " + pharmacy.address.postcode + " (" + pharmacy.id + ")",
3536
value: pharmacy.id
3637
}), items) %}
3738
{% endfor %}
@@ -44,7 +45,7 @@
4445
values: data.pharmacyIds,
4546
fieldset: {
4647
legend: {
47-
text: "Select the pharmacies where you want to start using RAVS",
48+
text: pageName,
4849
size: "l"
4950
}
5051
},

app/views/apply/pharmacy-chain-check.html

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515

1616
<h1 class="nhsuk-heading-l">{{ pageName }}</h1>
1717

18-
<p>You have selected <b>{{ pharmacies | length }} pharmacies</b>.</p>
18+
<p>You have selected <b>{{ pharmacies | length | plural("pharmacy") }}</b>.</p>
1919

2020
<table>
2121
<thead>
@@ -28,12 +28,17 @@ <h1 class="nhsuk-heading-l">{{ pageName }}</h1>
2828

2929
{% for pharmacy in pharmacies %}
3030
<tr>
31-
<td>{{ pharmacy.name | capitalize }}, {{ pharmacy.address.postcode }} ({{ pharmacy.id }})</td>
31+
<td>{{ pharmacy.name }}, {{ pharmacy.address.postcode }} ({{ pharmacy.id }})</td>
3232
<td class="nhsuk-u-text-align-right">
33-
{{ button({
34-
text: "Remove",
35-
classes: "nhsuk-button--small nhsuk-button--secondary nhsuk-u-margin-bottom-0"
36-
}) }}
33+
{% if pharmacies | length > 1 %}
34+
<form action="/apply/pharmacy-chain-check-remove-one" method="post">
35+
<input type="hidden" name="pharmacyIdToRemove" value="{{ pharmacy.id }}">
36+
{{ button({
37+
text: "Remove",
38+
classes: "nhsuk-button--small nhsuk-button--secondary nhsuk-u-margin-bottom-0"
39+
}) }}
40+
</form>
41+
{% endif %}
3742
</td>
3843
</tr>
3944
{% endfor %}

0 commit comments

Comments
 (0)