defmodule ClaperWeb.AdminLive.TableComponent do use ClaperWeb, :live_component @impl true def render(assigns) do ~H"""
<%= for {header, _index} <- Enum.with_index(@headers) do %> <% end %> <%= if length(@rows) > 0 do %> <%= for {row, row_index} <- Enum.with_index(@rows) do %> <%= for {cell_content, _cell_index} <- Enum.with_index(get_row_cells(row, @headers, @row_func)) do %> <% end %> <% end %> <% else %> <% end %>
{if is_binary(header), do: header, else: header.label} <%= if @sortable && header.sortable do %> <%= case @sort_config do %> <% %{field: field, direction: :asc} when field == header.field -> %> <% %{field: field, direction: :desc} when field == header.field -> %> <% _ -> %> <% end %> <% end %>
<%= case cell_content do %> <% {:safe, content} -> %> {raw(content)} <% content when is_binary(content) -> %> {content} <% content -> %> {to_string(content)} <% end %>
<%= if @empty_icon do %> <% end %>

{@empty_title || "No items found"}

{@empty_message || "There are no items to display."}

<%= if @empty_action do %>
{render_slot(@empty_action)}
<% end %>
<%= if @pagination do %>
<%= if @pagination.page_number > 1 do %> <% else %> Previous <% end %> <%= if @pagination.page_number < @pagination.total_pages do %> <% else %> Next <% end %>
<% end %>
""" end @impl true def mount(socket) do {:ok, assign(socket, sort_config: %{field: nil, direction: :asc})} end @impl true def update(assigns, socket) do socket = socket |> assign(assigns) |> assign_new(:sortable, fn -> false end) |> assign_new(:sort_config, fn -> %{field: nil, direction: :asc} end) |> assign_new(:row_click_enabled, fn -> false end) |> assign_new(:empty_title, fn -> nil end) |> assign_new(:empty_message, fn -> nil end) |> assign_new(:empty_icon, fn -> nil end) |> assign_new(:empty_action, fn -> [] end) |> assign_new(:pagination, fn -> nil end) |> assign_new(:row_func, fn -> nil end) {:ok, socket} end @impl true def handle_event("sort", %{"field" => field}, socket) do current_sort = socket.assigns.sort_config new_direction = if current_sort.field == field and current_sort.direction == :asc do :desc else :asc end sort_config = %{field: field, direction: new_direction} send(self(), {:table_sort_changed, sort_config}) {:noreply, assign(socket, sort_config: sort_config)} end def handle_event("paginate", %{"page" => page}, socket) do page_number = String.to_integer(page) send(self(), {:table_page_changed, page_number}) {:noreply, socket} end def handle_event("row_clicked", %{"row-index" => row_index}, socket) do index = String.to_integer(row_index) row = Enum.at(socket.assigns.rows, index) send(self(), {:table_row_clicked, row, index}) {:noreply, socket} end defp get_row_cells(row, headers, nil) do # Default behavior: assume row is a list/tuple matching header count case row do row when is_list(row) -> row row when is_tuple(row) -> Tuple.to_list(row) _ -> List.duplicate("", length(headers)) end end defp get_row_cells(row, _headers, row_func) when is_function(row_func) do row_func.(row) end defp get_page_range(pagination) do start_page = max(1, pagination.page_number - 2) end_page = min(pagination.total_pages, pagination.page_number + 2) start_page..end_page end end