defmodule MvWeb.MemberLive.Index do use MvWeb, :live_view @impl true def mount(params, _session, socket) do socket = socket |> assign(:page_title, gettext("Members")) |> assign_new(:sort_field, fn -> :first_name end) |> assign_new(:sort_order, fn -> :asc end) |> assign(:selected_members, []) # We call handle params to use the query from the URL {:noreply, socket} = handle_params(params, nil, socket) {:ok, socket} end # ----------------------------------------------------------------- # Handle Events # ----------------------------------------------------------------- # Delete a member @impl true def handle_event("delete", %{"id" => id}, socket) do member = Ash.get!(Mv.Membership.Member, id) Ash.destroy!(member) {:noreply, stream_delete(socket, :members, member)} end # Selects one member in the list of members @impl true def handle_event("select_member", %{"id" => id}, socket) do selected = if id in socket.assigns.selected_members do List.delete(socket.assigns.selected_members, id) else [id | socket.assigns.selected_members] end {:noreply, assign(socket, :selected_members, selected)} end # Selects all members in the list of members @impl true def handle_event("select_all", _params, socket) do members = socket.assigns.members all_ids = Enum.map(members, & &1.id) selected = if Enum.sort(socket.assigns.selected_members) == Enum.sort(all_ids) do [] else all_ids end {:noreply, assign(socket, :selected_members, selected)} end # ----------------------------------------------------------------- # Handle Infos from Child Components # ----------------------------------------------------------------- # Sorts the list of members according to a field, when you click on the column header @impl true def handle_info({:sort, field_str}, socket) do field = String.to_existing_atom(field_str) {new_order, new_field} = if socket.assigns.sort_field == field do {toggle_order(socket.assigns.sort_order), field} else {:asc, field} end active_id = :"sort_#{new_field}" # Update the SortHeader to send_update(MvWeb.Components.SortHeaderComponent, id: active_id, sort_field: new_field, sort_order: new_order ) # Build the URL with queries query_params = %{ "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) # Push the new URL {:noreply, push_patch(socket, to: new_path, # replace true replace: true )} end # ----------------------------------------------------------------- # Handle Params from the URL # ----------------------------------------------------------------- @impl true def handle_params(params, _url, socket) do socket = socket |> maybe_update_sort(params) |> load_members() {:noreply, socket} end # ------------------------------------------------------------- # FUNCTIONS # ------------------------------------------------------------- # Load members eg based on a query for sorting defp load_members(socket) do query = Mv.Membership.Member |> Ash.Query.new() |> Ash.Query.select([ :id, :first_name, :last_name, :email, :street, :house_number, :postal_code, :city, :phone_number, :join_date ]) |> maybe_sort(socket.assigns.sort_field, socket.assigns.sort_order) members = Ash.read!(query) assign(socket, :members, members) end # ------------------------------------------------------------- # Helper Functions # ------------------------------------------------------------- # Functions to toggle sorting order defp toggle_order(:asc), do: :desc defp toggle_order(:desc), do: :asc defp toggle_order(nil), do: :asc # Function to sort the column if needed defp maybe_sort(query, nil, _), do: query defp maybe_sort(query, field, :asc), do: Ash.Query.sort(query, [{field, :asc}]) defp maybe_sort(query, field, :desc), do: Ash.Query.sort(query, [{field, :desc}]) # Function to maybe update the sort defp maybe_update_sort(socket, %{"sort_field" => sf, "sort_order" => so}) do field = try do String.to_existing_atom(sf) rescue ArgumentError -> socket.assigns.sort_field end order = if so in ["asc", "desc"], do: String.to_atom(so), else: socket.assigns.sort_order socket |> assign(:sort_field, field) |> assign(:sort_order, order) end defp maybe_update_sort(socket, _), do: socket end