index.ex 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. defmodule VaccinsWeb.IndexLive do
  2. use VaccinsWeb, :live_view
  3. alias Vaccins.{LocationStore, Search}
  4. @refresh_period_ms 5 * 1000
  5. @impl true
  6. def mount(_params, %{"is_local?" => is_local?}, socket) do
  7. locations = LocationStore.get_locations()
  8. {:ok,
  9. socket
  10. |> assign(
  11. is_local?: is_local?,
  12. locations: locations,
  13. locations_with_early_slots: MapSet.new(),
  14. locations_with_slots: MapSet.new(),
  15. pending: %{},
  16. location_cs: LocationStore.LocationRaw.changeset(%{}),
  17. display_cs: false
  18. )
  19. |> trigger_global_refresh
  20. |> trigger_periodic_refresh}
  21. end
  22. @impl true
  23. def handle_params(%{}, _url, socket), do: {:noreply, socket}
  24. @impl true
  25. def handle_event("add_location", %{"location_raw" => params}, socket) do
  26. case params |> LocationStore.add_location() do
  27. :ok -> {:noreply, socket |> push_patch(to: Routes.index_path(socket, :index))}
  28. {:error, cs} -> {:noreply, socket |> assign(location_cs: cs)}
  29. end
  30. end
  31. def handle_event("reload_file", _, socket) do
  32. :ok = LocationStore.reload()
  33. {:noreply, socket |> assign(locations: LocationStore.get_locations())}
  34. end
  35. def handle_event("trigger_all", _, socket) do
  36. {:noreply, socket |> trigger_global_refresh}
  37. end
  38. def handle_event("toggle_form", _, socket = %{assigns: %{display_cs: display}}),
  39. do: {:noreply, socket |> assign(display_cs: not display)}
  40. @impl true
  41. def handle_info({:query_sent, id, ref}, socket = %{assigns: %{pending: pending}}) do
  42. {:noreply, socket |> assign(pending: pending |> Map.put(ref, id))}
  43. end
  44. def handle_info(:periodic_refresh, socket = %{assigns: %{display_cs: false}}),
  45. do:
  46. {:noreply,
  47. socket
  48. |> trigger_global_refresh
  49. |> trigger_periodic_refresh}
  50. def handle_info(:periodic_refresh, socket = %{assigns: %{display_cs: true}}),
  51. do: {:noreply, socket |> trigger_periodic_refresh}
  52. def handle_info({:location_has_slots, id, true}, socket) do
  53. {:noreply, socket |> update(:locations_with_early_slots, &(&1 |> MapSet.put(id)))}
  54. end
  55. def handle_info({:location_has_slots, id, false}, socket) do
  56. {:noreply, socket |> update(:locations_with_slots, &(&1 |> MapSet.put(id)))}
  57. end
  58. def handle_info({:location_no_more_slots, id}, socket) do
  59. {:noreply,
  60. socket
  61. |> update(:locations_with_slots, &(&1 |> MapSet.delete(id)))
  62. |> update(:locations_with_early_slots, &(&1 |> MapSet.delete(id)))}
  63. end
  64. def handle_info({:location_deleted, _}, socket),
  65. do: socket |> push_patch(to: Routes.index_path(socket, :index))
  66. @impl true
  67. def handle_info(
  68. {:query_result, ref, res},
  69. socket = %{assigns: %{locations: valid, pending: pending}}
  70. ) do
  71. id = pending |> Map.get(ref)
  72. send_update(VaccinsWeb.LocationComponent, id: id, availabilities: res)
  73. {:noreply, socket |> assign(pending: pending |> Map.delete(ref))}
  74. end
  75. defp trigger_global_refresh(socket = %{assigns: %{locations: locations}}) do
  76. locations
  77. |> Enum.each(&send_update(VaccinsWeb.LocationComponent, id: &1.id, force_refresh: true))
  78. socket
  79. end
  80. defp trigger_periodic_refresh(socket) do
  81. Process.send_after(self(), :periodic_refresh, @refresh_period_ms)
  82. socket
  83. end
  84. defp locations_by_availability(
  85. assigns = %{
  86. locations: locations,
  87. locations_with_slots: with_slots,
  88. locations_with_early_slots: with_early_slots
  89. }
  90. ) do
  91. locations
  92. |> Enum.sort(fn e1, e2 ->
  93. e1_has_early_spot? = e1.id in with_early_slots
  94. e1_has_spot? = e1.id in with_slots
  95. e2_has_early_spot? = e2.id in with_early_slots
  96. e2_has_spot? = e2.id in with_slots
  97. res =
  98. cond do
  99. e2_has_early_spot? -> false
  100. e2_has_spot? and not e1_has_early_spot? -> false
  101. e2_has_spot? and e1_has_spot? -> false
  102. true -> true
  103. end
  104. end)
  105. end
  106. end