From 6838e8814b37ad1d0e914a6820e3c2487da23d75 Mon Sep 17 00:00:00 2001 From: endoooo Date: Thu, 16 Nov 2023 14:25:52 -0300 Subject: [PATCH] refactor: removed `LantternWeb.AssessmetPointLive.CurriculumItemSearchInputComponent` moved all field handling to parent form components (create and update assessment point form) and removed `LantternWeb.AssessmetPointLive.CurriculumItemSearchInputComponent` in favor of `LantternWeb.CurriculumLive.CurriculumItemSearchComponent` --- assets/js/autocomplete-hook.js | 28 --- .../live/admin/strand_live/form_component.ex | 1 + .../assessment_point_create_form_component.ex | 73 ++++++- .../assessment_point_update_form_component.ex | 102 +++++++--- .../curriculum_item_search_input_component.ex | 183 ------------------ .../curriculum_item_search_component.ex | 3 +- 6 files changed, 148 insertions(+), 242 deletions(-) delete mode 100644 lib/lanttern_web/live/assessment_point_live/curriculum_item_search_input_component.ex diff --git a/assets/js/autocomplete-hook.js b/assets/js/autocomplete-hook.js index 73266096..94d6002e 100644 --- a/assets/js/autocomplete-hook.js +++ b/assets/js/autocomplete-hook.js @@ -24,15 +24,6 @@ const pushSelect = (hook, input, selected) => { input.value = selected.name; } - // force hidden input value change and trigger phx-change event - if (input.getAttribute("data-hidden-input-id")) { - const hiddenInput = document.getElementById( - input.getAttribute("data-hidden-input-id") - ); - hiddenInput.value = selected.id; - hiddenInput.dispatchEvent(new Event("input", { bubbles: true })); - } - // send event to liveview server hook.pushEventTo(input, "autocomplete_result_select", selected); }; @@ -92,19 +83,6 @@ function autocompleteSearchResults(event) { } } -function clearSelectedItem(event) { - const input = this.el; - - // force hidden input value change and trigger phx-change event - if (input.getAttribute("data-hidden-input-id")) { - const hiddenInput = document.getElementById( - input.getAttribute("data-hidden-input-id") - ); - hiddenInput.value = ""; - hiddenInput.dispatchEvent(new Event("input", { bubbles: true })); - } -} - // on click away function clickAwayHandler(event) { const input = this.el; @@ -201,12 +179,6 @@ const autocompleteHook = { { signal: hookAbortControllerMap[this.el.id].signal } ); - window.addEventListener( - `phx:clear_selected_item:${id}`, - clearSelectedItem.bind(this), - { signal: hookAbortControllerMap[this.el.id].signal } - ); - window.addEventListener("click", clickAwayHandler.bind(this), { signal: hookAbortControllerMap[this.el.id].signal, }); diff --git a/lib/lanttern_web/live/admin/strand_live/form_component.ex b/lib/lanttern_web/live/admin/strand_live/form_component.ex index 7c799e0e..43cff7e7 100644 --- a/lib/lanttern_web/live/admin/strand_live/form_component.ex +++ b/lib/lanttern_web/live/admin/strand_live/form_component.ex @@ -43,6 +43,7 @@ defmodule LantternWeb.Admin.StrandLive.FormComponent do module={CurriculumItemSearchComponent} id="curriculum-item-search" notify_component={@myself} + refocus_on_select="true" />
@@ -63,12 +65,30 @@ defmodule LantternWeb.AssessmentPointLive.AssessmentPointCreateFormComponent do />
- <.live_component - module={LantternWeb.AssessmetPointLive.CurriculumItemSearchInputComponent} - id="create-assessment-point-form-curriculum-item" - field={@form[:curriculum_item_id]} - class="mb-6" - /> + <.input field={@form[:curriculum_item_id]} type="hidden" label="Curriculum item" /> +
+ <.live_component + module={CurriculumItemSearchComponent} + id="create-assessment-point-form-curriculum-item-search" + notify_component={@myself} + /> + <.badge + :if={@selected_curriculum_item} + class="mt-2" + theme="cyan" + show_remove + phx-click="remove_curriculum_item" + phx-target={@myself} + > +
+ #<%= @selected_curriculum_item.id %> + + (<%= @selected_curriculum_item.code %>) + + <%= @selected_curriculum_item.name %> +
+ +
<.input field={@form[:scale_id]} type="select" @@ -155,14 +175,53 @@ defmodule LantternWeb.AssessmentPointLive.AssessmentPointCreateFormComponent do class_options: class_options, selected_classes: selected_classes, student_options: student_options, - selected_students: selected_students + selected_students: selected_students, + selected_curriculum_item: nil }) {:ok, socket} end + def update(%{action: {CurriculumItemSearchComponent, {:selected, curriculum_item}}}, socket) do + # basically a manual "validate" event to update curriculum_item id + params = + socket.assigns.form.params + |> Map.put("curriculum_item_id", curriculum_item.id) + + form = + %AssessmentPoint{} + |> Assessments.change_assessment_point(params) + |> Map.put(:action, :validate) + |> to_form() + + {:ok, + socket + |> assign(:selected_curriculum_item, curriculum_item) + |> assign(:form, form)} + end + + def update(assigns, socket), do: {:ok, assign(socket, assigns)} + # event handlers + def handle_event("remove_curriculum_item", _params, socket) do + # basically a manual "validate" event to update curriculum_item id + params = + socket.assigns.form.params + |> Map.put("curriculum_item_id", nil) + + form = + %AssessmentPoint{} + |> Assessments.change_assessment_point(params) + |> Map.put(:action, :validate) + |> to_form() + + {:noreply, + socket + |> assign(:selected_curriculum_item, nil) + |> assign(:form, form)} + end + def handle_event( "class_selected", %{"assessment_point" => %{"class_id" => class_id}}, diff --git a/lib/lanttern_web/live/assessment_point_live/assessment_point_update_form_component.ex b/lib/lanttern_web/live/assessment_point_live/assessment_point_update_form_component.ex index 82ee626c..02daabe4 100644 --- a/lib/lanttern_web/live/assessment_point_live/assessment_point_update_form_component.ex +++ b/lib/lanttern_web/live/assessment_point_live/assessment_point_update_form_component.ex @@ -2,10 +2,11 @@ defmodule LantternWeb.AssessmentPointLive.AssessmentPointUpdateFormComponent do use LantternWeb, :live_component alias Lanttern.Assessments - alias Lanttern.Assessments.AssessmentPoint alias LantternWeb.GradingHelpers alias LantternWeb.SchoolsHelpers + alias LantternWeb.CurriculumLive.CurriculumItemSearchComponent + def render(assigns) do ~H"""
@@ -64,12 +65,30 @@ defmodule LantternWeb.AssessmentPointLive.AssessmentPointUpdateFormComponent do />
- <.live_component - module={LantternWeb.AssessmetPointLive.CurriculumItemSearchInputComponent} - id="update-assessment-point-form-curriculum-item" - field={@form[:curriculum_item_id]} - class="mb-6" - /> + <.input field={@form[:curriculum_item_id]} type="hidden" label="Curriculum item" /> +
+ <.live_component + module={CurriculumItemSearchComponent} + id="update-assessment-point-form-curriculum-item-search" + notify_component={@myself} + /> + <.badge + :if={@selected_curriculum_item} + class="mt-2" + theme="cyan" + show_remove + phx-click="remove_curriculum_item" + phx-target={@myself} + > +
+ #<%= @selected_curriculum_item.id %> + + (<%= @selected_curriculum_item.code %>) + + <%= @selected_curriculum_item.name %> +
+ +
<%!-- <.input field={@form[:scale_id]} type="select" @@ -98,7 +117,8 @@ defmodule LantternWeb.AssessmentPointLive.AssessmentPointUpdateFormComponent do class_options: class_options, selected_classes: selected_classes, student_options: student_options, - selected_students: selected_students + selected_students: selected_students, + selected_curriculum_item: nil }) {:ok, socket} @@ -109,30 +129,66 @@ defmodule LantternWeb.AssessmentPointLive.AssessmentPointUpdateFormComponent do assessment_point |> Assessments.change_assessment_point() - socket = - socket - |> assign(assigns) - |> assign(:form, to_form(changeset)) + selected_curriculum_item = + case assessment_point.curriculum_item_id do + id when is_integer(id) -> Lanttern.Curricula.get_curriculum_item!(id) + _ -> nil + end + + {:ok, + socket + |> assign(assigns) + |> assign(:form, to_form(changeset)) + |> assign(:selected_curriculum_item, selected_curriculum_item)} + end - {:ok, socket} + def update(%{action: {CurriculumItemSearchComponent, {:selected, curriculum_item}}}, socket) do + # basically a manual "validate" event to update curriculum_item id + params = + socket.assigns.form.params + |> Map.put("curriculum_item_id", curriculum_item.id) + + form = + socket.assigns.assessment_point + |> Assessments.change_assessment_point(params) + |> Map.put(:action, :validate) + |> to_form() + + {:ok, + socket + |> assign(:selected_curriculum_item, curriculum_item) + |> assign(:form, form)} end def update(assigns, socket) do - socket = - Enum.reduce( - assigns, - socket, - fn {key, value}, socket -> - assign(socket, key, value) - end - ) + {:ok, + socket + |> assign(assigns)} + end - {:ok, socket} + # event handlers + + def handle_event("remove_curriculum_item", _params, socket) do + # basically a manual "validate" event to update curriculum_item id + params = + socket.assigns.form.params + |> Map.put("curriculum_item_id", nil) + + form = + socket.assigns.assessment_point + |> Assessments.change_assessment_point(params) + |> Map.put(:action, :validate) + |> to_form() + + {:noreply, + socket + |> assign(:selected_curriculum_item, nil) + |> assign(:form, form)} end def handle_event("validate", %{"assessment_point" => params}, socket) do form = - %AssessmentPoint{} + socket.assigns.assessment_point |> Assessments.change_assessment_point(params) |> Map.put(:action, :validate) |> to_form() diff --git a/lib/lanttern_web/live/assessment_point_live/curriculum_item_search_input_component.ex b/lib/lanttern_web/live/assessment_point_live/curriculum_item_search_input_component.ex deleted file mode 100644 index 50a5e3e3..00000000 --- a/lib/lanttern_web/live/assessment_point_live/curriculum_item_search_input_component.ex +++ /dev/null @@ -1,183 +0,0 @@ -defmodule LantternWeb.AssessmetPointLive.CurriculumItemSearchInputComponent do - use LantternWeb, :live_component - - alias Lanttern.Curricula - - def render(assigns) do - ~H""" -
- <.label for={@id}>Curriculum item -

