defmodule VaccinsWeb.IndexLive do use VaccinsWeb, :live_view alias Vaccins.{LocationStore, Search} @refresh_period_ms 5 * 1000 @impl true def mount(_params, %{"is_local?" => is_local?}, socket) do locations = LocationStore.get_locations() {:ok, socket |> assign( noob_mode: false, is_local?: is_local?, locations: locations, locations_with_early_slots: MapSet.new(), locations_with_slots: MapSet.new(), pending: %{}, location_cs: LocationStore.LocationRaw.changeset(%{}), display_cs: false ) |> set_title() |> trigger_global_refresh |> trigger_periodic_refresh} end defp set_title(socket = %{assigns: %{locations_with_early_slots: early}}) do if early |> Enum.empty?(), do: socket |> assign(page_title: "Disponibilités vaccins"), else: socket |> assign(page_title: "(!!) Disponibilités vaccins") end @impl true def handle_params(params, _url, socket) when params == %{}, do: {:noreply, socket} def handle_params(%{"noob" => _}, _url, socket), do: {:noreply, socket |> assign(noob_mode: true)} @impl true def handle_event("add_location", %{"location_raw" => params}, socket) do case params |> LocationStore.add_location() do :ok -> {:noreply, socket |> push_patch(to: Routes.index_path(socket, :index))} {:error, cs} -> {:noreply, socket |> assign(location_cs: cs)} end end def handle_event("reload_file", _, socket) do :ok = LocationStore.reload() {:noreply, socket |> assign(locations: LocationStore.get_locations())} end def handle_event("trigger_all", _, socket) do {:noreply, socket |> trigger_global_refresh} end def handle_event("toggle_form", _, socket = %{assigns: %{display_cs: display}}), do: {:noreply, socket |> assign(display_cs: not display)} def handle_event("trigger_noob_mode", _, socket = %{assigns: %{noob_mode: true}}), do: {:noreply, socket |> assign(noob_mode: false) |> push_patch(to: Routes.index_path(socket, :index))} def handle_event("trigger_noob_mode", _, socket = %{assigns: %{noob_mode: false}}), do: {:noreply, socket |> push_patch(to: Routes.index_path(socket, :index, noob: true))} @impl true def handle_info({:query_sent, id, ref}, socket = %{assigns: %{pending: pending}}) do {:noreply, socket |> assign(pending: pending |> Map.put(ref, id))} end def handle_info(:periodic_refresh, socket = %{assigns: %{display_cs: false}}), do: {:noreply, socket |> trigger_global_refresh |> trigger_periodic_refresh} def handle_info(:periodic_refresh, socket = %{assigns: %{display_cs: true}}), do: {:noreply, socket |> trigger_periodic_refresh} def handle_info({:location_has_slots, id, true}, socket) do {:noreply, socket |> update(:locations_with_early_slots, &(&1 |> MapSet.put(id))) |> set_title} end def handle_info({:location_has_slots, id, false}, socket) do {:noreply, socket |> update(:locations_with_slots, &(&1 |> MapSet.put(id))) |> set_title} end def handle_info({:location_no_more_slots, id}, socket) do {:noreply, socket |> update(:locations_with_slots, &(&1 |> MapSet.delete(id))) |> update(:locations_with_early_slots, &(&1 |> MapSet.delete(id))) |> set_title} end def handle_info({:location_deleted, _}, socket), do: socket |> push_patch(to: Routes.index_path(socket, :index)) @impl true def handle_info( {:query_result, ref, res}, socket = %{assigns: %{locations: valid, pending: pending}} ) do id = pending |> Map.get(ref) send_update(VaccinsWeb.LocationComponent, id: id, availabilities: res) {:noreply, socket |> assign(pending: pending |> Map.delete(ref))} end defp trigger_global_refresh(socket = %{assigns: %{locations: locations}}) do locations |> Enum.each(&send_update(VaccinsWeb.LocationComponent, id: &1.id, force_refresh: true)) socket end defp trigger_periodic_refresh(socket) do Process.send_after(self(), :periodic_refresh, @refresh_period_ms) socket end defp locations_by_availability( assigns = %{ locations: locations, locations_with_slots: with_slots, locations_with_early_slots: with_early_slots } ) do locations |> Enum.sort(fn e1, e2 -> e1_has_early_spot? = e1.id in with_early_slots e1_has_spot? = e1.id in with_slots e2_has_early_spot? = e2.id in with_early_slots e2_has_spot? = e2.id in with_slots res = cond do e2_has_early_spot? -> false e2_has_spot? and not e1_has_early_spot? -> false e2_has_spot? and e1_has_spot? -> false true -> true end end) end end