defmodule MicrowavepropWeb.RoverLocationsLive.Show do @moduledoc "Detail page for a single rover location, with a map + marker." use MicrowavepropWeb, :live_view alias Microwaveprop.Accounts.User alias Microwaveprop.Radio.Maidenhead alias Microwaveprop.Repo alias Microwaveprop.Rover alias Microwaveprop.Rover.Location @impl true def mount(%{"id" => id}, _session, socket) do case load_location(id) do %Location{} = loc -> {:ok, assign(socket, page_title: "Rover Location", location: loc, editing: false, working_lat: loc.lat, working_lon: loc.lon, grid: Maidenhead.from_latlon(loc.lat, loc.lon, 10) )} nil -> {:ok, socket |> put_flash(:error, "Location not found.") |> push_navigate(to: ~p"/rover-locations")} end end @impl true def handle_event("toggle_edit", _params, socket) do if can_modify?(socket.assigns[:current_scope], socket.assigns.location) do {:noreply, socket |> assign(editing: true) |> push_event("set_marker_draggable", %{draggable: true})} else {:noreply, put_flash(socket, :error, "You can only edit your own locations.")} end end def handle_event("cancel_edit", _params, socket) do loc = socket.assigns.location {:noreply, socket |> assign( editing: false, working_lat: loc.lat, working_lon: loc.lon, grid: Maidenhead.from_latlon(loc.lat, loc.lon, 10) ) |> push_event("reset_marker", %{lat: loc.lat, lon: loc.lon}) |> push_event("set_marker_draggable", %{draggable: false})} end # Hook fires this on `dragend` with the marker's new coordinates. # We only update the working preview — persistence waits for save. def handle_event("location_dragged", %{"lat" => lat, "lon" => lon}, socket) when is_number(lat) and is_number(lon) do {:noreply, assign(socket, working_lat: lat, working_lon: lon, grid: Maidenhead.from_latlon(lat, lon, 10) )} end def handle_event("save_edit", _params, socket) do case current_user(socket.assigns[:current_scope]) do %User{} = user -> attrs = %{lat: socket.assigns.working_lat, lon: socket.assigns.working_lon} case Rover.update_location(user, socket.assigns.location.id, attrs) do {:ok, updated} -> updated = Repo.preload(updated, :user) {:noreply, socket |> assign( location: updated, editing: false, working_lat: updated.lat, working_lon: updated.lon, grid: Maidenhead.from_latlon(updated.lat, updated.lon, 10) ) |> put_flash(:info, "Location updated.") |> push_event("set_marker_draggable", %{draggable: false})} {:error, :not_found} -> {:noreply, put_flash(socket, :error, "You can only edit your own locations.")} {:error, %Ecto.Changeset{}} -> {:noreply, put_flash(socket, :error, "Could not save those coordinates.")} end _ -> {:noreply, put_flash(socket, :error, "Sign in required.")} end end def handle_event("delete", _params, socket) do case current_user(socket.assigns[:current_scope]) do %User{} = user -> case Rover.delete_location(user, socket.assigns.location.id) do {:ok, _} -> {:noreply, socket |> put_flash(:info, "Location removed.") |> push_navigate(to: ~p"/rover-locations")} {:error, :not_found} -> {:noreply, put_flash(socket, :error, "You can only delete your own locations.")} end _ -> {:noreply, put_flash(socket, :error, "Sign in required.")} end end defp load_location(id) do case Ecto.UUID.cast(id) do {:ok, uuid} -> Location |> Repo.get(uuid) |> Repo.preload(:user) :error -> nil end end defp current_user(scope) do case scope do %{user: %User{} = user} -> user _ -> nil end end defp can_modify?(scope, %Location{user_id: user_id}) do case current_user(scope) do %User{is_admin: true} -> true %User{id: ^user_id} when not is_nil(user_id) -> true _ -> false end end defp status_label(:good), do: "Good" defp status_label(:bad), do: "Bad" defp status_label(_), do: "" defp status_class(:good), do: "badge badge-success" defp status_class(:bad), do: "badge badge-error" defp status_class(_), do: "badge" @impl true def render(assigns) do ~H""" <.header> Rover Location <:subtitle> {status_label(@location.status)} {@grid} Editing — drag the marker <:actions> <.link navigate={~p"/rover-locations"} class="btn btn-ghost btn-sm"> <.icon name="hero-arrow-left" class="w-4 h-4" /> Back
Grid
{@grid}
Coordinates
{Float.round(@working_lat, 6)}, {Float.round(@working_lon, 6)}
Status
{status_label(@location.status)}
Added
{Calendar.strftime(@location.inserted_at, "%Y-%m-%d %H:%M UTC")}
Submitted by
<.link navigate={~p"/u/#{@location.user.callsign}"} class="link link-primary font-mono" > {@location.user.callsign}

Notes

{@location.notes}

""" end end