- You can search by id adding # before the id - <.inline_code> - #123 - - and search by code wrapping it in parenthesis - <.inline_code> - (ABC123) - -

-
- - <.base_input - id={@id} - name="query" - type="text" - value="" - class="peer pr-10" - role="combobox" - autocomplete="off" - aria-controls="curriculum-item-search-controls" - aria-expanded="false" - phx-hook="Autocomplete" - phx-change="search" - phx-debounce="500" - phx-target={@myself} - phx-update="ignore" - errors={@errors} - data-hidden-input-id={@field.id} - /> - <.icon - name="hero-chevron-up-down" - class="absolute top-2.5 right-2.5 text-ltrn-subtle peer-phx-change-loading:hidden" - /> - - -
    -
  • -
    - - #<%= result.id %> - (<%= result.code %>) - -
    - <%= result.name %> -
    - <.icon - name="hero-check" - class={[ - "shrink-0 ml-2 text-ltrn-primary hidden", - "group-aria-selected:block group-data-[active=true]:text-white" - ]} - /> -
  • -
- - <.badge - :if={@selected} - class="mt-2" - theme="cyan" - show_remove - phx-click="remove_curriculum_item" - phx-target={@myself} - > -
- #<%= @selected.id %> - (<%= @selected.code %>) - <%= @selected.name %> -
- - <.error :for={msg <- @errors}><%= msg %> -
-
- """ - end - - # lifecycle - - def mount(socket) do - socket = - socket - |> stream(:results, []) - - {:ok, socket} - end - - def update(%{field: field} = assigns, socket) do - selected = - case field.value do - nil -> nil - "" -> nil - id -> Curricula.get_curriculum_item!(id) - end - - socket = - socket - |> assign(assigns) - |> assign(:errors, Enum.map(field.errors, &translate_error/1)) - |> assign(:selected, selected) - - {:ok, socket} - end - - # event handlers - - def handle_event("search", %{"query" => query}, socket) do - results = - cond do - # search when looking for id - query =~ ~r/#[0-9]+\z/ -> - Curricula.search_curriculum_items(query) - - # or when more than 3 characters were typed - String.length(query) > 3 -> - Curricula.search_curriculum_items(query) - - true -> - [] - end - - results_simplified = Enum.map(results, fn ci -> %{id: ci.id} end) - - socket = - socket - |> stream(:results, results, reset: true) - |> push_event("autocomplete_search_results:#{socket.assigns.id}", %{ - results: results_simplified - }) - - {:noreply, socket} - end - - def handle_event("autocomplete_result_select", %{"id" => id}, socket) do - selected = Curricula.get_curriculum_item!(id) - - socket = - socket - |> stream(:results, [], reset: true) - |> assign(:selected, selected) - - {:noreply, socket} - end - - def handle_event("remove_curriculum_item", _params, socket) do - socket = - socket - |> assign(:selected, nil) - |> push_event("clear_selected_item:#{socket.assigns.id}", %{}) - - {:noreply, socket} - end -end diff --git a/lib/lanttern_web/live/curriculum_live/curriculum_item_search_component.ex b/lib/lanttern_web/live/curriculum_live/curriculum_item_search_component.ex index 0d57fd61..ef561efa 100644 --- a/lib/lanttern_web/live/curriculum_live/curriculum_item_search_component.ex +++ b/lib/lanttern_web/live/curriculum_live/curriculum_item_search_component.ex @@ -32,7 +32,7 @@ defmodule LantternWeb.CurriculumLive.CurriculumItemSearchComponent do phx-debounce="500" phx-target={@myself} phx-update="ignore" - data-refocus-on-select="true" + data-refocus-on-select={@refocus_on_select} /> <.icon name="hero-chevron-up-down" @@ -92,6 +92,7 @@ defmodule LantternWeb.CurriculumLive.CurriculumItemSearchComponent do socket = socket |> assign(:class, nil) + |> assign(:refocus_on_select, "false") |> stream(:results, []) {:ok, socket}