diff --git a/lib/lanttern/learning_context/strand.ex b/lib/lanttern/learning_context/strand.ex index 8ebec12a..353d0814 100644 --- a/lib/lanttern/learning_context/strand.ex +++ b/lib/lanttern/learning_context/strand.ex @@ -15,6 +15,7 @@ defmodule Lanttern.LearningContext.Strand do field :is_starred, :boolean, virtual: true has_many :activities, Lanttern.LearningContext.Activity + has_many :assessment_points, Lanttern.Assessments.AssessmentPoint many_to_many :subjects, Lanttern.Taxonomy.Subject, join_through: "strands_subjects", diff --git a/lib/lanttern/rubrics/rubric.ex b/lib/lanttern/rubrics/rubric.ex index 830ccda3..9d72c5c6 100644 --- a/lib/lanttern/rubrics/rubric.ex +++ b/lib/lanttern/rubrics/rubric.ex @@ -14,8 +14,7 @@ defmodule Lanttern.Rubrics.Rubric do has_many :assessment_points, Lanttern.Assessments.AssessmentPoint many_to_many :students, Lanttern.Schools.Student, - join_through: "differentiation_rubrics_students", - on_replace: :delete + join_through: "differentiation_rubrics_students" timestamps() end diff --git a/lib/lanttern/schools.ex b/lib/lanttern/schools.ex index d781f830..2a0ec93b 100644 --- a/lib/lanttern/schools.ex +++ b/lib/lanttern/schools.ex @@ -381,6 +381,7 @@ defmodule Lanttern.Schools do `:preloads` – preloads associated data `:classes_ids` – filter students by provided list of ids + `:check_diff_rubrics_for_strand_id` - used to check if student has any differentiation rubric for given strand id ## Examples @@ -389,24 +390,49 @@ defmodule Lanttern.Schools do """ def list_students(opts \\ []) do - Student - |> maybe_filter_students_by_class(opts) + from( + s in Student, + order_by: s.name + ) + |> filter_students(opts) + |> load_has_diff_rubric_flag(Keyword.get(opts, :check_diff_rubrics_for_strand_id)) |> Repo.all() |> maybe_preload(opts) end - defp maybe_filter_students_by_class(student_query, opts) do - case Keyword.get(opts, :classes_ids) do - nil -> - student_query + defp filter_students(queryable, opts), + do: Enum.reduce(opts, queryable, &apply_students_filter/2) - classes_ids -> - from( - s in student_query, - join: c in assoc(s, :classes), - where: c.id in ^classes_ids - ) - end + defp apply_students_filter({:classes_ids, ids}, queryable) do + from( + s in queryable, + join: c in assoc(s, :classes), + where: c.id in ^ids + ) + end + + defp apply_students_filter(_, queryable), do: queryable + + defp load_has_diff_rubric_flag(queryable, nil), do: queryable + + defp load_has_diff_rubric_flag(queryable, strand_id) do + has_diff_query = + from( + s in Student, + left_join: dr in assoc(s, :diff_rubrics), + left_join: r in assoc(dr, :parent_rubric), + left_join: ap in Lanttern.Assessments.AssessmentPoint, + on: ap.rubric_id == r.id and ap.strand_id == ^strand_id, + group_by: s.id, + select: %{student_id: s.id, has_diff_rubric: count(ap) > 0} + ) + + from( + s in queryable, + join: d in subquery(has_diff_query), + on: d.student_id == s.id, + select: %{s | has_diff_rubric: d.has_diff_rubric} + ) end @doc """ diff --git a/lib/lanttern/schools/student.ex b/lib/lanttern/schools/student.ex index 43ba51e3..e2fe3b47 100644 --- a/lib/lanttern/schools/student.ex +++ b/lib/lanttern/schools/student.ex @@ -8,6 +8,7 @@ defmodule Lanttern.Schools.Student do schema "students" do field :name, :string field :classes_ids, {:array, :id}, virtual: true + field :has_diff_rubric, :boolean, virtual: true, default: false belongs_to :school, Lanttern.Schools.School @@ -16,6 +17,9 @@ defmodule Lanttern.Schools.Student do on_replace: :delete, preload_order: [asc: :name] + many_to_many :diff_rubrics, Lanttern.Rubrics.Rubric, + join_through: "differentiation_rubrics_students" + timestamps() end diff --git a/lib/lanttern_web/live/pages/strands/id/strand_live.ex b/lib/lanttern_web/live/pages/strands/id/strand_live.ex index 6b244185..47737c20 100644 --- a/lib/lanttern_web/live/pages/strands/id/strand_live.ex +++ b/lib/lanttern_web/live/pages/strands/id/strand_live.ex @@ -34,7 +34,7 @@ defmodule LantternWeb.StrandLive do # prevent user from navigating directly to nested views defp maybe_redirect(%{assigns: %{live_action: live_action}} = socket, params) - when live_action in [:manage_rubric, :diff_rubric], + when live_action in [:manage_rubric], do: redirect(socket, to: ~p"/strands/#{params["id"]}?tab=assessment") defp maybe_redirect(socket, _params), do: socket @@ -69,7 +69,7 @@ defmodule LantternWeb.StrandLive do do: assign(socket, :current_tab, Map.get(@tabs, tab, :about)) defp set_current_tab(socket, _params, live_action) - when live_action in [:manage_rubric, :diff_rubric], + when live_action in [:manage_rubric], do: assign(socket, :current_tab, :assessment) defp set_current_tab(socket, _params, _live_action), diff --git a/lib/lanttern_web/live/pages/strands/id/strand_live.html.heex b/lib/lanttern_web/live/pages/strands/id/strand_live.html.heex index 151ce235..aeb9cd1e 100644 --- a/lib/lanttern_web/live/pages/strands/id/strand_live.html.heex +++ b/lib/lanttern_web/live/pages/strands/id/strand_live.html.heex @@ -23,18 +23,18 @@ > About - <:tab - patch={~p"/strands/#{@strand}?#{%{tab: "activities"}}"} - is_current={@current_tab == :activities && "true"} - > - Activities - <:tab patch={~p"/strands/#{@strand}?#{%{tab: "assessment"}}"} is_current={@current_tab == :assessment && "true"} > Assessment + <:tab + patch={~p"/strands/#{@strand}?#{%{tab: "activities"}}"} + is_current={@current_tab == :activities && "true"} + > + Activities + <:tab patch={~p"/strands/#{@strand}?#{%{tab: "notes"}}"} is_current={@current_tab == :notes && "true"} @@ -71,13 +71,6 @@ strand={@strand} live_action={@live_action} /> - <.live_component - :if={@current_tab == :activities} - module={ActivitiesComponent} - id="strand-details-activities" - strand={@strand} - live_action={@live_action} - /> <.live_component :if={@current_tab == :assessment} module={AssessmentComponent} @@ -87,6 +80,13 @@ current_user={@current_user} live_action={@live_action} /> + <.live_component + :if={@current_tab == :activities} + module={ActivitiesComponent} + id="strand-details-activities" + strand={@strand} + live_action={@live_action} + /> <.live_component :if={@current_tab == :notes} module={NotesComponent} diff --git a/lib/lanttern_web/live/pages/strands/id/strand_rubrics_component.ex b/lib/lanttern_web/live/pages/strands/id/strand_rubrics_component.ex index 9c24a9e5..e556cfb6 100644 --- a/lib/lanttern_web/live/pages/strands/id/strand_rubrics_component.ex +++ b/lib/lanttern_web/live/pages/strands/id/strand_rubrics_component.ex @@ -95,6 +95,7 @@ defmodule LantternWeb.StrandLive.StrandRubricsComponent do container_selector="#differentiation-rubrics-section" on_click={JS.push("load_diff_rubrics", value: %{student_id: student.id})} phx-target={@myself} + theme={if student.has_diff_rubric, do: "cyan", else: "subtle"} />
assign_new(:students, fn -> case assigns.params do %{"classes_ids" => classes_ids} when is_list(classes_ids) and classes_ids != [] -> - Schools.list_students(classes_ids: classes_ids) + Schools.list_students( + classes_ids: classes_ids, + check_diff_rubrics_for_strand_id: strand.id + ) _ -> [] diff --git a/lib/lanttern_web/router.ex b/lib/lanttern_web/router.ex index 19f5caf9..1cfb7bbe 100644 --- a/lib/lanttern_web/router.ex +++ b/lib/lanttern_web/router.ex @@ -74,7 +74,6 @@ defmodule LantternWeb.Router do live "/strands/:id/goal/edit", StrandLive, :edit_goal live "/strands/:id/new_activity", StrandLive, :new_activity live "/strands/:id/rubric/manage", StrandLive, :manage_rubric - live "/strands/:id/rubric/differentiation", StrandLive, :diff_rubric live "/strands/activity/:id", ActivityLive, :show live "/strands/activity/:id/edit", ActivityLive, :edit diff --git a/test/lanttern/schools_test.exs b/test/lanttern/schools_test.exs index ec99a57c..1bb4c688 100644 --- a/test/lanttern/schools_test.exs +++ b/test/lanttern/schools_test.exs @@ -361,6 +361,51 @@ defmodule Lanttern.SchoolsTest do end end + test "list_students/1 with diff rubrics opts returns all students as expected" do + student_1 = student_fixture(%{name: "AAA"}) + student_2 = student_fixture(%{name: "BBB"}) + + strand = Lanttern.LearningContextFixtures.strand_fixture() + scale = Lanttern.GradingFixtures.scale_fixture() + parent_rubric = Lanttern.RubricsFixtures.rubric_fixture(%{scale_id: scale.id}) + + Lanttern.Rubrics.create_diff_rubric_for_student(student_1.id, %{ + criteria: "diff rubric for std 1", + scale_id: scale.id, + diff_for_rubric_id: parent_rubric.id + }) + + Lanttern.AssessmentsFixtures.assessment_point_fixture(%{ + strand_id: strand.id, + rubric_id: parent_rubric.id + }) + + # other rubrics for testing + other_strand = Lanttern.LearningContextFixtures.strand_fixture() + other_parent_rubric = Lanttern.RubricsFixtures.rubric_fixture(%{scale_id: scale.id}) + + Lanttern.Rubrics.create_diff_rubric_for_student(student_2.id, %{ + criteria: "diff rubric for std 2", + scale_id: scale.id, + diff_for_rubric_id: other_parent_rubric.id + }) + + Lanttern.AssessmentsFixtures.assessment_point_fixture(%{ + strand_id: other_strand.id, + rubric_id: other_parent_rubric.id + }) + + # assert + [expected_1, expected_2] = + Schools.list_students(check_diff_rubrics_for_strand_id: strand.id) + + assert expected_1.id == student_1.id + assert expected_1.has_diff_rubric + + assert expected_2.id == student_2.id + assert !expected_2.has_diff_rubric + end + test "get_student/2 returns the student with given id" do student = student_fixture() assert Schools.get_student(student.id) == student