lib/monitorex/components/live/error_boundary.ex

defmodule Monitorex.Components.Live.ErrorBoundary do
  @moduledoc """
  Error boundary wrapper for Monitorex LiveComponents.

  Catches crashes in child LiveComponents and displays a friendly error card
  instead of taking down the entire page. Click "Retry" to re-mount.
  """

  use Phoenix.LiveComponent

  @impl true
  def update(assigns, socket) do
    socket =
      socket
      |> assign(:error, nil)
      |> assign(:component_id, assigns[:id])

    {:ok, socket}
  end

  @impl true
  def handle_event("retry", _params, socket) do
    {:noreply, assign(socket, :error, nil)}
  end

  @impl true
  def render(assigns) do
    ~H"""
    <div id={@component_id} class="error-boundary">
      <%= if @error do %>
        <div class="error-boundary-card">
          <div class="error-boundary-icon">
            <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
              <circle cx="12" cy="12" r="10" />
              <line x1="12" y1="8" x2="12" y2="12" />
              <line x1="12" y1="16" x2="12.01" y2="16" />
            </svg>
          </div>
          <h4>Something went wrong</h4>
          <p><%= @error %></p>
          <button phx-click="retry" phx-target={@myself} class="error-retry-btn">
            <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
              <polyline points="23 4 23 10 17 10" />
              <path d="M20.49 15a9 9 0 11-2.12-9.36L23 10" />
            </svg>
            Retry
          </button>
        </div>
      <% else %>
        <%= render_slot(@inner_block) %>
      <% end %>
    </div>
    """
  end
end