diff --git a/app/controllers/dashboard_controller.rb b/app/controllers/dashboard_controller.rb index 40881803..b308b5da 100644 --- a/app/controllers/dashboard_controller.rb +++ b/app/controllers/dashboard_controller.rb @@ -3,6 +3,9 @@ class DashboardController < ApplicationController def index authenticate(district.name.downcase, "#{district.name.downcase}!") + @construct_graph_row_presenters = [ + ConstructGraphRowPresenter.new(construct: professional_qualifications_construct, score: 4.8) + ] end private @@ -16,7 +19,11 @@ class DashboardController < ApplicationController end def district - @school.district + @district ||= @school.district end -end \ No newline at end of file + def professional_qualifications_construct + Construct.new title: "Professional Qualifications", watch_low_benchmark: 2.48, growth_low_benchmark: 2.99, approval_low_benchmark: 3.49, ideal_low_benchmark: 4.7 + end + +end diff --git a/app/models/construct.rb b/app/models/construct.rb new file mode 100644 index 00000000..7f594936 --- /dev/null +++ b/app/models/construct.rb @@ -0,0 +1,33 @@ +class Construct + Zone = Struct.new(:low_benchmark, :high_benchmark, :type) do + def includes_score?(score) + score > low_benchmark and score < high_benchmark + end + end + + attr_reader :title, :warning_zone, :watch_zone, :growth_zone, :approval_zone, :ideal_zone + + def initialize(title:, watch_low_benchmark:, growth_low_benchmark:, approval_low_benchmark:, ideal_low_benchmark:) + @title = title + @warning_zone = Zone.new(1, watch_low_benchmark, :warning) + @watch_zone = Zone.new(watch_low_benchmark, growth_low_benchmark, :watch) + @growth_zone = Zone.new(growth_low_benchmark, approval_low_benchmark, :growth) + @approval_zone = Zone.new(approval_low_benchmark, ideal_low_benchmark, :approval) + @ideal_zone = Zone.new(ideal_low_benchmark, 5, :ideal) + end + + def zone_for_score(score) + case score + when ideal_zone.low_benchmark..ideal_zone.high_benchmark + ideal_zone + when approval_zone.low_benchmark..approval_zone.high_benchmark + approval_zone + when growth_zone.low_benchmark..growth_zone.high_benchmark + growth_zone + when watch_zone.low_benchmark..watch_zone.high_benchmark + watch_zone + else + warning_zone + end + end +end diff --git a/app/models/construct_graph_parameters.rb b/app/models/construct_graph_parameters.rb new file mode 100644 index 00000000..7b3e2e03 --- /dev/null +++ b/app/models/construct_graph_parameters.rb @@ -0,0 +1,36 @@ +module ConstructGraphParameters + TOTAL_GRAPH_WIDTH = 1152 + GRAPH_WIDTH = 0.75 * TOTAL_GRAPH_WIDTH + CONSTRUCT_ROW_HEIGHT = 40 + CONSTRUCT_ROW_BAR_HEIGHT = 20 + + module ZoneColor + WARNING = "#FF73C0" + WATCH = "#F096AD" + GROWTH = "#E0BA9A" + APPROVAL = "#D0DD86" + IDEAL = "#C0FF73" + end + + class ZoneParams + attr_reader :left_edge + attr_reader :width + + def initialize(left_edge:, width:) + @left_edge = left_edge + @width = width + end + + def right_edge + left_edge + width + end + end + + WARNING_ZONE = ZoneParams.new left_edge: 0, width: (GRAPH_WIDTH / 2) / 3 + WATCH_ZONE = ZoneParams.new left_edge: WARNING_ZONE.right_edge, width: (GRAPH_WIDTH / 2) / 3 + GROWTH_ZONE = ZoneParams.new left_edge: WATCH_ZONE.right_edge, width: (GRAPH_WIDTH / 2) / 3 + APPROVAL_ZONE = ZoneParams.new left_edge: GROWTH_ZONE.right_edge, width: (GRAPH_WIDTH / 2) / 2 + IDEAL_ZONE = ZoneParams.new left_edge: APPROVAL_ZONE.right_edge, width: (GRAPH_WIDTH / 2) / 2 + + KEY_BENCHMARK_WIDTH = 2 +end diff --git a/app/presenters/construct_graph_row_presenter.rb b/app/presenters/construct_graph_row_presenter.rb new file mode 100644 index 00000000..f2734d34 --- /dev/null +++ b/app/presenters/construct_graph_row_presenter.rb @@ -0,0 +1,77 @@ +class ConstructGraphRowPresenter + + def initialize(construct:, score:) + @construct = construct + @score = score + end + + def construct_title + @construct.title + end + + def bar_color + case zone.type + when :ideal + ConstructGraphParameters::ZoneColor::IDEAL + when :approval + ConstructGraphParameters::ZoneColor::APPROVAL + when :growth + ConstructGraphParameters::ZoneColor::GROWTH + when :watch + ConstructGraphParameters::ZoneColor::WATCH + else + ConstructGraphParameters::ZoneColor::WARNING + end + end + + def bar_width + percentage = (@score - zone.low_benchmark) / (zone.high_benchmark - zone.low_benchmark) + case zone.type + when :ideal + (percentage * ideal_zone_params.width + approval_zone_params.width).round + when :approval + (percentage * approval_zone_params.width).round + when :growth + (percentage * growth_zone_params.width).round + when :watch + (percentage * watch_zone_params.width + growth_zone_params.width).round + else + (percentage * warning_zone_params.width + watch_zone_params.width + growth_zone_params.width).round + end + end + + def x_offset + case zone.type + when :ideal, :approval + 0 + else + bar_width + end + end + + private + + def zone + @construct.zone_for_score(@score) + end + + def ideal_zone_params + ConstructGraphParameters::IDEAL_ZONE + end + + def approval_zone_params + ConstructGraphParameters::APPROVAL_ZONE + end + + def growth_zone_params + ConstructGraphParameters::GROWTH_ZONE + end + + def watch_zone_params + ConstructGraphParameters::WATCH_ZONE + end + + def warning_zone_params + ConstructGraphParameters::WARNING_ZONE + end +end diff --git a/app/views/dashboard/index.html.erb b/app/views/dashboard/index.html.erb index 7fb1b868..8d3bd669 100644 --- a/app/views/dashboard/index.html.erb +++ b/app/views/dashboard/index.html.erb @@ -1 +1,54 @@ -

