From ba0f1161a73b52ad2a855a7580c5430110c9998a Mon Sep 17 00:00:00 2001 From: Graham McIntire Date: Wed, 8 Apr 2026 16:23:46 -0500 Subject: [PATCH] Beacon improvements: anon submit, notes, /map nav, admin backfill - Anonymous users can submit beacons (held pending admin approval) - Added notes field to beacons (textarea on form, shown on detail page) - Added Beacons link to /map sidebar nav (mobile + desktop), removed stale Rover Planner link - Moved /backfill to /admin/backfill under the admin live_session - Beacon detail map zooms in two extra levels after fitBounds --- assets/js/beacon_map_hook.js | 4 ++- lib/microwaveprop/beacons.ex | 18 ++++++++--- lib/microwaveprop/beacons/beacon.ex | 4 ++- .../live/beacon_live/form.ex | 13 ++++++-- .../live/beacon_live/index.ex | 9 +----- .../live/beacon_live/show.ex | 3 ++ lib/microwaveprop_web/live/map_live.ex | 6 ++-- lib/microwaveprop_web/router.ex | 15 ++++------ .../20260408212103_add_notes_to_beacons.exs | 9 ++++++ test/microwaveprop/beacons_test.exs | 14 +++++++++ .../live/beacon_live_test.exs | 30 ++++++++++++++++--- 11 files changed, 93 insertions(+), 32 deletions(-) create mode 100644 priv/repo/migrations/20260408212103_add_notes_to_beacons.exs diff --git a/assets/js/beacon_map_hook.js b/assets/js/beacon_map_hook.js index 4b6d4455..9302d57d 100644 --- a/assets/js/beacon_map_hook.js +++ b/assets/js/beacon_map_hook.js @@ -56,9 +56,11 @@ export const BeaconMap = { offset: [0, -10] }) - // Fit to the rendered cells (initial view already set above). + // Fit to the rendered cells (initial view already set above), then zoom + // in two steps so the beacon's immediate surroundings are visible. if (allBounds.length > 0) { map.fitBounds(L.latLngBounds(allBounds), {padding: [20, 20]}) + map.setZoom(map.getZoom() + 2) } setTimeout(() => map.invalidateSize(), 50) diff --git a/lib/microwaveprop/beacons.ex b/lib/microwaveprop/beacons.ex index e0f917af..1d3ece79 100644 --- a/lib/microwaveprop/beacons.ex +++ b/lib/microwaveprop/beacons.ex @@ -1,8 +1,8 @@ defmodule Microwaveprop.Beacons do @moduledoc """ - The Beacons context. Any authenticated user can submit a beacon, - but submissions are held as unapproved until an admin approves - them. Only approved beacons appear in the public list. + The Beacons context. Anyone can submit a beacon — authenticated or not — + but submissions are held as unapproved until an admin approves them. + Only approved beacons appear in the public list. """ import Ecto.Query, warn: false @@ -50,8 +50,11 @@ defmodule Microwaveprop.Beacons do def get_beacon!(id), do: Repo.get!(Beacon, id) @doc """ - Creates a beacon. The user is recorded on the row as the creator. + Creates a beacon. When a user is provided they are recorded as the + creator; anonymous submissions pass `nil` and leave `user_id` unset. """ + def create_beacon(user, attrs) + def create_beacon(%User{} = user, attrs) do %Beacon{user_id: user.id} |> Beacon.changeset(attrs) @@ -59,6 +62,13 @@ defmodule Microwaveprop.Beacons do |> broadcast_if_ok(:created) end + def create_beacon(nil, attrs) do + %Beacon{} + |> Beacon.changeset(attrs) + |> Repo.insert() + |> broadcast_if_ok(:created) + end + @doc "Updates a beacon." def update_beacon(%Beacon{} = beacon, attrs) do beacon diff --git a/lib/microwaveprop/beacons/beacon.ex b/lib/microwaveprop/beacons/beacon.ex index 514b081c..17046c28 100644 --- a/lib/microwaveprop/beacons/beacon.ex +++ b/lib/microwaveprop/beacons/beacon.ex @@ -28,6 +28,7 @@ defmodule Microwaveprop.Beacons.Beacon do field :on_the_air, :boolean, default: true field :approved, :boolean, default: false field :keying, :string, default: "on_off" + field :notes, :string field :user_id, :binary_id timestamps(type: :utc_datetime) @@ -46,7 +47,8 @@ defmodule Microwaveprop.Beacons.Beacon do :power_mw, :height_ft, :on_the_air, - :keying + :keying, + :notes ]) |> update_change(:callsign, fn cs -> cs && String.upcase(String.trim(cs)) end) |> maybe_fill_latlon() diff --git a/lib/microwaveprop_web/live/beacon_live/form.ex b/lib/microwaveprop_web/live/beacon_live/form.ex index d5500a15..033ed018 100644 --- a/lib/microwaveprop_web/live/beacon_live/form.ex +++ b/lib/microwaveprop_web/live/beacon_live/form.ex @@ -51,6 +51,7 @@ defmodule MicrowavepropWeb.BeaconLive.Form do required /> <.input field={@form[:on_the_air]} type="checkbox" label="On the air" /> + <.input field={@form[:notes]} type="textarea" label="Notes" />