| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174 |
- 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,
- error_on_last_query?: 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"""
- <dl class="location">
- <dt>name</dt>
- <dd><%= @location.name %></dd>
- <dt>location</dt>
- <dd><%= @location.location %></dd>
- <dt>Status (<%= if @last_refresh_date, do: @last_refresh_date |> Time.to_string() %>) </dt>
- <dd><%= render_status(assigns) %></dd>
- <dt>booking page</dt>
- <dd><%= link @location.booking_page, to: @location.booking_page %></dd>
- <%= if has_slots?(assigns) do %>
- <dt>Avant 24h</dt>
- <dd><%= render_slots_before(assigns) %></dd>
- <dt>Après 24h</dt>
- <dd><%= render_slots_after(assigns) %></dd>
- <% end %>
- <dt>actions</dt>
- <dd><%= render_action_list(assigns) %></dd>
- </dl>
- """
- end
- @impl true
- def render(assigns = %{render_as: :table_row}) do
- ~L"""
- <td><%= @location.name %></td>
- <td><%= @location.geographic_area %></td>
- <td><%= @location.location %></td>
- <td><%= if @last_refresh_date, do: @last_refresh_date |> Time.to_string() %></td>
- <td><%= render_status(assigns) %></td>
- <td><%= link "RDV", to: @location.booking_page %></td>
- <td><%= render_slots_before(assigns) %></td>
- <td><%= render_slots_after(assigns) %></td>
- <%= if @is_local? do %><td><%= render_action_list(assigns) %></td><% end %>
- """
- end
- def render_table_header(is_local?),
- do: ~E"""
- <th>Nom</th>
- <th>Zone</th>
- <th>Lieu</th>
- <th>Dernier refresh</th>
- <th>Status</th>
- <th>Lien prise RDV</th>
- <th>Slots avant 24h</th>
- <th>Slots après 24h</th>
- <%= if is_local? do %><th>Actions</th><% end %>
- """
- defp render_status(assigns),
- do: ~L"""
- <%= cond do %>
- <%= @loading -> %>...
- <% @error_on_last_query? -> %>>__<
- <% 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) -> %><span class="alert-danger">Des dispos sous 24h !</span>
- <% has_slots?(assigns) -> %>Des dispos dans plus de 24h
- <% end %>
- """
- defp render_slots_before(assigns),
- do: ~L"""
- <ul class="slots-list"><%= for d <- @slots_before do %><li><%= d |> Calendar.strftime("%d/%m/%Y %H:%M") %></li><% end %></ul>
- """
- defp render_slots_after(assigns),
- do: ~L"""
- <ul class="slots-list"><%= for d <- @slots_after do %><li><%= d |> Calendar.strftime("%d/%m/%Y %H:%M") %></li><% end %></ul>
- """
- defp render_action_list(assigns),
- do: ~L"""
- <ul class="actions-list">
- <li><a href="<%= @location |> to_json_query %>"><button>Debug</button></a></li>
- <li><button class="alert-danger" phx-click="delete" phx-target="<%= @myself %>" data-confirm="Etes-vous sur?">Delete</button></li>
- </ul>
- """
- defp integrate_availabilities(assigns = %{availabilities: {:error, reason}}),
- do:
- assigns
- |> Map.put(:error_on_last_query?, reason != :no_availability)
- |> 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(:error_on_last_query?, false)
- |> 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(:error_on_last_query?, false)
- |> 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
|