defmodule MicrowavepropWeb.MapLive do @moduledoc false use MicrowavepropWeb, :live_view alias Microwaveprop.Propagation alias Microwaveprop.Propagation.BandConfig @default_band 10_000 @initial_bounds %{ "south" => 29.5, "north" => 36.3, "west" => -101.5, "east" => -92.5 } @impl true def mount(_params, _session, socket) do bands = BandConfig.all_bands() valid_time = Propagation.latest_valid_time() initial_scores = Propagation.latest_scores(@default_band, @initial_bounds) if connected?(socket) do Phoenix.PubSub.subscribe(Microwaveprop.PubSub, "propagation:updated") end {:ok, assign(socket, page_title: "Propagation Map", bands: bands, selected_band: @default_band, initial_scores_json: Jason.encode!(initial_scores), valid_time: valid_time, bounds: @initial_bounds, grid_visible: false )} end @impl true def handle_event("select_band", %{"value" => band}, socket) do band = if is_binary(band), do: String.to_integer(band), else: band scores = Propagation.latest_scores(band, socket.assigns.bounds) socket = socket |> assign(:selected_band, band) |> push_event("update_scores", %{scores: scores}) |> push_event("update_band_info", %{band_info: band_info(band)}) {:noreply, socket} end def handle_event("toggle_grid", _params, socket) do visible = !socket.assigns.grid_visible socket = socket |> assign(:grid_visible, visible) |> push_event("toggle_grid", %{visible: visible}) {:noreply, socket} end def handle_event("map_bounds", bounds, socket) do scores = Propagation.latest_scores(socket.assigns.selected_band, bounds) socket = socket |> assign(:bounds, bounds) |> push_event("update_scores", %{scores: scores}) {:noreply, socket} end @impl true def handle_info({:propagation_updated, valid_time}, socket) do scores = Propagation.latest_scores(socket.assigns.selected_band, socket.assigns.bounds) socket = socket |> assign(:valid_time, valid_time) |> push_event("update_scores", %{scores: scores}) {:noreply, socket} end defp band_info(band_mhz) do config = BandConfig.get(band_mhz) %{ band_label: config.label, typical_range_km: config.typical_range_km, extended_range_km: config.extended_range_km, exceptional_range_km: config.exceptional_range_km } end defp time_ago(dt) do seconds = DateTime.diff(DateTime.utc_now(), dt) cond do seconds < 60 -> "just now" seconds < 3600 -> "#{div(seconds, 60)}m ago" seconds < 86_400 -> "#{div(seconds, 3600)}h ago" true -> "#{div(seconds, 86_400)}d ago" end end defp selected_label(bands, selected_band) do case Enum.find(bands, &(&1.freq_mhz == selected_band)) do nil -> "Select Band" band -> band.label end end @impl true def render(assigns) do ~H"""