index.ex 3.4 KB

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