lib/tailwind/phoenix/index.ex

defmodule Tailwind.Phoenix.Index do
  @moduledoc """
  Helper to make useful notifications to be used in LiveView index.ex files.

  It implements handle_info/2 LiveView callbacks for events,
  updates the current assigns if a notification arrives.

  The value function gets passed the socket as first and only parameter.
  This way you can use any assign in the socket to use the correct query.

  ## Examples

  ```elixir
  defmodule MyWeb.MyDataLive.Index do
    use MyWeb, :live_view

    use Tailwind.Phoenix.Index,
      notifier: MyWeb.Notifier,
      key: :datas,
      data: %My.MyData{},
      value: &list_datas/1,
      to: &Routes.my_data_path(&1, :index)

    ...
  end
  ```
  """

  @doc """
  When used, implements handle_info/2 for index.ex.
  """
  defmacro __using__(opts) do
    notifier = Keyword.get(opts, :notifier)
    assign_key = Keyword.get(opts, :key)
    data_pattern = Keyword.get(opts, :pattern)
    assign_value_fn = Keyword.get(opts, :value)
    return_to_fn = Keyword.get(opts, :to)

    quote do
      @impl true
      def handle_info({_, unquote(data_pattern)} = msg, socket) do
        {:noreply,
         socket
         |> unquote(notifier).to_flash(msg)
         |> update(unquote(assign_key), fn _ -> unquote(assign_value_fn).(socket) end)}
      end

      @impl true
      def handle_info({:deleted, unquote(data_pattern) = data} = msg, socket) do
        if socket.assigns[unquote(assign_key)] != nil do
          to = unquote(return_to_fn).(socket)

          {:noreply,
           socket
           |> Tailwind.Phoenix.redirect_if_id(socket.assigns[unquote(assign_key)].id, data, to: to)
           |> unquote(notifier).to_flash(msg)}
        else
          {:noreply, socket}
        end
      end

      defdelegate handle_info(msg, socket), to: unquote(notifier)
    end
  end
end