diff --git a/DESIGN_DUIDELINES.md b/DESIGN_DUIDELINES.md index 18864b5..98e43db 100644 --- a/DESIGN_DUIDELINES.md +++ b/DESIGN_DUIDELINES.md @@ -209,6 +209,7 @@ If these cannot be met, use `secondary`/`outline` instead of `ghost`. ### 8.1 Default behavior: row click opens details - **DEFAULT:** Clicking a row navigates to the details page. - **EXCEPTIONS:** Highly interactive rows may disable row-click (document why). +- **Row outline (CoreComponents):** When `row_click` is set, rows get a subtle hover and focus-within ring (theme-friendly). Use `selected_row_id` to show a stronger selected outline (e.g. from URL `?highlight=id` or last selection); the Back link from detail can use `?highlight=id` so the row is visually selected when returning to the index. **IMPORTANT (correctness with our `<.table>` CoreComponent):** Our table implementation attaches the `phx-click` to the **`
| + <%= if col_idx == 0 && @row_click && @row_tooltip do %> + {@row_tooltip} + <% end %> {render_slot(col, @row_item.(row))} |
- gettext("All")
+ gettext("Apply filters")
end
end
@@ -487,7 +487,7 @@ defmodule MvWeb.Components.MemberFilterComponent do
# Get boolean filter label (comma-separated list of active filter names)
defp boolean_filter_label(_boolean_custom_fields, boolean_filters)
when map_size(boolean_filters) == 0 do
- gettext("Apply filters")
+ gettext("All")
end
defp boolean_filter_label(boolean_custom_fields, boolean_filters) do
diff --git a/lib/mv_web/live/custom_field_live/index_component.ex b/lib/mv_web/live/custom_field_live/index_component.ex
index a944c85..ebc4930 100644
--- a/lib/mv_web/live/custom_field_live/index_component.ex
+++ b/lib/mv_web/live/custom_field_live/index_component.ex
@@ -59,6 +59,7 @@ defmodule MvWeb.CustomFieldLive.IndexComponent do
JS.push("edit_custom_field", value: %{id: custom_field.id}, target: @myself)
end
}
+ row_tooltip={gettext("Click for dataield details")}
>
<:col :let={{_id, custom_field}} label={gettext("Name")}>{custom_field.name}
diff --git a/lib/mv_web/live/group_live/index.ex b/lib/mv_web/live/group_live/index.ex
index 70358e0..76663fd 100644
--- a/lib/mv_web/live/group_live/index.ex
+++ b/lib/mv_web/live/group_live/index.ex
@@ -62,6 +62,7 @@ defmodule MvWeb.GroupLive.Index do
rows={@groups}
row_id={fn group -> "group-#{group.id}" end}
row_click={fn group -> JS.navigate(~p"/groups/#{group.slug}") end}
+ row_tooltip={gettext("Click for group details")}
>
<:col :let={group} label={gettext("Name")}>
{group.name}
diff --git a/lib/mv_web/live/member_field_live/index_component.ex b/lib/mv_web/live/member_field_live/index_component.ex
index 1e8cf05..419b585 100644
--- a/lib/mv_web/live/member_field_live/index_component.ex
+++ b/lib/mv_web/live/member_field_live/index_component.ex
@@ -57,6 +57,7 @@ defmodule MvWeb.MemberFieldLive.IndexComponent do
JS.push("edit_member_field", value: %{"field" => field_name}, target: @myself)
end
}
+ row_tooltip={gettext("Click for datafield details")}
>
<:col :let={{_field_name, field_data}} label={gettext("Name")}>
{MemberFields.label(field_data.field)}
diff --git a/lib/mv_web/live/member_live/index.ex b/lib/mv_web/live/member_live/index.ex
index 4309611..1be35b4 100644
--- a/lib/mv_web/live/member_live/index.ex
+++ b/lib/mv_web/live/member_live/index.ex
@@ -122,6 +122,7 @@ defmodule MvWeb.MemberLive.Index do
|> assign(:groups, groups)
|> assign(:boolean_custom_field_filters, %{})
|> assign(:selected_members, MapSet.new())
+ |> assign(:selected_member_id, nil)
|> assign(:settings, settings)
|> assign(:custom_fields_visible, custom_fields_visible)
|> assign(:all_custom_fields, all_custom_fields)
@@ -160,6 +161,12 @@ defmodule MvWeb.MemberLive.Index do
- `"select_all"` - Toggles selection of all visible members
- `"sort"` - Sort event from SortHeaderComponent. Updates sort field/order and syncs URL
"""
+ @impl true
+ def handle_event("select_row_and_navigate", %{"id" => id}, socket) do
+ # Navigate to member show. Back button on show page uses ?highlight=id so returning to index shows row as selected.
+ {:noreply, push_navigate(socket, to: ~p"/members/#{id}")}
+ end
+
@impl true
def handle_event("select_member", %{"id" => id}, socket) do
selected =
@@ -599,6 +606,7 @@ defmodule MvWeb.MemberLive.Index do
|> assign(:member_fields_visible_db, visible_member_fields_db)
|> assign(:member_fields_visible_computed, visible_member_fields_computed)
|> assign(:visible_custom_field_ids, extract_custom_field_ids(visible_custom_fields))
+ |> assign(:selected_member_id, parse_highlight_param(params["highlight"]))
next_sig = build_signature(socket)
@@ -798,6 +806,18 @@ defmodule MvWeb.MemberLive.Index do
end
end
+ # Parses optional "highlight" URL param (member id for selected row styling). Returns nil if missing or invalid.
+ defp parse_highlight_param(nil), do: nil
+ defp parse_highlight_param(""), do: nil
+
+ defp parse_highlight_param(id) when is_binary(id) do
+ if String.length(id) <= @max_uuid_length and match?({:ok, _}, Ecto.UUID.cast(id)),
+ do: id,
+ else: nil
+ end
+
+ defp parse_highlight_param(_), do: nil
+
defp merge_fields_param_from_uri(params, nil), do: params
defp merge_fields_param_from_uri(params, %URI{query: query}) when is_binary(query) do
diff --git a/lib/mv_web/live/member_live/index.html.heex b/lib/mv_web/live/member_live/index.html.heex
index a696b00..eec49de 100644
--- a/lib/mv_web/live/member_live/index.html.heex
+++ b/lib/mv_web/live/member_live/index.html.heex
@@ -59,6 +59,7 @@
variant="secondary"
class={["gap-2", @show_current_cycle && "btn-active"]}
phx-click="toggle_cycle_view"
+ data-testid="toggle-cycle-view"
aria-label={
if(@show_current_cycle,
do: gettext("Current Cycle Payment Status"),
@@ -93,7 +94,9 @@
id="members"
rows={@members}
row_id={fn member -> "row-#{member.id}" end}
- row_click={fn member -> JS.navigate(~p"/members/#{member}") end}
+ row_click={fn member -> JS.push("select_row_and_navigate", value: %{id: member.id}) end}
+ row_tooltip={gettext("Click for member details")}
+ row_selected?={fn member -> MapSet.member?(@selected_members, member.id) end}
dynamic_cols={@dynamic_cols}
sort_field={@sort_field}
sort_order={@sort_order}
diff --git a/lib/mv_web/live/member_live/show.ex b/lib/mv_web/live/member_live/show.ex
index ae69c30..6757646 100644
--- a/lib/mv_web/live/member_live/show.ex
+++ b/lib/mv_web/live/member_live/show.ex
@@ -34,7 +34,7 @@ defmodule MvWeb.MemberLive.Show do
{MvWeb.Helpers.MemberHelpers.display_name(@member)}
<:actions>
<.button
- navigate={~p"/members"}
+ navigate={~p"/members?highlight=#{@member.id}"}
variant="neutral"
aria-label={gettext("Back to members list")}
>
diff --git a/lib/mv_web/live/role_live/index.html.heex b/lib/mv_web/live/role_live/index.html.heex
index 5829bca..5947472 100644
--- a/lib/mv_web/live/role_live/index.html.heex
+++ b/lib/mv_web/live/role_live/index.html.heex
@@ -17,6 +17,7 @@
id="roles"
rows={@roles}
row_click={fn role -> JS.navigate(~p"/admin/roles/#{role}") end}
+ row_tooltip={gettext("Click for role details")}
>
<:col :let={role} label={gettext("Name")}>
diff --git a/lib/mv_web/live/role_live/show.ex b/lib/mv_web/live/role_live/show.ex
index 8b5b1b2..dd2c4f2 100644
--- a/lib/mv_web/live/role_live/show.ex
+++ b/lib/mv_web/live/role_live/show.ex
@@ -174,8 +174,8 @@ defmodule MvWeb.RoleLive.Show do
{gettext("Back")}
<%= if can?(@current_user, :update, Mv.Authorization.Role) do %>
- <.button variant="primary" navigate={~p"/admin/roles/#{@role}/edit"}>
- <.icon name="hero-pencil-square" /> {gettext("Rolle bearbeiten")}
+ <.button variant="primary" navigate={~p"/admin/roles/#{@role}/edit"} data-testid=role-edit">
+ {gettext("Edit role")}
<% end %>
<%= if can?(@current_user, :destroy, Mv.Authorization.Role) and not @role.is_system_role do %>
diff --git a/lib/mv_web/live/user_live/index.html.heex b/lib/mv_web/live/user_live/index.html.heex
index 364e5a4..858e784 100644
--- a/lib/mv_web/live/user_live/index.html.heex
+++ b/lib/mv_web/live/user_live/index.html.heex
@@ -15,6 +15,7 @@
rows={@users}
row_id={fn user -> "row-#{user.id}" end}
row_click={fn user -> JS.navigate(~p"/users/#{user}") end}
+ row_tooltip={gettext("Click for user details")}
sort_field={@sort_field}
sort_order={@sort_order}
>
diff --git a/priv/gettext/de/LC_MESSAGES/default.po b/priv/gettext/de/LC_MESSAGES/default.po
index 49fbe83..4561f24 100644
--- a/priv/gettext/de/LC_MESSAGES/default.po
+++ b/priv/gettext/de/LC_MESSAGES/default.po
@@ -11,13 +11,11 @@ msgstr ""
"Language: de\n"
#: lib/mv_web/components/core_components.ex
-#: lib/mv_web/live/group_live/index.ex
#: lib/mv_web/live/group_live/show.ex
#, elixir-autogen, elixir-format
msgid "Actions"
msgstr "Aktionen"
-#: lib/mv_web/live/member_live/index.html.heex
#: lib/mv_web/live/membership_fee_settings_live.ex
#: lib/mv_web/live/membership_fee_type_live/index.ex
#: lib/mv_web/live/role_live/index.html.heex
@@ -42,7 +40,6 @@ msgstr "Stadt"
#: lib/mv_web/live/custom_field_live/index_component.ex
#: lib/mv_web/live/group_live/show.ex
-#: lib/mv_web/live/member_live/index.html.heex
#: lib/mv_web/live/member_live/show/membership_fees_component.ex
#: lib/mv_web/live/role_live/index.html.heex
#: lib/mv_web/live/user_live/index.html.heex
@@ -50,15 +47,8 @@ msgstr "Stadt"
msgid "Delete"
msgstr "Löschen"
-#: lib/mv_web/live/custom_field_live/index_component.ex
-#: lib/mv_web/live/group_live/index.ex
-#: lib/mv_web/live/group_live/show.ex
-#: lib/mv_web/live/member_field_live/index_component.ex
-#: lib/mv_web/live/member_live/index.html.heex
#: lib/mv_web/live/role_live/form.ex
-#: lib/mv_web/live/role_live/index.html.heex
#: lib/mv_web/live/user_live/form.ex
-#: lib/mv_web/live/user_live/index.html.heex
#, elixir-autogen, elixir-format
msgid "Edit"
msgstr "Bearbeiten"
@@ -277,7 +267,6 @@ msgstr "Dein Passwort wurde erfolgreich zurückgesetzt"
#: lib/mv_web/live/member_live/form.ex
#: lib/mv_web/live/member_live/show/membership_fees_component.ex
#: lib/mv_web/live/membership_fee_type_live/form.ex
-#: lib/mv_web/live/role_live/form.ex
#: lib/mv_web/live/user_live/form.ex
#, elixir-autogen, elixir-format
msgid "Cancel"
@@ -790,19 +779,18 @@ msgstr "Alle"
msgid "Address"
msgstr "Adresse"
+#: lib/mv_web/live/custom_field_live/form_component.ex
#: lib/mv_web/live/group_live/form.ex
#: lib/mv_web/live/group_live/show.ex
+#: lib/mv_web/live/member_field_live/form_component.ex
#: lib/mv_web/live/member_live/form.ex
#: lib/mv_web/live/member_live/show.ex
+#: lib/mv_web/live/role_live/form.ex
+#: lib/mv_web/live/role_live/show.ex
#, elixir-autogen, elixir-format
msgid "Back"
msgstr "Zurück"
-#: lib/mv_web/live/member_live/form.ex
-#, elixir-autogen, elixir-format
-msgid "Coming soon"
-msgstr "Demnächst verfügbar"
-
#: lib/mv_web/live/member_live/form.ex
#: lib/mv_web/live/member_live/show.ex
#, elixir-autogen, elixir-format
@@ -820,7 +808,6 @@ msgid "Payment Data"
msgstr "Beitragsdaten"
#: lib/mv_web/live/components/member_filter_component.ex
-#: lib/mv_web/live/member_live/form.ex
#, elixir-autogen, elixir-format
msgid "Payments"
msgstr "Zahlungen"
@@ -834,6 +821,7 @@ msgstr "Persönliche Daten"
#: lib/mv_web/live/group_live/form.ex
#: lib/mv_web/live/member_live/form.ex
#: lib/mv_web/live/member_live/show/membership_fees_component.ex
+#: lib/mv_web/live/role_live/form.ex
#, elixir-autogen, elixir-format
msgid "Save"
msgstr "Speichern"
@@ -851,11 +839,6 @@ msgstr "Mitglied erstellen"
msgid "Amount"
msgstr "Betrag"
-#: lib/mv_web/live/member_field_live/form_component.ex
-#, elixir-autogen, elixir-format
-msgid "Back to Settings"
-msgstr "Zurück zu den Einstellungen"
-
#: lib/mv_web/live/membership_fee_settings_live.ex
#: lib/mv_web/live/membership_fee_type_live/index.ex
#, elixir-autogen, elixir-format
@@ -1575,6 +1558,7 @@ msgid "Show/Hide Columns"
msgstr "Spalten ein-/ausblenden"
#: lib/mv_web/live/custom_field_live/form_component.ex
+#: lib/mv_web/live/member_field_live/form_component.ex
#, elixir-autogen, elixir-format, fuzzy
msgid "Back to settings"
msgstr "Zurück zu den Einstellungen"
@@ -1630,11 +1614,6 @@ msgstr "System-Rolle kann nicht gelöscht werden"
msgid "Custom"
msgstr "Benutzerdefiniert"
-#: lib/mv_web/live/role_live/show.ex
-#, elixir-autogen, elixir-format
-msgid "Edit Role"
-msgstr "Rolle bearbeiten"
-
#: lib/mv_web/live/role_live/index.ex
#: lib/mv_web/live/role_live/show.ex
#, elixir-autogen, elixir-format
@@ -1734,11 +1713,6 @@ msgstr "Rolle nicht gefunden."
msgid "Role saved successfully."
msgstr "Rolle erfolgreich gespeichert."
-#: lib/mv_web/live/role_live/form.ex
-#, elixir-autogen, elixir-format
-msgid "Save Role"
-msgstr "Rolle speichern"
-
#: lib/mv_web/live/role_live/form.ex
#, elixir-autogen, elixir-format
msgid "Select permission set"
@@ -1890,22 +1864,17 @@ msgstr "aktualisiert"
msgid "Unknown error"
msgstr "Unbekannter Fehler"
-#: lib/mv_web/live/member_live/index.ex
+#: lib/mv_web/live/member_live/show.ex
#, elixir-autogen, elixir-format
msgid "Member deleted successfully"
msgstr "Mitglied wurde erfolgreich gelöscht"
-#: lib/mv_web/live/member_live/index.ex
+#: lib/mv_web/live/member_live/show.ex
#, elixir-autogen, elixir-format
msgid "Member not found"
msgstr "Mitglied nicht gefunden"
-#: lib/mv_web/live/member_live/index.ex
-#, elixir-autogen, elixir-format
-msgid "You do not have permission to access this member"
-msgstr "Du hast keine Berechtigung, auf dieses Mitglied zuzugreifen"
-
-#: lib/mv_web/live/member_live/index.ex
+#: lib/mv_web/live/member_live/show.ex
#, elixir-autogen, elixir-format
msgid "You do not have permission to delete this member"
msgstr "Du hast keine Berechtigung, dieses Mitglied zu löschen"
@@ -1990,11 +1959,6 @@ msgstr "Mitgliedsfilter"
msgid "Payment Status"
msgstr "Bezahlstatus"
-#: lib/mv_web/live/components/member_filter_component.ex
-#, elixir-autogen, elixir-format
-msgid "Reset"
-msgstr "Zurücksetzen"
-
#: lib/mv_web/live/import_live/components.ex
#, elixir-autogen, elixir-format
msgid " (Field: %{field})"
@@ -3098,3 +3062,125 @@ msgstr "Nur OIDC-Anmeldung (Passwort-Login ausblenden)"
#, elixir-autogen, elixir-format
msgid "When enabled and OIDC is configured, the sign-in page shows only the Single Sign-On button."
msgstr "Wenn aktiviert und OIDC konfiguriert ist, zeigt die Anmeldeseite nur den Single-Sign-On-Button."
+
+#: lib/mv_web/live/components/member_filter_component.ex
+#, elixir-autogen, elixir-format
+msgid "Clear filters"
+msgstr "Filter zurücksetzen“"
+
+#: lib/mv_web/live/components/member_filter_component.ex
+#, elixir-autogen, elixir-format
+msgid "Apply filters"
+msgstr "Filter auswählen"
+
+#: lib/mv_web/live/member_live/show.ex
+#, elixir-autogen, elixir-format, fuzzy
+msgid "Are you sure you want to delete %{name}? This action cannot be undone."
+msgstr "Möchtest du diese Gruppe wirklich löschen? Die Aktion kann nicht rückgängig gemacht werden."
+
+#: lib/mv_web/live/member_live/show.ex
+#, elixir-autogen, elixir-format
+msgid "Danger zone"
+msgstr "Gefahrenzone"
+
+#: lib/mv_web/live/member_live/show.ex
+#, elixir-autogen, elixir-format, fuzzy
+msgid "Delete member"
+msgstr "Mitglied löschen"
+
+#: lib/mv_web/live/member_live/show.ex
+#, elixir-autogen, elixir-format
+msgid "Delete member %{name}"
+msgstr "Mitglied %{name} löschen"
+
+#: lib/mv_web/live/member_live/show.ex
+#, elixir-autogen, elixir-format
+msgid "Deleting this member cannot be undone. All related data (e.g. membership fee cycles) will be removed."
+msgstr "Das Löschen des Mitglieds kann nicht rückgängig gemacht werden. Alle dazugehörigen Daten (z.B. Mitgliedsbeitragszylen) werden gelöscht."
+
+#: lib/mv_web/live/custom_field_live/index_component.ex
+#: lib/mv_web/live/member_field_live/index_component.ex
+#, elixir-autogen, elixir-format, fuzzy
+msgid "Edit datafield"
+msgstr "Datenfeld bearbeiten"
+
+#: lib/mv_web/live/group_live/index.ex
+#: lib/mv_web/live/group_live/show.ex
+#, elixir-autogen, elixir-format, fuzzy
+msgid "Edit group"
+msgstr "Gruppe bearbeiten"
+
+#: lib/mv_web/live/member_live/show.ex
+#, elixir-autogen, elixir-format, fuzzy
+msgid "Edit member"
+msgstr "Mitglied bearbeiten"
+
+#: lib/mv_web/live/role_live/index.html.heex
+#, elixir-autogen, elixir-format, fuzzy
+msgid "Edit role"
+msgstr "Rolle bearbeiten"
+
+#: lib/mv_web/live/user_live/index.html.heex
+#, elixir-autogen, elixir-format, fuzzy
+msgid "Edit user"
+msgstr "Benutzer*in bearbeiten"
+
+#: lib/mv_web/live/role_live/show.ex
+#, elixir-autogen, elixir-format
+msgid "Rolle bearbeiten"
+msgstr "Rolle bearbeiten"
+
+#: lib/mv_web/live/custom_field_live/index_component.ex
+#, elixir-autogen, elixir-format
+msgid "Click for custom field details"
+msgstr "Klicke für Datenfeld-Details"
+
+#: lib/mv_web/live/member_field_live/index_component.ex
+#, elixir-autogen, elixir-format
+msgid "Click for datafield details"
+msgstr "Klicke für Datenfeld-Details"
+
+#: lib/mv_web/live/group_live/index.ex
+#, elixir-autogen, elixir-format
+msgid "Click for group details"
+msgstr "Klicke für Gruppen-Details"
+
+#: lib/mv_web/live/member_live/index.html.heex
+#, elixir-autogen, elixir-format
+msgid "Click for member details"
+msgstr "Klicke für Mitglieds-Details"
+
+#: lib/mv_web/live/role_live/index.html.heex
+#, elixir-autogen, elixir-format
+msgid "Click for role details"
+msgstr "Klicke für Rollen-Details"
+
+#: lib/mv_web/live/user_live/index.html.heex
+#, elixir-autogen, elixir-format
+msgid "Click for user details"
+msgstr "Klicke für Benutzer*innen-Details"
+
+#~ #: lib/mv_web/live/member_field_live/form_component.ex
+#~ #, elixir-autogen, elixir-format
+#~ msgid "Back to Settings"
+#~ msgstr "Zurück zu den Einstellungen"
+
+#~ #: lib/mv_web/live/member_live/form.ex
+#~ #, elixir-autogen, elixir-format
+#~ msgid "Coming soon"
+#~ msgstr "Demnächst verfügbar"
+
+#~ #: lib/mv_web/live/components/member_filter_component.ex
+#~ #, elixir-autogen, elixir-format
+#~ msgid "Reset"
+#~ msgstr "Zurücksetzen"
+
+#~ #: lib/mv_web/live/role_live/form.ex
+#~ #, elixir-autogen, elixir-format
+#~ msgid "Save Role"
+#~ msgstr "Rolle speichern"
+
+#~ #: lib/mv_web/live/member_live/index.ex
+#~ #, elixir-autogen, elixir-format
+#~ msgid "You do not have permission to access this member"
+#~ msgstr "Du hast keine Berechtigung, auf dieses Mitglied zuzugreifen"
diff --git a/priv/gettext/default.pot b/priv/gettext/default.pot
index ea8e976..cea7991 100644
--- a/priv/gettext/default.pot
+++ b/priv/gettext/default.pot
@@ -12,13 +12,11 @@ msgid ""
msgstr ""
#: lib/mv_web/components/core_components.ex
-#: lib/mv_web/live/group_live/index.ex
#: lib/mv_web/live/group_live/show.ex
#, elixir-autogen, elixir-format
msgid "Actions"
msgstr ""
-#: lib/mv_web/live/member_live/index.html.heex
#: lib/mv_web/live/membership_fee_settings_live.ex
#: lib/mv_web/live/membership_fee_type_live/index.ex
#: lib/mv_web/live/role_live/index.html.heex
@@ -43,7 +41,6 @@ msgstr ""
#: lib/mv_web/live/custom_field_live/index_component.ex
#: lib/mv_web/live/group_live/show.ex
-#: lib/mv_web/live/member_live/index.html.heex
#: lib/mv_web/live/member_live/show/membership_fees_component.ex
#: lib/mv_web/live/role_live/index.html.heex
#: lib/mv_web/live/user_live/index.html.heex
@@ -51,15 +48,8 @@ msgstr ""
msgid "Delete"
msgstr ""
-#: lib/mv_web/live/custom_field_live/index_component.ex
-#: lib/mv_web/live/group_live/index.ex
-#: lib/mv_web/live/group_live/show.ex
-#: lib/mv_web/live/member_field_live/index_component.ex
-#: lib/mv_web/live/member_live/index.html.heex
#: lib/mv_web/live/role_live/form.ex
-#: lib/mv_web/live/role_live/index.html.heex
#: lib/mv_web/live/user_live/form.ex
-#: lib/mv_web/live/user_live/index.html.heex
#, elixir-autogen, elixir-format
msgid "Edit"
msgstr ""
@@ -278,7 +268,6 @@ msgstr ""
#: lib/mv_web/live/member_live/form.ex
#: lib/mv_web/live/member_live/show/membership_fees_component.ex
#: lib/mv_web/live/membership_fee_type_live/form.ex
-#: lib/mv_web/live/role_live/form.ex
#: lib/mv_web/live/user_live/form.ex
#, elixir-autogen, elixir-format
msgid "Cancel"
@@ -791,19 +780,18 @@ msgstr ""
msgid "Address"
msgstr ""
+#: lib/mv_web/live/custom_field_live/form_component.ex
#: lib/mv_web/live/group_live/form.ex
#: lib/mv_web/live/group_live/show.ex
+#: lib/mv_web/live/member_field_live/form_component.ex
#: lib/mv_web/live/member_live/form.ex
#: lib/mv_web/live/member_live/show.ex
+#: lib/mv_web/live/role_live/form.ex
+#: lib/mv_web/live/role_live/show.ex
#, elixir-autogen, elixir-format
msgid "Back"
msgstr ""
-#: lib/mv_web/live/member_live/form.ex
-#, elixir-autogen, elixir-format
-msgid "Coming soon"
-msgstr ""
-
#: lib/mv_web/live/member_live/form.ex
#: lib/mv_web/live/member_live/show.ex
#, elixir-autogen, elixir-format
@@ -821,7 +809,6 @@ msgid "Payment Data"
msgstr ""
#: lib/mv_web/live/components/member_filter_component.ex
-#: lib/mv_web/live/member_live/form.ex
#, elixir-autogen, elixir-format
msgid "Payments"
msgstr ""
@@ -835,6 +822,7 @@ msgstr ""
#: lib/mv_web/live/group_live/form.ex
#: lib/mv_web/live/member_live/form.ex
#: lib/mv_web/live/member_live/show/membership_fees_component.ex
+#: lib/mv_web/live/role_live/form.ex
#, elixir-autogen, elixir-format
msgid "Save"
msgstr ""
@@ -852,11 +840,6 @@ msgstr ""
msgid "Amount"
msgstr ""
-#: lib/mv_web/live/member_field_live/form_component.ex
-#, elixir-autogen, elixir-format
-msgid "Back to Settings"
-msgstr ""
-
#: lib/mv_web/live/membership_fee_settings_live.ex
#: lib/mv_web/live/membership_fee_type_live/index.ex
#, elixir-autogen, elixir-format
@@ -1576,6 +1559,7 @@ msgid "Show/Hide Columns"
msgstr ""
#: lib/mv_web/live/custom_field_live/form_component.ex
+#: lib/mv_web/live/member_field_live/form_component.ex
#, elixir-autogen, elixir-format
msgid "Back to settings"
msgstr ""
@@ -1631,11 +1615,6 @@ msgstr ""
msgid "Custom"
msgstr ""
-#: lib/mv_web/live/role_live/show.ex
-#, elixir-autogen, elixir-format
-msgid "Edit Role"
-msgstr ""
-
#: lib/mv_web/live/role_live/index.ex
#: lib/mv_web/live/role_live/show.ex
#, elixir-autogen, elixir-format
@@ -1735,11 +1714,6 @@ msgstr ""
msgid "Role saved successfully."
msgstr ""
-#: lib/mv_web/live/role_live/form.ex
-#, elixir-autogen, elixir-format
-msgid "Save Role"
-msgstr ""
-
#: lib/mv_web/live/role_live/form.ex
#, elixir-autogen, elixir-format
msgid "Select permission set"
@@ -1891,22 +1865,17 @@ msgstr ""
msgid "Unknown error"
msgstr ""
-#: lib/mv_web/live/member_live/index.ex
+#: lib/mv_web/live/member_live/show.ex
#, elixir-autogen, elixir-format
msgid "Member deleted successfully"
msgstr ""
-#: lib/mv_web/live/member_live/index.ex
+#: lib/mv_web/live/member_live/show.ex
#, elixir-autogen, elixir-format
msgid "Member not found"
msgstr ""
-#: lib/mv_web/live/member_live/index.ex
-#, elixir-autogen, elixir-format
-msgid "You do not have permission to access this member"
-msgstr ""
-
-#: lib/mv_web/live/member_live/index.ex
+#: lib/mv_web/live/member_live/show.ex
#, elixir-autogen, elixir-format
msgid "You do not have permission to delete this member"
msgstr ""
@@ -1991,11 +1960,6 @@ msgstr ""
msgid "Payment Status"
msgstr ""
-#: lib/mv_web/live/components/member_filter_component.ex
-#, elixir-autogen, elixir-format
-msgid "Reset"
-msgstr ""
-
#: lib/mv_web/live/import_live/components.ex
#, elixir-autogen, elixir-format
msgid " (Field: %{field})"
@@ -3098,3 +3062,100 @@ msgstr ""
#, elixir-autogen, elixir-format
msgid "When enabled and OIDC is configured, the sign-in page shows only the Single Sign-On button."
msgstr ""
+
+#: lib/mv_web/live/components/member_filter_component.ex
+#, elixir-autogen, elixir-format
+msgid "Clear filters"
+msgstr ""
+
+#: lib/mv_web/live/components/member_filter_component.ex
+#, elixir-autogen, elixir-format
+msgid "Apply filters"
+msgstr ""
+
+#: lib/mv_web/live/member_live/show.ex
+#, elixir-autogen, elixir-format
+msgid "Are you sure you want to delete %{name}? This action cannot be undone."
+msgstr ""
+
+#: lib/mv_web/live/member_live/show.ex
+#, elixir-autogen, elixir-format
+msgid "Danger zone"
+msgstr ""
+
+#: lib/mv_web/live/member_live/show.ex
+#, elixir-autogen, elixir-format
+msgid "Delete member"
+msgstr ""
+
+#: lib/mv_web/live/member_live/show.ex
+#, elixir-autogen, elixir-format
+msgid "Delete member %{name}"
+msgstr ""
+
+#: lib/mv_web/live/member_live/show.ex
+#, elixir-autogen, elixir-format
+msgid "Deleting this member cannot be undone. All related data (e.g. membership fee cycles) will be removed."
+msgstr ""
+
+#: lib/mv_web/live/custom_field_live/index_component.ex
+#: lib/mv_web/live/member_field_live/index_component.ex
+#, elixir-autogen, elixir-format
+msgid "Edit datafield"
+msgstr ""
+
+#: lib/mv_web/live/group_live/index.ex
+#: lib/mv_web/live/group_live/show.ex
+#, elixir-autogen, elixir-format
+msgid "Edit group"
+msgstr ""
+
+#: lib/mv_web/live/member_live/show.ex
+#, elixir-autogen, elixir-format
+msgid "Edit member"
+msgstr ""
+
+#: lib/mv_web/live/role_live/index.html.heex
+#, elixir-autogen, elixir-format
+msgid "Edit role"
+msgstr ""
+
+#: lib/mv_web/live/user_live/index.html.heex
+#, elixir-autogen, elixir-format
+msgid "Edit user"
+msgstr ""
+
+#: lib/mv_web/live/role_live/show.ex
+#, elixir-autogen, elixir-format
+msgid "Rolle bearbeiten"
+msgstr ""
+
+#: lib/mv_web/live/custom_field_live/index_component.ex
+#, elixir-autogen, elixir-format
+msgid "Click for custom field details"
+msgstr ""
+
+#: lib/mv_web/live/member_field_live/index_component.ex
+#, elixir-autogen, elixir-format
+msgid "Click for datafield details"
+msgstr ""
+
+#: lib/mv_web/live/group_live/index.ex
+#, elixir-autogen, elixir-format
+msgid "Click for group details"
+msgstr ""
+
+#: lib/mv_web/live/member_live/index.html.heex
+#, elixir-autogen, elixir-format
+msgid "Click for member details"
+msgstr ""
+
+#: lib/mv_web/live/role_live/index.html.heex
+#, elixir-autogen, elixir-format
+msgid "Click for role details"
+msgstr ""
+
+#: lib/mv_web/live/user_live/index.html.heex
+#, elixir-autogen, elixir-format
+msgid "Click for user details"
+msgstr ""
diff --git a/priv/gettext/en/LC_MESSAGES/default.po b/priv/gettext/en/LC_MESSAGES/default.po
index 915fc52..9f38efe 100644
--- a/priv/gettext/en/LC_MESSAGES/default.po
+++ b/priv/gettext/en/LC_MESSAGES/default.po
@@ -12,13 +12,11 @@ msgstr ""
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: lib/mv_web/components/core_components.ex
-#: lib/mv_web/live/group_live/index.ex
#: lib/mv_web/live/group_live/show.ex
#, elixir-autogen, elixir-format
msgid "Actions"
msgstr ""
-#: lib/mv_web/live/member_live/index.html.heex
#: lib/mv_web/live/membership_fee_settings_live.ex
#: lib/mv_web/live/membership_fee_type_live/index.ex
#: lib/mv_web/live/role_live/index.html.heex
@@ -43,7 +41,6 @@ msgstr ""
#: lib/mv_web/live/custom_field_live/index_component.ex
#: lib/mv_web/live/group_live/show.ex
-#: lib/mv_web/live/member_live/index.html.heex
#: lib/mv_web/live/member_live/show/membership_fees_component.ex
#: lib/mv_web/live/role_live/index.html.heex
#: lib/mv_web/live/user_live/index.html.heex
@@ -51,15 +48,8 @@ msgstr ""
msgid "Delete"
msgstr ""
-#: lib/mv_web/live/custom_field_live/index_component.ex
-#: lib/mv_web/live/group_live/index.ex
-#: lib/mv_web/live/group_live/show.ex
-#: lib/mv_web/live/member_field_live/index_component.ex
-#: lib/mv_web/live/member_live/index.html.heex
#: lib/mv_web/live/role_live/form.ex
-#: lib/mv_web/live/role_live/index.html.heex
#: lib/mv_web/live/user_live/form.ex
-#: lib/mv_web/live/user_live/index.html.heex
#, elixir-autogen, elixir-format
msgid "Edit"
msgstr ""
@@ -278,7 +268,6 @@ msgstr ""
#: lib/mv_web/live/member_live/form.ex
#: lib/mv_web/live/member_live/show/membership_fees_component.ex
#: lib/mv_web/live/membership_fee_type_live/form.ex
-#: lib/mv_web/live/role_live/form.ex
#: lib/mv_web/live/user_live/form.ex
#, elixir-autogen, elixir-format
msgid "Cancel"
@@ -791,19 +780,18 @@ msgstr ""
msgid "Address"
msgstr ""
+#: lib/mv_web/live/custom_field_live/form_component.ex
#: lib/mv_web/live/group_live/form.ex
#: lib/mv_web/live/group_live/show.ex
+#: lib/mv_web/live/member_field_live/form_component.ex
#: lib/mv_web/live/member_live/form.ex
#: lib/mv_web/live/member_live/show.ex
+#: lib/mv_web/live/role_live/form.ex
+#: lib/mv_web/live/role_live/show.ex
#, elixir-autogen, elixir-format
msgid "Back"
msgstr ""
-#: lib/mv_web/live/member_live/form.ex
-#, elixir-autogen, elixir-format
-msgid "Coming soon"
-msgstr ""
-
#: lib/mv_web/live/member_live/form.ex
#: lib/mv_web/live/member_live/show.ex
#, elixir-autogen, elixir-format
@@ -821,7 +809,6 @@ msgid "Payment Data"
msgstr ""
#: lib/mv_web/live/components/member_filter_component.ex
-#: lib/mv_web/live/member_live/form.ex
#, elixir-autogen, elixir-format
msgid "Payments"
msgstr ""
@@ -835,6 +822,7 @@ msgstr ""
#: lib/mv_web/live/group_live/form.ex
#: lib/mv_web/live/member_live/form.ex
#: lib/mv_web/live/member_live/show/membership_fees_component.ex
+#: lib/mv_web/live/role_live/form.ex
#, elixir-autogen, elixir-format, fuzzy
msgid "Save"
msgstr ""
@@ -852,11 +840,6 @@ msgstr ""
msgid "Amount"
msgstr ""
-#: lib/mv_web/live/member_field_live/form_component.ex
-#, elixir-autogen, elixir-format
-msgid "Back to Settings"
-msgstr ""
-
#: lib/mv_web/live/membership_fee_settings_live.ex
#: lib/mv_web/live/membership_fee_type_live/index.ex
#, elixir-autogen, elixir-format
@@ -1576,6 +1559,7 @@ msgid "Show/Hide Columns"
msgstr ""
#: lib/mv_web/live/custom_field_live/form_component.ex
+#: lib/mv_web/live/member_field_live/form_component.ex
#, elixir-autogen, elixir-format, fuzzy
msgid "Back to settings"
msgstr ""
@@ -1631,11 +1615,6 @@ msgstr ""
msgid "Custom"
msgstr ""
-#: lib/mv_web/live/role_live/show.ex
-#, elixir-autogen, elixir-format, fuzzy
-msgid "Edit Role"
-msgstr ""
-
#: lib/mv_web/live/role_live/index.ex
#: lib/mv_web/live/role_live/show.ex
#, elixir-autogen, elixir-format, fuzzy
@@ -1735,11 +1714,6 @@ msgstr ""
msgid "Role saved successfully."
msgstr ""
-#: lib/mv_web/live/role_live/form.ex
-#, elixir-autogen, elixir-format, fuzzy
-msgid "Save Role"
-msgstr ""
-
#: lib/mv_web/live/role_live/form.ex
#, elixir-autogen, elixir-format
msgid "Select permission set"
@@ -1891,22 +1865,17 @@ msgstr ""
msgid "Unknown error"
msgstr ""
-#: lib/mv_web/live/member_live/index.ex
+#: lib/mv_web/live/member_live/show.ex
#, elixir-autogen, elixir-format
msgid "Member deleted successfully"
msgstr ""
-#: lib/mv_web/live/member_live/index.ex
+#: lib/mv_web/live/member_live/show.ex
#, elixir-autogen, elixir-format
msgid "Member not found"
msgstr ""
-#: lib/mv_web/live/member_live/index.ex
-#, elixir-autogen, elixir-format
-msgid "You do not have permission to access this member"
-msgstr ""
-
-#: lib/mv_web/live/member_live/index.ex
+#: lib/mv_web/live/member_live/show.ex
#, elixir-autogen, elixir-format
msgid "You do not have permission to delete this member"
msgstr ""
@@ -1991,11 +1960,6 @@ msgstr ""
msgid "Payment Status"
msgstr ""
-#: lib/mv_web/live/components/member_filter_component.ex
-#, elixir-autogen, elixir-format
-msgid "Reset"
-msgstr ""
-
#: lib/mv_web/live/import_live/components.ex
#, elixir-autogen, elixir-format
msgid " (Field: %{field})"
@@ -3098,3 +3062,125 @@ msgstr ""
#, elixir-autogen, elixir-format
msgid "When enabled and OIDC is configured, the sign-in page shows only the Single Sign-On button."
msgstr ""
+
+#: lib/mv_web/live/components/member_filter_component.ex
+#, elixir-autogen, elixir-format
+msgid "Clear filters"
+msgstr ""
+
+#: lib/mv_web/live/components/member_filter_component.ex
+#, elixir-autogen, elixir-format
+msgid "Apply filters"
+msgstr ""
+
+#: lib/mv_web/live/member_live/show.ex
+#, elixir-autogen, elixir-format, fuzzy
+msgid "Are you sure you want to delete %{name}? This action cannot be undone."
+msgstr ""
+
+#: lib/mv_web/live/member_live/show.ex
+#, elixir-autogen, elixir-format
+msgid "Danger zone"
+msgstr ""
+
+#: lib/mv_web/live/member_live/show.ex
+#, elixir-autogen, elixir-format, fuzzy
+msgid "Delete member"
+msgstr ""
+
+#: lib/mv_web/live/member_live/show.ex
+#, elixir-autogen, elixir-format
+msgid "Delete member %{name}"
+msgstr ""
+
+#: lib/mv_web/live/member_live/show.ex
+#, elixir-autogen, elixir-format
+msgid "Deleting this member cannot be undone. All related data (e.g. membership fee cycles) will be removed."
+msgstr ""
+
+#: lib/mv_web/live/custom_field_live/index_component.ex
+#: lib/mv_web/live/member_field_live/index_component.ex
+#, elixir-autogen, elixir-format, fuzzy
+msgid "Edit datafield"
+msgstr ""
+
+#: lib/mv_web/live/group_live/index.ex
+#: lib/mv_web/live/group_live/show.ex
+#, elixir-autogen, elixir-format, fuzzy
+msgid "Edit group"
+msgstr ""
+
+#: lib/mv_web/live/member_live/show.ex
+#, elixir-autogen, elixir-format, fuzzy
+msgid "Edit member"
+msgstr ""
+
+#: lib/mv_web/live/role_live/index.html.heex
+#, elixir-autogen, elixir-format, fuzzy
+msgid "Edit role"
+msgstr ""
+
+#: lib/mv_web/live/user_live/index.html.heex
+#, elixir-autogen, elixir-format, fuzzy
+msgid "Edit user"
+msgstr ""
+
+#: lib/mv_web/live/role_live/show.ex
+#, elixir-autogen, elixir-format
+msgid "Rolle bearbeiten"
+msgstr ""
+
+#: lib/mv_web/live/custom_field_live/index_component.ex
+#, elixir-autogen, elixir-format
+msgid "Click for custom field details"
+msgstr ""
+
+#: lib/mv_web/live/member_field_live/index_component.ex
+#, elixir-autogen, elixir-format
+msgid "Click for datafield details"
+msgstr ""
+
+#: lib/mv_web/live/group_live/index.ex
+#, elixir-autogen, elixir-format
+msgid "Click for group details"
+msgstr ""
+
+#: lib/mv_web/live/member_live/index.html.heex
+#, elixir-autogen, elixir-format
+msgid "Click for member details"
+msgstr ""
+
+#: lib/mv_web/live/role_live/index.html.heex
+#, elixir-autogen, elixir-format
+msgid "Click for role details"
+msgstr ""
+
+#: lib/mv_web/live/user_live/index.html.heex
+#, elixir-autogen, elixir-format
+msgid "Click for user details"
+msgstr ""
+
+#~ #: lib/mv_web/live/member_field_live/form_component.ex
+#~ #, elixir-autogen, elixir-format
+#~ msgid "Back to Settings"
+#~ msgstr ""
+
+#~ #: lib/mv_web/live/member_live/form.ex
+#~ #, elixir-autogen, elixir-format
+#~ msgid "Coming soon"
+#~ msgstr ""
+
+#~ #: lib/mv_web/live/components/member_filter_component.ex
+#~ #, elixir-autogen, elixir-format
+#~ msgid "Reset"
+#~ msgstr ""
+
+#~ #: lib/mv_web/live/role_live/form.ex
+#~ #, elixir-autogen, elixir-format, fuzzy
+#~ msgid "Save Role"
+#~ msgstr ""
+
+#~ #: lib/mv_web/live/member_live/index.ex
+#~ #, elixir-autogen, elixir-format
+#~ msgid "You do not have permission to access this member"
+#~ msgstr ""
diff --git a/test/mv_web/components/core_components_table_test.exs b/test/mv_web/components/core_components_table_test.exs
new file mode 100644
index 0000000..931b42a
--- /dev/null
+++ b/test/mv_web/components/core_components_table_test.exs
@@ -0,0 +1,154 @@
+defmodule MvWeb.Components.CoreComponentsTableTest do
+ @moduledoc """
+ Tests for the CoreComponents table: row hover/focus and selected styling.
+ """
+ use MvWeb.ConnCase, async: true
+
+ import Phoenix.LiveViewTest
+
+ alias MvWeb.CoreComponents
+
+ describe "table row_click styling" do
+ test "when row_click is set, table rows have hover and focus-within ring classes" do
+ rows = [%{id: "1", name: "Alice"}, %{id: "2", name: "Bob"}]
+
+ assigns = %{
+ id: "test-table",
+ rows: rows,
+ row_id: fn r -> "row-#{r.id}" end,
+ row_click: fn _ -> nil end,
+ row_item: &Function.identity/1,
+ col: [
+ %{
+ __slot__: :col,
+ label: "Name",
+ inner_block: fn _socket, item -> [item[:name] || item["name"] || ""] end
+ }
+ ],
+ dynamic_cols: [],
+ action: []
+ }
+
+ html = render_component(&CoreComponents.table/1, assigns)
+
+ assert html =~ "hover:ring-2"
+ assert html =~ "focus-within:ring-2"
+ assert html =~ "hover:ring-base-content/10"
+ end
+
+ test "when row_click is nil, table rows do not have hover ring classes" do
+ rows = [%{id: "1", name: "Alice"}]
+
+ assigns = %{
+ id: "test-table",
+ rows: rows,
+ row_id: fn r -> "row-#{r.id}" end,
+ row_click: nil,
+ row_item: &Function.identity/1,
+ col: [
+ %{
+ __slot__: :col,
+ label: "Name",
+ inner_block: fn _socket, item -> [item[:name] || ""] end
+ }
+ ],
+ dynamic_cols: [],
+ action: []
+ }
+
+ html = render_component(&CoreComponents.table/1, assigns)
+
+ refute html =~ "hover:ring-2"
+ refute html =~ "focus-within:ring-2"
+ end
+ end
+
+ describe "table selected_row_id styling" do
+ test "when selected_row_id matches a row id, that row has data-selected and ring-primary" do
+ rows = [%{id: "one", name: "Alice"}, %{id: "two", name: "Bob"}]
+
+ assigns = %{
+ id: "test-table",
+ rows: rows,
+ row_id: fn r -> "row-#{r.id}" end,
+ row_click: fn _ -> nil end,
+ selected_row_id: "two",
+ row_item: &Function.identity/1,
+ col: [
+ %{
+ __slot__: :col,
+ label: "Name",
+ inner_block: fn _socket, item -> [item[:name] || ""] end
+ }
+ ],
+ dynamic_cols: [],
+ action: []
+ }
+
+ html = render_component(&CoreComponents.table/1, assigns)
+
+ assert html =~ ~s(id="row-two")
+ assert html =~ ~s(data-selected="true")
+ assert html =~ "ring-primary"
+ end
+
+ test "when selected_row_id is nil, no row has data-selected" do
+ rows = [%{id: "1", name: "Alice"}]
+
+ assigns = %{
+ id: "test-table",
+ rows: rows,
+ row_id: fn r -> "row-#{r.id}" end,
+ row_click: nil,
+ selected_row_id: nil,
+ row_item: &Function.identity/1,
+ col: [
+ %{
+ __slot__: :col,
+ label: "Name",
+ inner_block: fn _socket, item -> [item[:name] || ""] end
+ }
+ ],
+ dynamic_cols: [],
+ action: []
+ }
+
+ html = render_component(&CoreComponents.table/1, assigns)
+
+ refute html =~ ~s(data-selected="true")
+ end
+
+ test "when row_selected? is set, multiple rows can have data-selected and ring-primary" do
+ rows = [%{id: "a", name: "Alice"}, %{id: "b", name: "Bob"}, %{id: "c", name: "Claire"}]
+ selected_ids = MapSet.new(["a", "c"])
+
+ assigns = %{
+ id: "test-table",
+ rows: rows,
+ row_id: fn r -> "row-#{r.id}" end,
+ row_click: fn _ -> nil end,
+ row_selected?: fn item -> MapSet.member?(selected_ids, item.id) end,
+ row_item: &Function.identity/1,
+ col: [
+ %{
+ __slot__: :col,
+ label: "Name",
+ inner_block: fn _socket, item -> [item[:name] || ""] end
+ }
+ ],
+ dynamic_cols: [],
+ action: []
+ }
+
+ html = render_component(&CoreComponents.table/1, assigns)
+
+ # Two rows selected (a and c), one not (b)
+ assert html =~ ~s(id="row-a")
+ assert html =~ ~s(id="row-b")
+ assert html =~ ~s(id="row-c")
+ # data-selected appears twice (for row a and row c)
+ assert String.contains?(html, ~s(data-selected="true"))
+ assert html =~ "ring-primary"
+ end
+ end
+end
diff --git a/test/mv_web/live/member_live_authorization_test.exs b/test/mv_web/live/member_live_authorization_test.exs
index 9a23019..c5db9d6 100644
--- a/test/mv_web/live/member_live_authorization_test.exs
+++ b/test/mv_web/live/member_live_authorization_test.exs
@@ -24,6 +24,7 @@ defmodule MvWeb.MemberLiveAuthorizationTest do
{:ok, view, _html} = live(conn, "/members")
+ # Index table has no Edit/Delete per row (only sr-only Show link); ensure they are not present
refute has_element?(view, "#row-#{member.id} [data-testid=member-edit]")
refute has_element?(view, "#row-#{member.id} [data-testid=member-delete]")
end
@@ -31,17 +32,18 @@ defmodule MvWeb.MemberLiveAuthorizationTest do
describe "Member Index - Kassenwart (normal_user)" do
@tag role: :normal_user
- test "sees New Member and Edit buttons", %{conn: conn} do
+ test "sees New Member and Show link in row", %{conn: conn} do
member = Fixtures.member_fixture()
{:ok, view, _html} = live(conn, "/members")
assert has_element?(view, "[data-testid=member-new]")
- assert has_element?(view, "#row-#{member.id} [data-testid=member-edit]")
+ # Index table action column has sr-only Show link only (Edit is on member show page)
+ assert has_element?(view, "#row-#{member.id} [data-testid=member-show-link]")
end
@tag role: :normal_user
- test "does not see Delete button", %{conn: conn} do
+ test "does not see Delete button in table", %{conn: conn} do
member = Fixtures.member_fixture()
{:ok, view, _html} = live(conn, "/members")
@@ -52,14 +54,14 @@ defmodule MvWeb.MemberLiveAuthorizationTest do
describe "Member Index - Admin" do
@tag role: :admin
- test "sees New Member, Edit and Delete buttons", %{conn: conn} do
+ test "sees New Member and Show link in row", %{conn: conn} do
member = Fixtures.member_fixture()
{:ok, view, _html} = live(conn, "/members")
assert has_element?(view, "[data-testid=member-new]")
- assert has_element?(view, "#row-#{member.id} [data-testid=member-edit]")
- assert has_element?(view, "#row-#{member.id} [data-testid=member-delete]")
+ # Index table action column has sr-only Show link only (Edit/Delete are on member show page)
+ assert has_element?(view, "#row-#{member.id} [data-testid=member-show-link]")
end
end
diff --git a/test/mv_web/member_live/index_membership_fee_status_test.exs b/test/mv_web/member_live/index_membership_fee_status_test.exs
index bbd9159..add2fba 100644
--- a/test/mv_web/member_live/index_membership_fee_status_test.exs
+++ b/test/mv_web/member_live/index_membership_fee_status_test.exs
@@ -107,9 +107,9 @@ defmodule MvWeb.MemberLive.IndexMembershipFeeStatusTest do
{:ok, view, _html} = live(conn, "/members")
- # Toggle to current cycle (use the button in the header, not the one in the column)
+ # Toggle to current cycle (use the button in the header)
view
- |> element("button[phx-click='toggle_cycle_view'].btn.gap-2")
+ |> element("[data-testid=toggle-cycle-view]")
|> render_click()
html = render(view)
diff --git a/test/mv_web/member_live/index_test.exs b/test/mv_web/member_live/index_test.exs
index d8846ea..1c8328f 100644
--- a/test/mv_web/member_live/index_test.exs
+++ b/test/mv_web/member_live/index_test.exs
@@ -304,6 +304,44 @@ defmodule MvWeb.MemberLive.IndexTest do
assert_redirect(view, ~p"/members/#{member}")
end
+ describe "table row outline (hover and selected)" do
+ @describetag :ui
+
+ test "clickable rows have hover and focus-within ring classes", %{conn: conn} do
+ system_actor = Mv.Helpers.SystemActor.get_system_actor()
+
+ {:ok, _member} =
+ Mv.Membership.create_member(
+ %{first_name: "Hover", last_name: "Test", email: "hover@example.com"},
+ actor: system_actor
+ )
+
+ conn = conn_with_oidc_user(conn)
+ {:ok, _view, html} = live(conn, "/members")
+
+ # CoreComponents table adds hover and focus-within ring when row_click is set
+ assert html =~ "hover:ring-2"
+ assert html =~ "focus-within:ring-2"
+ assert html =~ "hover:ring-base-content/10"
+ end
+
+ test "selected outline only from checkbox selection, not from highlight param", %{conn: conn} do
+ system_actor = Mv.Helpers.SystemActor.get_system_actor()
+
+ {:ok, member} =
+ Mv.Membership.create_member(
+ %{first_name: "Highlight", last_name: "Only", email: "highlight@example.com"},
+ actor: system_actor
+ )
+
+ conn = conn_with_oidc_user(conn)
+ {:ok, view, _html} = live(conn, "/members?highlight=#{member.id}")
+
+ # Outline is only for checkbox selection; highlight param does not set data-selected
+ refute has_element?(view, "tr#row-#{member.id}[data-selected='true']")
+ end
+ end
+
describe "copy_emails feature" do
setup do
system_actor = Mv.Helpers.SystemActor.get_system_actor()
|