prop/lib/microwaveprop_web/live/rover_locations_live/map.ex
Graham McIntire 3c9fbcdec6
feat(rover-locations): /rover-locations/map page with Maidenhead overlay
Adds a full-screen map view rendering every Good rover-location as a
green circle marker (popup links to the detail page). Uses the standard
OSM/Satellite + Maidenhead grid overlay pattern. Bad locations are
excluded. Adds a Map button next to Add location on the index header.
2026-05-03 11:14:58 -05:00

68 lines
1.7 KiB
Elixir

defmodule MicrowavepropWeb.RoverLocationsLive.Map do
@moduledoc """
`/rover-locations/map` — full-screen map of every rover-location
marked Good. Each marker links to its detail page.
"""
use MicrowavepropWeb, :live_view
import Ecto.Query
alias Microwaveprop.Radio.Maidenhead
alias Microwaveprop.Repo
alias Microwaveprop.Rover.Location
@impl true
def mount(_params, _session, socket) do
points =
Location
|> where([l], l.status == :good)
|> Repo.all()
|> Enum.map(&point_payload/1)
{:ok,
assign(socket,
page_title: "Rover Locations Map",
points: points,
points_json: Jason.encode!(points)
)}
end
defp point_payload(%Location{} = loc) do
%{
id: loc.id,
lat: loc.lat,
lon: loc.lon,
grid: Maidenhead.from_latlon(loc.lat, loc.lon, 6),
notes: loc.notes
}
end
@impl true
def render(assigns) do
~H"""
<Layouts.app flash={@flash} current_scope={@current_scope} max_width="max-w-7xl">
<.header>
Rover Locations Map
<:subtitle>
{length(@points)} good location{if length(@points) == 1, do: "", else: "s"} —
click a marker for details.
</:subtitle>
<:actions>
<.link navigate={~p"/rover-locations"} class="btn btn-ghost btn-sm">
<.icon name="hero-list-bullet" class="w-4 h-4" /> List
</.link>
</:actions>
</.header>
<div
id="rover-locations-map"
phx-hook="RoverLocationsMap"
phx-update="ignore"
data-points={@points_json}
class="h-[75vh] rounded border border-base-300 z-0"
>
</div>
</Layouts.app>
"""
end
end