defmodule VaccinsWeb.LocationComponent do
use VaccinsWeb, :live_component
alias Vaccins.{LocationStore, Search}
@impl true
def mount(socket),
do:
{:ok,
socket
|> assign(
slots_after: [],
slots_before: [],
loading: false,
last_refresh_date: nil
)}
@impl true
def update(assigns, socket) do
{force_refresh, assigns} = assigns |> Map.pop(:force_refresh)
assigns = assigns |> integrate_availabilities
if is_nil(force_refresh) do
{:ok, socket |> assign(assigns) |> assign(loading: false) |> signal_availabilities}
else
trigger_and_signal_query(
assigns |> Map.get(:location, socket.assigns.location),
assigns.id
)
{:ok,
socket |> assign(assigns) |> assign(loading: true, last_refresh_date: get_refresh_time())}
end
end
@impl true
def handle_event("trigger_query", _, socket = %{assigns: %{id: id, location: location}}) do
trigger_and_signal_query(location, id)
{:noreply, socket |> assign(loading: true, last_refresh_date: get_refresh_time())}
end
@impl true
def render(assigns) do
~L"""
- id
- <%= @location.id %>
- Status (<%= if @last_refresh_date, do: @last_refresh_date |> Time.to_string() %>)
-
<%= cond do %>
<%= @loading -> %>...
<%= not has_slots?(assigns) -> %>Pas de créneau
<%= has_slots?(assigns) -> %>Des dispos !
<% end %>
- booking page
- <%= link @location.booking_page, to: @location.booking_page %>
<%= if has_slots?(assigns) do %>
- Avant 24h
-
<%= for d <- @slots_before do %>- <%= d |> DateTime.to_string %>
<% end %>
- Après 24h
-
<%= for d <- @slots_after do %>- <%= d |> DateTime.to_string %>
<% end %>
<% end %>
- test availability
"""
end
defp integrate_availabilities(assigns = %{availabilities: {:error, reason}}),
do: assigns
defp integrate_availabilities(assigns = %{availabilities: {:ok, after_slots}})
when is_list(after_slots),
do:
assigns
|> Map.put(:slots_after, after_slots |> Enum.take(5))
defp integrate_availabilities(assigns = %{availabilities: {:ok, before_slots, after_slots}})
when is_list(before_slots),
do:
assigns
|> Map.put(:slots_after, after_slots |> Enum.take(5))
|> Map.put(:slots_before, before_slots)
defp integrate_availabilities(assigns), do: assigns
defp has_slots?(assigns = %{slots_before: before, slots_after: after_}),
do: not (before |> Enum.empty?() and after_ |> Enum.empty?())
defp trigger_and_signal_query(location, id) do
ref = Search.async_trigger_query(location)
send(self(), {:query_sent, id, ref})
end
defp get_refresh_time() do
with {:ok, now} <-
DateTime.utc_now() |> DateTime.shift_zone("Europe/Paris", Tzdata.TimeZoneDatabase),
do: now |> DateTime.to_time() |> Time.truncate(:second)
end
defp signal_availabilities(socket = %{assigns: %{loading: false, slots_after: slots_after}}) do
cond do
socket.assigns |> has_slots? ->
send(self(), {:location_has_slots, socket.assigns.id, not (slots_after |> Enum.empty?())})
true ->
send(self(), {:location_no_more_slots, socket.assigns.id})
end
socket
end
defp signal_availabilities(socket), do: socket
end