Merge remote-tracking branch 'origin/main' into feature/member-overview-groups
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/promote/production Build is passing

This commit is contained in:
Simon 2026-02-16 15:57:57 +01:00
commit 6831ba046f
Signed by: simon
GPG key ID: 40E7A58C4AA1EDB2
48 changed files with 3516 additions and 182 deletions

View file

@ -810,53 +810,59 @@ defmodule MvWeb.MemberLive.Index do
show_current_cycle,
boolean_filters
) do
field_str =
if is_atom(sort_field) do
Atom.to_string(sort_field)
else
sort_field
end
base_params = build_base_params(query, sort_field, sort_order)
base_params = add_cycle_status_filter(base_params, cycle_status_filter)
base_params = add_group_filters(base_params, group_filters)
base_params = add_show_current_cycle(base_params, show_current_cycle)
add_boolean_filters(base_params, boolean_filters)
end
order_str =
if is_atom(sort_order) do
Atom.to_string(sort_order)
else
sort_order
end
base_params = %{
"query" => query,
"sort_field" => field_str,
"sort_order" => order_str
defp build_base_params(query, sort_field, sort_order) do
%{
"query" => query || "",
"sort_field" => normalize_sort_field(sort_field),
"sort_order" => normalize_sort_order(sort_order)
}
end
base_params =
case cycle_status_filter do
nil -> base_params
:paid -> Map.put(base_params, "cycle_status_filter", "paid")
:unpaid -> Map.put(base_params, "cycle_status_filter", "unpaid")
end
defp normalize_sort_field(nil), do: ""
defp normalize_sort_field(field) when is_atom(field), do: Atom.to_string(field)
defp normalize_sort_field(field) when is_binary(field), do: field
defp normalize_sort_field(_), do: ""
base_params =
Enum.reduce(group_filters, base_params, fn {group_id_str, value}, acc ->
param_value = if value == :in, do: "in", else: "not_in"
Map.put(acc, "#{@group_filter_prefix}#{group_id_str}", param_value)
end)
defp normalize_sort_order(nil), do: ""
defp normalize_sort_order(order) when is_atom(order), do: Atom.to_string(order)
defp normalize_sort_order(order) when is_binary(order), do: order
defp normalize_sort_order(_), do: ""
base_params =
if show_current_cycle do
Map.put(base_params, "show_current_cycle", "true")
else
base_params
end
Enum.reduce(boolean_filters, base_params, fn {custom_field_id, filter_value}, acc ->
param_key = "#{@boolean_filter_prefix}#{custom_field_id}"
param_value = if filter_value == true, do: "true", else: "false"
Map.put(acc, param_key, param_value)
defp add_group_filters(params, group_filters) do
Enum.reduce(group_filters, params, fn {group_id_str, value}, acc ->
param_value = if value == :in, do: "in", else: "not_in"
Map.put(acc, "#{@group_filter_prefix}#{group_id_str}", param_value)
end)
end
defp add_cycle_status_filter(params, nil), do: params
defp add_cycle_status_filter(params, :paid), do: Map.put(params, "cycle_status_filter", "paid")
defp add_cycle_status_filter(params, :unpaid),
do: Map.put(params, "cycle_status_filter", "unpaid")
defp add_cycle_status_filter(params, _), do: params
defp add_show_current_cycle(params, true), do: Map.put(params, "show_current_cycle", "true")
defp add_show_current_cycle(params, _), do: params
defp add_boolean_filters(params, boolean_filters) do
Enum.reduce(boolean_filters, params, &add_boolean_filter/2)
end
defp add_boolean_filter({custom_field_id, filter_value}, acc) do
param_key = "#{@boolean_filter_prefix}#{custom_field_id}"
param_value = if filter_value == true, do: "true", else: "false"
Map.put(acc, param_key, param_value)
end
# -------------------------------------------------------------
# Loading members
# -------------------------------------------------------------

View file

@ -2,20 +2,12 @@
<.header>
{gettext("Members")}
<:actions>
<form method="post" action={~p"/members/export.csv"} target="_blank" class="inline">
<input type="hidden" name="_csrf_token" value={Plug.CSRFProtection.get_csrf_token()} />
<input type="hidden" name="payload" value={@export_payload_json} />
<button
type="submit"
class="btn btn-secondary gap-2"
aria-label={gettext("Export members to CSV")}
>
<.icon name="hero-arrow-down-tray" />
{gettext("Export to CSV")} ({if @selected_count == 0,
do: gettext("all"),
else: @selected_count})
</button>
</form>
<.live_component
module={MvWeb.Components.ExportDropdown}
id="export-dropdown"
export_payload_json={@export_payload_json}
selected_count={@selected_count}
/>
<.button
class="secondary"
id="copy-emails-btn"