Skip to content

Commit 6948ef3

Browse files
authored
feat: Dr. Rai Titration Indicator (#5643)
**Story card:** [sc-15931](https://app.shortcut.com/simpledotorg/story/15931/dr-rai-titration-indicator) ## Because Titration Indicator is the second indicator we have chosen to implement for Dr. Rai Reports. This indicator has SQL as its datasource — as opposed to the data in the Dashboard. ## This addresses - Creating the mechanism to use SQL as a data source - Creating the Titration Indicator (alongside its query) - Adding the Titration Indicator to the Dr. Rai component - Smoothening out component decisions made when there was just one indicator ## Test instructions suite tests
1 parent 317dfb5 commit 6948ef3

File tree

11 files changed

+507
-33
lines changed

11 files changed

+507
-33
lines changed

app/components/dashboard/dr_rai_report.html.erb

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
<% end %>
3333
</div>
3434
<div class="action-progress">
35-
<p class="statement"><%= action_plan.numerator %> of <%= action_plan.denominator %> overdue patients</p>
35+
<p class="statement"><%= action_plan.numerator %> of <%= action_plan.denominator %> <%= action_plan.unit %></p>
3636
<div class="bar">
3737
<div class="bar-fill" style="width: <%= action_plan.progress %>%">
3838
<span class="bar-number over-88-percent"><%= action_plan.progress %>%</span>
@@ -67,7 +67,7 @@
6767
<%# <button class="link-button edit">Edit</button> %>
6868
<ul>
6969
<% indicators.each do |indicator| %>
70-
<li><button class="link-button advancer" data-target-type="<%= indicator.target_type %>" data-target-ui="<%= indicator.target_type_frontend %>" data-indicator-id=<%= indicator.id %> data-indicator-denominator="<%= indicator_denominator(indicator) %>" data-indicator-previous-numerator="<%= indicator_previous_numerator(indicator) %>" data-indicator-action="<%= indicator.action %>">Contact overdue patients</button></li>
70+
<li><button class="link-button advancer" data-target-type="<%= indicator.target_type %>" data-target-ui="<%= indicator.target_type_frontend %>" data-indicator-id=<%= indicator.id %> data-indicator-denominator="<%= indicator_denominator(indicator) %>" data-indicator-previous-numerator="<%= indicator_previous_numerator(indicator) %>" data-indicator-action="<%= indicator.action %>" data-indicator-action-active="<%= indicator.action_active %>" data-indicator-action-passive="<%= indicator.action_passive %>" data-indicator-unit="<%= indicator.unit %>"><%= indicator.display_name %></button></li>
7171
<% end %>
7272
</ul>
7373
</div>
@@ -87,7 +87,7 @@
8787
</label>
8888
<p class="missing-input-warning d-none">Enter a goal value</p>
8989
</div>
90-
<p class="activity-promise d-none">Contact <span class="highlight target-number">500</span> overdue patients by <%= end_of(selected_period) %></p>
90+
<p class="activity-promise d-none"><span class="active-action"></span> <span class="highlight target-number">500</span> <span class="indicator-unit"></span> by <%= end_of(selected_period) %></p>
9191
<p class="activity-statement"><span class="highlight"><span class="previous-percentage">6</span>%</span> <span class='indicator-action'></span> (<span class='indicator-previous-numerator'></span> of <span class='indicator-denominator'></span>) in <%= human_readable(selected_period.previous) %></p>
9292
<button class="next-button">Next</button>
9393
</div>
@@ -108,9 +108,8 @@
108108
</label>
109109
<p class="missing-input-warning d-none">Enter a goal value</p>
110110
</div>
111-
<p class="activity-promise d-none">Contact <span class="highlight target-number">500</span> overdue patients by <%= end_of(selected_period) %></p>
111+
<p class="activity-promise d-none"><span class="active-action"></span> <span class="highlight target-number">500</span> <span class="indicator-unit"></span> by <%= end_of(selected_period) %></p>
112112
<p class="activity-statement"><span class="highlight"><span class="indicator-previous-numerator">6</span></span> <span class='indicator-action'></span> (<span class='indicator-previous-numerator'></span> of <span class='indicator-denominator'></span>) in <%= human_readable(selected_period.previous) %></p>
113-
<p class="activity-statement"><span class="highlight">6%</span> overdue patients called (600 of 10,000) in <%= human_readable(selected_period.previous) %></p>
114113
<button class="next-button">Next</button>
115114
</div>
116115
<div class="inactive d-none">
@@ -225,6 +224,9 @@
225224
$('.indicator-action').text(indicator.action)
226225
$('.indicator-denominator').text(indicator.denominator)
227226
$('.indicator-previous-numerator').text(indicator.previous_numerator)
227+
$('.active-action').text(indicator.active_action)
228+
$('.passive-passion').text(indicator.passive_passion)
229+
$('.indicator-unit').text(indicator.unit)
228230
if (nextStep === 3) {
229231
$(e.currentTarget).find('.step-statement').text($(e.currentTarget).find('.activity-promise').text())
230232
$('#dr-rai--sidebar').data('statement', $(e.currentTarget).find('.step-statement').text())
@@ -322,6 +324,9 @@
322324
'denominator': $(e.currentTarget).data('indicator-denominator'),
323325
'previous_numerator': $(e.currentTarget).data('indicator-previous-numerator'),
324326
'action': $(e.currentTarget).data('indicator-action'),
327+
'passive_action': $(e.currentTarget).data('indicator-action-passive'),
328+
'active_action': $(e.currentTarget).data('indicator-action-active'),
329+
'unit': $(e.currentTarget).data('indicator-unit'),
325330
}
326331
])
327332
})

