mirror of
https://github.com/edcommonwealth/sqm-dashboards.git
synced 2026-03-07 13:38:18 -08:00
Replace javascript logic with hotwire. Also hide district dropdown on
home page if there is only one district.
This commit is contained in:
parent
87802c034e
commit
69179ce157
16 changed files with 3223 additions and 1259 deletions
|
|
@ -2,10 +2,53 @@
|
|||
|
||||
class HomeController < ApplicationController
|
||||
helper HeaderHelper
|
||||
def index
|
||||
@districts = District.all.order(:name)
|
||||
@schools = School.all.includes([:district]).order(:name)
|
||||
|
||||
def index
|
||||
@districts = districts
|
||||
@district = district
|
||||
|
||||
@schools = schools
|
||||
@school = school
|
||||
|
||||
@year = year
|
||||
@categories = Category.sorted.map { |category| CategoryPresenter.new(category:) }
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def districts
|
||||
District.all.order(:name).map do |district|
|
||||
[district.name, district.id]
|
||||
end
|
||||
end
|
||||
|
||||
def district
|
||||
return District.first if District.count == 1
|
||||
|
||||
District.find(params[:district]) if params[:district].present?
|
||||
end
|
||||
|
||||
def schools
|
||||
if district.present?
|
||||
district.schools.order(:name).map do |school|
|
||||
[school.name, school.id]
|
||||
end
|
||||
else
|
||||
[]
|
||||
end
|
||||
end
|
||||
|
||||
def school
|
||||
School.find(params[:school]) if params[:school].present?
|
||||
end
|
||||
|
||||
def year
|
||||
latest_response_rate = ResponseRate.where(school:)
|
||||
.where('meets_student_threshold = ? or meets_teacher_threshold = ?', true, true)
|
||||
.joins('inner join academic_years a on response_rates.academic_year_id=a.id')
|
||||
.order('a.range DESC').first
|
||||
academic_year = latest_response_rate.academic_year.range if latest_response_rate.present?
|
||||
|
||||
academic_year || AcademicYear.order('range DESC').first.range
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -34,26 +34,6 @@ module HeaderHelper
|
|||
end
|
||||
end
|
||||
|
||||
def school_mapper(school)
|
||||
academic_year = latest_year(school)
|
||||
{
|
||||
name: school.name,
|
||||
district_id: school.district_id,
|
||||
url: district_school_overview_index_path(school.district, school,
|
||||
{ year: academic_year.range })
|
||||
}
|
||||
end
|
||||
|
||||
def latest_year(school)
|
||||
latest_response_rate = ResponseRate.where(school:)
|
||||
.where('meets_student_threshold = ? or meets_teacher_threshold = ?', true, true)
|
||||
.joins('inner join academic_years a on response_rates.academic_year_id=a.id')
|
||||
.order('a.range DESC').first
|
||||
academic_year = latest_response_rate.academic_year if latest_response_rate.present?
|
||||
|
||||
academic_year || AcademicYear.order('range DESC').first
|
||||
end
|
||||
|
||||
def link_weight(path:)
|
||||
active?(path:) ? 'weight-700' : 'weight-400'
|
||||
end
|
||||
|
|
|
|||
|
|
@ -9,12 +9,10 @@ import {
|
|||
initializeListenersForNavDropdowns,
|
||||
initializePopovers,
|
||||
} from "./overview";
|
||||
import { initializeListenersForHomeDropdowns } from "./home";
|
||||
import { showEmptyDatasetModal } from "./modal";
|
||||
|
||||
document.addEventListener("turbo:load", () => {
|
||||
initializeListenersForNavDropdowns();
|
||||
initializeListenersForHomeDropdowns();
|
||||
initializePopovers();
|
||||
showEmptyDatasetModal();
|
||||
});
|
||||
|
|
|
|||
13
app/javascript/controllers/form_controller.js
Normal file
13
app/javascript/controllers/form_controller.js
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
import { Controller } from "@hotwired/stimulus"
|
||||
import debounce from "debounce";
|
||||
|
||||
// Connects to data-controller="form"
|
||||
export default class extends Controller {
|
||||
initialize() {
|
||||
this.submit = debounce(this.submit.bind(this), 300)
|
||||
}
|
||||
|
||||
submit() {
|
||||
this.element.requestSubmit();
|
||||
}
|
||||
}
|
||||
|
|
@ -6,3 +6,6 @@ import { application } from "./application"
|
|||
|
||||
import AnalyzeController from "./analyze_controller.js"
|
||||
application.register("analyze", AnalyzeController)
|
||||
|
||||
import FormController from "./form_controller.js"
|
||||
application.register("form", FormController)
|
||||
|
|
|
|||
|
|
@ -1,49 +0,0 @@
|
|||
import 'bootstrap';
|
||||
|
||||
export function initializeListenersForHomeDropdowns() {
|
||||
const districtDropdown = document.querySelector("#district-dropdown");
|
||||
if (districtDropdown) {
|
||||
const schoolDropdown = document.querySelector("#school-dropdown");
|
||||
districtDropdown.addEventListener("change", (event) => {
|
||||
const districtId = Number(event.target.value);
|
||||
const schoolsInDistrict = window.schools.filter(
|
||||
(school) => school.district_id === districtId
|
||||
);
|
||||
|
||||
schoolDropdown.replaceChildren(
|
||||
...schoolsInDistrict.map((school) => {
|
||||
return createOptionForSelect(school.name, school.url, false);
|
||||
})
|
||||
);
|
||||
|
||||
let optionElem = createOptionForSelect("Select a school", schoolDropdown.firstChild.value, true)
|
||||
schoolDropdown.insertBefore(optionElem, schoolDropdown.firstChild);
|
||||
|
||||
schoolDropdown.disabled = false;
|
||||
});
|
||||
|
||||
schoolDropdown.addEventListener("change", (event) => {
|
||||
const goButton = document.querySelector('button[data-id="go-to-school"]');
|
||||
goButton.disabled = false;
|
||||
});
|
||||
|
||||
document
|
||||
.querySelector('button[data-id="go-to-school"]')
|
||||
.addEventListener("click", (event) => {
|
||||
const selectedSchoolURL = schoolDropdown.value;
|
||||
window.location = selectedSchoolURL;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function createOptionForSelect(name, value, selected) {
|
||||
const optionElem = document.createElement("option");
|
||||
optionElem.setAttribute("value", value);
|
||||
|
||||
if (selected === true) {
|
||||
optionElem.setAttribute("selected", "selected");
|
||||
}
|
||||
const schoolNameNode = document.createTextNode(name);
|
||||
optionElem.appendChild(schoolNameNode);
|
||||
return optionElem;
|
||||
}
|
||||
|
|
@ -9,13 +9,39 @@
|
|||
<div class="container">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-6 welcome-controls d-flex justify-content-center">
|
||||
<%= collection_select(:district, :id, @districts, :id, :name, { prompt: 'Select a district', selected: "" }, { id: 'district-dropdown', 'data-id': 'district-dropdown', class: 'form-select' }) %>
|
||||
|
||||
<select id="school-dropdown" class="mx-3 form-select" data-id="school-dropdown" disabled>
|
||||
<option value="Select a school">Select a school</option>
|
||||
</select>
|
||||
<%= form_with(url: welcome_path, method: :get,
|
||||
data: {
|
||||
turbo_frame: "schools",
|
||||
turbo_action: "advance",
|
||||
controller: "form",
|
||||
action: "input->form#submit"
|
||||
}) do |f| %>
|
||||
|
||||
<%= turbo_frame_tag "schools" do %>
|
||||
<div class="d-flex">
|
||||
<% if District.count > 1 %>
|
||||
<div class="row">
|
||||
<%= f.select :district, @districts,
|
||||
{include_blank: "Select a District", selected: params[:district] } , {id: "district-dropdown", class: "form-select", hidden: @districts.count == 1} %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<div>
|
||||
<%= f.select :school, @schools,
|
||||
{include_blank: "Select a School", selected: params[:school]}, { id: "school-dropdown", class: "form-select mx-3"} if @schools %>
|
||||
</div>
|
||||
|
||||
<% if @school.present? %>
|
||||
<%= link_to "Go", district_school_overview_index_path(@district, @school, {year: @year} ), class: "mx-4 btn btn-secondary" , data: {turbo_frame: "_top"} %>
|
||||
<% else %>
|
||||
<%= button_to "Go", "/", class: "mx-4 btn btn-secondary" , data: {turbo_frame: "_top"}, disabled: true %>
|
||||
<% end %>
|
||||
|
||||
</div>
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
||||
<button data-id="go-to-school" class="mx-3 btn btn-secondary" disabled>Go</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -27,8 +27,5 @@
|
|||
<%= render partial: 'layouts/footer' %>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
window.schools = <%= @schools.map{ |school| school_mapper(school) }.to_json.html_safe %>;
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -17,7 +17,8 @@
|
|||
"babel-preset-es2015": "^6.24.1",
|
||||
"bootstrap": "^5.1.3",
|
||||
"esbuild": "^0.13.6",
|
||||
"sass": "^1.43.4"
|
||||
"sass": "^1.43.4",
|
||||
"debounce": "^1.2.1"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "esbuild app/javascript/*.* --bundle --outdir=app/assets/builds",
|
||||
|
|
|
|||
|
|
@ -4,6 +4,11 @@ describe HomeController, type: :controller do
|
|||
let!(:categories) do
|
||||
[create(:category, name: 'Second', sort_index: 2), create(:category, name: 'First', sort_index: 1)]
|
||||
end
|
||||
let(:academic_year) { create(:academic_year) }
|
||||
|
||||
before :each do
|
||||
academic_year
|
||||
end
|
||||
|
||||
it 'fetches categories sorted by sort_index' do
|
||||
get :index
|
||||
|
|
|
|||
|
|
@ -1,94 +0,0 @@
|
|||
import { initializeListenersForHomeDropdowns } from "home";
|
||||
|
||||
describe("School selection and go button", () => {
|
||||
let changeDistrict, changeSchool, clickGo;
|
||||
|
||||
beforeEach(() => {
|
||||
window.schools = [
|
||||
{
|
||||
district_id: 1,
|
||||
url: "/school1url",
|
||||
name: "school 1 name",
|
||||
},
|
||||
{
|
||||
district_id: 2,
|
||||
url: "/school2url",
|
||||
name: "school 2 name",
|
||||
},
|
||||
];
|
||||
|
||||
document.body.innerHTML = `
|
||||
<div>
|
||||
<select id="school-dropdown" data-id="school-dropdown" disabled></select>
|
||||
<select id="district-dropdown" data-id="district-dropdown">
|
||||
<option value="1">District 1</option>
|
||||
<option value="2">District 2</option>
|
||||
</select>
|
||||
<button data-id="go-to-school" disabled></button>
|
||||
</div>`;
|
||||
|
||||
const districtDropdown = document.getElementById("district-dropdown");
|
||||
changeDistrict = (districtName) => {
|
||||
districtDropdown.value = Array.from(districtDropdown.children).find(
|
||||
(element) => element.innerHTML === districtName
|
||||
).value;
|
||||
|
||||
const event = new Event("change");
|
||||
districtDropdown.dispatchEvent(event);
|
||||
};
|
||||
|
||||
changeSchool = (schoolName) => {
|
||||
const schoolDropdown = document.getElementById("school-dropdown");
|
||||
schoolDropdown.value = Array.from(schoolDropdown.children).find(
|
||||
(element) => element.innerHTML === schoolName
|
||||
).value;
|
||||
const event = new Event("change");
|
||||
schoolDropdown.dispatchEvent(event);
|
||||
};
|
||||
|
||||
clickGo = () => {
|
||||
const goButton = document.querySelector('button[data-id="go-to-school"]');
|
||||
const clickEvent = new Event("click");
|
||||
goButton.dispatchEvent(clickEvent);
|
||||
};
|
||||
|
||||
initializeListenersForHomeDropdowns();
|
||||
});
|
||||
|
||||
it("populates school dropdown only with schools from the selected district and the prompt", () => {
|
||||
const schoolDropdown = document.getElementById("school-dropdown");
|
||||
|
||||
changeDistrict("District 1");
|
||||
expect(schoolDropdown.firstChild.innerHTML).toBe("Select a school");
|
||||
expect(schoolDropdown.childElementCount).toBe(2);
|
||||
|
||||
changeDistrict("District 2");
|
||||
expect(schoolDropdown.childElementCount).toBe(2);
|
||||
expect(Array.from(schoolDropdown.options).map((o) => o.text)).toContain(
|
||||
"school 2 name"
|
||||
);
|
||||
});
|
||||
|
||||
it("Clicking the go button redirects to the school url", () => {
|
||||
delete window.location;
|
||||
window.location = "";
|
||||
|
||||
changeDistrict("District 1");
|
||||
changeSchool("school 1 name");
|
||||
clickGo();
|
||||
expect(window.location).toBe("/school1url");
|
||||
});
|
||||
|
||||
it("enables School dropdown once a district is selected", () => {
|
||||
const schoolDropdown = document.getElementById("school-dropdown");
|
||||
changeDistrict("District 1");
|
||||
expect(schoolDropdown.disabled).toBe(false);
|
||||
});
|
||||
|
||||
it("enables Go button once a school is selected", () => {
|
||||
changeDistrict("District 1");
|
||||
changeSchool("school 1 name");
|
||||
const goButton = document.querySelector('button[data-id="go-to-school"]');
|
||||
expect(goButton.disabled).toBe(false);
|
||||
});
|
||||
});
|
||||
|
|
@ -163,8 +163,13 @@ def district_admin_sees_problem_solving_emphasis
|
|||
end
|
||||
|
||||
def go_to_school_overview_from_welcome_page(district, school)
|
||||
expect(page).to have_select('district', selected: 'Select a District')
|
||||
select district.name, from: 'district-dropdown'
|
||||
expect(page).to have_select('school', selected: 'Select a School')
|
||||
visit welcome_path({ district: district.id, school: school.id })
|
||||
expect(page).to have_select('school', selected: 'Winchester High School')
|
||||
select school.name, from: 'school-dropdown'
|
||||
|
||||
click_on 'Go'
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
require 'rails_helper'
|
||||
|
||||
describe 'home/index' do
|
||||
let(:school) { create(:school) }
|
||||
let(:district) { create(:district) }
|
||||
subject { Nokogiri::HTML(rendered) }
|
||||
|
||||
before :each do
|
||||
|
|
|
|||
2410
yarn-error.log
2410
yarn-error.log
File diff suppressed because it is too large
Load diff
|
|
@ -2205,6 +2205,11 @@ data-urls@^2.0.0:
|
|||
whatwg-mimetype "^2.3.0"
|
||||
whatwg-url "^8.0.0"
|
||||
|
||||
debounce@^1.2.1:
|
||||
version "1.2.1"
|
||||
resolved "https://registry.yarnpkg.com/debounce/-/debounce-1.2.1.tgz#38881d8f4166a5c5848020c11827b834bcb3e0a5"
|
||||
integrity sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==
|
||||
|
||||
debug@4, debug@^4.1.0, debug@^4.1.1:
|
||||
version "4.3.4"
|
||||
resolved "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue