Skip to content

Commit ef2ebe2

Browse files
jhendersonthomasleese
authored andcommitted
Merge pull request #4384 from nhsuk/prescribers-can-create-psd-instructions-in-bulk
Prescribers can create PSD instructions in bulk
2 parents 5280902 + 141701e commit ef2ebe2

File tree

16 files changed

+397
-29
lines changed

16 files changed

+397
-29
lines changed

app/assets/stylesheets/components/_action-list.scss

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,59 @@
3333
margin-right: 0;
3434
padding-right: 0;
3535
}
36+
37+
.nhsuk-action-link {
38+
@include nhsuk-responsive-margin(6, "bottom");
39+
}
40+
41+
.nhsuk-action-link__link {
42+
display: inline-block; // [1]
43+
padding-left: 38px; // [2]
44+
position: relative; // [3]
45+
text-decoration: none; // [4]
46+
47+
@include nhsuk-font(22, $weight: bold);
48+
49+
&:not(:focus):hover {
50+
.nhsuk-action-link__text {
51+
text-decoration: underline; // [6]
52+
}
53+
}
54+
55+
@include nhsuk-media-query($until: tablet) {
56+
padding-left: 26px; // [2]
57+
}
58+
59+
@include nhsuk-media-query($media-type: print) {
60+
color: $nhsuk-print-text-color;
61+
62+
&:visited {
63+
color: $nhsuk-print-text-color;
64+
}
65+
}
66+
67+
.nhsuk-icon__arrow-right-circle {
68+
// stylelint-disable-next-line declaration-no-important
69+
fill: $color_nhsuk-green !important;
70+
height: 36px;
71+
left: -3px;
72+
position: absolute;
73+
top: -3px;
74+
width: 36px;
75+
76+
@include nhsuk-print-color($nhsuk-print-text-color);
77+
78+
@include nhsuk-media-query($until: tablet) {
79+
height: 24px;
80+
left: -2px;
81+
margin-bottom: 0;
82+
top: 1px;
83+
width: 24px;
84+
}
85+
}
86+
87+
&:focus .nhsuk-icon__arrow-right-circle {
88+
// stylelint-disable-next-line declaration-no-important
89+
fill: $color_nhsuk-black !important;
90+
}
91+
}

app/components/app_patient_session_search_result_card_component.rb

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ class AppPatientSessionSearchResultCardComponent < ViewComponent::Base
3737
end
3838
end
3939
40-
if (note = patient_session.latest_note)
40+
if context != :patient_specific_direction && (note = patient_session.latest_note)
4141
summary_list.with_row do |row|
4242
row.with_key { "Notes" }
4343
row.with_value { render note_to_log_event(note) }
@@ -57,7 +57,16 @@ class AppPatientSessionSearchResultCardComponent < ViewComponent::Base
5757
def initialize(patient_session, context:, programmes: [])
5858
super
5959

60-
unless context.in?(%i[patients consent triage register record])
60+
unless context.in?(
61+
%i[
62+
patients
63+
consent
64+
triage
65+
register
66+
record
67+
patient_specific_direction
68+
]
69+
)
6170
raise "Unknown context: #{context}"
6271
end
6372

@@ -157,6 +166,8 @@ def status_tags
157166
[consent_status_tag]
158167
when :triage
159168
[triage_status_tag]
169+
when :patient_specific_direction
170+
[patient_specific_direction_status_tag]
160171
else
161172
[vaccination_status_tag]
162173
end
@@ -203,8 +214,9 @@ def register_status_tag
203214
key: :register,
204215
value:
205216
render(
206-
AppRegisterStatusTagComponent.new(
207-
patient_session.registration_status&.status || "unknown"
217+
AppStatusTagComponent.new(
218+
patient_session.registration_status&.status || "unknown",
219+
context: :register
208220
)
209221
)
210222
}
@@ -240,6 +252,19 @@ def triage_status_value(triage_status, programme)
240252
{ status: status }
241253
end
242254

255+
def patient_specific_direction_status_tag
256+
{
257+
key: :patient_specific_direction,
258+
value:
259+
render(
260+
AppStatusTagComponent.new(
261+
psd_exists?(programmes.first) ? :added : :not_added,
262+
context: :patient_specific_direction
263+
)
264+
)
265+
}
266+
end
267+
243268
def note_to_log_event(note)
244269
truncated_body = note.body.truncate_words(80, omission: "…")
245270

@@ -260,4 +285,10 @@ def note_to_log_event(note)
260285

261286
AppLogEventComponent.new(body:, at: note.created_at, by: note.created_by)
262287
end
288+
289+
def psd_exists?(programme)
290+
patient.patient_specific_directions.any? do
291+
it.programme_id == programme.id && it.academic_year == academic_year
292+
end
293+
end
263294
end

app/components/app_register_status_tag_component.rb

Lines changed: 0 additions & 21 deletions
This file was deleted.

app/components/app_search_results_component.rb

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
class AppSearchResultsComponent < ViewComponent::Base
44
erb_template <<-ERB
5-
<h3 class="nhsuk-heading-m nhsuk-u-margin-bottom-2">Search results</h3>
5+
<h3 class="nhsuk-heading-m nhsuk-u-margin-bottom-2"><%= heading %></h3>
66
77
<p class="nhsuk-caption-m nhsuk-u-margin-bottom-4">
88
<% if has_results? %>
@@ -19,16 +19,17 @@ class AppSearchResultsComponent < ViewComponent::Base
1919
<% end %>
2020
ERB
2121

22-
def initialize(pagy, label:)
22+
def initialize(pagy, label:, heading: "Search results")
2323
super
2424

