prop/lib/microwaveprop_web/live/beacon_live/index.ex
Graham McIntire 67e095bd47 Label beacon TX power as EIRP
The power_mw field represents the beacon's effective radiated power,
not just transmitter output. Relabel it as "TX power (EIRP)" on the
form and detail list, "EIRP (mW)" in the index, and drop the now-
meaningless tx_gain_dbi constant in RangeEstimate since the stored
value already includes antenna gain.
2026-04-08 13:32:32 -05:00

86 lines
2.9 KiB
Elixir

defmodule MicrowavepropWeb.BeaconLive.Index do
@moduledoc false
use MicrowavepropWeb, :live_view
alias Microwaveprop.Beacons
@impl true
def render(assigns) do
~H"""
<Layouts.app flash={@flash} current_scope={@current_scope} max_width="max-w-6xl">
<.header>
Beacons
<:subtitle>Microwave beacons tracked by NTMS.</:subtitle>
<:actions>
<.button :if={admin?(@current_scope)} variant="primary" navigate={~p"/beacons/new"}>
<.icon name="hero-plus" /> New Beacon
</.button>
</:actions>
</.header>
<.table
id="beacons"
rows={@streams.beacons}
row_click={fn {_id, beacon} -> JS.navigate(~p"/beacons/#{beacon}") end}
>
<:col :let={{_id, beacon}} label="Frequency (MHz)">{beacon.frequency_mhz}</:col>
<:col :let={{_id, beacon}} label="Call">{beacon.callsign}</:col>
<:col :let={{_id, beacon}} label="Grid">{beacon.grid}</:col>
<:col :let={{_id, beacon}} label="Lat">{beacon.lat}</:col>
<:col :let={{_id, beacon}} label="Lon">{beacon.lon}</:col>
<:col :let={{_id, beacon}} label="EIRP (mW)">{beacon.power_mw}</:col>
<:col :let={{_id, beacon}} label="Height AGL (ft)">{beacon.height_ft}</:col>
<:col :let={{_id, beacon}} label="On air">
<span class={["badge badge-sm", beacon.on_the_air && "badge-success" || "badge-ghost"]}>
{if beacon.on_the_air, do: "Yes", else: "No"}
</span>
</:col>
<:action :let={{_id, beacon}}>
<div class="sr-only">
<.link navigate={~p"/beacons/#{beacon}"}>Show</.link>
</div>
<.link :if={admin?(@current_scope)} navigate={~p"/beacons/#{beacon}/edit"}>Edit</.link>
</:action>
<:action :let={{id, beacon}}>
<.link
:if={admin?(@current_scope)}
phx-click={JS.push("delete", value: %{id: beacon.id}) |> hide("##{id}")}
data-confirm="Delete this beacon?"
>
Delete
</.link>
</:action>
</.table>
</Layouts.app>
"""
end
@impl true
def mount(_params, _session, socket) do
if connected?(socket), do: Beacons.subscribe_beacons()
{:ok,
socket
|> assign(:page_title, "Beacons")
|> stream(:beacons, Beacons.list_beacons())}
end
@impl true
def handle_event("delete", %{"id" => id}, socket) do
if admin?(socket.assigns.current_scope) do
beacon = Beacons.get_beacon!(id)
{:ok, _} = Beacons.delete_beacon(beacon)
{:noreply, stream_delete(socket, :beacons, beacon)}
else
{:noreply, put_flash(socket, :error, "Admins only.")}
end
end
@impl true
def handle_info({type, %Microwaveprop.Beacons.Beacon{}}, socket) when type in [:created, :updated, :deleted] do
{:noreply, stream(socket, :beacons, Beacons.list_beacons(), reset: true)}
end
defp admin?(%{user: %{is_admin: true}}), do: true
defp admin?(_), do: false
end