Skip to content

Commit 8a76a03

Browse files
Append to referrer chain so we return to the right place (#201)
* Append to referrer chain so we return to the right place * Fix more bugs
1 parent 978a6cd commit 8a76a03

File tree

18 files changed

+145
-29
lines changed

18 files changed

+145
-29
lines changed

app/lib/utils/referrers.js

Lines changed: 118 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,118 @@
11
// app/lib/utils/referrers.js
22

33
/**
4-
* Handle chained referrer URLs for back navigation
5-
* Allows deep linking while maintaining proper back navigation chains
4+
* Referrer Chain Navigation System
5+
*
6+
* This module handles multi-level back navigation by maintaining a chain of URLs
7+
* that grows as users navigate deeper and shrinks as they navigate back.
8+
*
9+
* ## Mental Model
10+
*
11+
* Think of the referrer chain as a breadcrumb trail:
12+
* - As you navigate TO deeper pages, add current URL to the chain
13+
* - As you navigate BACK, pop the last URL from the chain
14+
* - The chain is stored as a query parameter: ?referrerChain=/page1,/page2,/page3
15+
* - In templates, `referrerChain` refers to the template variable (populated from query.referrerChain)
16+
*
17+
* ## The Three Navigation Patterns
18+
*
19+
* ### 1. Navigating TO a page (extending the chain)
20+
* Use when: Going deeper into a flow, user should be able to return to current page
21+
*
22+
* ```nunjucks
23+
* {# Extending an existing chain (most common in multi-level flows) #}
24+
* <a href="{{ '/next-page' | urlWithReferrer(referrerChain | appendReferrer(currentUrl)) }}">
25+
*
26+
* {# Starting a new chain (no existing referrer) #}
27+
* <a href="{{ '/next-page' | urlWithReferrer(currentUrl) }}">
28+
* ```
29+
*
30+
* ### 2. Navigating BACK (consuming the chain)
31+
* Use when: On a "Continue" or "Save and return" button
32+
*
33+
* ```nunjucks
34+
* {# Extracts destination from chain, includes remaining chain #}
35+
* {{ button({
36+
* text: "Continue",
37+
* href: '../fallback' | getReturnUrl(referrerChain)
38+
* }) }}
39+
* ```
40+
*
41+
* ### 3. Building chains manually (advanced)
42+
* Use when: Pre-building chains for complex flows (e.g., "add" buttons that bypass review page)
43+
*
44+
* ```nunjucks
45+
* {# Build chain for add journey that returns through review page #}
46+
* {% set addReferrerChain = currentUrl | appendReferrer('/review') %}
47+
* <a href="{{ '/add' | urlWithReferrer(addReferrerChain) }}">Add item</a>
48+
* ```
49+
*
50+
* ## Real-World Example: Check Information Flow
51+
*
52+
* Starting point: User is on `/clinics/123/events/456/check-information`
53+
*
54+
* 1. **check-information** → **confirm-information/medical-history**
55+
* ```nunjucks
56+
* {# Start new chain with current page #}
57+
* <a href="{{ './confirm-information/medical-history' | urlWithReferrer(currentUrl) }}">
58+
* {# Result: ?referrerChain=/clinics/123/events/456/check-information #}
59+
* ```
60+
*
61+
* 2. **confirm-information/medical-history** → **edit form**
62+
* ```nunjucks
63+
* {# Extend chain by appending current page to existing chain #}
64+
* <a href="{{ './edit/123' | urlWithReferrer(referrerChain | appendReferrer(currentUrl)) }}">
65+
* {# Result: ?referrerChain=/check-information,/confirm-information/medical-history #}
66+
* ```
67+
*
68+
* 3. **edit form** → **back to confirm-information/medical-history**
69+
* ```nunjucks
70+
* {# Navigate back: pops last URL from chain and goes there #}
71+
* {{ button({ href: '../fallback' | getReturnUrl(referrerChain) }) }}
72+
* {# Goes to: /confirm-information/medical-history?referrerChain=/check-information #}
73+
* ```
74+
*
75+
* 4. **confirm-information/medical-history** → **back to check-information**
76+
* ```nunjucks
77+
* {# Navigate back again: pops last remaining URL #}
78+
* {{ button({ href: '../fallback' | getReturnUrl(referrerChain) }) }}
79+
* {# Goes to: /check-information (no chain param, it's exhausted) #}
80+
* ```
81+
*
82+
* ## Common Mistakes to Avoid
83+
*
84+
* ❌ **Using urlWithReferrer for back links**
85+
* ```nunjucks
86+
* {# WRONG: Adds referrer instead of consuming it #}
87+
* <a href="{{ '../previous' | urlWithReferrer(referrerChain) }}">Back</a>
88+
* ```
89+
* ✅ **Use getReturnUrl for back links**
90+
* ```nunjucks
91+
* {# CORRECT: Extracts destination from referrer chain #}
92+
* <a href="{{ '../previous' | getReturnUrl(referrerChain) }}">Back</a>
93+
* ```
94+
*
95+
* ❌ **Forgetting to extend the chain**
96+
* ```nunjucks
97+
* {# WRONG: Replaces chain instead of extending it #}
98+
* <a href="{{ '/next' | urlWithReferrer(currentUrl) }}">Continue</a>
99+
* ```
100+
* ✅ **Extend the chain when going deeper**
101+
* ```nunjucks
102+
* {# CORRECT: Extends existing chain with current URL #}
103+
* <a href="{{ '/next' | urlWithReferrer(referrerChain | appendReferrer(currentUrl)) }}">
104+
* ```
105+
*
106+
* ❌ **Not providing fallback for getReturnUrl**
107+
* ```nunjucks
108+
* {# WRONG: Returns empty string if no referrer #}
109+
* <a href="{{ '' | getReturnUrl(referrerChain) }}">Back</a>
110+
* ```
111+
* ✅ **Always provide a sensible fallback**
112+
* ```nunjucks
113+
* {# CORRECT: Falls back to sensible default #}
114+
* <a href="{{ '../parent-page' | getReturnUrl(referrerChain) }}">Back</a>
115+
* ```
6116
*/
7117

8118
/**
@@ -144,6 +254,12 @@ const appendReferrer = (existingReferrerChain, newUrl) => {
144254
if (!existingReferrerChain) return newUrl
145255

146256
const chain = parseReferrerChain(existingReferrerChain)
257+
258+
// Don't append if it's already the last item in the chain (prevents duplicates)
259+
if (chain.length > 0 && chain[chain.length - 1] === newUrl) {
260+
return existingReferrerChain
261+
}
262+
147263
chain.push(newUrl)
148264
return chain.join(',')
149265
}

app/views/_includes/add-symptom-button-menu.njk

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
{% for symptomType in data.symptomTypes %}
1414
{% set buttonMenuItems = buttonMenuItems | push({
1515
text: symptomType.name | sentenceCase,
16-
href: (methodUrl ~ symptomType.slug) | urlWithReferrer(referrerChain, scrollTo),
16+
href: (methodUrl ~ symptomType.slug) | urlWithReferrer(referrerChain | appendReferrer(currentUrl), scrollTo),
1717
classes: "nhsuk-button--secondary js-expand-parent-section"
1818
}) %}
1919
{% endfor %}

app/views/_includes/medical-information/breast-features.njk

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@
4747
{% endif %}
4848

4949
{% set linkHref %}
50-
{{ contextUrl + "/medical-information/record-breast-features" | urlWithReferrer(currentUrl, scrollTo) }}
50+
{{ contextUrl + "/medical-information/record-breast-features" | urlWithReferrer(referrerChain | appendReferrer(currentUrl), scrollTo) }}
5151
{% endset %}
5252

5353
{% if allowEdits %}
@@ -58,7 +58,7 @@
5858
<div class="nhsuk-form-group">
5959
{{ button({
6060
text: "Add a feature" if not hasBreastFeatures else "View or edit breast features",
61-
href: contextUrl + "/medical-information/record-breast-features" | urlWithReferrer(currentUrl, scrollTo),
61+
href: contextUrl + "/medical-information/record-breast-features" | urlWithReferrer(referrerChain | appendReferrer(currentUrl), scrollTo),
6262
classes: "nhsuk-button--secondary app-button--small"
6363
}) }}
6464
</div>

app/views/_includes/medical-information/mammogram-history.njk

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@
104104
actions: {
105105
items: [
106106
{
107-
href: contextUrl + "/previous-mammograms/edit/" + previousMammogram.id | urlWithReferrer(currentUrl, scrollTo),
107+
href: contextUrl + "/previous-mammograms/edit/" + previousMammogram.id | urlWithReferrer(referrerChain | appendReferrer(currentUrl), scrollTo),
108108
text: "Change",
109109
visuallyHiddenText: "Participant reported mammogram"
110110
}

app/views/_includes/medical-information/medical-history/index.njk

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@
7070

7171
{% for historyItem in historyItemArray %}
7272

73-
{% set changeHref = contextUrl + "/medical-information/medical-history/" + typeData.slug + "/edit/" + historyItem.id | urlWithReferrer(currentUrl, scrollTo) %}
73+
{% set changeHref = contextUrl + "/medical-information/medical-history/" + typeData.slug + "/edit/" + historyItem.id | urlWithReferrer(referrerChain | appendReferrer(currentUrl), scrollTo) %}
7474

7575
{# Attribution text #}
7676
{% set addedByText %}
@@ -611,7 +611,7 @@
611611
{% if typeData.canHaveMultiple %}
612612
{{ button({
613613
text: typeData.name,
614-
href: contextUrl + "/medical-information/medical-history/" + typeData.slug + "/add" | urlWithReferrer(currentUrl, scrollTo),
614+
href: contextUrl + "/medical-information/medical-history/" + typeData.slug + "/add" | urlWithReferrer(referrerChain | appendReferrer(currentUrl), scrollTo),
615615
classes: "nhsuk-button--secondary app-button--small"
616616
}) }}
617617
{% endif %}

app/views/_includes/medical-information/symptoms-card-content.njk

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
{% for symptomType in data.symptomTypes %}
3636
{{ button({
3737
text: symptomType.name | sentenceCase,
38-
href: (contextUrl + "/medical-information/symptoms/add?symptomType=" + symptomType.slug) | urlWithReferrer(currentUrl, scrollTo),
38+
href: (contextUrl + "/medical-information/symptoms/add?symptomType=" + symptomType.slug) | urlWithReferrer(referrerChain | appendReferrer(currentUrl), scrollTo),
3939
classes: "nhsuk-button--secondary app-button--small"
4040
}) }}
4141
{% endfor %}

app/views/_includes/summary-lists/medical-information/other-relevant-information.njk

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@
9393
actions: {
9494
items: [
9595
{
96-
href: contextUrl + "/medical-information/hormone-replacement-therapy" | urlWithReferrer(currentUrl, scrollTo),
96+
href: contextUrl + "/medical-information/hormone-replacement-therapy" | urlWithReferrer(referrerChain | appendReferrer(currentUrl), scrollTo),
9797
text: "Change",
9898
visuallyHiddenText: "hormone replacement therapy (HRT)"
9999
}
@@ -110,7 +110,7 @@
110110
actions: {
111111
items: [
112112
{
113-
href: contextUrl + "/medical-information/pregnancy-and-breastfeeding" | urlWithReferrer(currentUrl, scrollTo),
113+
href: contextUrl + "/medical-information/pregnancy-and-breastfeeding" | urlWithReferrer(referrerChain | appendReferrer(currentUrl), scrollTo),
114114
text: "Change",
115115
visuallyHiddenText: "pregnancy and breastfeeding"
116116
}
@@ -127,7 +127,7 @@
127127
actions: {
128128
items: [
129129
{
130-
href: contextUrl + "/medical-information/other-medical-information" | urlWithReferrer(currentUrl, scrollTo),
130+
href: contextUrl + "/medical-information/other-medical-information" | urlWithReferrer(referrerChain | appendReferrer(currentUrl), scrollTo),
131131
text: "Change",
132132
visuallyHiddenText: "other medical information"
133133
}

app/views/_includes/summary-lists/medical-information/symptoms/summary.njk

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@
129129
actions: {
130130
items: [
131131
{
132-
href: contextUrl + "/medical-information/symptoms/edit/" + symptom.id | urlWithReferrer(currentUrl),
132+
href: contextUrl + "/medical-information/symptoms/edit/" + symptom.id | urlWithReferrer(referrerChain | appendReferrer(currentUrl)),
133133
text: "Change",
134134
visuallyHiddenText: symptom.type | lower
135135
}

app/views/_includes/summary-lists/rows/address.njk

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
actions: {
3434
items: [
3535
{
36-
href: contextUrl ~ "/personal-details/contact-details" | urlWithReferrer(referrerChain),
36+
href: contextUrl ~ "/personal-details/contact-details" | urlWithReferrer(referrerChain | appendReferrer(currentUrl)),
3737
text: "Change",
3838
visuallyHiddenText: "home address"
3939
} if allowEdits

app/views/_includes/summary-lists/rows/email.njk

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
actions: {
1212
items: [
1313
{
14-
href: contextUrl ~ "/personal-details/contact-details" | urlWithReferrer(referrerChain or currentUrl),
14+
href: contextUrl ~ "/personal-details/contact-details" | urlWithReferrer(referrerChain | appendReferrer(currentUrl)),
1515
text: "Change",
1616
visuallyHiddenText: "email"
1717
} if allowEdits

0 commit comments

Comments
 (0)