View Source Rephex.AsyncActionMulti (rephex v0.1.1)

Manages multiple asynchronous operations under a specified map in Phoenix LiveViews, extending Rephex.AsyncAction capabilities.

Rephex.AsyncGroupAction builds upon the foundation of Rephex.AsyncAction by introducing the management of multiple AsyncResult instances within a single, specified map.

This module is designed for scenarios where concurrent asynchronous tasks need to be executed and monitored within the same LiveView component, offering granular control over each task's lifecycle and state.

Example:

# AsyncAction need Rephex state.
defmodule RephexPgWeb.State do
  alias Phoenix.LiveView.AsyncResult

  @initial_state %{
    count: 0,
    # AsyncActionMulti requires map will contain AsyncResult.
    delayed_add_multi: %{}
  }

  use Rephex.State, initial_state: @initial_state

  def add_count(socket, %{amount: amount} = _payload) when is_integer(amount) do
    update_state_in(socket, [:count], &(&1 + amount))
  end
end

# Minimal implementation
defmodule RephexPgWeb.State.DelayedAddAsync do
  alias RephexPgWeb.State

  use Rephex.AsyncActionMulti, result_map_path: [:delayed_add_multi]

  @impl true
  def start_async(_state, _path, %{amount: amount} = _payload, _progress) do
    :timer.sleep(1000)
    amount
  end

  @impl true
  def after_resolve(socket, _result_path, result) do
    case result do
      {:ok, amount} ->
        socket
        |> State.add_count(%{amount: amount})

      {:exit, _reason} ->
        socket
    end
  end
end

# Usage in LiveView
defmodule RephexPgWeb.AccountLive.Index do
  alias RephexPgWeb.State
  use RephexPgWeb, :live_view
  use Rephex.LiveView

  alias Phoenix.LiveView.AsyncResult

  @impl true
  def mount(_params, _session, socket) do
    {:ok, socket |> State.init()}
  end

  @impl true
  def handle_event(
        "start_delayed_add",
        %{"multi_key" => key, "amount" => amount},
        socket
      ) do
    {am, _} = Integer.parse(amount)
    {:noreply, socket |> State.DelayedAddAsync.start(key, %{amount: am})}
  end

  def start_delayed_add_button(assigns) do
    ~H"""
    <button
      class="border-2"
      phx-click="start_delayed_add"
      phx-value-amount={@amount}
      phx-value-multi_key={@multi_key}
    >
      <%= @text %>
    </button>
    """
  end

  @impl true
  def render(assigns) do
    ~H"""
    <div class="border-2 m-5">
      <div class="underline">AsyncActionMulti Example</div>
      <div>We can run multiple async actions with the same module.</div>
      <%= for i <- 1..3 do %>
        <%= ~s{(AsyncResult is at [:delayed_add_multi, "key-#{i}"])} %>
        <.start_delayed_add_button
          amount={i}
          multi_key={"key-#{i}"}
          text={"Start delayed add #{i} by key-#{i}"}
        />
      <% end %>
    </div>
    """
  end
end