app/components/dashboard/dr_rai_report.rb

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,14 @@ def initialize(quarterlies, region_slug, selected_quarter = nil)
1717
region: @region,
1818
dr_rai_target: {period: @selected_period.value.to_s}
1919
)
20-
@indicators = DrRai::Indicator.all
20+
@indicators = custom_indicators
21+
end
22+
23+
def custom_indicators
24+
return [] unless region.source_type == "Facility"
25+
DrRai::Indicator.all.filter do |indicator|
26+
indicator.is_supported?(region)
27+
end
2128
end
2229

2330
def indicator_previous_numerator(indicator)

app/models/dr_rai/action_plan.rb

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,20 @@ def denominator
2424
end
2525

2626
def progress
27-
return 0 unless denominator.positive?
27+
return 0 if unprocessible?
2828
return 100 unless numerator < denominator
2929

3030
(numerator.to_f / denominator * 100).round
3131
end
32+
33+
def unit
34+
indicator.unit
35+
end
36+
37+
private
38+
39+
def unprocessible?
40+
denominator.negative? ||
41+
numerator.nil?
42+
end
3243
end
Lines changed: 18 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,11 @@
11
module DrRai
22
class ContactOverduePatientsIndicator < Indicator
3-
def display_name
4-
"Contact overdue patients"
5-
end
6-
7-
def numerator(region, the_period = period)
8-
numerators(region)[the_period]
9-
end
10-
11-
def denominator(region, the_period = period)
12-
denominators(region)[the_period]
13-
end
14-
15-
def numerators(region)
16-
quarterlies(region).map do |t, data|
17-
[t, data[numerator_key]]
18-
end.to_h
19-
end
20-
21-
def denominators(region)
22-
quarterlies(region).map do |t, data|
23-
[t, data[denominator_key]]
24-
end.to_h
3+
def datasource(region)
4+
quarterlies(region)
255
end
266

27-
def target_type
28-
"DrRai::PercentageTarget"
7+
def display_name
8+
"Contact overdue patients"
299
end
3010

3111
def target_type_frontend
@@ -40,8 +20,20 @@ def denominator_key
4020
"overdue_patients"
4121
end
4222

