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, 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 "Résa.", 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 résa 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 ! <% end %> """ defp render_slots_before(assigns), do: ~L""" """ defp render_slots_after(assigns), do: ~L""" """ 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?(assigns = %{slots_before: before, slots_after: after_}), do: not (before |> Enum.empty?() and after_ |> Enum.empty?()) defp has_early_slots?(assigns = %{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(l = %{availability_query: q, provider: provider}), do: q |> provider.to_url() |> URI.to_string() end