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 b15e49d..c4002bc 100644 --- a/lib/mv_web/live/custom_field_live/index_component.ex +++ b/lib/mv_web/live/custom_field_live/index_component.ex @@ -19,8 +19,8 @@ defmodule MvWeb.CustomFieldLive.IndexComponent do assigns = assign(assigns, :field_type_label, &MvWeb.Translations.FieldTypes.label/1) ~H""" -
-
+
+

{gettext("These will appear in addition to other data when adding new members.")}

@@ -118,15 +118,15 @@ defmodule MvWeb.CustomFieldLive.IndexComponent do

{ngettext( - "%{count} member has a value assigned for this custom field.", - "%{count} members have values assigned for this custom field.", + "%{count} member has a value assigned for this datafield.", + "%{count} members have values assigned for this datafield.", @custom_field_to_delete.assigned_members_count, count: @custom_field_to_delete.assigned_members_count )}

{gettext( - "All custom field values will be permanently deleted when you delete this custom field." + "All datafield values will be permanently deleted when you delete this datfield." )}

@@ -192,8 +192,8 @@ defmodule MvWeb.CustomFieldLive.IndexComponent do @impl true def update(assigns, socket) do - # Track previous show_form state to detect when form is closed - previous_show_form = Map.get(socket.assigns, :show_form, false) + # Use socket state so send_update(open_delete_for_id: ...) does not trigger false "form closed" + previous_show_form = socket.assigns[:show_form] || false # If show_form is explicitly provided in assigns, reset editing state socket = @@ -205,13 +205,6 @@ defmodule MvWeb.CustomFieldLive.IndexComponent do socket end - # Detect when form is closed (show_form changes from true to false) - new_show_form = Map.get(assigns, :show_form, false) - - if previous_show_form and not new_show_form do - send(self(), {:editing_section_changed, nil}) - end - # Get actor from assigns or fall back to socket assigns actor = Map.get(assigns, :actor, socket.assigns[:actor]) @@ -246,6 +239,13 @@ defmodule MvWeb.CustomFieldLive.IndexComponent do |> assign(:open_delete_for_id, nil) end + # Detect form closed only from final socket state (not from assigns alone) + current_show_form = socket.assigns[:show_form] || false + + if previous_show_form and not current_show_form do + send(self(), {:editing_section_changed, nil}) + end + {:ok, socket} end diff --git a/lib/mv_web/live/datafields_live.ex b/lib/mv_web/live/datafields_live.ex index 916864b..11ec613 100644 --- a/lib/mv_web/live/datafields_live.ex +++ b/lib/mv_web/live/datafields_live.ex @@ -29,27 +29,47 @@ defmodule MvWeb.DatafieldsLive do <.header> {gettext("Datafields")} <:subtitle> - {gettext("Configure which data you want to save for your members. Define individual datafields.")} + {gettext( + "Configure which data you want to save for your members. Define individual datafields." + )} - <.form_section title={gettext("Member fields")}> + <%!-- Overview: both sections with form_section wrappers --%> +
+ <.form_section title={gettext("Personal Data")}> + <.live_component + module={MvWeb.MemberFieldLive.IndexComponent} + id="member-fields-component" + settings={@settings} + /> + + + <.form_section title={gettext("Individual Datafields")}> + <.live_component + module={MvWeb.CustomFieldLive.IndexComponent} + id="custom-fields-component" + actor={@current_user} + /> + +
+ + <%!-- Edit mode: only the active section, no section title/card wrapper --%> +
<.live_component - :if={@active_editing_section != :custom_fields} module={MvWeb.MemberFieldLive.IndexComponent} id="member-fields-component" settings={@settings} /> - +
- <.form_section title={gettext("Custom fields")}> +
<.live_component - :if={@active_editing_section != :member_fields} module={MvWeb.CustomFieldLive.IndexComponent} id="custom-fields-component" actor={@current_user} /> - +
""" end 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 d8b2616..97dc9ff 100644 --- a/lib/mv_web/live/member_field_live/index_component.ex +++ b/lib/mv_web/live/member_field_live/index_component.ex @@ -25,7 +25,7 @@ defmodule MvWeb.MemberFieldLive.IndexComponent do ~H"""
-

+

{gettext( "These fields are neccessary for MILA to handle member identification and payment calculations in the future. Thus you cannot delete these fields but hide them in the member overview." )} @@ -100,8 +100,8 @@ defmodule MvWeb.MemberFieldLive.IndexComponent do @impl true def update(assigns, socket) do - # Track previous show_form state to detect when form is closed - previous_show_form = Map.get(socket.assigns, :show_form, false) + # Use socket state so send_update(show_form: false) is the only trigger for "form closed" + previous_show_form = socket.assigns[:show_form] || false # If show_form is explicitly provided in assigns, reset editing state socket = @@ -113,20 +113,22 @@ defmodule MvWeb.MemberFieldLive.IndexComponent do socket end - # Detect when form is closed (show_form changes from true to false) - new_show_form = Map.get(assigns, :show_form, false) + socket = + socket + |> assign(assigns) + |> assign_new(:settings, fn -> get_settings() end) + |> assign_new(:show_form, fn -> false end) + |> assign_new(:form_id, fn -> "member-field-form-new" end) + |> assign_new(:editing_member_field, fn -> nil end) - if previous_show_form and not new_show_form do + # Detect form closed only from final socket state (not from assigns alone) + current_show_form = socket.assigns[:show_form] || false + + if previous_show_form and not current_show_form do send(self(), {:editing_section_changed, nil}) end - {:ok, - socket - |> assign(assigns) - |> assign_new(:settings, fn -> get_settings() end) - |> assign_new(:show_form, fn -> false end) - |> assign_new(:form_id, fn -> "member-field-form-new" end) - |> assign_new(:editing_member_field, fn -> nil end)} + {:ok, socket} end @impl true diff --git a/lib/mv_web/live/user_live/form.ex b/lib/mv_web/live/user_live/form.ex index 4934e3a..0cd898f 100644 --- a/lib/mv_web/live/user_live/form.ex +++ b/lib/mv_web/live/user_live/form.ex @@ -79,7 +79,7 @@ defmodule MvWeb.UserLive.Form do />

<% end %> - +
- + <%= if @can_manage_member_linking do %>
diff --git a/test/mv_web/live/custom_field_live/deletion_test.exs b/test/mv_web/live/custom_field_live/deletion_test.exs index 5ec955e..759ca1d 100644 --- a/test/mv_web/live/custom_field_live/deletion_test.exs +++ b/test/mv_web/live/custom_field_live/deletion_test.exs @@ -71,6 +71,10 @@ defmodule MvWeb.CustomFieldLive.DeletionTest do # Modal should be visible assert has_element?(view, "#delete-custom-field-modal") + # Edit mode: section titles must not reappear when modal opens (regression) + refute has_element?(view, "h2", "Member fields") + refute has_element?(view, "h2", "Custom fields") + # Should show correct member count (1 member) assert render(view) =~ "1 member has a value assigned for this custom field" diff --git a/test/mv_web/live/member_field_live/index_component_test.exs b/test/mv_web/live/member_field_live/index_component_test.exs index d3c1612..4356279 100644 --- a/test/mv_web/live/member_field_live/index_component_test.exs +++ b/test/mv_web/live/member_field_live/index_component_test.exs @@ -83,6 +83,21 @@ defmodule MvWeb.MemberFieldLive.IndexComponentTest do end end + describe "edit mode visibility" do + test "clicking member field row shows only form, no section titles", %{conn: conn} do + {:ok, view, _html} = live(conn, ~p"/admin/datafields") + + # Row click is on the first td (no col_click); click that cell to open edit form + view + |> element("tr#member_field-first_name td:first-child") + |> render_click() + + assert has_element?(view, "#member-field-form-first_name") + refute has_element?(view, "h2", "Custom fields") + refute has_element?(view, "h2", "Member fields") + end + end + describe "required fields" do setup do {:ok, settings} = Membership.get_settings() diff --git a/test/mv_web/live/statistics_live_test.exs b/test/mv_web/live/statistics_live_test.exs index ed6128f..49c4167 100644 --- a/test/mv_web/live/statistics_live_test.exs +++ b/test/mv_web/live/statistics_live_test.exs @@ -29,9 +29,8 @@ defmodule MvWeb.StatisticsLiveTest do test "page shows overview of all relevant years without year selector", %{conn: conn} do {:ok, _view, html} = live(conn, ~p"/statistics") - # No year dropdown: single select for year should not be present as main control - assert html =~ "Overview" or html =~ "overview" - # table header or legend + # Page shows multi-year data (member numbers by year) and year column; no single-year selector as main control + assert html =~ "Member numbers by year" assert html =~ "Year" end diff --git a/test/mv_web/user_live/index_test.exs b/test/mv_web/user_live/index_test.exs index f748000..596d02d 100644 --- a/test/mv_web/user_live/index_test.exs +++ b/test/mv_web/user_live/index_test.exs @@ -123,13 +123,17 @@ defmodule MvWeb.UserLive.IndexTest do {:ok, index_view, _html} = live(conn, "/users") assert render(index_view) =~ "delete-me@example.com" - # Navigate to user show and trigger delete from Danger zone + # Navigate to user show, open delete modal, then confirm in modal (WCAG modal pattern) {:ok, show_view, _html} = live(conn, "/users/#{user.id}") show_view |> element("[data-testid=user-delete]") |> render_click() + show_view + |> element("#delete-user-modal button", "Delete") + |> render_click() + # Should redirect to index assert_redirect(show_view, "/users")