From 5761e5ee1f98a60988eff5063c699b891f27db6d Mon Sep 17 00:00:00 2001 From: Moritz Date: Thu, 17 Jul 2025 16:11:49 +0200 Subject: [PATCH] feat: migration to phoenix 1.8 - fix PropertyLive.Form --- lib/mv_web/live/property_live/form.ex | 171 ++++++++++++++++++++++++-- 1 file changed, 164 insertions(+), 7 deletions(-) diff --git a/lib/mv_web/live/property_live/form.ex b/lib/mv_web/live/property_live/form.ex index 2987b3e..3535987 100644 --- a/lib/mv_web/live/property_live/form.ex +++ b/lib/mv_web/live/property_live/form.ex @@ -11,9 +11,35 @@ 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 +50,106 @@ 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