Skip to content

Commit 796e98c

Browse files
Sticky appointment nav (#132)
* Make appointment bar sticky, and also add sticky confirm button * Fix CSS forward * Add event navigation to sticky header * Move appointment nav to sticky header * Fix completed tick messing with layout * Use a tag to show appointment type * Remove sticky footer stuff for now * Use consistent button styles --------- Co-authored-by: Ed Horsford <[email protected]>
1 parent cc6413f commit 796e98c

17 files changed

+316
-74
lines changed
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
// app/assets/sass/components/_header.scss
2+
3+
@use 'nhsuk-frontend/dist/nhsuk/core/settings' as *;
4+
@use 'nhsuk-frontend/dist/nhsuk/core/tools' as *;
5+
6+
.app-appointment-header--sticky {
7+
position: sticky;
8+
top: 0;
9+
z-index: 100;
10+
border-bottom: 1px solid $nhsuk-border-color;
11+
background-color: $color_nhsuk-grey-5;
12+
13+
// Sticky things
14+
// border-bottom-color: $color_nhsuk-grey-3;
15+
// box-shadow: 0 $nhsuk-border-width 0 red;
16+
}
17+
18+
.app-appointment-header--sticky[data-stuck="true"] {
19+
border-bottom-color: $color_nhsuk-grey-3;
20+
// box-shadow: 0 $nhsuk-border-width 0 red;
21+
box-shadow: 0 $nhsuk-border-width 0 rgba($color_nhsuk-grey-3, 50%);
22+
}
23+
24+
.app-appointment-header {
25+
26+
.app-secondary-navigation {
27+
margin-bottom: 0;
28+
}
29+
30+
.app-secondary-navigation__list-item:first-of-type .app-secondary-navigation__link {
31+
padding-left: 0;
32+
}
33+
34+
.app-secondary-navigation__link {
35+
font-size: 16px;
36+
padding: 0;
37+
}
38+
39+
.app-secondary-navigation__list-item {
40+
padding-top: 8px;
41+
padding-bottom: 8px;
42+
}
43+
44+
.app-secondary-navigation__list {
45+
box-shadow: none;
46+
}
47+
}

app/assets/sass/components/_secondary-navigation-overrides.scss

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@
1111
}
1212

