diff --git a/lib/mv_web.ex b/lib/mv_web.ex index fff24b6..46e4e8b 100644 --- a/lib/mv_web.ex +++ b/lib/mv_web.ex @@ -52,6 +52,8 @@ defmodule MvWeb do quote do use Phoenix.LiveView + on_mount MvWeb.LiveHelpers + unquote(html_helpers()) end end diff --git a/lib/mv_web/live/property_live/form.ex b/lib/mv_web/live/property_live/form.ex index 2987b3e..42814a3 100644 --- a/lib/mv_web/live/property_live/form.ex +++ b/lib/mv_web/live/property_live/form.ex @@ -11,9 +11,32 @@ defmodule MvWeb.PropertyLive.Form do <.form for={@form} id="property-form" phx-change="validate" phx-submit="save"> - <.input field={@form[:value]} type="text" label={gettext("Value")} /> - <.input field={@form[:member_id]} type="text" label={gettext("Member")} /> - <.input field={@form[:property_type_id]} type="text" label={gettext("Property type")} /> + + <.input + field={@form[:property_type_id]} + type="select" + label={gettext("Property type")} + options={property_type_options(@property_types)} + prompt={gettext("Choose a property type")} + /> + + + <.input + field={@form[:member_id]} + type="select" + label={gettext("Member")} + options={member_options(@members)} + prompt={gettext("Choose a member")} + /> + + + <%= if @selected_property_type do %> + <.union_value_input form={@form} property_type={@selected_property_type} /> + <% else %> +
+ {gettext("Please select a property type first")} +
+ <% end %> <.button phx-disable-with={gettext("Saving...")} variant="primary"> {gettext("Save Property")} @@ -24,22 +47,109 @@ defmodule MvWeb.PropertyLive.Form do """ end + # Helper function for Union-Value Input + defp union_value_input(assigns) do + # Extract the current value from the Property + current_value = extract_current_value(assigns.form.data, assigns.property_type.value_type) + assigns = assign(assigns, :current_value, current_value) + + ~H""" +
+ + + <%= case @property_type.value_type do %> + <% :string -> %> + <.inputs_for :let={value_form} field={@form[:value]}> + <.input field={value_form[:value]} type="text" label="" value={@current_value} /> + + + <% :integer -> %> + <.inputs_for :let={value_form} field={@form[:value]}> + <.input field={value_form[:value]} type="number" label="" value={@current_value} /> + + + <% :boolean -> %> + <.inputs_for :let={value_form} field={@form[:value]}> + <.input field={value_form[:value]} type="checkbox" label="" checked={@current_value} /> + + + <% :date -> %> + <.inputs_for :let={value_form} field={@form[:value]}> + <.input + field={value_form[:value]} + type="date" + label="" + value={format_date_value(@current_value)} + /> + + + <% :email -> %> + <.inputs_for :let={value_form} field={@form[:value]}> + <.input field={value_form[:value]} type="email" label="" value={@current_value} /> + + + <% _ -> %> +
+ {gettext("Unsupported value type: %{type}", type: @property_type.value_type)} +
+ <% end %> +
+ """ + end + + # Helper function to extract the current value from the Property + defp extract_current_value( + %Mv.Membership.Property{value: %Ash.Union{value: value}}, + _value_type + ) do + value + end + + defp extract_current_value(_data, _value_type) do + nil + end + + # Helper function to format Date values for HTML input + defp format_date_value(%Date{} = date) do + Date.to_iso8601(date) + end + + defp format_date_value(nil), do: "" + + defp format_date_value(date) when is_binary(date) do + case Date.from_iso8601(date) do + {:ok, parsed_date} -> Date.to_iso8601(parsed_date) + _ -> "" + end + end + + defp format_date_value(_), do: "" + @impl true def mount(params, _session, socket) do property = case params["id"] do nil -> nil - id -> Ash.get!(Mv.Membership.Property, id) + id -> Ash.get!(Mv.Membership.Property, id) |> Ash.load!([:property_type]) end action = if is_nil(property), do: "New", else: "Edit" page_title = action <> " " <> "Property" + # Load all PropertyTypes and Members for the selection fields + property_types = Ash.read!(Mv.Membership.PropertyType) + members = Ash.read!(Mv.Membership.Member) + {:ok, socket |> assign(:return_to, return_to(params["return_to"])) |> assign(property: property) |> assign(:page_title, page_title) + |> assign(:property_types, property_types) + |> assign(:members, members) + |> assign(:selected_property_type, property && property.property_type) |> assign_form()} end @@ -48,12 +158,40 @@ defmodule MvWeb.PropertyLive.Form do @impl true def handle_event("validate", %{"property" => property_params}, socket) do + # Find the selected PropertyType + selected_property_type = + case property_params["property_type_id"] do + "" -> nil + nil -> nil + id -> Enum.find(socket.assigns.property_types, &(&1.id == id)) + end + + # Set the Union type based on the selected PropertyType + updated_params = + if selected_property_type do + union_type = to_string(selected_property_type.value_type) + put_in(property_params, ["value", "_union_type"], union_type) + else + property_params + end + {:noreply, - assign(socket, form: AshPhoenix.Form.validate(socket.assigns.form, property_params))} + socket + |> assign(:selected_property_type, selected_property_type) + |> assign(form: AshPhoenix.Form.validate(socket.assigns.form, updated_params))} end def handle_event("save", %{"property" => property_params}, socket) do - case AshPhoenix.Form.submit(socket.assigns.form, params: property_params) do + # Set the Union type based on the selected PropertyType + updated_params = + if socket.assigns.selected_property_type do + union_type = to_string(socket.assigns.selected_property_type.value_type) + put_in(property_params, ["value", "_union_type"], union_type) + else + property_params + end + + case AshPhoenix.Form.submit(socket.assigns.form, params: updated_params) do {:ok, property} -> notify_parent({:saved, property}) @@ -81,7 +219,17 @@ defmodule MvWeb.PropertyLive.Form do defp assign_form(%{assigns: %{property: property}} = socket) do form = if property do - AshPhoenix.Form.for_update(property, :update, as: "property") + # Determine the Union type based on the property_type + union_type = property.property_type && property.property_type.value_type + + params = + if union_type do + %{"value" => %{"_union_type" => to_string(union_type)}} + else + %{} + end + + AshPhoenix.Form.for_update(property, :update, as: "property", params: params) else AshPhoenix.Form.for_create(Mv.Membership.Property, :create, as: "property") end @@ -91,4 +239,13 @@ defmodule MvWeb.PropertyLive.Form do defp return_path("index", _property), do: ~p"/properties" defp return_path("show", property), do: ~p"/properties/#{property.id}" + + # Helper functions for selection options + defp property_type_options(property_types) do + Enum.map(property_types, &{&1.name, &1.id}) + end + + defp member_options(members) do + Enum.map(members, &{"#{&1.first_name} #{&1.last_name}", &1.id}) + end end diff --git a/test/mv_web/member_live/index_test.exs b/test/mv_web/member_live/index_test.exs index ce47a43..e3e77dc 100644 --- a/test/mv_web/member_live/index_test.exs +++ b/test/mv_web/member_live/index_test.exs @@ -35,8 +35,7 @@ defmodule MvWeb.MemberLive.IndexTest do test "shows translated flash message after creating a member in German", %{conn: conn} do conn = conn_with_oidc_user(conn) conn = Plug.Test.init_test_session(conn, locale: "de") - {:ok, view, _html} = live(conn, "/members") - view |> element("a", "Neues Mitglied") |> render_click() + {:ok, form_view, _html} = live(conn, "/members/new") form_data = %{ "member[first_name]" => "Max", @@ -44,15 +43,20 @@ defmodule MvWeb.MemberLive.IndexTest do "member[email]" => "max@example.com" } - view |> form("#member-form", form_data) |> render_submit() - assert has_element?(view, "#flash-group", "Mitglied erstellt erfolgreich") + # Submit form and follow the redirect to get the flash message + {:ok, index_view, _html} = + form_view + |> form("#member-form", form_data) + |> render_submit() + |> follow_redirect(conn, "/members") + + assert has_element?(index_view, "#flash-group", "Mitglied erstellt erfolgreich") end test "shows translated flash message after creating a member in English", %{conn: conn} do conn = conn_with_oidc_user(conn) conn = Plug.Test.init_test_session(conn, locale: "en") - {:ok, view, _html} = live(conn, "/members") - view |> element("a", "New Member") |> render_click() + {:ok, form_view, _html} = live(conn, "/members/new") form_data = %{ "member[first_name]" => "Max", @@ -60,7 +64,13 @@ defmodule MvWeb.MemberLive.IndexTest do "member[email]" => "max@example.com" } - view |> form("#member-form", form_data) |> render_submit() - assert has_element?(view, "#flash-group", "Member create successfully") + # Submit form and follow the redirect to get the flash message + {:ok, index_view, _html} = + form_view + |> form("#member-form", form_data) + |> render_submit() + |> follow_redirect(conn, "/members") + + assert has_element?(index_view, "#flash-group", "Member create successfully") end end