index.ex 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. defmodule VaccinsWeb.IndexLive do
  2. use VaccinsWeb, :live_view
  3. alias Vaccins.LocationStore
  4. @impl true
  5. def mount(_params, %{"is_local?" => is_local?}, socket) do
  6. locations = LocationStore.get_locations()
  7. Phoenix.PubSub.subscribe(Vaccins.PubSub, "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_all_areas
  21. |> init_area_filters()
  22. |> set_title()}
  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 == %{},
  31. do:
  32. {:noreply,
  33. socket
  34. |> assign(noob_mode: false, area_filters: socket.assigns.all_areas, params: params)}
  35. def handle_params(params, _url, socket)
  36. when is_map_key(params, "noob") or is_map_key(params, "geographic_areas") do
  37. all_areas = socket.assigns.all_areas
  38. areas = params |> Map.get("geographic_areas", all_areas)
  39. {:noreply,
  40. socket
  41. |> assign(
  42. noob_mode: params |> Map.has_key?("noob"),
  43. area_filters: areas |> MapSet.new() |> MapSet.intersection(all_areas),
  44. params: params
  45. )}
  46. end
  47. @impl true
  48. def handle_event("areas_filter_change", %{"areas_filter" => %{"areas" => areas}}, socket) do
  49. {:noreply,
  50. socket |> push_patch(to: Routes.index_path(socket, :index, geographic_areas: areas))}
  51. end
  52. def handle_event("areas_filter_change", params, socket)
  53. when not is_map_key(params, "areas_filter") do
  54. {:noreply, socket |> push_patch(to: Routes.index_path(socket, :index))}
  55. end
  56. def handle_event("add_location", %{"location_raw" => params}, socket) do
  57. case params |> LocationStore.add_location() do
  58. :ok -> {:noreply, socket |> push_patch(to: Routes.index_path(socket, :index))}
  59. {:error, cs} -> {:noreply, socket |> assign(location_cs: cs)}
  60. end
  61. end
  62. def handle_event("reload_file", _, socket) do
  63. :ok = LocationStore.reload()
  64. {:noreply, socket |> assign(locations: LocationStore.get_locations())}
  65. end
  66. def handle_event("toggle_form", _, socket = %{assigns: %{display_cs: display}}),
  67. do: {:noreply, socket |> assign(display_cs: not display)}
  68. def handle_event("trigger_noob_mode", _, socket = %{assigns: %{noob_mode: true}}),
  69. do:
  70. {:noreply,
  71. socket |> assign(noob_mode: false) |> push_patch(to: Routes.index_path(socket, :index))}
  72. def handle_event("trigger_noob_mode", _, socket = %{assigns: %{noob_mode: false}}),
  73. do: {:noreply, socket |> push_patch(to: Routes.index_path(socket, :index, noob: true))}
  74. @impl true
  75. def handle_info({:location_has_slots, id, true}, socket) do
  76. {:noreply,
  77. socket |> update(:locations_with_early_slots, &(&1 |> MapSet.put(id))) |> set_title}
  78. end
  79. def handle_info({:location_has_slots, id, false}, socket) do
  80. {:noreply, socket |> update(:locations_with_slots, &(&1 |> MapSet.put(id))) |> set_title}
  81. end
  82. def handle_info({:location_no_more_slots, id}, socket) do
  83. {:noreply,
  84. socket
  85. |> update(:locations_with_slots, &(&1 |> MapSet.delete(id)))
  86. |> update(:locations_with_early_slots, &(&1 |> MapSet.delete(id)))
  87. |> set_title}
  88. end
  89. def handle_info({:location_deleted, _}, socket),
  90. do: socket |> push_patch(to: Routes.index_path(socket, :index))
  91. @impl true
  92. def handle_info({:new_availabilities, id, res}, socket) do
  93. send_update(VaccinsWeb.LocationComponent, id: id, availabilities: res)
  94. {:noreply, socket}
  95. end
  96. defp filter(locations, %{area_filters: filters}),
  97. do:
  98. locations
  99. |> Enum.filter(&(&1.geographic_area in filters))
  100. defp locations_by_availability(%{
  101. locations: locations,
  102. locations_with_slots: with_slots,
  103. locations_with_early_slots: with_early_slots
  104. }) do
  105. locations
  106. |> Enum.sort(fn e1, e2 ->
  107. e1_has_early_spot? = e1.id in with_early_slots
  108. e1_has_spot? = e1.id in with_slots
  109. e2_has_early_spot? = e2.id in with_early_slots
  110. e2_has_spot? = e2.id in with_slots
  111. cond do
  112. e2_has_early_spot? -> false
  113. e2_has_spot? and not e1_has_early_spot? -> false
  114. e2_has_spot? and e1_has_spot? -> false
  115. true -> true
  116. end
  117. end)
  118. end
  119. defp set_all_areas(socket), do: socket |> assign(all_areas: socket |> get_all_areas)
  120. defp init_area_filters(socket), do: socket |> assign(area_filters: socket.assigns.all_areas)
  121. defp get_all_areas(%{assigns: %{locations: locations}}),
  122. do: locations |> Enum.map(& &1.geographic_area) |> MapSet.new()
  123. end