Skip to content

Commit 8944305

Browse files
committed
Implement programme status tallies for the new session overview pahe
The session overview page is getting a new design layout which focuses on giving greater details about the progress of a session using tallies across various metrics such Eligible cohort, Vaccinated, Could not vaccinate etc. The overview page no is longer divided into 2 columns, and instead split up into 5 sections: 1. Programme status 2. Consent status 3. Session dates 4. Action required 5. About the location This commit will start with Programme status. The new design will only activate if the URL has the query param "tallies=true". This gives the testers are chance to see and understand the new design as it's built out.
1 parent 9a50dfe commit 8944305

File tree

6 files changed

+522
-84
lines changed

6 files changed

+522
-84
lines changed

app/assets/stylesheets/components/_card.scss

Lines changed: 122 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -3,90 +3,168 @@
33

44
.app-card {
55
&--aqua-green {
6-
.nhsuk-card__heading--feature {
7-
background-color: nhsuk-colour("aqua-green");
6+
background-color: nhsuk-tint(nhsuk-colour("aqua-green"), 80%);
7+
border-color: nhsuk-tint(nhsuk-colour("aqua-green"), 50%);
8+
color: nhsuk-shade(nhsuk-colour("aqua-green"), 50%);
9+
10+
&.nhsuk-card__clickable:active {
11+
border-color: nhsuk-shade(nhsuk-colour("aqua-green"), 50%);
812
}
913
}
1014

11-
&--dark-orange {
12-
.nhsuk-card__heading--feature {
13-
background-color: app.$dark-orange-colour;
15+
&--blue {
16+
background-color: nhsuk-tint(nhsuk-colour("blue"), 80%);
17+
border-color: nhsuk-tint(nhsuk-colour("blue"), 30%);
18+
color: nhsuk-shade(nhsuk-colour("blue"), 30%);
19+
20+
&.nhsuk-card__clickable:active {
21+
border-color: nhsuk-shade(nhsuk-colour("blue"), 30%);
1422
}
1523
}
1624

1725
&--green {
18-
.nhsuk-card__heading--feature {
19-
background-color: nhsuk-colour("green");
26+
background-color: nhsuk-tint(nhsuk-colour("green"), 80%);
27+
border-color: nhsuk-tint(nhsuk-colour("green"), 40%);
28+
color: nhsuk-shade(nhsuk-colour("green"), 40%);
29+
30+
&.nhsuk-card__clickable:active {
31+
border-color: nhsuk-shade(nhsuk-colour("green"), 40%);
2032
}
2133
}
2234

2335
&--grey {
24-
.nhsuk-card__heading--feature {
25-
background-color: nhsuk-colour("grey-1");
26-
}
27-
}
36+
background-color: nhsuk-tint(nhsuk-colour("grey-1"), 80%);
37+
border-color: nhsuk-tint(nhsuk-colour("grey-1"), 30%);
38+
color: nhsuk-shade(nhsuk-colour("grey-1"), 30%);
2839

29-
&--purple {
30-
.nhsuk-card__heading--feature {
31-
background-color: nhsuk-colour("purple");
40+
&.nhsuk-card__clickable:active {
41+
border-color: nhsuk-shade(nhsuk-colour("grey-1"), 30%);
3242
}
3343
}
3444

3545
&--red {
36-
.nhsuk-card__heading--feature {
37-
background-color: nhsuk-colour("red");
46+
background-color: nhsuk-tint(nhsuk-colour("red"), 80%);
47+
border-color: nhsuk-tint(nhsuk-colour("red"), 50%);
48+
color: nhsuk-shade(nhsuk-colour("red"), 50%);
49+
50+
&.nhsuk-card__clickable:active {
51+
border-color: nhsuk-shade(nhsuk-colour("red"), 50%);
3852
}
3953
}
4054

41-
&--reversed {
42-
background-color: nhsuk-colour("blue");
43-
border-color: nhsuk-shade(nhsuk-colour("blue"), 25%);
44-
color: nhsuk-colour("white");
55+
&--yellow {
56+
background-color: nhsuk-tint(nhsuk-colour("warm-yellow"), 80%);
57+
border-color: nhsuk-colour("warm-yellow");
4558

46-
&:active {
47-
border-color: nhsuk-shade(nhsuk-colour("blue"), 50%);
59+
.nhsuk-card__heading--feature {
60+
background-color: nhsuk-colour("warm-yellow");
61+
color: $nhsuk-text-colour;
62+
}
63+
64+
blockquote {
65+
border-color: nhsuk-colour("warm-yellow");
4866
}
67+
}
4968

50-
.nhsuk-card__link {
51-
@include nhsuk-link-style-white;
69+
&--aqua-green,
70+
&--blue,
71+
&--green,
72+
&--grey,
73+
&--red,
74+
&--yellow {
75+
.nhsuk-card__link,
76+
.nhsuk-card__link:hover {
77+
color: inherit;
5278
}
5379
}
5480

5581
&--offset {
5682
background-color: rgba(nhsuk-colour("grey-5"), 0.5);
5783
}
84+
}
5885

59-
&--data {
60-
display: flex;
86+
.app-card--compact {
87+
@include nhsuk-responsive-margin(3, "bottom");
6188

62-
.nhsuk-card__content {
63-
display: flex;
64-
flex-direction: column;
65-
flex-grow: 1;
66-
}
89+
.nhsuk-card__heading {
90+
@include nhsuk-responsive-margin(1, "bottom");
91+
}
6792

68-
.nhsuk-card__heading {
69-
@include nhsuk-typography-weight-normal;
70-
}
93+
.nhsuk-card__content {
94+
@include nhsuk-responsive-padding(4);
95+
@include nhsuk-responsive-padding(3, "bottom");
96+
}
97+
}
7198

72-
.nhsuk-card__description {
73-
margin-top: auto;
99+
.app-card--dense {
100+
@include nhsuk-responsive-margin(2, "bottom", $important: true);
74101

75-
@include nhsuk-font-size(48);
76-
@include nhsuk-typography-weight-bold;
77-
}
102+
.nhsuk-card__heading {
103+
@include nhsuk-responsive-margin(1, "bottom");
104+
}
105+
106+
.nhsuk-card__content {
107+
@include nhsuk-responsive-padding(3);
108+
@include nhsuk-responsive-padding(2, "bottom");
78109
}
79110
}
80111

81-
.app-card--compact {
82-
@include nhsuk-responsive-margin(3, "bottom");
112+
// Align counts across cards
113+
.nhsuk-card:has(> .nhsuk-card__content > .app-card__count) {
114+
display: flex;
83115

84116
.nhsuk-card__heading {
85-
@include nhsuk-responsive-margin(1, "bottom");
117+
line-height: 1.2;
86118
}
87119

88120
.nhsuk-card__content {
89-
@include nhsuk-responsive-padding(4);
90-
@include nhsuk-responsive-padding(3, "bottom");
121+
display: flex;
122+
flex: 1;
123+
flex-direction: column;
124+
justify-content: space-between;
125+
}
126+
}
127+
128+
.app-card__count {
129+
@include nhsuk-font-size(48);
130+
@include nhsuk-typography-weight-bold;
131+
132+
.app-card--dense & {
133+
@include nhsuk-font-size(26);
134+
}
135+
}
136+
137+
.app-card__heading--xxs {
138+
@include nhsuk-font(16, $weight: bold);
139+
}
140+
141+
.app-card__heading {
142+
&--aqua-green {
143+
background-color: nhsuk-colour("aqua-green");
144+
}
145+
146+
&--dark-orange {
147+
background-color: app.$dark-orange-colour;
148+
}
149+
150+
&--green {
151+
background-color: nhsuk-colour("green");
152+
}
153+
154+
&--grey {
155+
background-color: nhsuk-colour("grey-1");
156+
}
157+
158+
&--purple {
159+
background-color: nhsuk-colour("purple");
160+
}
161+
162+
&--red {
163+
background-color: nhsuk-colour("red");
164+
}
165+
166+
&--warm-yellow {
167+
background-color: nhsuk-colour("warm-yellow");
168+
color: $nhsuk-text-colour;
91169
}
92170
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
<div class="nhsuk-grid-column-full">
2+
<% programmes.each do |programme| %>
3+
<section>
4+
<h3 class="nhsuk-heading-m nhsuk-u-margin-bottom-4">
5+
<%= programme.name %>
6+
</h3>
7+
<ul class="nhsuk-grid-row nhsuk-card-group">
8+
<li class="nhsuk-grid-column-one-quarter nhsuk-card-group__item">
9+
<%= render AppCardComponent.new(heading_level: 5, colour: "blue", data: true, compact: true) do |card|
10+
card.with_heading { "Eligible cohort" }
11+
card.with_description { eligible_for_vaccination_count(programme).to_s }
12+
end %>
13+
</li>
14+
<li class="nhsuk-grid-column-one-quarter nhsuk-card-group__item">
15+
<%= render AppCardComponent.new(heading_level: 5,
16+
colour: "green",
17+
data: true,
18+
compact: true,
19+
link_to: session_patients_path(@session, vaccination_status: "vaccinated",
20+
programme_types: [programme.type])) do |card|
21+
card.with_heading { "Vaccinated" }
22+
card.with_description { vaccinated_count(programme).to_s }
23+
end %>
24+
</li>
25+
<li class="nhsuk-grid-column-one-quarter nhsuk-card-group__item">
26+
<%= render AppCardComponent.new(heading_level: 5,
27+
colour: "red",
28+
data: true,
29+
compact: true,
30+
link_to: session_patients_path(@session, vaccination_status: "could_not_vaccinate",
31+
programme_types: [programme.type])) do |card|
32+
card.with_heading { "Could not vaccinate" }
33+
card.with_description { could_not_vaccinate_count(programme).to_s }
34+
end %>
35+
</li>
36+
<li class="nhsuk-grid-column-one-quarter nhsuk-card-group__item">
37+
<%= render AppCardComponent.new(heading_level: 5,
38+
colour: "grey",
39+
data: true,
40+
compact: true,
41+
link_to: session_patients_path(@session, vaccination_status: "none_yet",
42+
programme_types: [programme.type])) do |card|
43+
card.with_heading { "No outcome" }
44+
card.with_description { no_outcome_count(programme).to_s }
45+
end %>
46+
</li>
47+
</ul>
48+
</section>
49+
<% end %>
50+
</div>
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
# frozen_string_literal: true
2+
3+
class AppSessionOverviewTalliesComponent < ViewComponent::Base
4+
def initialize(session)
5+
@session = session
6+
@patient_ids = session.patient_ids
7+
@academic_year = session.academic_year
8+
end
9+
10+
attr_reader :session, :patient_ids, :academic_year
11+
12+
delegate :govuk_table, to: :helpers
13+
delegate :programmes, to: :session
14+
15+
def eligible_for_vaccination_count(programme)
16+
patients_in_programme_cohort(programme).count -
17+
previously_vaccinated_count(programme) -
18+
vaccinated_at_different_locations_count(programme)
19+
end
20+
21+
def vaccinated_count(programme)
22+
administered_vaccination_count(programme)
23+
end
24+
25+
def could_not_vaccinate_count(programme)
26+
@could_not_vaccinate_count ||= {}
27+
@could_not_vaccinate_count[programme.id] ||= Patient::VaccinationStatus
28+
.where(programme:, academic_year:, patient_id: patient_ids)
29+
.could_not_vaccinate
30+
.count
31+
end
32+
33+
def no_outcome_count(programme)
34+
@no_outcome_count ||= {}
35+
@no_outcome_count[programme.id] ||= Patient::VaccinationStatus
36+
.where(programme:, academic_year:, patient_id: patient_ids)
37+
.none_yet
38+
.count
39+
end
40+
41+
private
42+
43+
def patients_in_programme_cohort(programme)
44+
@patients_in_programme_cohort ||= {}
45+
@patients_in_programme_cohort[
46+
programme.id
47+
] ||= session.patients.appear_in_programmes(programme, academic_year:)
48+
end
49+
50+
def previously_vaccinated_count(programme)
51+
return 0 if programme.seasonal?
52+
53+
Patient::VaccinationStatus
54+
.where(programme_id: programme.id, patient_id: patient_ids)
55+
.where("academic_year < ?", academic_year)
56+
.vaccinated
57+
.count
58+
end
59+
60+
def administered_vaccination_count(programme)
61+
Patient::VaccinationStatus
62+
.where(
63+
academic_year:,
64+
programme_id: programme.id,
65+
patient_id: patient_ids
66+
)
67+
.vaccinated
68+
.count
69+
end
70+
71+
def vaccinated_at_different_locations_count(programme)
72+
VaccinationRecord
73+
.where(
74+
programme_id: programme.id,
75+
patient_id: patient_ids,
76+
outcome: %w[administered already_had]
77+
)
78+
.where.not(location: session.location)
79+
.distinct
80+
.count(:patient_id)
81+
end
82+
end

app/views/sessions/_header.html.erb

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
<%= h1 @session.location.name, class: "nhsuk-u-margin-bottom-2" %>
22

3-
<p class="nhsuk-caption-l nhsuk-u-margin-bottom-4">
4-
<%= @session.programmes.map(&:name).to_sentence %>
5-
(<%= format_academic_year(@session.academic_year) %>)
6-
</p>
3+
<% unless params[:tallies] == "true" %>
4+
<p class="nhsuk-caption-l nhsuk-u-margin-bottom-4">
5+
<%= @session.programmes.map(&:name).to_sentence %>
6+
(<%= format_academic_year(@session.academic_year) %>)
7+
</p>
8+
<% end %>
79

810
<%= render AppSecondaryNavigationComponent.new do |nav|
911
nav.with_item(

0 commit comments

Comments
 (0)