defmodule MicrowavepropWeb.Admin.ContactEditLive do @moduledoc false use MicrowavepropWeb, :live_view alias Microwaveprop.Radio alias Microwaveprop.Radio.EditNotifier @impl true def mount(_params, _session, socket) do edits = Radio.list_pending_edits() {:ok, assign(socket, page_title: "Review Contact Edits", edits: edits, reviewing: nil, admin_note: "" )} end @impl true def handle_event("review", %{"id" => id}, socket) do edit = Radio.get_contact_edit!(id) {:noreply, assign(socket, reviewing: edit, admin_note: "")} end def handle_event("cancel_review", _params, socket) do {:noreply, assign(socket, reviewing: nil, admin_note: "")} end def handle_event("update_note", %{"note" => note}, socket) do {:noreply, assign(socket, admin_note: note)} end def handle_event("approve", _params, socket) do edit = socket.assigns.reviewing admin = socket.assigns.current_scope.user note = normalize_note(socket.assigns.admin_note) case Radio.approve_edit(edit, admin, note) do {:ok, approved} -> EditNotifier.deliver_edit_approved(approved) {:noreply, socket |> assign(reviewing: nil, admin_note: "", edits: Radio.list_pending_edits()) |> put_flash(:info, "Edit approved and applied.")} {:error, _} -> {:noreply, put_flash(socket, :error, "Failed to approve edit.")} end end def handle_event("reject", _params, socket) do edit = socket.assigns.reviewing admin = socket.assigns.current_scope.user note = normalize_note(socket.assigns.admin_note) case Radio.reject_edit(edit, admin, note) do {:ok, rejected} -> EditNotifier.deliver_edit_rejected(rejected) {:noreply, socket |> assign(reviewing: nil, admin_note: "", edits: Radio.list_pending_edits()) |> put_flash(:info, "Edit rejected.")} {:error, _} -> {:noreply, put_flash(socket, :error, "Failed to reject edit.")} end end defp normalize_note(""), do: nil defp normalize_note(note), do: String.trim(note) defp format_band(nil), do: "?" defp format_band(band) do mhz = Decimal.to_integer(band) if mhz >= 1000, do: "#{div(mhz, 1000)} GHz", else: "#{mhz} MHz" end defp format_ts(nil), do: "?" defp format_ts(ts), do: Calendar.strftime(ts, "%Y-%m-%d %H:%M UTC") defp changed_fields_summary(proposed_changes) do proposed_changes |> Map.keys() |> Enum.sort() |> Enum.join(", ") end defp field_label("station1"), do: "Station 1" defp field_label("station2"), do: "Station 2" defp field_label("grid1"), do: "Grid 1" defp field_label("grid2"), do: "Grid 2" defp field_label("band"), do: "Band" defp field_label("mode"), do: "Mode" defp field_label("qso_timestamp"), do: "Timestamp" defp field_label(other), do: other defp current_value(contact, "station1"), do: contact.station1 defp current_value(contact, "station2"), do: contact.station2 defp current_value(contact, "grid1"), do: contact.grid1 defp current_value(contact, "grid2"), do: contact.grid2 defp current_value(contact, "band"), do: if(contact.band, do: Decimal.to_string(contact.band)) defp current_value(contact, "mode"), do: contact.mode defp current_value(contact, "qso_timestamp"), do: if(contact.qso_timestamp, do: format_ts(contact.qso_timestamp)) defp current_value(_contact, _), do: "?" defp format_proposed("band", val), do: to_string(val) defp format_proposed("qso_timestamp", val) when is_binary(val), do: val defp format_proposed(_field, val), do: to_string(val) @impl true def render(assigns) do ~H""" <.header> Review Contact Edits <:subtitle>{length(@edits)} pending <:actions> <.link navigate={~p"/admin/backfill"} class="btn btn-sm btn-ghost"> <.icon name="hero-arrow-left" class="w-4 h-4" /> Admin <%= if @reviewing do %>

Review Edit from {@reviewing.user.callsign}

Contact: <.link navigate={~p"/contacts/#{@reviewing.contact.id}"} class="link link-primary"> {@reviewing.contact.station1} / {@reviewing.contact.station2} · {format_band(@reviewing.contact.band)} · {format_ts( @reviewing.contact.qso_timestamp )}
<%= for {field, proposed_val} <- Enum.sort(@reviewing.proposed_changes) do %> <% end %>
Field Current Proposed
{field_label(field)} {current_value(@reviewing.contact, field)} {format_proposed(field, proposed_val)}
<% end %> <%= if @edits == [] do %>
<.icon name="hero-check-circle" class="w-12 h-12 mx-auto mb-2" />

No pending edits to review.

<% else %>
<%= for edit <- @edits do %> <% end %>
Contact Submitted By Fields Changed Submitted
<.link navigate={~p"/contacts/#{edit.contact.id}"} class="link link-primary"> {edit.contact.station1} / {edit.contact.station2}
{format_band(edit.contact.band)}
{edit.user.callsign} {changed_fields_summary(edit.proposed_changes)} {format_ts(edit.inserted_at)}
<% end %>
""" end end