fix(weather): tolerate stale map_bounds from /map → /weather navigation

/map's PropagationMap hook pushes `map_bounds` on every moveend/zoomend.
When a user live-navigates from /map to /weather, an in-flight bounds
push can land on the new WeatherMapLive (the same LV channel survives
the navigation), and WeatherMapLive's `handle_event/3` had no clause
for it — the LV process crashed with FunctionClauseError, taking the
user's session down.

WeatherMapLive doesn't need viewport bounds — the /weather/cells HTTP
endpoint reads them off the URL the client builds — so the safe fix is
a no-op handler. Tested.
This commit is contained in:
Graham McIntire 2026-04-30 17:34:38 -05:00
parent b14c87126c
commit 1f8765f757
No known key found for this signature in database
GPG key ID: F4ABF488E6029E59
2 changed files with 30 additions and 0 deletions

View file

@ -232,6 +232,14 @@ defmodule MicrowavepropWeb.WeatherMapLive do
end
end
# `/map`'s PropagationMap hook pushes `map_bounds` on moveend/zoomend.
# When a user navigates /map → /weather, an in-flight bounds push from
# the old hook can land on the new WeatherMapLive (LV reuses sockets
# across live navigation). WeatherMapLive doesn't need bounds — the
# /weather/cells HTTP endpoint computes them client-side — so swallow
# the event instead of crashing the LV process.
def handle_event("map_bounds", _params, socket), do: {:noreply, socket}
def handle_event("point_detail", %{"lat" => lat, "lon" => lon}, socket) do
detail =
if socket.assigns.valid_time do

View file

@ -319,4 +319,26 @@ defmodule MicrowavepropWeb.WeatherMapLiveTest do
assert html =~ ~s(data-selected-layer=)
end
end
describe "stale client events" do
test "ignores `map_bounds` from a stale browser tab without crashing", %{conn: conn} do
# A user can navigate /map → /weather while the propagation map's
# JS hook still has a queued moveend → pushEvent("map_bounds", …)
# in flight. The WeatherMapLive doesn't need viewport bounds (it
# fetches /weather/cells over HTTP using the *client* viewport),
# but it MUST tolerate the rogue event instead of crashing the
# LV process.
{:ok, lv, _html} = live(conn, ~p"/weather")
bounds = %{
"south" => 32.57,
"north" => 33.62,
"west" => -97.37,
"east" => -95.76
}
html = render_hook(lv, "map_bounds", bounds)
assert is_binary(html)
end
end
end