1313
// Style the tick SVG specifically
14-
.app-secondary-navigation__link .app-icon--tick {
14+
.app-secondary-navigation .app-icon--tick {
15+
vertical-align: middle;
1516
width: 20px;
1617
height: 20px;
1718
flex-shrink: 0; // Prevent SVG from shrinking

app/assets/sass/components/_status-bar.scss

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,14 @@
1212

1313
.app-status-bar a {
1414
color: $color_nhsuk-white;
15+
16+
&:hover,
17+
&:active {
18+
color: $color_nhsuk-white;
19+
}
20+
&:focus {
21+
color: $nhsuk-text-color;
22+
}
1523
}
1624

1725
.app-status-bar__row {
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
2+
.app-sidebar-sticky {
3+
position: sticky;
4+
top: 20px;
5+
z-index: 100;
6+
height: fit-content;
7+
}
8+
9+
10+
// .app-status-bar {
11+
// position: sticky;
12+
// top: 0;
13+
// z-index: 100;
14+
// box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
15+
// }
16+
17+
.app-status-bar.is-sticky {
18+
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
19+
}
20+
21+
/* Sticky action button */
22+
23+
.app-sticky-bottom-container {
24+
position: fixed;
25+
bottom: 0;
26+
left: 0;
27+
right: 0;
28+
z-index: 200;
29+
background: #ffffff;
30+
border-top: 1px solid #d8dde0;
31+
padding: 20px;
32+
box-shadow: 0 -2px 8px rgba(0, 0, 0, 0.1);
33+
}
34+
35+
.app-sticky-bottom-container .nhsuk-grid-row {
36+
max-width: 960px;
37+
margin: 0 auto;
38+
}
39+
40+
.app-sticky-bottom-button {
41+
/* Use standard NHS button styling */
42+
margin: 0;
43+
}

app/assets/sass/main.scss

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
@forward 'components/button-menu';
66
@forward 'components/details';
77
@forward 'components/dark-mode';
8+
@forward 'components/appointment-header';
89
@forward 'components/list-border';
910
@forward 'components/modal';
1011
@forward 'components/related-nav';
@@ -19,6 +20,7 @@
1920
@forward 'components/overrides';
2021
@forward 'components/checkboxes';
2122
@forward 'components/breast-features';
23+
@forward 'components/sticky-appointment-bar';
2224

2325

2426
@forward 'components/annotation';

app/lib/generators/participant-generator.js

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,34 @@ const generateNHSNumber = () => {
146146
return `${baseNumber}${finalCheckDigit}`
147147
}
148148

149+
// Generate GP practice names (common UK naming patterns)
150+
const generateGPPracticeName = () => {
151+
const practiceTypes = [
152+
'Medical Centre',
153+
'Health Centre',
154+
'Surgery',
155+
'Medical Practice',
156+
'Family Practice'
157+
]
158+
159+
const nameFormats = [
160+
() => `${faker.location.street()} ${faker.helpers.arrayElement(practiceTypes)}`,
161+
// () => `${faker.person.lastName()} & ${faker.person.lastName()} ${faker.helpers.arrayElement(practiceTypes)}`,
162+
() => `${faker.helpers.arrayElement(['St', 'The', 'Manor', 'Park', 'Grove'])} ${faker.word.adjective()} ${faker.helpers.arrayElement(practiceTypes)}`,
163+
]
164+
165+
return faker.helpers.arrayElement(nameFormats)()
166+
}
167+
168+
// Generate GP information
169+
const generateGPInformation = (bsu) => {
170+
return {
171+
name: `Dr ${faker.person.fullName()}`,
172+
practiceName: generateGPPracticeName(),
173+
address: generateBSUAppropriateAddress(bsu)
174+
}
175+
}
176+
149177
const generateParticipant = ({
150178
ethnicities,
151179
breastScreeningUnits,
@@ -190,6 +218,7 @@ const generateParticipant = ({
190218
},
191219
medicalInformation: {
192220
nhsNumber: generateNHSNumber(),
221+
gp: generateGPInformation(assignedBSU),
193222
},
194223
currentHealthInformation: {
195224
isPregnant: false,

app/views/_components/secondary-navigation/template.njk

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,18 @@
33
{% for item in params.items %}
44
{% if item %}
55
<li class="app-secondary-navigation__list-item {{ "app-secondary-navigation__list-item--current" if item.current }}{% if item.classes %} {{ item.classes }}{% endif -%}">
6-
{% if not item.disabled %}
7-
<a class="app-secondary-navigation__link" href="{{ item.href }}" {{ "aria-current=page" if item.current }}>
8-
{{ item.text | safe }}
9-
</a>
6+
{% if item.html %}
7+
{{ item.html | safe }}
108
{% else %}
11-
<span class="app-secondary-navigation__link app-secondary-navigation__link--disabled">
12-
{{ item.text | safe }}
13-
</span>
9+
{% if not item.disabled %}
10+
<a class="app-secondary-navigation__link" href="{{ item.href }}" {{ "aria-current=page" if item.current }}>
11+
{{ item.text | safe }}
12+
</a>
13+
{% else %}
14+
<span class="app-secondary-navigation__link app-secondary-navigation__link--disabled">
15+
{{ item.text | safe }}
16+
</span>
17+
{% endif %}
1418
{% endif %}
1519
</li>
1620
{% endif %}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{# app/views/_includes/event-active-header.njk #}
2+
3+
<div class="app-appointment-header app-appointment-header--sticky" data-stuck="true">
4+
{% include "_includes/appointment-status-bar.njk" %}
5+
6+
<div class="nhsuk-width-container">
7+
{% include "_includes/event-active-tabs.njk" %}
8+
</div>
9+
</div>

app/views/_includes/appointment-status-bar.njk

Lines changed: 32 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,24 @@
11
{# app/views/_includes/appointment-status-bar.njk #}
22

3-
{% set firstRowItems = [] %}
3+
{% set leaveAppointmentLink %}
4+
<a href="/clinics/{{ clinicId }}">Leave this appointment</a>
5+
{% endset %}
6+
7+
8+
{% set manageAppointmentLink %}
9+
<a href="#">Manage appointment</a>
10+
{% endset %}
11+
12+
{% set appointmentActionItems = [
13+
{
14+
html: leaveAppointmentLink
15+
},
16+
{
17+
html: manageAppointmentLink
18+
}
19+
] %}
20+
21+
{% set appointmentRowItems = [] %}
422

523
{# Location name #}
624
{# {% set locationName %}
@@ -10,7 +28,7 @@
1028
{{ location.name }}
1129
{% endif %}
1230
{% endset %}
13-
{% set firstRowItems = firstRowItems | push({
31+
{% set appointmentRowItems = appointmentRowItems | push({
1432
key: "Location:",
1533
value: locationName
1634
}) %} #}
@@ -25,16 +43,20 @@
2543
})}}
2644
{% endif %}
2745
{% endset %}
28-
{% set firstRowItems = firstRowItems | push({
46+
{% set appointmentRowItems = appointmentRowItems | push({
2947
key: "Appointment:",
3048
value: appointmentHtml
3149
}) %}
3250

3351
{# Appointment type #}
34-
{% set firstRowItems = firstRowItems | push({
35-
key: "Type:",
36-
value: clinic.clinicType | formatWords | sentenceCase
37-
}) %}
52+
{% set screeningTagHtml %}
53+
<strong class="nhsuk-tag nhsuk-tag--blue">
54+
Screening
55+
</strong>
56+
{% endset %}
57+
{% set appointmentRowItems = appointmentRowItems | push({
58+
html: screeningTagHtml
59+
}) %}
3860

3961
{% set statusHtml %}
4062
{{ event.status | getStatusText | default(event.status | formatWords | sentenceCase) }}
@@ -49,7 +71,7 @@
4971
{% endset %}
5072

5173
{# Appointment status #}
52-
{# {% set firstRowItems = firstRowItems | push({
74+
{# {% set appointmentRowItems = appointmentRowItems | push({
5375
key: "Status:",
5476
value: statusHtml
5577
}) %} #}
@@ -86,7 +108,8 @@
86108

87109
{{ appStatusBar({
88110
rows: [
89-
{ items: firstRowItems },
111+
{ items: appointmentActionItems },
112+
{ items: appointmentRowItems },
90113
{ items: participantRowItems }
91114
]
92115
}) }}
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
{# app/views/_includes/event-active-tabs.njk #}
2+
3+
{# Tracking of status #}
4+
{% set identityStageCompleted = true if data.event.workflowStatus['identity'] == 'completed' else false %}
5+
{% set medicalInformationStageCompleted = true if data.event.workflowStatus['record-medical-information'] == 'completed' else false %}
6+
{% set awaitingImagesStageCompleted = true if data.event.workflowStatus['awaiting-images'] == 'completed' else false %}
7+
{% set imagesStageCompleted = true if data.event.workflowStatus['images'] == 'completed' else false %}
8+
9+
{# Build secondary nav #}
10+
{% set secondaryNavItems = [] %}
11+
12+
{# { id: 'appointment', label: 'Appointment' }, #}
13+
14+
{% for item in [
15+
{ id: 'identity', label: 'Participant' },
16+
17+
{ id: 'record-medical-information', label: 'Medical information' },
18+
{ id: 'images', label: 'Images' },
19+
{ id: 'review', label: 'Review' }
20+
] %}
21+
{% set href -%}
22+
/clinics/{{ clinicId }}/events/{{event.id}}{{ ("/" + item.id) if item.id !== 'all' }}
23+
{% endset %}
24+
25+
{# { id: 'eligibility', label: 'Eligibility' }, #}
26+
27+
{# SVG copied from https://service-manual.nhs.uk/design-system/components/do-and-dont-lists #}
28+
{% set tickSvg %}
29+
<svg class="app-icon app-icon--tick" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" aria-hidden="true">
30+
<path stroke-linecap="round" d="M18.4 7.8l-8.5 8.4L5.6 12"></path>
31+
</svg>
32+
{% endset %}
33+
34+
{% set isCompleted = data.event.workflowStatus[item.id] == 'completed' %}
35+
36+
37+
38+
{% set isDisabled = false %}
39+
{# Todo: refactor this be easier to check status #}
40+
41+
{% if item.id == 'record-medical-information' %}
42+
{% set isDisabled = true %}
43+
{% if identityStageCompleted %}
44+
{% set isDisabled = false %}
45+
{% endif %}
46+
{% endif %}
47+
48+
{# Disable images tab until other stages are completed #}
49+
{% if item.id == 'images' %}
50+
{% set isDisabled = true %}
51+
{% if identityStageCompleted and medicalInformationStageCompleted %}
52+
{% set isDisabled = false %}
53+
{% endif %}
54+
{% endif %}
55+
56+
{% if item.id == 'review' %}
57+
{% set isDisabled = true %}
58+
{% if identityStageCompleted and medicalInformationStageCompleted and awaitingImagesStageCompleted and imagesStageCompleted %}
59+
{% set isDisabled = false %}
60+
{% endif %}
61+
{% endif %}
62+
63+
{% set linkHtml %}
64+
{% if isDisabled %}
65+
<span class="app-secondary-navigation__link app-secondary-navigation__link--disabled">
66+
{{ item.label | safe }}
67+
</span>
68+
{% else %}
69+
{{ (tickSvg | safe) if isCompleted }}
70+
<a class="app-secondary-navigation__link" href="{{ href }}" {{ "aria-current=page" if item.id == activeTab }}>
71+
{{ item.label | safe }}
72+
</a>
73+
{% endif %}
74+
{% endset %}
75+
76+
{% set secondaryNavItems = secondaryNavItems | push({
77+
html: linkHtml,
78+
current: true if item.id == activeTab
79+
}) %}
80+
81+
{# text: (tickSvg if isCompleted) + item.label,
82+
href: href | trim,
83+
current: true if item.id == activeTab,
84+
disabled: isDisabled #}
85+
86+
{% endfor %}
87+
88+
{{ appSecondaryNavigation({
89+
visuallyHiddenTitle: "Secondary menu",
90+
items: secondaryNavItems
91+
}) }}

0 commit comments

Comments
 (0)