index.ex 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  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. noob_mode: false,
  12. is_local?: is_local?,
  13. locations: locations,
  14. locations_with_early_slots: MapSet.new(),
  15. locations_with_slots: MapSet.new(),
  16. pending: %{},
  17. location_cs: LocationStore.LocationRaw.changeset(%{}),
  18. display_cs: false
  19. )
  20. |> set_title()
  21. |> trigger_global_refresh
  22. |> trigger_periodic_refresh}
  23. end
  24. defp set_title(socket = %{assigns: %{locations_with_early_slots: early}}) do
  25. if early |> Enum.empty?(),
  26. do: socket |> assign(page_title: "Disponibilités vaccins"),
  27. else: socket |> assign(page_title: "(!!) Disponibilités vaccins")
  28. end
  29. @impl true
  30. def handle_params(params, _url, socket) when params == %{}, do: {:noreply, socket}
  31. def handle_params(%{"noob" => _}, _url, socket),
  32. do: {:noreply, socket |> assign(noob_mode: true)}
  33. @impl true
  34. def handle_event("add_location", %{"location_raw" => params}, socket) do
  35. case params |> LocationStore.add_location() do
  36. :ok -> {:noreply, socket |> push_patch(to: Routes.index_path(socket, :index))}
  37. {:error, cs} -> {:noreply, socket |> assign(location_cs: cs)}
  38. end
  39. end
  40. def handle_event("reload_file", _, socket) do
  41. :ok = LocationStore.reload()
  42. {:noreply, socket |> assign(locations: LocationStore.get_locations())}
  43. end
  44. def handle_event("trigger_all", _, socket) do
  45. {:noreply, socket |> trigger_global_refresh}
  46. end
  47. def handle_event("toggle_form", _, socket = %{assigns: %{display_cs: display}}),
  48. do: {:noreply, socket |> assign(display_cs: not display)}
  49. def handle_event("trigger_noob_mode", _, socket = %{assigns: %{noob_mode: true}}),
  50. do:
  51. {:noreply,
  52. socket |> assign(noob_mode: false) |> push_patch(to: Routes.index_path(socket, :index))}
  53. def handle_event("trigger_noob_mode", _, socket = %{assigns: %{noob_mode: false}}),
  54. do: {:noreply, socket |> push_patch(to: Routes.index_path(socket, :index, noob: true))}
  55. @impl true
  56. def handle_info({:query_sent, id, ref}, socket = %{assigns: %{pending: pending}}) do
  57. {:noreply, socket |> assign(pending: pending |> Map.put(ref, id))}
  58. end
  59. def handle_info(:periodic_refresh, socket = %{assigns: %{display_cs: false}}),
  60. do:
  61. {:noreply,
  62. socket
  63. |> trigger_global_refresh
  64. |> trigger_periodic_refresh}
  65. def handle_info(:periodic_refresh, socket = %{assigns: %{display_cs: true}}),
  66. do: {:noreply, socket |> trigger_periodic_refresh}
  67. def handle_info({:location_has_slots, id, true}, socket) do
  68. {:noreply,
  69. socket |> update(:locations_with_early_slots, &(&1 |> MapSet.put(id))) |> set_title}
  70. end
  71. def handle_info({:location_has_slots, id, false}, socket) do
  72. {:noreply, socket |> update(:locations_with_slots, &(&1 |> MapSet.put(id))) |> set_title}
  73. end
  74. def handle_info({:location_no_more_slots, id}, socket) do
  75. {:noreply,
  76. socket
  77. |> update(:locations_with_slots, &(&1 |> MapSet.delete(id)))
  78. |> update(:locations_with_early_slots, &(&1 |> MapSet.delete(id)))
  79. |> set_title}
  80. end
  81. def handle_info({:location_deleted, _}, socket),
  82. do: socket |> push_patch(to: Routes.index_path(socket, :index))
  83. @impl true
  84. def handle_info(
  85. {:query_result, ref, res},
  86. socket = %{assigns: %{locations: valid, pending: pending}}
  87. ) do
  88. id = pending |> Map.get(ref)
  89. send_update(VaccinsWeb.LocationComponent, id: id, availabilities: res)
  90. {:noreply, socket |> assign(pending: pending |> Map.delete(ref))}
  91. end
  92. defp trigger_global_refresh(socket = %{assigns: %{locations: locations}}) do
  93. locations
  94. |> Enum.each(&send_update(VaccinsWeb.LocationComponent, id: &1.id, force_refresh: true))
  95. socket
  96. end
  97. defp trigger_periodic_refresh(socket) do
  98. Process.send_after(self(), :periodic_refresh, @refresh_period_ms)
  99. socket
  100. end
  101. defp locations_by_availability(
  102. assigns = %{
  103. locations: locations,
  104. locations_with_slots: with_slots,
  105. locations_with_early_slots: with_early_slots
  106. }
  107. ) do
  108. locations
  109. |> Enum.sort(fn e1, e2 ->
  110. e1_has_early_spot? = e1.id in with_early_slots
  111. e1_has_spot? = e1.id in with_slots
  112. e2_has_early_spot? = e2.id in with_early_slots
  113. e2_has_spot? = e2.id in with_slots
  114. res =
  115. cond do
  116. e2_has_early_spot? -> false
  117. e2_has_spot? and not e1_has_early_spot? -> false
  118. e2_has_spot? and e1_has_spot? -> false
  119. true -> true
  120. end
  121. end)
  122. end
  123. end