parent
0ceaad3a2b
commit
0a5500ecc9
@ -0,0 +1,45 @@
|
|||||||
|
class ResponseRatePresenter
|
||||||
|
attr_reader :focus, :academic_year, :school, :survey_items
|
||||||
|
|
||||||
|
def initialize(focus:, academic_year:, school:)
|
||||||
|
@focus = focus
|
||||||
|
@academic_year = academic_year
|
||||||
|
@school = school
|
||||||
|
@survey_items = SurveyItem.student_survey_items if focus == :student
|
||||||
|
@survey_items = SurveyItem.teacher_survey_items if focus == :teacher
|
||||||
|
end
|
||||||
|
|
||||||
|
def date
|
||||||
|
SurveyItemResponse.where(survey_item: survey_items, school:).order(updated_at: :DESC).first&.updated_at || Date.new
|
||||||
|
end
|
||||||
|
|
||||||
|
def percentage
|
||||||
|
cap_at_100(actual_count.to_f / respondents_count.to_f * 100).round
|
||||||
|
end
|
||||||
|
|
||||||
|
def color
|
||||||
|
# Problem: the color (either $gold or $purple) is determined by the scss variable, but the
|
||||||
|
# percentage is decided by the presenter. Therefore the class style must be generated
|
||||||
|
# within this file and not the scss file.
|
||||||
|
# TODO: Fix this.
|
||||||
|
percentage > 75 ? '#49416D' : '#FFC857'
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def cap_at_100(value)
|
||||||
|
value > 100 ? 100 : value
|
||||||
|
end
|
||||||
|
|
||||||
|
def actual_count
|
||||||
|
SurveyItemResponse.where(school:, academic_year:,
|
||||||
|
survey_item: survey_items).select(:response_id).distinct.count
|
||||||
|
end
|
||||||
|
|
||||||
|
def respondents_count
|
||||||
|
respondents = Respondent.find_by(school:, academic_year:)
|
||||||
|
count = respondents.total_students if focus == :student
|
||||||
|
count = respondents.total_teachers if focus == :teacher
|
||||||
|
count
|
||||||
|
end
|
||||||
|
end
|
||||||
@ -0,0 +1,8 @@
|
|||||||
|
<div class="overall-response-rate-container">
|
||||||
|
<div>Response Rates as of <%= response_rate_presenter.date.to_date.strftime("%m/%d/%y") %> </div>
|
||||||
|
<div style="display: flex; justify-content:space-between; width: 100px;">
|
||||||
|
<div><%= response_rate_presenter.focus.capitalize %> </div>
|
||||||
|
<%= render partial: "response_rate_graphic", locals: {response_rate_presenter: response_rate_presenter}, cached: true %>
|
||||||
|
<div><%= response_rate_presenter.percentage %>% </div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@ -0,0 +1,35 @@
|
|||||||
|
<style>
|
||||||
|
/*
|
||||||
|
For some reason, none of the sizing in the pie class works, and it always
|
||||||
|
fills 100% of the containing frame, so the size has to be dictated by .prog
|
||||||
|
*/
|
||||||
|
.prog {
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
position: relative;
|
||||||
|
border: 1px solid black;
|
||||||
|
border-radius: 50%;
|
||||||
|
margin-top: 0.2em;
|
||||||
|
}
|
||||||
|
.pie {
|
||||||
|
aspect-ratio: 1;
|
||||||
|
display: inline-grid;
|
||||||
|
place-content: center;
|
||||||
|
margin: 5px;
|
||||||
|
font-size: 25px;
|
||||||
|
font-weight: bold;
|
||||||
|
font-family: sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
#response-rate-pie-<%= response_rate_presenter.focus %>:before{
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
border-radius: 50%;
|
||||||
|
inset: 0;
|
||||||
|
background: conic-gradient(<%= response_rate_presenter.color %> calc(<%= response_rate_presenter.percentage %>*1%),#0000 0);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div class="prog">
|
||||||
|
<div id="response-rate-pie-<%= response_rate_presenter.focus %>" class="pie"></div>
|
||||||
|
</div>
|
||||||
|
@ -0,0 +1,160 @@
|
|||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
describe ResponseRatePresenter do
|
||||||
|
let(:academic_year) { create(:academic_year, range: '2022-23') }
|
||||||
|
let(:school) { create(:school, name: 'A school') }
|
||||||
|
let(:respondents) { create(:respondent, school:, academic_year:, total_students: 40, total_teachers: 40) }
|
||||||
|
let(:wrong_school) { create(:school, name: 'Wrong school') }
|
||||||
|
let(:wrong_academic_year) { create(:academic_year) }
|
||||||
|
let(:wrong_respondents) do
|
||||||
|
create(:respondent, school: wrong_school, academic_year: wrong_academic_year, total_students: 40,
|
||||||
|
total_teachers: 40)
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:student_survey_item) { create(:student_survey_item) }
|
||||||
|
let(:teacher_survey_item) { create(:teacher_survey_item) }
|
||||||
|
let(:oldest_student_survey_response) do
|
||||||
|
create(:survey_item_response, school:, academic_year:, survey_item: student_survey_item)
|
||||||
|
end
|
||||||
|
let(:newest_student_survey_response) do
|
||||||
|
create(:survey_item_response, school:, academic_year:, survey_item: student_survey_item)
|
||||||
|
end
|
||||||
|
let(:oldest_teacher_survey_response) do
|
||||||
|
create(:survey_item_response, school:, academic_year:, survey_item: teacher_survey_item)
|
||||||
|
end
|
||||||
|
let(:newest_teacher_survey_response) do
|
||||||
|
create(:survey_item_response, school:, academic_year:, survey_item: teacher_survey_item)
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:wrong_student_survey_response) do
|
||||||
|
create(:survey_item_response, school: wrong_school, academic_year: wrong_academic_year,
|
||||||
|
survey_item: student_survey_item)
|
||||||
|
end
|
||||||
|
let(:wrong_teacher_survey_response) do
|
||||||
|
create(:survey_item_response, school: wrong_school, academic_year: wrong_academic_year,
|
||||||
|
survey_item: teacher_survey_item)
|
||||||
|
end
|
||||||
|
|
||||||
|
context '.date' do
|
||||||
|
context 'when focus is student' do
|
||||||
|
before :each do
|
||||||
|
oldest_student_survey_response
|
||||||
|
newest_student_survey_response
|
||||||
|
wrong_student_survey_response
|
||||||
|
wrong_teacher_survey_response
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'ignores all teacher items and only gets the modified date of the last student item' do
|
||||||
|
rdate = ResponseRatePresenter.new(focus: :student, academic_year:, school:).date
|
||||||
|
expect(rdate).to eq(newest_student_survey_response.updated_at)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
context 'when focus is teacher' do
|
||||||
|
before :each do
|
||||||
|
oldest_teacher_survey_response
|
||||||
|
newest_teacher_survey_response
|
||||||
|
wrong_student_survey_response
|
||||||
|
wrong_teacher_survey_response
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'ignores all student responses and only gets the modified date of the last teacher item' do
|
||||||
|
rdate = ResponseRatePresenter.new(focus: :teacher, academic_year:, school:).date
|
||||||
|
expect(rdate).to eq(newest_teacher_survey_response.updated_at)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context '.percentage' do
|
||||||
|
before :each do
|
||||||
|
respondents
|
||||||
|
wrong_respondents
|
||||||
|
end
|
||||||
|
context 'when no survey responses are found for a school' do
|
||||||
|
it 'returns a response rate of 0' do
|
||||||
|
rdate = ResponseRatePresenter.new(focus: :teacher, academic_year:, school:).percentage
|
||||||
|
expect(rdate).to eq(0)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when there all possible teacher respondents answered questions' do
|
||||||
|
before :each do
|
||||||
|
create_list(:survey_item_response, 40, school:, academic_year:,
|
||||||
|
survey_item: teacher_survey_item)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns a response rate of 100' do
|
||||||
|
rdate = ResponseRatePresenter.new(focus: :teacher, academic_year:, school:).percentage
|
||||||
|
expect(rdate).to eq(100)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when more teachers responded than staff the school' do
|
||||||
|
before :each do
|
||||||
|
create_list(:survey_item_response, 80, school:, academic_year:,
|
||||||
|
survey_item: teacher_survey_item)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns a response rate of 100' do
|
||||||
|
rdate = ResponseRatePresenter.new(focus: :teacher, academic_year:, school:).percentage
|
||||||
|
expect(rdate).to eq(100)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when three quarters of the teachers responded to the survey' do
|
||||||
|
before :each do
|
||||||
|
create_list(:survey_item_response, 30, school:, academic_year:,
|
||||||
|
survey_item: teacher_survey_item)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns a response rate of 75' do
|
||||||
|
rdate = ResponseRatePresenter.new(focus: :teacher, academic_year:, school:).percentage
|
||||||
|
expect(rdate).to eq(75)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
context 'when one quarter of the teachers responded to the survey' do
|
||||||
|
before :each do
|
||||||
|
create_list(:survey_item_response, 10, school:, academic_year:,
|
||||||
|
survey_item: teacher_survey_item)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns a response rate of 25' do
|
||||||
|
rdate = ResponseRatePresenter.new(focus: :teacher, academic_year:, school:).percentage
|
||||||
|
expect(rdate).to eq(25)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
context 'When the percentage is not a round number' do
|
||||||
|
before :each do
|
||||||
|
create_list(:survey_item_response, 9, school:, academic_year:,
|
||||||
|
survey_item: teacher_survey_item)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'its rounded to the nearest integer' do
|
||||||
|
rdate = ResponseRatePresenter.new(focus: :teacher, academic_year:, school:).percentage
|
||||||
|
expect(rdate).to eq(23)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when there all possible student respondents answered questions' do
|
||||||
|
before :each do
|
||||||
|
create_list(:survey_item_response, 40, school:, academic_year:,
|
||||||
|
survey_item: student_survey_item)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns a response rate of 100' do
|
||||||
|
rdate = ResponseRatePresenter.new(focus: :student, academic_year:, school:).percentage
|
||||||
|
expect(rdate).to eq(100)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
context 'when half of all students responded' do
|
||||||
|
before :each do
|
||||||
|
create_list(:survey_item_response, 20, school:, academic_year:,
|
||||||
|
survey_item: student_survey_item)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns a response rate of 50' do
|
||||||
|
rdate = ResponseRatePresenter.new(focus: :student, academic_year:, school:).percentage
|
||||||
|
expect(rdate).to eq(50)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
Loading…
Reference in new issue