refactor: improve email copy with MapSet, RFC 5322 commas, and cond
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
Performance optimization, RFC-compliant separator, better tests
This commit is contained in:
parent
ba78a6ac7a
commit
39d2cb7820
4 changed files with 92 additions and 271 deletions
|
|
@ -59,7 +59,7 @@ defmodule MvWeb.MemberLive.Index do
|
|||
|> assign(:query, "")
|
||||
|> assign_new(:sort_field, fn -> :first_name end)
|
||||
|> assign_new(:sort_order, fn -> :asc end)
|
||||
|> assign(:selected_members, [])
|
||||
|> assign(:selected_members, MapSet.new())
|
||||
|> assign(:custom_fields_visible, custom_fields_visible)
|
||||
|
||||
# We call handle params to use the query from the URL
|
||||
|
|
@ -92,10 +92,10 @@ defmodule MvWeb.MemberLive.Index do
|
|||
@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)
|
||||
if MapSet.member?(socket.assigns.selected_members, id) do
|
||||
MapSet.delete(socket.assigns.selected_members, id)
|
||||
else
|
||||
[id | socket.assigns.selected_members]
|
||||
MapSet.put(socket.assigns.selected_members, id)
|
||||
end
|
||||
|
||||
{:noreply, assign(socket, :selected_members, selected)}
|
||||
|
|
@ -103,13 +103,11 @@ defmodule MvWeb.MemberLive.Index do
|
|||
|
||||
@impl true
|
||||
def handle_event("select_all", _params, socket) do
|
||||
members = socket.assigns.members
|
||||
|
||||
all_ids = Enum.map(members, & &1.id)
|
||||
all_ids = socket.assigns.members |> Enum.map(& &1.id) |> MapSet.new()
|
||||
|
||||
selected =
|
||||
if Enum.sort(socket.assigns.selected_members) == Enum.sort(all_ids) do
|
||||
[]
|
||||
if MapSet.equal?(socket.assigns.selected_members, all_ids) do
|
||||
MapSet.new()
|
||||
else
|
||||
all_ids
|
||||
end
|
||||
|
|
@ -121,26 +119,26 @@ defmodule MvWeb.MemberLive.Index do
|
|||
def handle_event("copy_emails", _params, socket) do
|
||||
selected_ids = socket.assigns.selected_members
|
||||
|
||||
if selected_ids == [] do
|
||||
{:noreply, put_flash(socket, :error, gettext("No members selected"))}
|
||||
else
|
||||
# Filter members that are in the selection
|
||||
selected_members =
|
||||
socket.assigns.members
|
||||
|> Enum.filter(fn member -> member.id in selected_ids end)
|
||||
# Filter members that are in the selection and have email addresses
|
||||
formatted_emails =
|
||||
socket.assigns.members
|
||||
|> Enum.filter(fn member ->
|
||||
MapSet.member?(selected_ids, member.id) && member.email && member.email != ""
|
||||
end)
|
||||
|> Enum.map(&format_member_email/1)
|
||||
|
||||
# Format emails and filter out members without email
|
||||
formatted_emails =
|
||||
selected_members
|
||||
|> Enum.filter(fn member -> member.email && member.email != "" end)
|
||||
|> Enum.map(&format_member_email/1)
|
||||
email_count = length(formatted_emails)
|
||||
|
||||
email_count = length(formatted_emails)
|
||||
cond do
|
||||
MapSet.size(selected_ids) == 0 ->
|
||||
{:noreply, put_flash(socket, :error, gettext("No members selected"))}
|
||||
|
||||
if email_count == 0 do
|
||||
email_count == 0 ->
|
||||
{:noreply, put_flash(socket, :error, gettext("No email addresses found"))}
|
||||
else
|
||||
email_string = Enum.join(formatted_emails, "; ")
|
||||
|
||||
true ->
|
||||
# RFC 5322 uses comma as separator for email address lists
|
||||
email_string = Enum.join(formatted_emails, ", ")
|
||||
|
||||
socket =
|
||||
socket
|
||||
|
|
@ -160,7 +158,6 @@ defmodule MvWeb.MemberLive.Index do
|
|||
)
|
||||
|
||||
{:noreply, socket}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -3,18 +3,18 @@
|
|||
{gettext("Members")}
|
||||
<:actions>
|
||||
<.button
|
||||
:if={Enum.any?(@members, &(&1.id in @selected_members))}
|
||||
:if={Enum.any?(@members, &MapSet.member?(@selected_members, &1.id))}
|
||||
id="copy-emails-btn"
|
||||
phx-hook="CopyToClipboard"
|
||||
phx-click="copy_emails"
|
||||
aria-label={gettext("Copy email addresses of selected members")}
|
||||
>
|
||||
<.icon name="hero-clipboard-document" />
|
||||
{gettext("Copy emails")} ({Enum.count(@members, &(&1.id in @selected_members))})
|
||||
{gettext("Copy emails")} ({Enum.count(@members, &MapSet.member?(@selected_members, &1.id))})
|
||||
</.button>
|
||||
<.button
|
||||
:if={Enum.any?(@members, &(&1.id in @selected_members))}
|
||||
href={"mailto:?bcc=#{@members |> Enum.filter(&(&1.id in @selected_members and &1.email)) |> Enum.map(& &1.email) |> Enum.join(",")}"}
|
||||
:if={Enum.any?(@members, &MapSet.member?(@selected_members, &1.id))}
|
||||
href={"mailto:?bcc=#{@members |> Enum.filter(&(MapSet.member?(@selected_members, &1.id) && &1.email)) |> Enum.map(& &1.email) |> Enum.join(",")}"}
|
||||
aria-label={gettext("Open email program with BCC recipients")}
|
||||
>
|
||||
<.icon name="hero-envelope" />
|
||||
|
|
@ -51,7 +51,7 @@
|
|||
type="checkbox"
|
||||
name="select_all"
|
||||
phx-click="select_all"
|
||||
checked={Enum.sort(@selected_members) == Enum.map(@members, & &1.id) |> Enum.sort()}
|
||||
checked={MapSet.equal?(@selected_members, @members |> Enum.map(& &1.id) |> MapSet.new())}
|
||||
aria-label={gettext("Select all members")}
|
||||
role="checkbox"
|
||||
/>
|
||||
|
|
@ -63,7 +63,7 @@
|
|||
name={member.id}
|
||||
phx-click="select_member"
|
||||
phx-value-id={member.id}
|
||||
checked={member.id in @selected_members}
|
||||
checked={MapSet.member?(@selected_members, member.id)}
|
||||
phx-capture-click
|
||||
phx-stop-propagation
|
||||
aria-label={gettext("Select member")}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue