Height in feet doesn't need decimal precision. Migrates the DB column, updates schema type, and strips trailing .0 from form input so the integer cast succeeds.
166 lines
4.9 KiB
Elixir
166 lines
4.9 KiB
Elixir
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"""
|
|
<Layouts.app flash={@flash} current_scope={@current_scope}>
|
|
<.header>
|
|
{@page_title}
|
|
<:subtitle>
|
|
Enter either a grid or lat/lon — whichever you leave blank is filled in
|
|
from the other.
|
|
</:subtitle>
|
|
</.header>
|
|
|
|
<.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" />
|
|
<footer>
|
|
<.button phx-disable-with="Saving..." variant="primary">Save Beacon</.button>
|
|
<.button navigate={return_path(@return_to, @beacon)}>Cancel</.button>
|
|
</footer>
|
|
</.form>
|
|
</Layouts.app>
|
|
"""
|
|
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) -> v |> String.replace(~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
|