diff --git a/app/controllers/dashboard/analyze_controller.rb b/app/controllers/dashboard/analyze_controller.rb new file mode 100644 index 0000000..f46fa90 --- /dev/null +++ b/app/controllers/dashboard/analyze_controller.rb @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +class AnalyzeController < SqmApplicationController + def index + @presenter = Analyze::Presenter.new(params:, school: @school, academic_year: @academic_year) + @background ||= BackgroundPresenter.new(num_of_columns: @presenter.graph.columns.count) + end +end diff --git a/app/controllers/dashboard/categories_controller.rb b/app/controllers/dashboard/categories_controller.rb new file mode 100644 index 0000000..e44a57b --- /dev/null +++ b/app/controllers/dashboard/categories_controller.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +class CategoriesController < SqmApplicationController + helper GaugeHelper + + def show + @categories = Category.sorted.map { |category| CategoryPresenter.new(category:) } + + @category = CategoryPresenter.new(category: Category.find_by_slug(params[:id])) + end +end diff --git a/app/controllers/dashboard/gps_controller.rb b/app/controllers/dashboard/gps_controller.rb new file mode 100644 index 0000000..aaaedec --- /dev/null +++ b/app/controllers/dashboard/gps_controller.rb @@ -0,0 +1,8 @@ +class GpsController < ActionController::Base + def index + # respond_to do |format| + # format.html + # format.csv { send_data Report::Gps.to_csv, disposition: 'attachment', filename: "gps_#{Date.today}.csv" } + # end + end +end diff --git a/app/controllers/dashboard/home_controller.rb b/app/controllers/dashboard/home_controller.rb index 89c50aa..d6837ce 100644 --- a/app/controllers/dashboard/home_controller.rb +++ b/app/controllers/dashboard/home_controller.rb @@ -49,7 +49,7 @@ module Dashboard academic_year = AcademicYear.all.order(range: :DESC).find do |ay| Subcategory.all.any? do |subcategory| rate = subcategory.response_rate(school:, academic_year: ay) - rate.meets_student_threshold || rate.meets_teacher_threshold + rate.meets_student_threshold? || rate.meets_teacher_threshold? end end diff --git a/app/controllers/dashboard/overview_controller.rb b/app/controllers/dashboard/overview_controller.rb new file mode 100644 index 0000000..37a6eea --- /dev/null +++ b/app/controllers/dashboard/overview_controller.rb @@ -0,0 +1,44 @@ +# frozen_string_literal: true + +module Dashboard + class OverviewController < SqmApplicationController + before_action :check_empty_dataset, only: [:index] + helper VarianceHelper + + def index + @variance_chart_row_presenters = measures.map(&method(:presenter_for_measure)) + @category_presenters = categories.map { |category| CategoryPresenter.new(category:) } + @student_response_rate_presenter = ResponseRatePresenter.new(focus: :student, school: @school, + academic_year: @academic_year) + @teacher_response_rate_presenter = ResponseRatePresenter.new(focus: :teacher, school: @school, + academic_year: @academic_year) + end + + private + + def presenter_for_measure(measure) + score = measure.score(school: @school, academic_year: @academic_year) + + VarianceChartRowPresenter.new(measure:, score:) + end + + def check_empty_dataset + @has_empty_dataset = subcategories.none? do |subcategory| + response_rate = subcategory.response_rate(school: @school, academic_year: @academic_year) + response_rate.meets_student_threshold? || response_rate.meets_teacher_threshold? + end + end + + def measures + @measures ||= subcategories.flat_map(&:measures) + end + + def subcategories + @subcategories ||= categories.flat_map(&:subcategories) + end + + def categories + @categories ||= Category.sorted.includes(%i[measures scales admin_data_items subcategories]) + end + end +end diff --git a/app/controllers/dashboard/reports_controller.rb b/app/controllers/dashboard/reports_controller.rb new file mode 100644 index 0000000..5ab4246 --- /dev/null +++ b/app/controllers/dashboard/reports_controller.rb @@ -0,0 +1,3 @@ +class ReportsController < ApplicationController + def index; end +end diff --git a/app/controllers/dashboard/sqm_application_controller.rb b/app/controllers/dashboard/sqm_application_controller.rb new file mode 100644 index 0000000..d1156ba --- /dev/null +++ b/app/controllers/dashboard/sqm_application_controller.rb @@ -0,0 +1,44 @@ +# frozen_string_literal: true + +module Dashboard + class SqmApplicationController < ApplicationController + protect_from_forgery with: :exception, prepend: true + before_action :set_schools_and_districts + before_action :authenticate_district + + helper HeaderHelper + + private + + def authenticate_district + authenticate(district_name, "#{district_name}!") + end + + def district_name + @district_name ||= @district.name.split(" ").first.downcase + end + + def set_schools_and_districts + @district = District.find_by_slug district_slug + @districts = District.all.order(:name) + @school = School.find_by_slug(school_slug) + @schools = School.includes([:district]).where(district: @district).order(:name) + @academic_year = AcademicYear.find_by_range params[:year] + @academic_years = AcademicYear.all.order(range: :desc) + end + + def district_slug + params[:district_id] + end + + def school_slug + params[:school_id] + end + + def authenticate(username, password) + authenticate_or_request_with_http_basic do |u, p| + u == username && p == password + end + end + end +end diff --git a/app/helpers/dashboard/analyze_helper.rb b/app/helpers/dashboard/analyze_helper.rb new file mode 100644 index 0000000..17f8e50 --- /dev/null +++ b/app/helpers/dashboard/analyze_helper.rb @@ -0,0 +1,70 @@ +# frozen_string_literal: true + +module Dashboard + module AnalyzeHelper + def svg_height + 400 + end + + def zone_label_width + 15 + end + + def graph_width + 85 + end + + def analyze_graph_height + 85 + end + + def analyze_zone_height + analyze_graph_height / 5 + end + + def zone_height_percentage + analyze_zone_height / 100.0 + end + + def analyze_category_link(district:, school:, academic_year:, category:) + year = academic_year.range + "/districts/#{district.slug}/schools/#{school.slug}/analyze?year=#{year}&academic_years=#{year}&category=#{category.category_id}" + end + + def analyze_subcategory_link(district:, school:, academic_year:, category:, subcategory:) + "/districts/#{district.slug}/schools/#{school.slug}/analyze?year=#{academic_year.range}&category=#{category.category_id}&subcategory=#{subcategory.subcategory_id}" + end + + def colors + @colors ||= ["#49416D", "#FFC857", "#920020", "#00B0B3", "#B2D236", "#004D61", "#FFB3CC", "#FF3D00", "#212121", "#9E9D24", + "#689F38", "#388E3C", "#00897B", "#00796B", "#00695C", "#004D40", "#1B5E20", "#FF6F00", "#33691E", "#D50000", + "#827717", "#F57F17", "#FF6F00", "#E65100", "#BF360C", "#3E2723", "#263238", "#37474F", "#455A64"] + end + + def empty_dataset?(measures:, school:, academic_year:) + @empty_dataset ||= Hash.new do |memo, (school, academic_year)| + memo[[school, academic_year]] = measures.none? do |measure| + response_rate = measure.subcategory.response_rate(school:, academic_year:) + response_rate.meets_student_threshold || response_rate.meets_teacher_threshold || measure.sufficient_admin_data?(school:, academic_year:) + end + end + + @empty_dataset[[school, academic_year]] + end + + def empty_survey_dataset?(measures:, school:, academic_year:) + @empty_survey_dataset ||= Hash.new do |memo, (school, academic_year)| + memo[[school, academic_year]] = measures.none? do |measure| + response_rate = measure.subcategory.response_rate(school:, academic_year:) + response_rate.meets_student_threshold || response_rate.meets_teacher_threshold + end + end + @empty_survey_dataset[[school, academic_year]] + end + + def base_url + analyze_subcategory_link(district: @district, school: @school, academic_year: @academic_year, category: @presenter.category, + subcategory: @presenter.subcategory) + end + end +end diff --git a/app/helpers/dashboard/gauge_helper.rb b/app/helpers/dashboard/gauge_helper.rb new file mode 100644 index 0000000..b596885 --- /dev/null +++ b/app/helpers/dashboard/gauge_helper.rb @@ -0,0 +1,99 @@ +# frozen_string_literal: true + +Point = Struct.new(:x, :y) +Rect = Struct.new(:x, :y, :width, :height) + +module GaugeHelper + def outer_radius + 100 + end + + def inner_radius + 50 + end + + def stroke_width + 1 + end + + def effective_radius + outer_radius + stroke_width + end + + def diameter + 2 * effective_radius + end + + def width + diameter + end + + def height + outer_radius + 2 * stroke_width + key_benchmark_indicator_gutter + end + + def key_benchmark_indicator_gutter + 10 + end + + def viewbox + x = arc_center.x - effective_radius + y = arc_center.y - effective_radius - key_benchmark_indicator_gutter + Rect.new(x, y, width, height) + end + + def arc_center + Point.new(0, 0) + end + + def arc_radius(radius) + "#{radius} #{radius}" + end + + def angle_for(percentage:) + -Math::PI * (1 - percentage) + end + + def arc_end_point_for(radius:, percentage:) + angle = angle_for(percentage:) + + x = arc_center.x + radius * Math.cos(angle) + y = arc_center.y + radius * Math.sin(angle) + Point.new(x, y) + end + + def arc_end_line_destination(radius:, percentage:) + angle = angle_for(percentage:) + x = arc_center.x + radius * Math.cos(angle) + y = arc_center.y + radius * Math.sin(angle) + Point.new(x, y) + end + + def arc_start_point + Point.new(arc_center.x - outer_radius, arc_center.y) + end + + def move_to(point:) + "M #{coordinates_for(point)}" + end + + def draw_arc(radius:, percentage:, clockwise:) + sweep_flag = clockwise ? 1 : 0 + "A #{arc_radius(radius)} 0 0 #{sweep_flag} #{coordinates_for(arc_end_point_for(radius:, + percentage:))}" + end + + def draw_line_to(point:) + "L #{coordinates_for(point)}" + end + + def benchmark_line_point(radius, angle) + x = (radius * Math.cos(angle)).to_s + y = (radius * Math.sin(angle) + arc_center.y).to_s + Point.new(x, y) + end + + def coordinates_for(point) + "#{point.x} #{point.y}" + end +end diff --git a/app/helpers/dashboard/variance_helper.rb b/app/helpers/dashboard/variance_helper.rb new file mode 100644 index 0000000..20b90b7 --- /dev/null +++ b/app/helpers/dashboard/variance_helper.rb @@ -0,0 +1,54 @@ +# frozen_string_literal: true + +module Dashboard + module VarianceHelper + def heading_gutter + 30 + end + + def footer_gutter + 50 + end + + def measure_row_height + 40 + end + + def graph_height(number_of_rows) + number_of_rows * measure_row_height + heading_gutter + footer_gutter + end + + def graph_background_height(number_of_rows:) + number_of_rows += 1 if @has_empty_dataset + graph_height(number_of_rows) - footer_gutter + end + + def measure_row_bar_height + 20 + end + + def label_width_percentage + 30 + end + + def graph_width_percentage + 100 - label_width_percentage + end + + def zones + %w[warning watch growth approval ideal] + end + + def zone_width_percentage + 100.0 / zones.size + end + + def availability_indicator_percentage + 3 + end + + def partial_data_indicator_size + 20 + end + end +end diff --git a/app/models/dashboard/academic_year.rb b/app/models/dashboard/academic_year.rb index a87b4a2..2580faa 100644 --- a/app/models/dashboard/academic_year.rb +++ b/app/models/dashboard/academic_year.rb @@ -37,6 +37,5 @@ module Dashboard private_class_method :academic_years private_class_method :parse_year_range end + AcademicYearRange = Struct.new(:start, :end) end - -AcademicYearRange = Struct.new(:start, :end) diff --git a/app/models/dashboard/measure.rb b/app/models/dashboard/measure.rb index c1cce60..25cdc05 100644 --- a/app/models/dashboard/measure.rb +++ b/app/models/dashboard/measure.rb @@ -1,11 +1,11 @@ module Dashboard class Measure < ApplicationRecord belongs_to :subcategory, class_name: "Subcategory", foreign_key: :dashboard_subcategory_id - has_one :dashboard_category, through: :dashboard_subcategory - has_many :dashboard_scales - has_many :dashboard_admin_data_items, through: :scales - has_many :dashboard_survey_items, through: :scales - has_many :dashboard_survey_item_responses, through: :survey_items + has_one :dashboard_category, through: :subcategory + has_many :scales, class_name: "Scale", foreign_key: :dashboard_measure_id + has_many :admin_data_items, through: :scales + has_many :survey_items, through: :scales + has_many :survey_item_responses, through: :survey_items def none_meet_threshold?(school:, academic_year:) @none_meet_threshold ||= Hash.new do |memo, (school, academic_year)| @@ -24,15 +24,17 @@ module Dashboard end def student_survey_items_with_sufficient_responses(school:, academic_year:) - @student_survey_items_with_sufficient_responses ||= SurveyItem.where(id: SurveyItem.joins("inner join survey_item_responses on survey_item_responses.survey_item_id = survey_items.id") - .student_survey_items - .where("survey_item_responses.school": school, - "survey_item_responses.academic_year": academic_year, - "survey_item_responses.survey_item_id": survey_items.student_survey_items, - "survey_item_responses.grade": school.grades(academic_year:)) - .group("survey_items.id") - .having("count(*) >= 10") - .count.keys) + # @student_survey_items_with_sufficient_responses ||= SurveyItem.where(id: SurveyItem.joins("inner join dashboard_survey_item_responses on dashboard_survey_item_responses.survey_item_id = dashboard_survey_items.id") + # .student_survey_items + # .where("dashboard_survey_item_responses.school": school, + # "dashboard_survey_item_responses.academic_year": academic_year, + # "dashboard_survey_item_responses.survey_item_id": survey_items.student_survey_items, + # "dashboard_survey_item_responses.grade": school.grades(academic_year:)) + # .group("survey_items.id") + # .having("count(*) >= 10") + # .count.keys) + + @student_survey_items_with_sufficient_responses ||= student_survey_items end def teacher_scales diff --git a/app/models/dashboard/response_rate.rb b/app/models/dashboard/response_rate.rb index 612a5d3..bd9a058 100644 --- a/app/models/dashboard/response_rate.rb +++ b/app/models/dashboard/response_rate.rb @@ -1,7 +1,18 @@ module Dashboard class ResponseRate < ApplicationRecord - belongs_to :dashboard_subcategory - belongs_to :school - belongs_to :dashboard_academic_year + TEACHER_RATE_THRESHOLD = 24.5 + STUDENT_RATE_THRESHOLD = 24.5 + + belongs_to :subcategory, class_name: "Subcategory", foreign_key: :dashboard_subcategory_id + belongs_to :school, class_name: "School", foreign_key: :dashboard_school_id + belongs_to :academic_year, class_name: "AcademicYear", foreign_key: :dashboard_academic_year_id + + def meets_student_threshold? + student_response_rate >= 24.5 + end + + def meets_teacher_threshold? + teacher_response_rate >= 24.5 + end end end diff --git a/app/models/dashboard/response_rate_calculator.rb b/app/models/dashboard/response_rate_calculator.rb index e9683a6..f30e203 100644 --- a/app/models/dashboard/response_rate_calculator.rb +++ b/app/models/dashboard/response_rate_calculator.rb @@ -2,8 +2,6 @@ module Dashboard class ResponseRateCalculator - TEACHER_RATE_THRESHOLD = 25 - STUDENT_RATE_THRESHOLD = 25 attr_reader :subcategory, :school, :academic_year def initialize(subcategory:, school:, academic_year:) @@ -22,14 +20,6 @@ module Dashboard cap_at_one_hundred(raw_response_rate).round end - def meets_student_threshold? - rate >= STUDENT_RATE_THRESHOLD - end - - def meets_teacher_threshold? - rate >= TEACHER_RATE_THRESHOLD - end - private def cap_at_one_hundred(response_rate) diff --git a/app/models/dashboard/scale.rb b/app/models/dashboard/scale.rb index 6f47ab4..564239b 100644 --- a/app/models/dashboard/scale.rb +++ b/app/models/dashboard/scale.rb @@ -1,9 +1,9 @@ module Dashboard class Scale < ApplicationRecord belongs_to :measure, class_name: "Measure", foreign_key: :dashboard_measure_id - has_many :survey_items + has_many :survey_items, class_name: "SurveyItem", foreign_key: :dashboard_scale_id has_many :survey_item_responses, through: :survey_items - has_many :admin_data_items, class_name: "AdminDataItem", foreign_key: :admin_data_item_id + has_many :admin_data_items, class_name: "AdminDataItem", foreign_key: :dashboard_scale_id def score(school:, academic_year:) @score ||= Hash.new do |memo, (school, academic_year)| diff --git a/app/models/dashboard/subcategory.rb b/app/models/dashboard/subcategory.rb index 9e2f723..764507d 100644 --- a/app/models/dashboard/subcategory.rb +++ b/app/models/dashboard/subcategory.rb @@ -37,8 +37,7 @@ module Dashboard student = StudentResponseRateCalculator.new(subcategory: self, school:, academic_year:) teacher = TeacherResponseRateCalculator.new(subcategory: self, school:, academic_year:) memo[[school, academic_year]] = ResponseRate.new(school:, academic_year:, subcategory: self, student_response_rate: student.rate, - teacher_response_rate: teacher.rate, meets_student_threshold: student.meets_student_threshold?, - meets_teacher_threshold: teacher.meets_teacher_threshold?) + teacher_response_rate: teacher.rate) end @response_rate[[school, academic_year]] diff --git a/app/models/dashboard/survey_item.rb b/app/models/dashboard/survey_item.rb index cecf380..b97c5c1 100644 --- a/app/models/dashboard/survey_item.rb +++ b/app/models/dashboard/survey_item.rb @@ -15,26 +15,26 @@ module Dashboard end scope :student_survey_items, lambda { - where("survey_items.survey_item_id LIKE 's-%'") + where("dashboard_survey_items.survey_item_id LIKE 's-%'") } scope :standard_survey_items, lambda { - where("survey_items.survey_item_id LIKE 's-%-q%'") + where("dashboard_survey_items.survey_item_id LIKE 's-%-q%'") } scope :teacher_survey_items, lambda { - where("survey_items.survey_item_id LIKE 't-%'") + where("dashboard_survey_items.survey_item_id LIKE 't-%'") } scope :short_form_survey_items, lambda { where(on_short_form: true) } scope :early_education_survey_items, lambda { - where("survey_items.survey_item_id LIKE '%-%-es%'") + where("dashboard_survey_items.survey_item_id LIKE '%-%-es%'") } scope :survey_items_for_grade, lambda { |school, academic_year, grade| includes(:survey_item_responses) - .where("survey_item_responses.grade": grade, - "survey_item_responses.school": school, - "survey_item_responses.academic_year": academic_year).distinct + .where("dashboard_survey_item_responses.grade": grade, + "dashboard_survey_item_responses.school": school, + "dashboard_survey_item_responses.academic_year": academic_year).distinct } scope :survey_item_ids_for_grade, lambda { |school, academic_year, grade| @@ -45,9 +45,9 @@ module Dashboard includes(:survey_item_responses) .where( survey_item_id: subcategory.survey_items.pluck(:survey_item_id), - "survey_item_responses.school": school, - "survey_item_responses.academic_year": academic_year, - "survey_item_responses.grade": grade + "dashboard_survey_item_responses.school": school, + "dashboard_survey_item_responses.academic_year": academic_year, + "dashboard_survey_item_responses.grade": grade ) } diff --git a/app/models/dashboard/survey_item_response.rb b/app/models/dashboard/survey_item_response.rb index 1ecec75..97b63ed 100644 --- a/app/models/dashboard/survey_item_response.rb +++ b/app/models/dashboard/survey_item_response.rb @@ -3,16 +3,16 @@ module Dashboard TEACHER_RESPONSE_THRESHOLD = 2 STUDENT_RESPONSE_THRESHOLD = 10 - belongs_to :school - belongs_to :dashboard_survey_item - belongs_to :dashboard_academic_year + belongs_to :school, class_name: "School", foreign_key: :dashboard_school_id + belongs_to :survey_item, class_name: "SurveyItem", foreign_key: :dashboard_survey_item_id + belongs_to :academic_year, class_name: "AcademicYear", foreign_key: :dashboard_academic_year belongs_to :dashboard_student, optional: true belongs_to :dashboard_gender, optional: true belongs_to :dashboard_income, optional: true belongs_to :dashboard_ell, optional: true belongs_to :dashboard_sped, optional: true - has_one :dashboard_measure, through: :dashboard_survey_item + has_one :dashboard_measure, through: :survey_item validates :likert_score, numericality: { greater_than: 0, less_than_or_equal_to: 5 } @@ -61,10 +61,10 @@ module Dashboard def self.teacher_survey_items_with_sufficient_responses(school:, academic_year:) @teacher_survey_items_with_sufficient_responses ||= Hash.new do |memo, (school, academic_year)| - hash = SurveyItem.joins("inner join survey_item_responses on survey_item_responses.survey_item_id = survey_items.id") + hash = SurveyItem.joins("inner join dashboard_survey_item_responses on dashboard_survey_item_responses.dashboard_survey_item_id = dashboard_survey_items.id") .teacher_survey_items - .where("survey_item_responses.school": school, "survey_item_responses.academic_year": academic_year) - .group("survey_items.id") + .where("dashboard_survey_item_responses.dashboard_school_id": school.id, "dashboard_survey_item_responses.dashboard_academic_year_id": academic_year.id) + .group("dashboard_survey_items.id") .having("count(*) > 0").count memo[[school, academic_year]] = hash end @@ -73,9 +73,9 @@ module Dashboard def self.student_survey_items_with_sufficient_responses_by_grade(school:, academic_year:) @student_survey_items_with_sufficient_responses_by_grade ||= Hash.new do |memo, (school, academic_year)| - hash = SurveyItem.joins("inner join survey_item_responses on survey_item_responses.survey_item_id = survey_items.id") + hash = SurveyItem.joins("inner join dashboard_survey_item_responses on dashboard_survey_item_responses.dashboard_survey_item_id = dashboard_survey_items.id") .student_survey_items - .where("survey_item_responses.school": school, "survey_item_responses.academic_year": academic_year) + .where("dashboard_survey_item_responses.dashboard_school_id": school.id, "dashboard_survey_item_responses.dashboard_academic_year_id": academic_year.id) .group(:grade, :id) .count memo[[school, academic_year]] = hash diff --git a/app/presenters/dashboard/analyze/graph/column/score_for_race.rb b/app/presenters/dashboard/analyze/graph/column/score_for_race.rb index 5fdc2e9..e1b9ce5 100644 --- a/app/presenters/dashboard/analyze/graph/column/score_for_race.rb +++ b/app/presenters/dashboard/analyze/graph/column/score_for_race.rb @@ -29,7 +29,7 @@ module Analyze def sufficient_student_responses?(academic_year:) return false unless measure.subcategory.response_rate(school:, academic_year:).meets_student_threshold? - number_of_students_for_a_racial_group = SurveyItemResponse.joins("JOIN student_races on survey_item_responses.student_id = student_races.student_id JOIN students on students.id = student_races.student_id").where( + number_of_students_for_a_racial_group = SurveyItemResponse.joins("JOIN student_races on dashboard_survey_item_responses.student_id = student_races.student_id JOIN students on students.id = student_races.student_id").where( school:, academic_year: ).where("student_races.race_id": race.id).distinct.pluck(:student_id).count number_of_students_for_a_racial_group >= 10 diff --git a/app/services/dashboard/disaggregation_loader.rb b/app/services/dashboard/disaggregation_loader.rb deleted file mode 100644 index 2b2f708..0000000 --- a/app/services/dashboard/disaggregation_loader.rb +++ /dev/null @@ -1,32 +0,0 @@ -module Dashboard - class DisaggregationLoader - attr_reader :path - - def initialize(path:) - @path = path - initialize_directory - end - - def load - data = {} - Dir.glob(Rails.root.join(path, "*.csv")).each do |filepath| - puts filepath - File.open(filepath) do |file| - headers = CSV.parse(file.first).first - - file.lazy.each_slice(1000) do |lines| - CSV.parse(lines.join, headers:).map do |row| - values = DisaggregationRow.new(row:, headers:) - data[[values.lasid, values.district, values.academic_year]] = values - end - end - end - end - data - end - - def initialize_directory - FileUtils.mkdir_p(path) - end - end -end diff --git a/app/services/dashboard/disaggregation_row.rb b/app/services/dashboard/disaggregation_row.rb deleted file mode 100644 index caacbbc..0000000 --- a/app/services/dashboard/disaggregation_row.rb +++ /dev/null @@ -1,56 +0,0 @@ -module Dashboard - class DisaggregationRow - attr_reader :row, :headers - - def initialize(row:, headers:) - @row = row - @headers = headers - end - - def district - @district ||= value_from(pattern: /District/i) - end - - def academic_year - @academic_year ||= value_from(pattern: /Academic\s*Year/i) - end - - def raw_income - @income ||= value_from(pattern: /Low\s*Income/i) - end - - def lasid - @lasid ||= value_from(pattern: /LASID/i) - end - - def raw_ell - @raw_ell ||= value_from(pattern: /EL Student First Year/i) - end - - def ell - @ell ||= begin - value = value_from(pattern: /EL Student First Year/i).downcase - - case value - when /lep student 1st year|LEP student not 1st year/i - "ELL" - when /Does not apply/i - "Not ELL" - else - "Unknown" - end - end - end - - def value_from(pattern:) - output = nil - matches = headers.select do |header| - pattern.match(header) - end.map { |item| item.delete("\n") } - matches.each do |match| - output ||= row[match] - end - output - end - end -end diff --git a/app/services/dashboard/response_rate_loader.rb b/app/services/dashboard/response_rate_loader.rb deleted file mode 100644 index f2a02c1..0000000 --- a/app/services/dashboard/response_rate_loader.rb +++ /dev/null @@ -1,55 +0,0 @@ -# frozen_string_literal: true - -module Dashboard - class ResponseRateLoader - def self.reset(schools: School.all, academic_years: AcademicYear.all, subcategories: Subcategory.all) - subcategories.each do |subcategory| - schools.each do |school| - next if test_env? && (school != milford) - - academic_years.each do |academic_year| - next if test_env? && (academic_year != test_year) - - process_response_rate(subcategory:, school:, academic_year:) - end - end - end - end - - private - - def self.milford - School.find_by_slug "milford-high-school" - end - - def self.test_year - AcademicYear.find_by_range "2020-21" - end - - def self.rails_env - @rails_env ||= ENV["RAILS_ENV"] - end - - def self.process_response_rate(subcategory:, school:, academic_year:) - student = StudentResponseRateCalculator.new(subcategory:, school:, academic_year:) - teacher = TeacherResponseRateCalculator.new(subcategory:, school:, academic_year:) - - response_rate = ResponseRate.find_or_create_by!(subcategory:, school:, academic_year:) - - response_rate.update!(student_response_rate: student.rate, - teacher_response_rate: teacher.rate, - meets_student_threshold: student.meets_student_threshold?, - meets_teacher_threshold: teacher.meets_teacher_threshold?) - end - - def self.test_env? - rails_env == "test" - end - - private_class_method :milford - private_class_method :test_year - private_class_method :rails_env - private_class_method :process_response_rate - private_class_method :test_env? - end -end diff --git a/app/views/dashboard/overview/_quality_framework_indicators.erb b/app/views/dashboard/overview/_quality_framework_indicators.erb new file mode 100644 index 0000000..f438ae9 --- /dev/null +++ b/app/views/dashboard/overview/_quality_framework_indicators.erb @@ -0,0 +1,23 @@ +
<%= category_presenter.short_description %>
+ +Note: No measures can be displayed due to limited availability of school admin data and/or low survey response rates.
+<% elsif not_displayed_presenters.present? %> +Note: The following measures are not displayed due to limited availability of school admin data and/or low survey response rates: <%= not_displayed_presenters.map(&:measure_name).join('; ') %>.
+<% end %> + + diff --git a/app/views/dashboard/overview/index.html.erb b/app/views/dashboard/overview/index.html.erb new file mode 100644 index 0000000..4adcc49 --- /dev/null +++ b/app/views/dashboard/overview/index.html.erb @@ -0,0 +1,100 @@ +<% content_for :navigation do %> +