From 8512be02827cef0da97684cda904ee1f6b11cca7 Mon Sep 17 00:00:00 2001 From: carla Date: Thu, 4 Dec 2025 12:32:24 +0100 Subject: [PATCH] feat: reuse form_section in settings --- lib/mv_web/components/core_components.ex | 59 +++- .../live/custom_field_live/index_component.ex | 270 +++++++++--------- lib/mv_web/live/global_settings_live.ex | 30 +- lib/mv_web/live/member_live/form.ex | 19 -- 4 files changed, 209 insertions(+), 169 deletions(-) diff --git a/lib/mv_web/components/core_components.ex b/lib/mv_web/components/core_components.ex index be64655..f70d245 100644 --- a/lib/mv_web/components/core_components.ex +++ b/lib/mv_web/components/core_components.ex @@ -153,7 +153,7 @@ defmodule MvWeb.CoreComponents do aria-haspopup="menu" aria-expanded={@open} aria-controls={@id} - class="btn btn-ghost" + class="btn" phx-click="toggle_dropdown" phx-target={@phx_target} data-testid="dropdown-button" @@ -236,6 +236,30 @@ defmodule MvWeb.CoreComponents do """ end + @doc """ + Renders a section in with a border similar to cards. + + + ## Examples + + <.form_section title={gettext("Personal Data")}> +

input

+ + """ + attr :title, :string, required: true + slot :inner_block, required: true + + def form_section(assigns) do + ~H""" +
+

{@title}

+
+ {render_slot(@inner_block)} +
+
+ """ + end + @doc """ Renders an input with label and error messages. @@ -434,7 +458,7 @@ defmodule MvWeb.CoreComponents do ~H"""
-

+

{render_slot(@inner_block)}

@@ -474,6 +498,7 @@ defmodule MvWeb.CoreComponents do slot :col, required: true do attr :label, :string + attr :class, :string end slot :action, doc: "the slot for showing user actions in the last table column" @@ -489,7 +514,7 @@ defmodule MvWeb.CoreComponents 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 9187aa6..8f63bf8 100644 --- a/lib/mv_web/live/custom_field_live/index_component.ex +++ b/lib/mv_web/live/custom_field_live/index_component.ex @@ -18,141 +18,149 @@ defmodule MvWeb.CustomFieldLive.IndexComponent do ~H"""
- <.form_section title={gettext("Custom Fields")}> -
-

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

