diff --git a/lib/lanttern_web/live/assessment_point_live/details.ex b/lib/lanttern_web/live/assessment_point_live/details.ex index 5bb316e7..f2b290df 100644 --- a/lib/lanttern_web/live/assessment_point_live/details.ex +++ b/lib/lanttern_web/live/assessment_point_live/details.ex @@ -363,6 +363,7 @@ defmodule LantternWeb.AssessmentPointLive.Details do socket |> assign(:rubric, nil) |> assign(:has_rubric_change, has_rubric_change) + |> assign(:is_creating_rubric, false) {:noreply, socket} end @@ -382,6 +383,7 @@ defmodule LantternWeb.AssessmentPointLive.Details do socket |> assign(:rubric, Rubrics.get_full_rubric!(rubric_id)) |> assign(:has_rubric_change, has_rubric_change) + |> assign(:is_creating_rubric, false) {:noreply, socket} end @@ -398,6 +400,7 @@ defmodule LantternWeb.AssessmentPointLive.Details do socket = socket |> assign(:has_rubric_change, false) + |> assign(:is_creating_rubric, false) |> update(:assessment_point, &Map.put(&1, :rubric_id, rubric_id)) {:noreply, socket} @@ -512,6 +515,23 @@ defmodule LantternWeb.AssessmentPointLive.Details do {:noreply, socket} end + def handle_info({LantternWeb.RubricsLive.FormComponent, {:created, rubric}}, socket) do + assessment_point = socket.assigns.assessment_point + + assessment_point + |> Assessments.update_assessment_point(%{ + rubric_id: rubric.id + }) + |> case do + {:ok, _assessment_point} -> + {:noreply, + push_navigate(socket, to: ~p"/assessment_points/#{assessment_point.id}/rubrics")} + + {:error, _changeset} -> + {:noreply, put_flash(socket, :error, "Something went wrong")} + end + end + def handle_info({FeedbackCommentFormComponent, {:created, comment}}, socket) do socket = socket diff --git a/lib/lanttern_web/live/assessment_point_live/details.html.heex b/lib/lanttern_web/live/assessment_point_live/details.html.heex index 495bdcd8..0728c65c 100644 --- a/lib/lanttern_web/live/assessment_point_live/details.html.heex +++ b/lib/lanttern_web/live/assessment_point_live/details.html.heex @@ -120,9 +120,15 @@ phx-change="assessment_point_rubric_selected" class="flex-1" /> - <.button :if={@has_rubric_change} type="submit" class="shrink-0">Save + <.button + type="submit" + disabled={!@has_rubric_change || @is_creating_rubric} + class={["shrink-0", if(!@has_rubric_change || @is_creating_rubric, do: "hidden")]} + > + Save + - <%= if @rubric do %> + <%= if @rubric && !@is_creating_rubric do %>

Descriptors

<%= if descriptor.scale_type == "ordinal" do %> @@ -137,6 +143,20 @@ <.markdown class="mt-2" text={descriptor.descriptor} />
<% end %> + <.live_component + :if={@is_creating_rubric} + module={LantternWeb.RubricsLive.FormComponent} + id={:new} + action={:new} + rubric={ + %Lanttern.Rubrics.Rubric{ + scale_id: @assessment_point.scale_id + } + } + hide_diff_and_scale + show_submit + class="mt-6" + /> <.slide_over :if={@live_action == :feedback} diff --git a/lib/lanttern_web/live/rubrics_live/explorer.html.heex b/lib/lanttern_web/live/rubrics_live/explorer.html.heex index faaa7f8e..d5454119 100644 --- a/lib/lanttern_web/live/rubrics_live/explorer.html.heex +++ b/lib/lanttern_web/live/rubrics_live/explorer.html.heex @@ -61,7 +61,7 @@ :if={@live_action in [:new, :edit]} id="rubric-form-overlay" show={true} - prevent_close_on_click_away + on_cancel={JS.patch(~p"/rubrics")} > <:title><%= @overlay_title %> <.live_component @@ -85,7 +85,11 @@ <:actions> - <.button type="button" theme="ghost" phx-click={JS.patch(~p"/rubrics")}> + <.button + type="button" + theme="ghost" + phx-click={JS.exec("data-cancel", to: "#rubric-form-overlay")} + > Cancel <.button type="submit" form="rubric-form" phx-disable-with="Saving..."> diff --git a/lib/lanttern_web/live/rubrics_live/form_component.ex b/lib/lanttern_web/live/rubrics_live/form_component.ex index a2cacf65..00ddfc42 100644 --- a/lib/lanttern_web/live/rubrics_live/form_component.ex +++ b/lib/lanttern_web/live/rubrics_live/form_component.ex @@ -14,14 +14,14 @@ defmodule LantternWeb.RubricsLive.FormComponent do @impl true def render(assigns) do ~H""" -
+
<.form for={@form} id="rubric-form" phx-target={@myself} phx-change="validate" phx-submit="save"> <.input field={@form[:criteria]} type="text" label="Criteria" phx-debounce="1500" /> <.input field={@form[:is_differentiation]} type="toggle" label="Is differentiation" - class="mt-6" + class={["mt-6", if(@hide_diff_and_scale, do: "hidden")]} /> <.input field={@form[:scale_id]} @@ -31,9 +31,12 @@ defmodule LantternWeb.RubricsLive.FormComponent do prompt="Select scale" phx-target={@myself} phx-change="scale_selected" - class="mt-6" + class={["mt-6", if(@hide_diff_and_scale, do: "hidden")]} /> <.descriptors_fields scale={@scale} field={@form[:descriptors]} myself={@myself} /> +
+ <.button type="submit">Save +
""" @@ -52,6 +55,7 @@ defmodule LantternWeb.RubricsLive.FormComponent do defp descriptors_fields(%{scale: %{type: "ordinal"}} = assigns) do ~H"""
Descriptors
+ <.markdown_supported /> <.inputs_for :let={ef} field={@field}> <.input type="hidden" field={ef[:scale_id]} /> <.input type="hidden" field={ef[:scale_type]} /> @@ -71,6 +75,7 @@ defmodule LantternWeb.RubricsLive.FormComponent do defp descriptors_fields(%{scale: %{type: "numeric"}} = assigns) do ~H"""
Descriptors
+ <.markdown_supported /> <.inputs_for :let={ef} field={@field}>
@@ -99,6 +104,20 @@ defmodule LantternWeb.RubricsLive.FormComponent do """ end + defp markdown_supported(assigns) do + ~H""" +

