mitgliederverwaltung/lib/mv_web/live/member_live/index.ex
carla 78cbd3cf80
All checks were successful
continuous-integration/drone/push Build is passing
formatting
2025-10-09 16:33:00 +02:00

195 lines
5.3 KiB
Elixir

defmodule MvWeb.MemberLive.Index do
use MvWeb, :live_view
import Ash.Expr
import Ash.Query
@impl true
def mount(params, _session, socket) do
socket =
socket
|> assign(:page_title, gettext("Members"))
|> assign(:query, "")
|> 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
# 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
{:noreply,
socket
|> assign(:query, q)
|> assign(:members, members)}
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