defmodule MicrowavepropWeb.BeaconLive.Form do @moduledoc false use MicrowavepropWeb, :live_view alias Microwaveprop.Beacons alias Microwaveprop.Beacons.Beacon @impl true def render(assigns) do ~H""" <.header> {@page_title} <:subtitle> Enter either a grid or lat/lon — whichever you leave blank is filled in from the other. <.form for={@form} id="beacon-form" phx-change="validate" phx-submit="save"> <.input field={@form[:frequency_mhz]} type="text" label="Frequency (MHz)" inputmode="decimal" phx-hook="CommaNumber" required /> <.input field={@form[:callsign]} type="text" label="Call" required /> <.input field={@form[:grid]} type="text" label="Grid" /> <.input field={@form[:lat]} type="number" label="Latitude" step="any" /> <.input field={@form[:lon]} type="number" label="Longitude" step="any" /> <.input field={@form[:power_mw]} type="number" label="TX power (EIRP) (mW)" step="any" required /> <.input field={@form[:height_ft]} type="number" label="Height above ground (ft)" required /> <.input field={@form[:bearing]} type="text" label="Bearing" placeholder="omni or 0-360 degrees" /> <.input field={@form[:beamwidth_deg]} type="number" label="Beamwidth (degrees)" step="any" placeholder="Leave blank for omni" /> <.input field={@form[:keying]} type="select" label="Keying" options={Beacon.keying_options()} required /> <.input field={@form[:on_the_air]} type="checkbox" label="On the air" /> <.input field={@form[:notes]} type="textarea" label="Notes" /> """ end @impl true def mount(params, _session, socket) do {:ok, socket |> assign(:return_to, return_to(params["return_to"])) |> apply_action(socket.assigns.live_action, params)} end defp return_to("show"), do: "show" defp return_to(_), do: "index" defp apply_action(socket, :edit, %{"id" => id}) do beacon = Beacons.get_beacon!(id) socket |> assign(:page_title, "Edit beacon") |> assign(:beacon, beacon) |> assign(:form, to_form(Beacons.change_beacon(beacon))) end defp apply_action(socket, :new, _params) do beacon = %Beacon{} socket |> assign(:page_title, "New beacon") |> assign(:beacon, beacon) |> assign(:form, to_form(Beacons.change_beacon(beacon))) end @impl true def handle_event("validate", %{"beacon" => beacon_params}, socket) do changeset = Beacons.change_beacon(socket.assigns.beacon, strip_commas(beacon_params)) {:noreply, assign(socket, form: to_form(changeset, action: :validate))} end def handle_event("save", %{"beacon" => beacon_params}, socket) do save_beacon(socket, socket.assigns.live_action, strip_commas(beacon_params)) end defp strip_commas(params) do params |> Map.update("frequency_mhz", nil, fn v when is_binary(v) -> String.replace(v, ",", "") v -> v end) |> Map.update("height_ft", nil, fn v when is_binary(v) -> String.replace(v, ~r/\.0*$/, "") v -> v end) end defp save_beacon(socket, :edit, beacon_params) do case Beacons.update_beacon(socket.assigns.beacon, beacon_params) do {:ok, beacon} -> {:noreply, socket |> put_flash(:info, "Beacon updated") |> push_navigate(to: return_path(socket.assigns.return_to, beacon))} {:error, %Ecto.Changeset{} = changeset} -> {:noreply, assign(socket, form: to_form(changeset))} end end defp save_beacon(socket, :new, beacon_params) do user = current_user(socket.assigns.current_scope) case Beacons.create_beacon(user, beacon_params) do {:ok, beacon} -> flash = if user, do: "Beacon submitted — pending admin approval.", else: "Thanks! Your beacon has been submitted and is awaiting admin approval." {:noreply, socket |> put_flash(:info, flash) |> push_navigate(to: return_path(socket.assigns.return_to, beacon))} {:error, %Ecto.Changeset{} = changeset} -> {:noreply, assign(socket, form: to_form(changeset))} end end defp current_user(%{user: user}), do: user defp current_user(_), do: nil defp return_path("index", _beacon), do: ~p"/beacons" defp return_path("show", beacon), do: ~p"/beacons/#{beacon}" end