diff --git a/lib/mv_web/live/member_live/index.ex b/lib/mv_web/live/member_live/index.ex index 8857298..bb2f9fc 100644 --- a/lib/mv_web/live/member_live/index.ex +++ b/lib/mv_web/live/member_live/index.ex @@ -145,7 +145,10 @@ defmodule MvWeb.MemberLive.Index do MapSet.put(socket.assigns.selected_members, id) end - {:noreply, assign(socket, :selected_members, selected)} + {:noreply, + socket + |> assign(:selected_members, selected) + |> update_selection_assigns()} end @impl true @@ -159,7 +162,10 @@ defmodule MvWeb.MemberLive.Index do all_ids end - {:noreply, assign(socket, :selected_members, selected)} + {:noreply, + socket + |> assign(:selected_members, selected) + |> update_selection_assigns()} end @impl true @@ -238,6 +244,7 @@ defmodule MvWeb.MemberLive.Index do socket |> assign(:query, q) |> load_members() + |> update_selection_assigns() existing_field_query = socket.assigns.sort_field existing_sort_query = socket.assigns.sort_order @@ -263,6 +270,7 @@ defmodule MvWeb.MemberLive.Index do socket |> assign(:paid_filter, filter) |> load_members() + |> update_selection_assigns() # Build the URL with all params including new filter query_params = @@ -309,6 +317,7 @@ defmodule MvWeb.MemberLive.Index do |> assign(:visible_custom_field_ids, extract_custom_field_ids(visible_custom_fields)) |> load_members() |> prepare_dynamic_cols() + |> update_selection_assigns() |> push_field_selection_url() {:noreply, socket} @@ -338,6 +347,7 @@ defmodule MvWeb.MemberLive.Index do |> assign(:visible_custom_field_ids, extract_custom_field_ids(visible_custom_fields)) |> load_members() |> prepare_dynamic_cols() + |> update_selection_assigns() |> push_field_selection_url() {:noreply, socket} @@ -389,6 +399,7 @@ defmodule MvWeb.MemberLive.Index do |> assign(:visible_custom_field_ids, extract_custom_field_ids(visible_custom_fields)) |> load_members() |> prepare_dynamic_cols() + |> update_selection_assigns() {:noreply, socket} end @@ -1112,4 +1123,30 @@ defmodule MvWeb.MemberLive.Index do # Public helper function to format dates for use in templates def format_date(date), do: DateFormatter.format_date(date) + + # Updates selection-related assigns (selected_count, any_selected?, mailto_bcc) + # to avoid recalculating Enum.any? and Enum.count multiple times in templates. + defp update_selection_assigns(socket) do + members = socket.assigns.members + selected_members = socket.assigns.selected_members + + selected_count = + Enum.count(members, &MapSet.member?(selected_members, &1.id)) + + any_selected? = + Enum.any?(members, &MapSet.member?(selected_members, &1.id)) + + mailto_bcc = + if any_selected? do + format_selected_member_emails(members, selected_members) + |> Enum.join(", ") + else + "" + end + + socket + |> assign(:selected_count, selected_count) + |> assign(:any_selected?, any_selected?) + |> assign(:mailto_bcc, mailto_bcc) + end end diff --git a/lib/mv_web/live/member_live/index.html.heex b/lib/mv_web/live/member_live/index.html.heex index 8e8d18b..b01db85 100644 --- a/lib/mv_web/live/member_live/index.html.heex +++ b/lib/mv_web/live/member_live/index.html.heex @@ -7,25 +7,17 @@ id="copy-emails-btn" phx-hook="CopyToClipboard" phx-click="copy_emails" - disabled={not Enum.any?(@members, &MapSet.member?(@selected_members, &1.id))} + disabled={not @any_selected?} aria-label={gettext("Copy email addresses of selected members")} > <.icon name="hero-clipboard-document" /> - {gettext("Copy email addresses")} ({Enum.count( - @members, - &MapSet.member?(@selected_members, &1.id) - )}) + {gettext("Copy email addresses")} ({@selected_count}) <.button class="secondary" id="open-email-btn" - href={ - "mailto:?bcc=" <> - (MvWeb.MemberLive.Index.format_selected_member_emails(@members, @selected_members) - |> Enum.join(", ") - |> URI.encode()) - } - disabled={not Enum.any?(@members, &MapSet.member?(@selected_members, &1.id))} + href={"mailto:?bcc=" <> URI.encode(@mailto_bcc)} + disabled={not @any_selected?} aria-label={gettext("Open email program with BCC recipients")} > <.icon name="hero-envelope" />