Skip to content

Commit

Permalink
feat: added support to view activities assessment point entries filte…
Browse files Browse the repository at this point in the history
…red by class

- added `:classes_ids` opt to `Assessments.list_activity_students_entries/2`

- added `:classes_ids` and `:preload` opts to `Schools.list_user_classes/2`

- created `LantternWeb.Helpers.NotifyHelpers` to centralize `notify_parent` and `notify_component` calls (we need to replace local implementations with the helper yet)

- created `SchoolLive.ClassFilterFormComponent`
  • Loading branch information
endoooo committed Nov 29, 2023
1 parent c50a5b6 commit 720cdbc
Show file tree
Hide file tree
Showing 10 changed files with 293 additions and 63 deletions.
25 changes: 22 additions & 3 deletions lib/lanttern/assessments.ex
Original file line number Diff line number Diff line change
Expand Up @@ -586,16 +586,35 @@ defmodule Lanttern.Assessments do
Entries are ordered by `ActivityAssessmentPoint` position,
which is the same order used by `list_activity_assessment_points/1`.
## Options:
- `:classes_ids` – filter entries by classes
"""

@spec list_activity_students_entries(integer()) :: [{Student.t(), [AssessmentPointEntry.t()]}]
@spec list_activity_students_entries(integer(), Keyword.t()) :: [
{Student.t(), [AssessmentPointEntry.t()]}
]

def list_activity_students_entries(activity_id, opts \\ []) do
students_query =
case Keyword.get(opts, :classes_ids) do
nil ->
from(s in Student)

classes_ids ->
from(
s in Student,
join: c in assoc(s, :classes),
where: c.id in ^classes_ids
)
end

def list_activity_students_entries(activity_id) do
results =
from(
ap in AssessmentPoint,
join: aap in assoc(ap, :activity_assessment_points),
join: s in Student,
join: s in subquery(students_query),
on: true,
left_join: e in AssessmentPointEntry,
on: e.student_id == s.id and e.assessment_point_id == ap.id,
Expand Down
25 changes: 21 additions & 4 deletions lib/lanttern/schools.ex
Original file line number Diff line number Diff line change
Expand Up @@ -235,29 +235,46 @@ defmodule Lanttern.Schools do
The list is sorted by cycle end date (desc), class year (asc), and class name (asc).
## Options:
- `:classes_ids` – filter results
## Examples
iex> list_user_classes()
[%Class{}, ...]
"""
def list_user_classes(%{current_profile: %{teacher: %{school_id: school_id}}} = _current_user) do
def list_user_classes(current_user, opts \\ [])

def list_user_classes(%{current_profile: %{teacher: %{school_id: school_id}}}, opts) do
from(
cl in Class,
join: cy in assoc(cl, :cycle),
left_join: s in assoc(cl, :students),
left_join: y in assoc(cl, :years),
group_by: [cl.id, cy.end_at],
order_by: [desc: cy.end_at, asc: min(y.id), asc: cl.name],
where: cl.school_id == ^school_id,
preload: [:cycle, :students, :years]
where: [school_id: ^school_id]
)
|> apply_list_user_classes_opts(opts)
|> Repo.all()
end

def list_user_classes(_current_user),
def list_user_classes(_current_user, _opts),
do: {:error, "User not allowed to list classes"}

defp apply_list_user_classes_opts(query, opts),
do: Enum.reduce(opts, query, &apply_list_user_classes_opt/2)

defp apply_list_user_classes_opt({:classes_ids, classes_ids}, query),
do: from(cl in query, where: cl.id in ^classes_ids)

defp apply_list_user_classes_opt({:preload, true}, query),
do: from(cl in query, preload: [:cycle, :students, :years])

defp apply_list_user_classes_opt(_, query), do: query

@doc """
Gets a single class.
Expand Down
11 changes: 11 additions & 0 deletions lib/lanttern_web/helpers/notify_helpers.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
defmodule LantternWeb.Helpers.NotifyHelpers do
def notify_parent(module, msg, %{notify_parent: true}),
do: send(self(), {module, msg})

def notify_parent(_module, _msg, _assigns), do: nil

def notify_component(module, msg, %{notify_component: %Phoenix.LiveComponent.CID{} = cid}),
do: Phoenix.LiveView.send_update(cid, action: {module, msg})

def notify_component(_module, _msg, _assigns), do: nil
end
55 changes: 55 additions & 0 deletions lib/lanttern_web/live/school_live/class_filter_form_component.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
defmodule LantternWeb.SchoolLive.ClassFilterFormComponent do
@moduledoc """
Class filter form component.
This form is used inside a `<.slide_over>` component,
where the "submit" button is rendered.
"""

use LantternWeb, :live_component
alias Lanttern.Schools
import LantternWeb.Helpers.NotifyHelpers

def render(assigns) do
~H"""
<div>
<.form id="class-filter-form" for={@form} phx-submit="save" phx-target={@myself}>
<div class="flex gap-6">
<fieldset class="flex-1">
<legend class="text-base font-semibold leading-6 text-ltrn-subtle">Classes</legend>
<div class="mt-4 divide-y divide-ltrn-lighter border-b border-t border-ltrn-lighter">
<.check_field
:for={opt <- @classes}
id={"class-#{opt.id}"}
field={@form[:classes_ids]}
opt={opt}
/>
</div>
</fieldset>
</div>
</.form>
</div>
"""
end

# lifecycle

def update(%{current_user: current_user} = assigns, socket) do
classes_ids = Map.get(assigns, :classes_ids, [])

{:ok,
socket
|> assign(assigns)
|> assign(:classes, Schools.list_user_classes(current_user))
|> assign(:form, to_form(%{"classes_ids" => classes_ids}, as: :classes))}
end

# event handlers

def handle_event("save", params, socket) do
params = Map.get(params, "classes", %{"classes_ids" => []})
notify_parent(__MODULE__, {:save, params}, socket.assigns)
notify_component(__MODULE__, {:save, params}, socket.assigns)
{:noreply, socket}
end
end
2 changes: 1 addition & 1 deletion lib/lanttern_web/live/school_live/show.ex
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ defmodule LantternWeb.SchoolLive.Show do
socket.assigns.current_user.current_profile.teacher.school
end

classes = Schools.list_user_classes(socket.assigns.current_user)
classes = Schools.list_user_classes(socket.assigns.current_user, preload: true)

{:ok,
socket
Expand Down
13 changes: 13 additions & 0 deletions lib/lanttern_web/live/strand_live/activity.ex
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ defmodule LantternWeb.StrandLive.Activity do
def handle_params(params, _url, socket) do
{:noreply,
socket
|> assign(:params, params)
|> assign(:assessment_point_id, nil)
|> set_current_tab(params, socket.assigns.live_action)
|> apply_action(socket.assigns.live_action, params)}
Expand Down Expand Up @@ -67,6 +68,18 @@ defmodule LantternWeb.StrandLive.Activity do

# info handlers

def handle_info(
{ActivityTabs.AssessmentComponent, {:apply_class_filters, classes_ids}},
socket
) do
{:noreply,
socket
|> push_navigate(
to:
~p"/strands/activity/#{socket.assigns.activity}?#{%{tab: "assessment", classes_ids: classes_ids}}"
)}
end

def handle_info(
{ActivityTabs.AssessmentComponent, {:assessment_point_deleted, _assessment_point}},
socket
Expand Down
4 changes: 3 additions & 1 deletion lib/lanttern_web/live/strand_live/activity.html.heex
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
<div class="flex items-center gap-2 mb-4">
<.icon name="hero-arrow-left" class="w-6 h-6" />
<.link
navigate={~p"/strands/#{@activity.strand}"}
navigate={~p"/strands/#{@activity.strand}?tab=activities"}
class="font-display font-black text-lg underline"
>
<%= @activity.strand.name %>
Expand Down Expand Up @@ -60,6 +60,8 @@
activity={@activity}
live_action={@live_action}
assessment_point_id={@assessment_point_id}
params={@params}
current_user={@current_user}
/>
<.live_component
:if={@current_tab == :notes}
Expand Down
Loading

0 comments on commit 720cdbc

Please sign in to comment.