Skip to content

Commit 8d8b9e3

Browse files
Handle referrers so edit flows return users to where they came from (#86)
1 parent 59033f8 commit 8d8b9e3

20 files changed

Lines changed: 118 additions & 131 deletions

File tree

app.js

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Core dependencies
22
const path = require('path');
33
const fs = require('fs');
4+
const url = require('url')
45

56
// External dependencies
67
const bodyParser = require('body-parser');
@@ -105,7 +106,7 @@ if (useCookieSessionStore === 'true' && !onlyDocumentation) {
105106
// Somewhat similar file store to GOV.UK
106107
const FileStore = require('session-file-store')(sessionInMemory)
107108
const sessionPath = path.join(__dirname, '.tmp/sessions')
108-
109+
109110
// Make sure the sessions directory exists
110111
if (!fs.existsSync(sessionPath)) {
111112
fs.mkdirSync(sessionPath, { recursive: true })
@@ -260,7 +261,11 @@ app.use('/prototype-admin', prototypeAdminRoutes);
260261

261262
// Redirect all POSTs to GETs - this allows users to use POST for autoStoreData
262263
app.post(/^\/([^.]+)$/, (req, res) => {
263-
res.redirect(`/${req.params[0]}`);
264+
res.redirect(url.format({
265+
pathname: '/' + req.params[0],
266+
query: req.query
267+
})
268+
)
264269
});
265270

266271
// Catch 404 and forward to error handler

app/lib/utils/referrers.js

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -8,29 +8,29 @@
88
/**
99
* Parse referrer string into array of URLs
1010
* @private
11-
* @param {string|Array} referrer - Referrer string or array
11+
* @param {string|Array} referrerChain - Referrer string or array
1212
* @returns {Array} Array of referrer URLs
1313
*/
14-
const parseReferrerChain = (referrer) => {
15-
if (!referrer) return []
16-
if (Array.isArray(referrer)) return referrer
17-
return referrer.split(',').filter(Boolean)
14+
const parseReferrerChain = (referrerChain) => {
15+
if (!referrerChain) return []
16+
if (Array.isArray(referrerChain)) return referrerChain
17+
return referrerChain.split(',').filter(Boolean)
1818
}
1919

2020
/**
2121
* Get destination from referrer chain, falling back to provided URL if no referrer
2222
* @param {string} url - Default URL to use if no referrer
23-
* @param {string} referrer - Referrer chain
23+
* @param {string} referrerChain - Referrer chain
2424
* @returns {string} URL to use for back link
2525
* @example
2626
* // In templates:
27-
* <a href="{{ '/default-path' | orReferrer(referrer) }}">Back</a>
27+
* <a href="{{ '/default-path' | getReturnUrl(referrerChain) }}">Back</a>
2828
*/
29-
const orReferrer = function(url, referrer) {
29+
const getReturnUrl = function(url, referrerChain) {
3030
// Get currentUrl from context if available
3131
const currentUrl = this?.ctx?.currentUrl
3232

33-
const chain = parseReferrerChain(referrer)
33+
const chain = parseReferrerChain(referrerChain)
3434
.filter(ref => ref !== currentUrl)
3535

3636
if (!chain.length) return url
@@ -42,43 +42,43 @@ const orReferrer = function(url, referrer) {
4242
const remainingChain = chain.slice(0, -1)
4343
const destination = chain[chain.length - 1]
4444

45-
return `${destination}?referrer=${remainingChain.join(',')}`
45+
return `${destination}?referrerChain=${remainingChain.join(',')}`
4646
}
4747

4848
/**
4949
* Add referrer to URL as query parameter
5050
* @param {string} url - Base URL
51-
* @param {string} referrer - Referrer to append
51+
* @param {string} referrerChain - Referrer to append
5252
* @returns {string} URL with referrer query param
5353
* @example
5454
* // In templates:
55-
* <a href="{{ '/next-page' | withReferrer(referrer) }}">Continue</a>
55+
* <a href="{{ '/next-page' | urlWithReferrer(referrer) }}">Continue</a>
5656
*/
57-
const withReferrer = (url, referrer) => {
58-
if (!referrer) return url
59-
return `${url}?referrer=${referrer}`
57+
const urlWithReferrer = (url, referrerChain) => {
58+
if (!referrerChain) return url
59+
return `${url}?referrerChain=${referrerChain}`
6060
}
6161

6262
/**
6363
* Append a URL to an existing referrer chain
64-
* @param {string|Array} existingReferrer - Existing referrer chain
64+
* @param {string|Array} existingReferrerChain - Existing referrer chain
6565
* @param {string} newUrl - URL to append
6666
* @returns {string} Combined referrer chain
6767
* @example
6868
* // In templates:
69-
* {% set updatedReferrer = referrer | appendReferrer(currentUrl) %}
69+
* {% set updatedReferrer = referrerChain | appendReferrer(currentUrl) %}
7070
*/
71-
const appendReferrer = (existingReferrer, newUrl) => {
72-
if (!newUrl) return existingReferrer
73-
if (!existingReferrer) return newUrl
71+
const appendReferrer = (existingReferrerChain, newUrl) => {
72+
if (!newUrl) return existingReferrerChain
73+
if (!existingReferrerChain) return newUrl
7474

7575
const chain = parseReferrerChain(existingReferrer)
7676
chain.push(newUrl)
7777
return chain.join(',')
7878
}
7979

8080
module.exports = {
81-
orReferrer,
82-
withReferrer,
81+
getReturnUrl,
82+
urlWithReferrer,
8383
appendReferrer,
8484
}

app/locals.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ module.exports = (config) => (req, res, next) => {
77
currentUrl: req.path,
88
flash: req.flash(),
99
query: req.query,
10-
referrer: req.query.referrer
10+
referrerChain: req.query.referrerChain
1111
}
1212

1313
// Assign all local variables at once

app/routes/clinics.js

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
const dayjs = require('dayjs')
44
const { getFilteredClinics, getClinicEvents } = require('../lib/utils/clinics')
55
const { filterEventsByStatus } = require('../lib/utils/status')
6+
const { getReturnUrl, urlWithReferrer, appendReferrer } = require('../lib/utils/referrers')
7+
68

79
/**
810
* Get clinic and its related data from id
@@ -210,7 +212,7 @@ module.exports = router => {
210212
const data = req.session.data
211213

212214
// Get current filter from query param, or default to the current page's filter
213-
const currentFilter = req.query.filter || req.query.currentFilter || 'all'
215+
const currentFilter = req.query.filter || req.query.currentFilter || 'remaining'
214216

215217
// Find the event
216218
const eventIndex = data.events.findIndex(e => e.id === eventId && e.clinicId === clinicId)
@@ -257,13 +259,9 @@ module.exports = router => {
257259
})
258260
}
259261

260-
// If there's a returnTo path, use that, otherwise go back to the filter view
261-
const referrer = req.query.referrer
262-
if (referrer) {
263-
res.redirect(referrer)
264-
} else {
265-
res.redirect(`/clinics/${clinicId}/${currentFilter}`)
266-
}
262+
const returnUrl = getReturnUrl(`/clinics/${clinicId}/${currentFilter}`, req.query.referrerChain)
263+
res.redirect(returnUrl)
264+
267265
})
268266

269267

@@ -273,6 +271,12 @@ module.exports = router => {
273271
// Support both /clinics/:id and /clinics/:id/:filter
274272
router.get(['/clinics/:id', '/clinics/:id/:filter'], (req, res, next) => {
275273

274+
// Remaining is our default, so we can redirect to /clinics/:id
275+
if (req.params.filter == 'remaining'){
276+
res.redirect(`/clinics/${req.params.id}`)
277+
return
278+
}
279+
276280
// Check filter from either URL param or query string
277281
let defaultFilter = 'remaining'
278282
const filter = req.params.filter || req.query.filter || defaultFilter

app/routes/events.js

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ const { getFullName } = require('../lib/utils/participants')
55
const { generateMammogramImages } = require('../lib/generators/mammogram-generator')
66
const { getEvent, saveTempEventToEvent, updateEventStatus } = require('../lib/utils/event-data')
77
const generateId = require('../lib/utils/id-generator')
8+
const { getReturnUrl, urlWithReferrer, appendReferrer } = require('../lib/utils/referrers')
89

910
/**
1011
* Get single event and its related data
@@ -282,7 +283,7 @@ module.exports = router => {
282283
const { clinicId, eventId } = req.params
283284
const data = req.session.data
284285
const action = req.body.action // 'save' or 'save-and-add'
285-
const referrer = req.query.referrer
286+
const referrerChain = req.query.referrerChain
286287

287288
// Save temp symptom to array
288289
if (data.event?.symptomTemp) {
@@ -384,13 +385,10 @@ module.exports = router => {
384385

385386
// Redirect based on action
386387
if (action === 'save-and-add') {
387-
res.redirect(`/clinics/${clinicId}/events/${eventId}/medical-information/symptoms/add`)
388+
res.redirect(urlWithReferrer(`/clinics/${clinicId}/events/${eventId}/medical-information/symptoms/add`, referrerChain))
388389
} else {
389-
if (referrer) {
390-
res.redirect(referrer)
391-
return;
392-
}
393-
res.redirect(`/clinics/${clinicId}/events/${eventId}/record-medical-information`)
390+
const returnUrl = getReturnUrl(`/clinics/${clinicId}/events/${eventId}/record-medical-information`, referrerChain)
391+
res.redirect(returnUrl)
394392
}
395393
})
396394

@@ -417,7 +415,7 @@ module.exports = router => {
417415
}
418416

419417
// Go directly to details page since we already know the type
420-
res.redirect(`/clinics/${clinicId}/events/${eventId}/medical-information/symptoms/details`)
418+
res.redirect(urlWithReferrer(`/clinics/${clinicId}/events/${eventId}/medical-information/symptoms/details`, req.query.referrerChain))
421419
})
422420

423421
// Delete symptom
@@ -437,13 +435,14 @@ module.exports = router => {
437435

438436
req.flash('success', 'Symptom deleted')
439437

440-
res.redirect(`/clinics/${clinicId}/events/${eventId}/record-medical-information`)
438+
const returnUrl = getReturnUrl(`/clinics/${clinicId}/events/${eventId}/record-medical-information`, req.query.referrerChain)
439+
res.redirect(returnUrl)
441440
})
442441

443442
// Main route in to starting an event - used to clear any temp data
444443
router.get('/clinics/:clinicId/events/:eventId/medical-information/symptoms/add', (req, res) => {
445444
delete req.session.data.event.symptomTemp
446-
res.redirect(`/clinics/${req.params.clinicId}/events/${req.params.eventId}/medical-information/symptoms/type`)
445+
res.redirect(urlWithReferrer(`/clinics/${req.params.clinicId}/events/${req.params.eventId}/medical-information/symptoms/type`, req.query.referrerChain))
447446
})
448447

449448
const MAMMOGRAPHY_VIEWS = [

app/views/_components/event-status/template.njk

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,11 @@
1616

1717
{# Build href with optional referrer #}
1818
{% set href -%}
19-
/clinics/{{ params.clinicId }}/check-in/{{ params.event.id }}
20-
{%- if params.referrer %}?referrer={{ params.referrer }}{% endif %}
19+
/clinics/{{ params.clinicId }}/check-in/{{ params.event.id }}
2120
{%- endset %}
2221

22+
{% set href = href | trim | urlWithReferrer(params.referrerChain) %}
23+
2324
{% if params.event.status === 'event_scheduled' %}
2425
<p class="nhsuk-u-margin-top-2 nhsuk-u-margin-bottom-0">
2526
<a href="{{ href | trim }}" class="nhsuk-link nhsuk-link--no-visited-state js-check-in-link" data-clinic-id="{{ params.clinicId }}"

app/views/_includes/cards/medical-information/other-information.njk

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@
9393
actions: {
9494
items: [
9595
{
96-
href: "./medical-information/hormone-replacement-therapy",
96+
href: "./medical-information/hormone-replacement-therapy" | urlWithReferrer(currentUrl),
9797
text: "Change",
9898
visuallyHiddenText: "hormone replacement therapy (HRT)"
9999
}
@@ -110,7 +110,7 @@
110110
actions: {
111111
items: [
112112
{
113-
href: "./medical-information/pregnancy-and-breastfeeding",
113+
href: "./medical-information/pregnancy-and-breastfeeding" | urlWithReferrer(currentUrl),
114114
text: "Change",
115115
visuallyHiddenText: "pregnancy and breastfeeding"
116116
}

app/views/_includes/cards/medical-information/symptoms.njk

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,12 @@
1414
}) }}
1515
{% endif %}
1616

17+
{% set linkHref %}
18+
{{ "./medical-information/symptoms/add" | urlWithReferrer(currentUrl) }}
19+
{% endset %}
20+
1721
<p class="nhsuk-u-margin-top-4 nhsuk-u-margin-bottom-0">
18-
<a href="./medical-information/symptoms/add" class="nhsuk-link">{{ "Add another symptom" if hasSymptoms else "Add a symptom" }}</a>
22+
<a href="{{ linkHref }}" class="nhsuk-link">{{ "Add another symptom" if hasSymptoms else "Add a symptom" }}</a>
1923
</p>
2024
{% endset %}
2125

app/views/_includes/event-header.njk

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
{{ eventStatus({
66
clinicId: clinicId,
77
event: event,
8-
referrer: currentUrl
8+
referrerChain: currentUrl
99
})}}
1010
{% endset %}
1111

@@ -29,5 +29,5 @@
2929

3030
<p>{{ event.timing.startTime | formatTimeString }} ({{ event.timing.duration }} minutes) - {{ clinic.date | formatDate }} ({{ clinic.date | formatRelativeDate }})<span class="nhsuk-u-margin-left-3"><a href="#">Reschedule appointment</a></span></p>
3131

32-
<p class="nhsuk-u-margin-bottom-4"><a href="{{ '/participants/' + participant.id | withReferrer(currentUrl) }}">View participant record</a></p>
32+
<p class="nhsuk-u-margin-bottom-4"><a href="{{ '/participants/' + participant.id | urlWithReferrer(currentUrl) }}">View participant record</a></p>
3333

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,4 @@
1-
<p class="nhsuk-u-margin-top-x9"><a class="nhsuk-link nhsuk-link--no-visited-state" href="./attended-not-screened-reason">Appointment cannot proceed</a></p>
1+
<p class="">
2+
<a class="nhsuk-link nhsuk-link--no-visited-state" href="./attended-not-screened-reason">Appointment cannot proceed
3+
</a>
4+
</p>

0 commit comments

Comments
 (0)