defmodule MicrowavepropWeb.RoverLocationsLive do @moduledoc """ Globally-shared list of rover-friendly (or off-limits) parking locations. Everyone sees the list; only logged-in users can add or edit entries (and only the creator can edit/delete their own). """ use MicrowavepropWeb, :live_view alias Microwaveprop.Accounts.User alias Microwaveprop.Radio.Maidenhead alias Microwaveprop.Rover alias Microwaveprop.Rover.Location @impl true def mount(_params, _session, socket) do {:ok, assign(socket, page_title: "Rover Locations", locations: Rover.list_locations(), form: nil, editing_id: nil, expanded_id: nil )} end @impl true def handle_event("toggle_map", %{"id" => id}, socket) do new_id = if socket.assigns.expanded_id == id, do: nil, else: id {:noreply, assign(socket, expanded_id: new_id)} end def handle_event("new", _params, socket) do if user = current_user(socket) do form = blank_form(user) {:noreply, assign(socket, form: form, editing_id: nil)} else {:noreply, put_flash(socket, :error, "Sign in to add a location.")} end end def handle_event("edit", %{"id" => id}, socket) do case current_user(socket) do %User{id: user_id} -> case Enum.find(socket.assigns.locations, &(&1.id == id)) do %Location{user_id: ^user_id} = loc -> cs = Location.changeset(loc, %{}) {:noreply, assign(socket, form: to_form(cs), editing_id: id)} _ -> {:noreply, put_flash(socket, :error, "You can only edit your own locations.")} end _ -> {:noreply, put_flash(socket, :error, "Sign in to edit a location.")} end end def handle_event("cancel", _, socket) do {:noreply, assign(socket, form: nil, editing_id: nil)} end def handle_event("validate", %{"location" => params}, socket) do base = if socket.assigns.editing_id, do: location_for_edit(socket), else: %Location{} cs = base |> Location.changeset(params) |> Map.put(:action, :validate) {:noreply, assign(socket, form: to_form(cs))} end def handle_event("save", %{"location" => params}, socket) do user = current_user(socket) cond do is_nil(user) -> {:noreply, put_flash(socket, :error, "Sign in required.")} socket.assigns.editing_id -> save_update(socket, user, params) true -> save_create(socket, user, params) end end def handle_event("delete", %{"id" => id}, socket) do case current_user(socket) do %User{} = user -> case Rover.delete_location(user, id) do {:ok, _} -> {:noreply, socket |> assign(locations: Rover.list_locations()) |> put_flash(:info, "Location removed.")} {: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 save_create(socket, user, params) do case Rover.create_location(user, params) do {:ok, _loc} -> {:noreply, socket |> assign(form: nil, editing_id: nil, locations: Rover.list_locations()) |> put_flash(:info, "Location added.")} {:error, cs} -> {:noreply, assign(socket, form: to_form(cs))} end end defp save_update(socket, user, params) do case Rover.update_location(user, socket.assigns.editing_id, params) do {:ok, _loc} -> {:noreply, socket |> assign(form: nil, editing_id: nil, locations: Rover.list_locations()) |> put_flash(:info, "Location updated.")} {:error, :not_found} -> {:noreply, put_flash(socket, :error, "You can only edit your own locations.")} {:error, cs} -> {:noreply, assign(socket, form: to_form(cs))} end end defp location_for_edit(socket) do Enum.find(socket.assigns.locations, &(&1.id == socket.assigns.editing_id)) || %Location{} end defp blank_form(_user) do %Location{} |> Location.changeset(%{}) |> to_form() end defp current_user(%Phoenix.LiveView.Socket{assigns: assigns}), do: scope_user(assigns) defp current_user(assigns) when is_map(assigns), do: scope_user(assigns) defp scope_user(assigns) do case assigns[:current_scope] do %{user: %User{} = user} -> user _ -> nil end end defp can_edit?(_assigns, %Location{user_id: nil}), do: false defp can_edit?(assigns, %Location{user_id: uid}) do case current_user(assigns) do %User{id: ^uid} -> true _ -> false end end defp status_label(:ideal), do: "Ideal" defp status_label(:off_limits), do: "Off Limits" defp status_class(:ideal), do: "badge badge-success" defp status_class(:off_limits), do: "badge badge-error" @impl true def render(assigns) do ~H"""

Rover Locations

Community-shared parking spots for portable rover ops.

Sign in to add or edit locations.

{if @editing_id, do: "Edit location", else: "New location"}

<.form for={@form} phx-change="validate" phx-submit="save" id="location-form">
<.input field={@form[:lat]} type="number" step="any" label="Latitude" placeholder="32.5" /> <.input field={@form[:lon]} type="number" step="any" label="Longitude" placeholder="-97.5" /> <.input field={@form[:status]} type="select" label="Status" options={[{"Ideal", :ideal}, {"Off Limits", :off_limits}]} />
<.input field={@form[:notes]} type="textarea" label="Notes" rows="3" placeholder="Trail access, line-of-sight notes, contact info, etc." />
No locations yet. Be the first to share one.
""" end end