+ + Markdown supported in descriptors <.icon name="hero-information-circle" /> + +

+ """ + end + attr :ordinal_values, :list, required: true attr :ordinal_value_id, :integer, required: true @@ -133,20 +152,38 @@ defmodule LantternWeb.RubricsLive.FormComponent do socket |> assign(:scale_options, scale_options) |> assign(:scale, nil) + |> assign(:hide_diff_and_scale, false) + |> assign(:class, nil) + |> assign(:patch, nil) + |> assign(:show_submit, false) {:ok, socket} end @impl true def update(%{rubric: rubric} = assigns, socket) do - changeset = Rubrics.change_rubric(rubric) - scale = case rubric.scale_id do nil -> nil scale_id -> Grading.get_scale!(scale_id, preloads: :ordinal_values) end + changeset = + case {rubric.id, scale} do + {nil, nil} -> + Rubrics.change_rubric(rubric) + + {nil, scale} -> + # if scale is selected and rubric is new, generate empty descriptors + Rubrics.change_rubric( + rubric, + %{"descriptors" => generate_new_descriptors(scale)} + ) + + _ -> + Rubrics.change_rubric(rubric) + end + {:ok, socket |> assign(assigns) @@ -178,30 +215,7 @@ defmodule LantternWeb.RubricsLive.FormComponent do def handle_event("scale_selected", %{"rubric" => %{"scale_id" => scale_id}}, socket) do scale = Grading.get_scale!(scale_id, preloads: :ordinal_values) - - descriptors = - case scale.type do - "ordinal" -> - scale.ordinal_values - |> Enum.map( - &%{ - scale_id: &1.scale_id, - scale_type: scale.type, - ordinal_value_id: &1.id, - descriptor: "—" - } - ) - - "numeric" -> - %{ - "0" => - blank_numeric_descriptor(scale) - |> Map.put("score", scale.start), - "1" => - blank_numeric_descriptor(scale) - |> Map.put("score", scale.stop) - } - end + descriptors = generate_new_descriptors(scale) changeset = socket.assigns.rubric @@ -275,6 +289,31 @@ defmodule LantternWeb.RubricsLive.FormComponent do save_rubric(socket, socket.assigns.action, rubric_params) end + defp generate_new_descriptors(scale) do + case scale.type do + "ordinal" -> + scale.ordinal_values + |> Enum.map( + &%{ + scale_id: &1.scale_id, + scale_type: scale.type, + ordinal_value_id: &1.id, + descriptor: "—" + } + ) + + "numeric" -> + %{ + "0" => + blank_numeric_descriptor(scale) + |> Map.put("score", scale.start), + "1" => + blank_numeric_descriptor(scale) + |> Map.put("score", scale.stop) + } + end + end + defp blank_numeric_descriptor(scale) do %{ "scale_id" => scale.id, @@ -292,7 +331,7 @@ defmodule LantternWeb.RubricsLive.FormComponent do {:noreply, socket |> put_flash(:info, "Rubric updated successfully") - |> push_patch(to: socket.assigns.patch)} + |> maybe_push_patch(socket.assigns.patch)} {:error, %Ecto.Changeset{} = changeset} -> {:noreply, assign_form(socket, changeset)} @@ -307,13 +346,16 @@ defmodule LantternWeb.RubricsLive.FormComponent do {:noreply, socket |> put_flash(:info, "Rubric created successfully") - |> push_patch(to: socket.assigns.patch)} + |> maybe_push_patch(socket.assigns.patch)} {:error, %Ecto.Changeset{} = changeset} -> {:noreply, assign_form(socket, changeset)} end end + defp maybe_push_patch(socket, nil), do: socket + defp maybe_push_patch(socket, patch_assign), do: push_patch(socket, to: patch_assign) + defp assign_form(socket, %Ecto.Changeset{} = changeset) do assign(socket, :form, to_form(changeset)) end