From 580d78f18d50e46df44f202b3ec45b19035561ae Mon Sep 17 00:00:00 2001 From: carla Date: Thu, 23 Oct 2025 15:43:08 +0200 Subject: [PATCH] fix: keep search term while sorting --- .../live/components/sort_header_component.ex | 48 ++++++----- lib/mv_web/live/member_live/index.ex | 84 ++++++++++++++----- 2 files changed, 89 insertions(+), 43 deletions(-) diff --git a/lib/mv_web/live/components/sort_header_component.ex b/lib/mv_web/live/components/sort_header_component.ex index e69357e..3439d91 100644 --- a/lib/mv_web/live/components/sort_header_component.ex +++ b/lib/mv_web/live/components/sort_header_component.ex @@ -2,9 +2,9 @@ defmodule MvWeb.Components.SortHeaderComponent do @moduledoc """ Sort Header that can be used as column header and sorts a table: Props: - - field: atom() # Ash‑Field for sorting - - label: string() # Column Heading (can be aan heex templyte) - - sort_field: atom() | nil # current sort-field from parent liveview + - field: atom() # Ash Field for sorting + - label: string() # Column Heading (can be an heex template) + - sort_field: atom() | nil # current sort field from parent liveview - sort_order: :asc | :desc | nil # current sorting order """ use MvWeb, :live_component @@ -19,25 +19,27 @@ defmodule MvWeb.Components.SortHeaderComponent do @impl true def render(assigns) do ~H""" - +
+ +
""" end @@ -48,7 +50,7 @@ defmodule MvWeb.Components.SortHeaderComponent do end # ------------------------------------------------- - # Hilfsfunktionen für ARIA‑Attribute & Icon‑SVG + # Hilfsfunktionen für ARIA Attribute & Icon SVG # ------------------------------------------------- defp aria_sort(field, sort_field, dir) when field == sort_field do case dir do diff --git a/lib/mv_web/live/member_live/index.ex b/lib/mv_web/live/member_live/index.ex index 7a0de39..4a05e29 100644 --- a/lib/mv_web/live/member_live/index.ex +++ b/lib/mv_web/live/member_live/index.ex @@ -4,7 +4,7 @@ defmodule MvWeb.MemberLive.Index do import Ash.Query @impl true - def mount(params, _session, socket) do + def mount(_params, _session, socket) do socket = socket |> assign(:page_title, gettext("Members")) @@ -14,7 +14,6 @@ defmodule MvWeb.MemberLive.Index do |> assign(:selected_members, []) # We call handle params to use the query from the URL - {:noreply, socket} = handle_params(params, nil, socket) {:ok, socket} end @@ -70,6 +69,7 @@ defmodule MvWeb.MemberLive.Index do @impl true def handle_info({:sort, field_str}, socket) do field = String.to_existing_atom(field_str) + old_field = socket.assigns.sort_field {new_order, new_field} = if socket.assigns.sort_field == field do @@ -79,28 +79,38 @@ defmodule MvWeb.MemberLive.Index do end active_id = :"sort_#{new_field}" + old_id = :"sort_#{old_field}" - # Update the SortHeader to + # Update the new SortHeader send_update(MvWeb.Components.SortHeaderComponent, id: active_id, sort_field: new_field, sort_order: new_order ) + # Reset the current SortHeader + send_update(MvWeb.Components.SortHeaderComponent, + id: old_id, + sort_field: new_field, + sort_order: new_order + ) + + existing_search_query = socket.assigns.query + # Build the URL with queries query_params = %{ + "query" => existing_search_query, "sort_field" => Atom.to_string(new_field), "sort_order" => Atom.to_string(new_order) } - # "/members" is the path you defined in router.ex - new_path = "/members?" <> URI.encode_query(query_params) + # Set the new path with params + new_path = ~p"/members?#{query_params}" # Push the new URL {:noreply, push_patch(socket, to: new_path, - # replace true replace: true )} end @@ -108,19 +118,27 @@ defmodule MvWeb.MemberLive.Index do # Function to handle search @impl true def handle_info({:search_changed, q}, socket) do - members = - if String.trim(q) == "" do - Ash.read!(Mv.Membership.Member) - else - Mv.Membership.Member - |> filter(expr(fragment("search_vector @@ plainto_tsquery('simple', ?)", ^q))) - |> Ash.read!() - end + socket = load_members(socket, q) + existing_field_query = socket.assigns.sort_field + existing_sort_query = socket.assigns.sort_order + + # Build the URL with queries + query_params = %{ + "query" => q, + "sort_field" => existing_field_query, + "sort_order" => existing_sort_query + } + + # Set the new path with params + new_path = ~p"/members?#{query_params}" + + # Push the new URL {:noreply, - socket - |> assign(:query, q) - |> assign(:members, members)} + push_patch(socket, + to: new_path, + replace: true + )} end # ----------------------------------------------------------------- @@ -130,8 +148,9 @@ defmodule MvWeb.MemberLive.Index do def handle_params(params, _url, socket) do socket = socket + |> maybe_update_search(params) |> maybe_update_sort(params) - |> load_members() + |> load_members(params["query"]) {:noreply, socket} end @@ -140,7 +159,7 @@ defmodule MvWeb.MemberLive.Index do # FUNCTIONS # ------------------------------------------------------------- # Load members eg based on a query for sorting - defp load_members(socket) do + defp load_members(socket, search_query) do query = Mv.Membership.Member |> Ash.Query.new() @@ -156,7 +175,12 @@ defmodule MvWeb.MemberLive.Index do :phone_number, :join_date ]) - |> maybe_sort(socket.assigns.sort_field, socket.assigns.sort_order) + + # Apply the search filter first + query = apply_search_filter(query, search_query) + + # Apply sorting based on current socket state + query = maybe_sort(query, socket.assigns.sort_field, socket.assigns.sort_order) members = Ash.read!(query) assign(socket, :members, members) @@ -166,6 +190,16 @@ defmodule MvWeb.MemberLive.Index do # Helper Functions # ------------------------------------------------------------- + # Function to apply search query + defp apply_search_filter(query, search_query) do + if search_query && String.trim(search_query) != "" do + query + |> filter(expr(fragment("search_vector @@ plainto_tsquery('simple', ?)", ^search_query))) + else + query + end + end + # Functions to toggle sorting order defp toggle_order(:asc), do: :desc defp toggle_order(:desc), do: :asc @@ -193,4 +227,14 @@ defmodule MvWeb.MemberLive.Index do end defp maybe_update_sort(socket, _), do: socket + + # Function to update search parameters + defp maybe_update_search(socket, %{"query" => query}) when query != "" do + assign(socket, :query, query) + end + + defp maybe_update_search(socket, _params) do + # Keep the previous search query if no new one is provided + socket + end end