-
- <.button class="ml-auto" variant="primary" phx-click="new_custom_field" phx-target={@myself}> - <.icon name="hero-plus" /> {gettext("New Custom field")} - -
-
- <%!-- Show form when creating or editing --%> -
- <.live_component - module={MvWeb.CustomFieldLive.FormComponent} - id={@form_id} - custom_field={@editing_custom_field} - on_save={ - fn custom_field, action -> send(self(), {:custom_field_saved, custom_field, action}) end - } - on_cancel={fn -> send_update(__MODULE__, id: @id, show_form: false) end} - /> -
- - <%!-- Hide table when form is visible --%> - <.table - :if={!@show_form} - id="custom_fields" - rows={@streams.custom_fields} - row_click={ - fn {_id, custom_field} -> - JS.push("edit_custom_field", value: %{id: custom_field.id}, target: @myself) - end - } - > - <:col :let={{_id, custom_field}} label={gettext("Name")}>{custom_field.name} - - <:col :let={{_id, custom_field}} label={gettext("Value Type")}> - {@field_type_label.(custom_field.value_type)} - - - <:col :let={{_id, custom_field}} label={gettext("Description")}> - {custom_field.description} - - - <:col :let={{_id, custom_field}} label={gettext("Show in overview")} class="max-w-[9.375rem] text-center"> - - {gettext("Yes")} - - - {gettext("No")} - - - - <:action :let={{_id, custom_field}}> - <.icon_button - icon="hero-pencil" - label={gettext("Edit custom field")} - size="sm" - phx-click={JS.push("edit_custom_field", value: %{id: custom_field.id}, target: @myself)} - /> - - - <:action :let={{_id, custom_field}}> - <.icon_button - icon="hero-trash" - label={gettext("Delete custom field")} - size="sm" - class="btn-error" - phx-click={JS.push("prepare_delete", value: %{id: custom_field.id}, target: @myself)} - /> - - - - <%!-- Delete Confirmation Modal --%> - - + <%!-- Show form when creating or editing --%> +
+ <.live_component + module={MvWeb.CustomFieldLive.FormComponent} + id={@form_id} + custom_field={@editing_custom_field} + on_save={ + fn custom_field, action -> send(self(), {:custom_field_saved, custom_field, action}) end + } + on_cancel={fn -> send_update(__MODULE__, id: @id, show_form: false) end} + /> +
+ + <%!-- Hide table when form is visible --%> + <.table + :if={!@show_form} + id="custom_fields" + rows={@streams.custom_fields} + row_click={ + fn {_id, custom_field} -> + JS.push("edit_custom_field", value: %{id: custom_field.id}, target: @myself) + end + } + > + <:col :let={{_id, custom_field}} label={gettext("Name")}>{custom_field.name} + + <:col :let={{_id, custom_field}} label={gettext("Value Type")}> + {@field_type_label.(custom_field.value_type)} + + + <:col :let={{_id, custom_field}} label={gettext("Description")}> + {custom_field.description} + + + <:col + :let={{_id, custom_field}} + label={gettext("Show in overview")} + class="max-w-[9.375rem] text-center" + > + + {gettext("Yes")} + + + {gettext("No")} + + + + <:action :let={{_id, custom_field}}> + <.link phx-click={ + JS.push("edit_custom_field", value: %{id: custom_field.id}, target: @myself) + }> + {gettext("Edit")} + + + + <:action :let={{_id, custom_field}}> + <.link phx-click={ + JS.push("prepare_delete", value: %{id: custom_field.id}, target: @myself) + }> + {gettext("Delete")} + + + + + <%!-- Delete Confirmation Modal --%> + +
diff --git a/lib/mv_web/live/global_settings_live.ex b/lib/mv_web/live/global_settings_live.ex index bb919cb..0b3ec1c 100644 --- a/lib/mv_web/live/global_settings_live.ex +++ b/lib/mv_web/live/global_settings_live.ex @@ -46,22 +46,22 @@ defmodule MvWeb.GlobalSettingsLive do <%!-- Club Settings Section --%> - <.header> - {gettext("Club Settings")} - - <.form for={@form} id="settings-form" phx-change="validate" phx-submit="save"> - <.input - field={@form[:club_name]} - type="text" - label={gettext("Association Name")} - required - /> - - <.button phx-disable-with={gettext("Saving...")} variant="primary"> - {gettext("Save Settings")} - - + <.form_section title={gettext("Club Settings")}> + <.form for={@form} id="settings-form" phx-change="validate" phx-submit="save"> +
+ <.input + field={@form[:club_name]} + type="text" + label={gettext("Association Name")} + required + /> +
+ <.button phx-disable-with={gettext("Saving...")} variant="primary"> + {gettext("Save Settings")} + + + <%!-- Custom Fields Section --%> <.live_component module={MvWeb.CustomFieldLive.IndexComponent} diff --git a/lib/mv_web/live/member_live/form.ex b/lib/mv_web/live/member_live/form.ex index 5380d0f..87148ad 100644 --- a/lib/mv_web/live/member_live/form.ex +++ b/lib/mv_web/live/member_live/form.ex @@ -348,25 +348,6 @@ defmodule MvWeb.MemberLive.Form do defp return_path("show", nil), do: ~p"/members" defp return_path("show", member), do: ~p"/members/#{member.id}" - # ----------------------------------------------------------------- - # Helper Components - # ----------------------------------------------------------------- - - # Renders a form section box with border and title. - attr :title, :string, required: true - slot :inner_block, required: true - - defp form_section(assigns) do - ~H""" -
-

{@title}

-
- {render_slot(@inner_block)} -
-
- """ - end - # ----------------------------------------------------------------- # Helper Functions for Custom Fields # -----------------------------------------------------------------
{col[:label]}{col[:label]} <.live_component module={MvWeb.Components.SortHeaderComponent} @@ -510,7 +535,33 @@ defmodule MvWeb.CoreComponents do {render_slot(col, @row_item.(row))}