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()