diff --git a/lib/microwaveprop_web/live/skewt_live.ex b/lib/microwaveprop_web/live/skewt_live.ex index 124fe6b7..920fbb6e 100644 --- a/lib/microwaveprop_web/live/skewt_live.ex +++ b/lib/microwaveprop_web/live/skewt_live.ex @@ -30,7 +30,8 @@ defmodule MicrowavepropWeb.SkewtLive do selected_valid_time: nil, profile: nil, derived: nil, - svg: nil + svg: nil, + loading?: false )} end @@ -52,8 +53,55 @@ defmodule MicrowavepropWeb.SkewtLive do {:noreply, push_patch(socket, to: ~p"/skewt?#{params}")} end + @impl true + def handle_async(:load_skewt, {:ok, {:ok, result}}, socket) do + {:noreply, + assign(socket, + location: result.location, + error: nil, + valid_times: result.valid_times, + selected_valid_time: result.selected_valid_time, + profile: result.profile, + derived: result.derived, + svg: result.svg, + loading?: false + )} + end + + def handle_async(:load_skewt, {:ok, {:error, reason}}, socket) do + {:noreply, + assign(socket, + location: nil, + error: reason, + valid_times: [], + selected_valid_time: nil, + profile: nil, + derived: nil, + svg: nil, + loading?: false + )} + end + + def handle_async(:load_skewt, {:exit, reason}, socket) do + require Logger + + Logger.warning("SkewtLive async exit: #{inspect(reason)}") + + {:noreply, + assign(socket, + error: "Sorry, something went wrong loading this profile. Try again.", + loading?: false + )} + end + # ── Refresh logic ────────────────────────────────────────────────── + # The page chrome (header + search bar) renders synchronously on + # mount; everything else (geocoding, HRRR file/DB read, sounding + # parameter derivation, SVG render) lands via `:load_skewt` async. + # Repeated calls under the same key cancel any in-flight task, so + # rapid URL patches don't race. + defp refresh(socket, "", _time) do assign(socket, query: "", @@ -63,48 +111,45 @@ defmodule MicrowavepropWeb.SkewtLive do selected_valid_time: nil, profile: nil, derived: nil, - svg: nil + svg: nil, + loading?: false ) end defp refresh(socket, query, requested_time) do + socket + |> assign( + query: query, + error: nil, + loading?: true + ) + |> start_async(:load_skewt, fn -> resolve_and_load(query, requested_time) end) + end + + defp resolve_and_load(query, requested_time) do case SkewtLocationResolver.resolve(query) do {:ok, %{lat: lat, lon: lon} = location} -> valid_times = available_valid_times(lat, lon) - chosen = pick_valid_time(valid_times, requested_time) {profile, derived, svg} = case chosen do - nil -> - {nil, nil, nil} - - time -> - load_profile(time, lat, lon) + nil -> {nil, nil, nil} + time -> load_profile(time, lat, lon) end - assign(socket, - query: query, - location: location, - error: nil, - valid_times: valid_times, - selected_valid_time: chosen, - profile: profile, - derived: derived, - svg: svg - ) + {:ok, + %{ + location: location, + valid_times: valid_times, + selected_valid_time: chosen, + profile: profile, + derived: derived, + svg: svg + }} {:error, reason} -> - assign(socket, - query: query, - location: nil, - error: reason, - valid_times: [], - selected_valid_time: nil, - profile: nil, - derived: nil, - svg: nil - ) + {:error, reason} end end @@ -284,6 +329,13 @@ defmodule MicrowavepropWeb.SkewtLive do <% end %> + <%= if @loading? do %> +