feat: add csv export
Some checks failed
continuous-integration/drone/push Build is failing

This commit is contained in:
carla 2026-02-04 16:40:41 +01:00
parent d34ff57531
commit c82f4b7fd7
7 changed files with 487 additions and 1 deletions

View file

@ -131,6 +131,7 @@ defmodule MvWeb.MemberLive.Index do
)
|> assign(:show_current_cycle, false)
|> assign(:membership_fee_status_filter, nil)
|> assign_export_payload()
# We call handle params to use the query from the URL
{:ok, socket}
@ -1729,5 +1730,36 @@ defmodule MvWeb.MemberLive.Index do
|> assign(:selected_count, selected_count)
|> assign(:any_selected?, any_selected?)
|> assign(:mailto_bcc, mailto_bcc)
|> assign_export_payload()
end
# Builds the export payload map and assigns :export_payload_json for the CSV export form.
# Called when selection, visible fields, query, or sort change so the form always has current data.
defp assign_export_payload(socket) do
payload = build_export_payload(socket)
assign(socket, :export_payload_json, Jason.encode!(payload))
end
defp build_export_payload(socket) do
member_fields_visible = socket.assigns[:member_fields_visible] || []
visible_custom_field_ids = socket.assigns[:visible_custom_field_ids] || []
%{
selected_ids: socket.assigns.selected_members |> MapSet.to_list(),
member_fields: Enum.map(member_fields_visible, &Atom.to_string/1),
custom_field_ids: visible_custom_field_ids,
query: socket.assigns[:query] || nil,
sort_field: export_sort_field(socket.assigns[:sort_field]),
sort_order: export_sort_order(socket.assigns[:sort_order])
}
end
defp export_sort_field(nil), do: nil
defp export_sort_field(f) when is_atom(f), do: Atom.to_string(f)
defp export_sort_field(f) when is_binary(f), do: f
defp export_sort_order(nil), do: nil
defp export_sort_order(:asc), do: "asc"
defp export_sort_order(:desc), do: "desc"
defp export_sort_order(o) when is_binary(o), do: o
end

View file

@ -2,6 +2,20 @@
<.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>
<.button
class="secondary"
id="copy-emails-btn"