<%= @school.name %>

\ No newline at end of file +

<%= @school.name %>

+ +<% heading_gutter = 30 %> +<% graph_height = @construct_graph_row_presenters.length * ConstructGraphParameters::CONSTRUCT_ROW_HEIGHT + heading_gutter %> + height=<%= graph_height %> xmlns="http://www.w3.org/2000/svg"> + <% graph_center = ConstructGraphParameters::GRAPH_WIDTH / 2 %> + <% label_padding_right = 24 %> + + <% warning_zone = ConstructGraphParameters::WARNING_ZONE %> + <% watch_zone = ConstructGraphParameters::WATCH_ZONE %> + <% growth_zone = ConstructGraphParameters::GROWTH_ZONE %> + <% approval_zone = ConstructGraphParameters::APPROVAL_ZONE %> + <% ideal_zone = ConstructGraphParameters::IDEAL_ZONE %> + + <% key_benchmark_width = ConstructGraphParameters::KEY_BENCHMARK_WIDTH %> + <% key_benchmark_left_edge = graph_center - key_benchmark_width / 2 %> + + <% construct_row_height = ConstructGraphParameters::CONSTRUCT_ROW_HEIGHT %> + <% construct_row_bar_height = ConstructGraphParameters::CONSTRUCT_ROW_BAR_HEIGHT %> + + + + y=<%= heading_gutter / 2 %> text-anchor="middle" dominant-baseline="middle">Warning + y=<%= heading_gutter / 2 %> text-anchor="middle" dominant-baseline="middle">Watch + y=<%= heading_gutter / 2 %> text-anchor="middle" dominant-baseline="middle">Growth + y=<%= heading_gutter / 2 %> text-anchor="middle" dominant-baseline="middle">Approval + y=<%= heading_gutter / 2 %> text-anchor="middle" dominant-baseline="middle">Ideal + + + + y="0" width=<%= warning_zone.width %> height="100%" fill=<%= ConstructGraphParameters::ZoneColor::WARNING %> fill-opacity="0.2" /> + y="0" width=<%= watch_zone.width %> height="100%" fill=<%= ConstructGraphParameters::ZoneColor::WATCH %> fill-opacity="0.2" /> + y="0" width=<%= growth_zone.width %> height="100%" fill=<%= ConstructGraphParameters::ZoneColor::GROWTH %> fill-opacity="0.2" /> + y="0" width=<%= approval_zone.width %> height="100%" fill=<%= ConstructGraphParameters::ZoneColor::APPROVAL %> fill-opacity="0.2" /> + y="0" width=<%= ideal_zone.width %> height="100%" fill=<%= ConstructGraphParameters::ZoneColor::IDEAL %> fill-opacity="0.2" /> + + y="0" width=<%= key_benchmark_width %> height="100%" fill="black" /> + + + + + > + <%= @construct_graph_row_presenters.each_with_index do |presenter, index| %> + y=<%= index * construct_row_height + construct_row_height / 2 %> text-anchor="end" dominant-baseline="middle"><%= presenter.construct_title %> + <% end %> + + + > + <%= @construct_graph_row_presenters.each_with_index do |presenter, index| %> + y=<%= index * construct_row_height + (construct_row_height - construct_row_bar_height) / 2 %> width="<%= presenter.bar_width %>" height=<%= construct_row_bar_height %> fill=<%= presenter.bar_color %> /> + <% end %> + + + diff --git a/spec/presenters/construct_graph_row_presenter_spec.rb b/spec/presenters/construct_graph_row_presenter_spec.rb new file mode 100644 index 00000000..46f3975d --- /dev/null +++ b/spec/presenters/construct_graph_row_presenter_spec.rb @@ -0,0 +1,119 @@ +require 'rails_helper' + +RSpec.describe "construct graph row presenter" do + + let(:watch_low_benchmark) { 2.9 } + let(:growth_low_benchmark) { 3.1 } + let(:approval_low_benchmark) { 3.6 } + let(:ideal_low_benchmark) { 3.8 } + + let(:construct) { + Construct.new( + title: 'Some Title', + watch_low_benchmark: watch_low_benchmark, + growth_low_benchmark: growth_low_benchmark, + approval_low_benchmark: approval_low_benchmark, + ideal_low_benchmark: ideal_low_benchmark + ) + } + + let(:presenter) { + ConstructGraphRowPresenter.new construct: construct, score: score + } + + shared_examples_for 'construct_title' do + it('returns the construct title') do + expect(presenter.construct_title).to eq 'Some Title' + end + end + + context('when the score is in the Ideal zone') do + let(:score) { 4.4 } + + it_behaves_like 'construct_title' + + it('returns the correct color') do + expect(presenter.bar_color).to eq ConstructGraphParameters::ZoneColor::IDEAL + end + + it('returns a bar width equal to the approval zone width plus the proportionate ideal zone width') do + expect(presenter.bar_width).to eq 324 + end + + it('returns an x-offset of 0') do + expect(presenter.x_offset).to eq 0 + end + end + + context('when the score is in the Approval zone') do + let(:score) { 3.7 } + + it_behaves_like 'construct_title' + + it("returns the correct color") do + expect(presenter.bar_color).to eq ConstructGraphParameters::ZoneColor::APPROVAL + end + + it('returns a bar width equal to the proportionate approval zone width') do + expect(presenter.bar_width).to eq 108 + end + + it('returns an x-offset of 0') do + expect(presenter.x_offset).to eq 0 + end + end + + context('when the score is in the Growth zone') do + let(:score) { 3.2 } + + it_behaves_like 'construct_title' + + it("returns the correct color") do + expect(presenter.bar_color).to eq ConstructGraphParameters::ZoneColor::GROWTH + end + + it('returns a bar width equal to the proportionate growth zone width') do + expect(presenter.bar_width).to eq 29 + end + + it('returns an x-offset equal to the bar width') do + expect(presenter.x_offset).to eq 29 + end + end + + context('when the score is in the Watch zone') do + let(:score) { 3.0 } + + it_behaves_like 'construct_title' + + it("returns the correct color") do + expect(presenter.bar_color).to eq ConstructGraphParameters::ZoneColor::WATCH + end + + it('returns a bar width equal to the proportionate watch zone width plus the growth zone width') do + expect(presenter.bar_width).to eq 216 + end + + it('returns an x-offset equal to the bar width') do + expect(presenter.x_offset).to be > 0 + end + end + + context('when the score is in the Warning zone') do + let(:score) { 2.8 } + + it_behaves_like 'construct_title' + + it("returns the correct color") do + expect(presenter.bar_color).to eq ConstructGraphParameters::ZoneColor::WARNING + end + + it('returns a bar width equal to the proportionate warning zone width plus the watch & growth zone widths') do + expect(presenter.bar_width).to eq 424 + end + + it('returns an x-offset equal to the bar width') do + expect(presenter.x_offset).to eq 424 + end + end +end