diff --git a/lib/mv_web/components/core_components.ex b/lib/mv_web/components/core_components.ex index be64655..d19b1eb 100644 --- a/lib/mv_web/components/core_components.ex +++ b/lib/mv_web/components/core_components.ex @@ -474,6 +474,7 @@ defmodule MvWeb.CoreComponents do slot :col, required: true do attr :label, :string + attr :col_click, :any, doc: "optional column-specific click handler that overrides row_click" end slot :action, doc: "the slot for showing user actions in the last table column" @@ -509,8 +510,11 @@ defmodule MvWeb.CoreComponents do {render_slot(col, @row_item.(row))} diff --git a/lib/mv_web/live/member_live/index.ex b/lib/mv_web/live/member_live/index.ex index ad4a4a9..f9d8aa1 100644 --- a/lib/mv_web/live/member_live/index.ex +++ b/lib/mv_web/live/member_live/index.ex @@ -1082,6 +1082,16 @@ defmodule MvWeb.MemberLive.Index do |> Enum.map(&format_member_email/1) end + @doc """ + Returns a JS command to toggle member selection when clicking the checkbox column. + + Used as `col_click` handler to ensure clicking anywhere in the checkbox column + toggles the checkbox instead of navigating to the member details. + """ + def checkbox_column_click(member) do + JS.push("select_member", value: %{id: member.id}) + end + # Formats a member's email in the format "First Last " # Used for copy_emails feature and mailto links to create email-client-friendly format. def format_member_email(member) do diff --git a/lib/mv_web/live/member_live/index.html.heex b/lib/mv_web/live/member_live/index.html.heex index 1658209..fbeb416 100644 --- a/lib/mv_web/live/member_live/index.html.heex +++ b/lib/mv_web/live/member_live/index.html.heex @@ -65,6 +65,7 @@ <:col :let={member} + col_click={&MvWeb.MemberLive.Index.checkbox_column_click/1} label={ ~H""" <.input @@ -81,11 +82,7 @@ <.input type="checkbox" name={member.id} - phx-click="select_member" - phx-value-id={member.id} checked={MapSet.member?(@selected_members, member.id)} - phx-capture-click - phx-stop-propagation aria-label={gettext("Select member")} role="checkbox" /> diff --git a/test/mv_web/member_live/index_test.exs b/test/mv_web/member_live/index_test.exs index 0bcc731..9e3323f 100644 --- a/test/mv_web/member_live/index_test.exs +++ b/test/mv_web/member_live/index_test.exs @@ -285,14 +285,9 @@ defmodule MvWeb.MemberLive.IndexTest do conn = conn_with_oidc_user(conn) {:ok, view, _html} = live(conn, "/members") - # Select two members - view - |> element("[phx-click='select_member'][phx-value-id='#{member1.id}']") - |> render_click() - - view - |> element("[phx-click='select_member'][phx-value-id='#{member2.id}']") - |> render_click() + # Select two members by sending the select_member event directly + render_click(view, "select_member", %{"id" => member1.id}) + render_click(view, "select_member", %{"id" => member2.id}) # Trigger copy_emails event view |> element("#copy-emails-btn") |> render_click() @@ -336,10 +331,8 @@ defmodule MvWeb.MemberLive.IndexTest do conn = conn_with_oidc_user(conn) {:ok, view, _html} = live(conn, "/members") - # Select member with umlauts - view - |> element("[phx-click='select_member'][phx-value-id='#{member3.id}']") - |> render_click() + # Select member with umlauts by sending the select_member event directly + render_click(view, "select_member", %{"id" => member3.id}) # Trigger copy_emails event - should not crash view |> element("#copy-emails-btn") |> render_click() @@ -355,10 +348,8 @@ defmodule MvWeb.MemberLive.IndexTest do conn = conn_with_oidc_user(conn) {:ok, view, _html} = live(conn, "/members") - # Select a member - view - |> element("[phx-click='select_member'][phx-value-id='#{member1.id}']") - |> render_click() + # Select a member by sending the select_member event directly + render_click(view, "select_member", %{"id" => member1.id}) # Delete the member from the database Ash.destroy!(member1) @@ -379,14 +370,9 @@ defmodule MvWeb.MemberLive.IndexTest do conn = conn_with_oidc_user(conn) {:ok, view, _html} = live(conn, "/members") - # Select two members - view - |> element("[phx-click='select_member'][phx-value-id='#{member1.id}']") - |> render_click() - - view - |> element("[phx-click='select_member'][phx-value-id='#{member2.id}']") - |> render_click() + # Select two members by sending the select_member event directly + render_click(view, "select_member", %{"id" => member1.id}) + render_click(view, "select_member", %{"id" => member2.id}) # Get the socket state to verify the formatted email string state = :sys.get_state(view.pid) @@ -415,10 +401,8 @@ defmodule MvWeb.MemberLive.IndexTest do {:ok, view, _html} = live(conn, "/members") - # Select the test member - view - |> element("[phx-click='select_member'][phx-value-id='#{test_member.id}']") - |> render_click() + # Select the test member by sending the select_member event directly + render_click(view, "select_member", %{"id" => test_member.id}) # The format should be "Test Format " # We verify this by checking the flash shows 1 email was copied @@ -441,10 +425,8 @@ defmodule MvWeb.MemberLive.IndexTest do conn = conn_with_oidc_user(conn) {:ok, view, _html} = live(conn, "/members") - # Select a member - view - |> element("[phx-click='select_member'][phx-value-id='#{member1.id}']") - |> render_click() + # Select a member by sending the select_member event directly + render_click(view, "select_member", %{"id" => member1.id}) # Button should now be visible assert has_element?(view, "#copy-emails-btn") @@ -457,10 +439,8 @@ defmodule MvWeb.MemberLive.IndexTest do conn = conn_with_oidc_user(conn) {:ok, view, _html} = live(conn, "/members") - # Select a member - view - |> element("[phx-click='select_member'][phx-value-id='#{member1.id}']") - |> render_click() + # Select a member by sending the select_member event directly + render_click(view, "select_member", %{"id" => member1.id}) # Click copy button view |> element("#copy-emails-btn") |> render_click()