2525
@pagy = pagy
2626
@label = label
27+
@heading = heading
2728
end
2829

2930
private
3031

31-
attr_reader :pagy, :label
32+
attr_reader :pagy, :label, :heading
3233

3334
def has_results? = pagy.count.positive?
3435
end
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# frozen_string_literal: true
2+
3+
class AppStatusTagComponent < ViewComponent::Base
4+
def initialize(status, context:)
5+
super
6+
7+
@status = status
8+
@context = context
9+
end
10+
11+
def call = tag.strong(text, class: ["nhsuk-tag nhsuk-tag--#{colour}"])
12+
13+
private
14+
15+
def text
16+
I18n.t(@status, scope: [:status, @context, :label])
17+
end
18+
19+
def colour
20+
I18n.t(@status, scope: [:status, @context, :colour])
21+
end
22+
end
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
# frozen_string_literal: true
2+
3+
class Sessions::PatientSpecificDirectionsController < ApplicationController
4+
include PatientSearchFormConcern
5+
6+
before_action :set_session
7+
before_action :set_patient_search_form
8+
9+
layout "full"
10+
11+
def show
12+
scope =
13+
@session.patient_sessions.includes_programmes.includes(
14+
patient: {
15+
patient_specific_directions: :programme
16+
}
17+
)
18+
@eligible_for_bulk_psd_count = patient_sessions_allowed_psd.count
19+
patient_sessions = @form.apply(scope)
20+
@pagy, @patient_sessions = pagy(patient_sessions)
21+
end
22+
23+
def create
24+
ActiveRecord::Base.transaction do
25+
PatientSpecificDirection.import!(
26+
psds_to_create,
27+
on_duplicate_key_ignore: true
28+
)
29+
end
30+
31+
redirect_to session_patient_specific_directions_path(@session),
32+
flash: {
33+
success: "PSDs added"
34+
}
35+
end
36+
37+
def bulk_add
38+
@eligible_for_bulk_psd_count = patient_sessions_allowed_psd.count
39+
end
40+
41+
private
42+
43+
def set_session
44+
@session = policy_scope(Session).find_by!(slug: params[:session_slug])
45+
end
46+
47+
def programme
48+
@session.programmes.includes(:vaccines).first
49+
end
50+
51+
def psds_to_create
52+
patient_sessions_allowed_psd.map do |patient_session|
53+
PatientSpecificDirection.new(
54+
academic_year: @session.academic_year,
55+
patient_id: patient_session.patient_id,
56+
programme_id: programme.id,
57+
vaccine_id: programme.vaccines.first.id,
58+
created_by_user_id: current_user.id,
59+
vaccine_method: :nasal,
60+
delivery_site: :nose
61+
)
62+
end
63+
end
64+
65+
def patient_sessions_allowed_psd
66+
@patient_sessions_allowed_psd ||=
67+
@session
68+
.patient_sessions
69+
.has_consent_status(:given, programme:)
70+
.without_patient_specific_direction(programme:)
71+
end
72+
end

app/models/patient_session.rb

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,18 @@ class PatientSession < ApplicationRecord
257257
end
258258
end
259259

260+
scope :without_patient_specific_direction,
261+
->(programme:) do
262+
joins(:session).where.not(
263+
PatientSpecificDirection
264+
.where("patient_id = patient_sessions.patient_id")
265+
.where("academic_year = sessions.academic_year")
266+
.where(programme:)
267+
.arel
268+
.exists
269+
)
270+
end
271+
260272
scope :destroy_all_if_safe,
261273
-> do
262274
includes(

app/views/patient_sessions/_header.html.erb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636
<% end %>
3737

3838
<li class="app-action-list__item">
39-
<%= render AppRegisterStatusTagComponent.new(@patient_session.registration_status&.status || "unknown") %>
39+
<%= render AppStatusTagComponent.new(@patient_session.registration_status&.status || "unknown", context: :register) %>
4040
</li>
4141

4242
<% if policy(session_attendance).edit? && @session.requires_registration? %>

app/views/sessions/_header.html.erb

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,14 @@
2424
selected: request.path == session_consent_path(@session),
2525
)
2626

27+
if @session.psd_enabled?
28+
nav.with_item(
29+
href: session_patient_specific_directions_path(@session),
30+
text: t("sessions.tabs.patient_specific_directions"),
31+
selected: request.path == session_patient_specific_directions_path(@session),
32+
)
33+
end
34+
2735
nav.with_item(
2836
href: session_triage_path(@session),
2937
text: t("sessions.tabs.triage"),
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<% content_for :before_main do %>
2+
<%= render AppBreadcrumbComponent.new(items: [
3+
{ text: t("dashboard.index.title"), href: dashboard_path },
4+
{ text: t("sessions.index.title"), href: sessions_path },
5+
{ text: @session.location.name, href: session_path(@session) },
6+
]) %>
7+
<% end %>
8+
9+
<%= h1 "Are you sure you want to add #{@eligible_for_bulk_psd_count} new PSDs?" %>
10+
11+
<div class="nhsuk-grid-row">
12+
<div class="nhsuk-grid-column-two-thirds">
13+
<p class="nhsuk-body">This cannot be undone.</p>
14+
<div class="app-button-group">
15+
<%= govuk_button_to "Yes, add PSDs", session_patient_specific_directions_path(@session) %>
16+
<%= govuk_link_to "No, return to session",
17+
bulk_add_session_patient_specific_directions_path(@session),
18+
method: :post,
19+
prevent_double_click: true %>
20+
</div>
21+
</div>
22+
</div>

0 commit comments

Comments
 (0)