43-
def action
44-
"overdue patients called"
23+
def unit
24+
"overdue patients"
25+
end
26+
27+
def action_passive
28+
"called"
29+
end
30+
31+
def action_active
32+
"Contact"
33+
end
34+
35+
def is_supported?(region)
36+
true
4537
end
4638
end
4739
end

app/models/dr_rai/indicator.rb

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,4 +28,32 @@ def quarterlies(region)
2828
def period
2929
Period.new(type: :quarter, value: target.period)
3030
end
31+
32+
def target_type
33+
DrRai::Target::TYPES[target_type_frontend]
34+
end
35+
36+
def numerator(region, the_period = period)
37+
numerators(region)[the_period]
38+
end
39+
40+
def denominator(region, the_period = period)
41+
denominators(region)[the_period]
42+
end
43+
44+
def numerators(region)
45+
datasource(region).map do |t, data|
46+
[t, data[numerator_key]]
47+
end.to_h
48+
end
49+
50+
def denominators(region)
51+
datasource(region).map do |t, data|
52+
[t, data[denominator_key]]
53+
end.to_h
54+
end
55+
56+
def action
57+
[unit, action_passive].join(" ")
58+
end
3159
end

app/models/dr_rai/target.rb

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
11
class DrRai::Target < ApplicationRecord
2+
TYPES = {
3+
"percent" => "DrRai::PercentageTarget",
4+
"numeric" => "DrRai::NumericTarget",
5+
"boolean" => "DrRai::BooleanTarget"
6+
}
7+
28
belongs_to :indicator, class_name: "DrRai::Indicator", foreign_key: "dr_rai_indicators_id"
39

410
validates :period, presence: true, format: {with: /\AQ\d-\d{4}\Z/}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
module DrRai
2+
class TitrationIndicator < Indicator
3+
attr_reader :region
4+
5+
def datasource(region)
6+
@region = region
7+
@query ||= TitrationQuery.new(region).call
8+
@query[region.name]
9+
end
10+
11+
def display_name
12+
"Titration"
13+
end
14+
15+
def target_type_frontend
16+
"percent"
17+
end
18+
19+
def numerator_key
20+
"titrated"
21+
end
22+
23+
def denominator_key
24+
"patients"
25+
end
26+
27+
def action_passive
28+
"titrated"
29+
end
30+
31+
def action_active
32+
"Titrate"
33+
end
34+
35+
def unit
36+
"patients"
37+
end
38+
39+
def is_supported?(region)
40+
case CountryConfig.current[:name]
41+
when "Bangladesh"
42+
region.path.split(".").include?("nhf")
43+
when "Ethiopia"
44+
region.path.split(".").none? { |level| level.include?("non_rtsl") }
45+
when "Sri Lanka"
46+
region.path.split(".").include?("sri_lanka_organization")
47+
else
48+
false
49+
end
50+
end
51+
end
52+
end
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# Base Query for a DrRai indicator
2+
#
3+
# This is our harness to force the queries created in Metabase to follow the
4+
# format of the data in the Simple Dashboard. Thus, all queries we would want
5+
# to use with the Dr Rai component should include this module.
6+
module DrRai
7+
module IndicatorFunction
8+
def valid?
9+
raise "The result of the query must be present beforehand." if @result.nil?
10+
11+
raise "Invalid structure" unless valid_structure?
12+
end
13+
14+
# This method is what the indicator uses to verify that it gets what should
15+
# come back from the DB. Ideally, it would be validating a 2D array for the
16+
# columns. If indicators want to get ambitious, they can validate the
17+
# column types. But this is not necessary.
18+
def valid_structure?
19+
raise "Unimplemented"
20+
end
21+
22+
# This is the method all Dr. Rai indicator functions should implement to
23+
# transform their resultant query to the dashboard format
24+
def transform!
25+
raise "Unimplemented"
26+
end
27+
end
28+
end

0 commit comments

Comments
 (0)