defmodule MvWeb.PropertyLive.Form do use MvWeb, :live_view @impl true def render(assigns) do ~H""" <.header> {@page_title} <:subtitle>{gettext("Use this form to manage property records in your database.")} <.form for={@form} id="property-form" phx-change="validate" phx-submit="save"> <.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")} <.button navigate={return_path(@return_to, @property)}>{gettext("Cancel")}
""" 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) |> 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 defp return_to("show"), do: "show" defp return_to(_), do: "index" @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, 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 # 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}) action = case socket.assigns.form.source.type do :create -> gettext("create") :update -> gettext("update") other -> to_string(other) end socket = socket |> put_flash(:info, gettext("Property %{action} successfully", action: action)) |> push_navigate(to: return_path(socket.assigns.return_to, property)) {:noreply, socket} {:error, form} -> {:noreply, assign(socket, form: form)} end end defp notify_parent(msg), do: send(self(), {__MODULE__, msg}) defp assign_form(%{assigns: %{property: property}} = socket) do form = if property do # 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 assign(socket, form: to_form(form)) end 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