defmodule VaccinsWeb.LocationComponent do
use VaccinsWeb, :live_component
alias Vaccins.LocationStore
@impl true
def mount(socket),
do:
{:ok,
socket
|> assign(
slots_after: [],
slots_before: [],
loading: false,
last_refresh_date: nil,
last_early_slot_seen: nil,
render_as: :description_list,
is_local?: false
)}
@impl true
def update(assigns, socket) do
assigns = assigns |> integrate_availabilities
socket =
if assigns |> Map.has_key?(:availabilities),
do: socket |> assign(last_refresh_date: get_refresh_time()),
else: socket
{:ok, socket |> assign(assigns) |> signal_availabilities}
end
@impl true
def handle_event("delete", _, socket = %{assigns: %{id: id}}) do
if :ok == LocationStore.delete_location(id), do: send(self(), {:location_deleted, id})
{:noreply, socket}
end
@impl true
def render(assigns = %{render_as: :description_list}) do
~L"""
- name
- <%= @location.name %>
- location
- <%= @location.location %>
- Status (<%= if @last_refresh_date, do: @last_refresh_date |> Time.to_string() %>)
- <%= render_status(assigns) %>
- booking page
- <%= link @location.booking_page, to: @location.booking_page %>
<%= if has_slots?(assigns) do %>
- Avant 24h
- <%= render_slots_before(assigns) %>
- Après 24h
- <%= render_slots_after(assigns) %>
<% end %>
- actions
- <%= render_action_list(assigns) %>
"""
end
@impl true
def render(assigns = %{render_as: :table_row}) do
~L"""
<%= @location.name %> |
<%= @location.geographic_area %> |
<%= @location.location %> |
<%= if @last_refresh_date, do: @last_refresh_date |> Time.to_string() %> |
<%= render_status(assigns) %> |
<%= link "RDV", to: @location.booking_page %> |
<%= render_slots_before(assigns) %> |
<%= render_slots_after(assigns) %> |
<%= if @is_local? do %><%= render_action_list(assigns) %> | <% end %>
"""
end
def render_table_header(is_local?),
do: ~E"""
Nom |
Zone |
Lieu |
Dernier refresh |
Status |
Lien prise RDV |
Slots avant 24h |
Slots après 24h |
<%= if is_local? do %>Actions | <% end %>
"""
defp render_status(assigns),
do: ~L"""
<%= cond do %>
<%= @loading -> %>...
<% not has_slots?(assigns) -> %>Pas de créneau <%= if @last_early_slot_seen do %>(<%= @last_early_slot_seen |> DateTime.to_time() |> Time.truncate(:second) |> Time.to_string %>)<% end %>
<% has_early_slots?(assigns) -> %>Des dispos sous 24h !
<% has_slots?(assigns) -> %>Des dispos dans plus de 24h
<% end %>
"""
defp render_slots_before(assigns),
do: ~L"""
<%= for d <- @slots_before do %>- <%= d |> Calendar.strftime("%d/%m/%Y %H:%M") %>
<% end %>
"""
defp render_slots_after(assigns),
do: ~L"""
<%= for d <- @slots_after do %>- <%= d |> Calendar.strftime("%d/%m/%Y %H:%M") %>
<% end %>
"""
defp render_action_list(assigns),
do: ~L"""
"""
defp integrate_availabilities(assigns = %{availabilities: {:error, _reason}}),
do:
assigns
|> Map.put(:slots_after, [])
|> Map.put(:slots_before, [])
defp integrate_availabilities(assigns = %{availabilities: {:ok, after_slots}})
when is_list(after_slots),
do:
assigns
|> Map.put(:slots_after, after_slots |> Enum.take(2))
|> Map.put(:slots_before, [])
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(2))
|> Map.put(:slots_before, before_slots |> Enum.take(2))
|> Map.put(:last_early_slot_seen, DateTime.utc_now())
defp integrate_availabilities(assigns), do: assigns
defp has_slots?(%{slots_before: before, slots_after: after_}),
do: not (before |> Enum.empty?() and after_ |> Enum.empty?())
defp has_early_slots?(%{slots_before: before}),
do: not (before |> Enum.empty?())
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}}) do
cond do
socket.assigns |> has_slots? ->
send(self(), {:location_has_slots, socket.assigns.id, socket.assigns |> has_early_slots?})
true ->
send(self(), {:location_no_more_slots, socket.assigns.id})
end
socket
end
defp signal_availabilities(socket), do: socket
defp to_json_query(%{availability_query: q, provider: provider}),
do: q |> provider.to_url() |> URI.to_string()
end