Current section

Files

Jump to
phoenix_better_table lib phoenix_better_table.ex.orig
Raw

lib/phoenix_better_table.ex.orig

defmodule PhoenixBetterTable do
@moduledoc """
A table component whose contents can be sorted by clicking on each header.
## Assigns
* `:meta` - a map containing a `:headers` key:
* `headers:` - a list of maps, each representing a header in the table:
* `:id` - the column's id, which will be used as the key for rendering and sorting
* `:label` - the column's label (optional)
* `:sort` - either a boolean indicating whether the column is sortable (optional, default true), or a compare/2 function that returns true if the first argument precedes or is in the same place as the second one.
* `:render` - an optional component that renders cells in the column
* `:rows` - a list of maps, each representing a row in the table
* `:sort` - a tuple containing the column id and the sort order (`:asc` or `:desc`) (optional)
* `:class` - a string containing additional classes to be added to the table (optional)
"""
use Phoenix.LiveComponent
import Phoenix.LiveView.TagEngine, only: [component: 3]
@impl true
def handle_event(
"sort",
%{"header" => header_id},
socket
) do
sort_column = String.to_existing_atom(header_id)
socket =
update(socket, :sort, fn
nil -> {sort_column, :asc}
{^sort_column, :asc} -> {sort_column, :desc}
{^sort_column, :desc} -> {sort_column, :asc}
_ -> {sort_column, :asc}
end)
<<<<<<< HEAD
{:noreply, process_rows(socket)}
||||||| parent of f96a43f (WIP: basic filter support)
{:noreply, assign(socket, :processed_rows, update_rows(rows, socket.assigns.sort, meta))}
=======
{:noreply, process_rows(socket)}
end
def handle_event(
"filter_toggle",
%{"header" => header_id},
socket
) do
filter_column = String.to_existing_atom(header_id)
socket =
update(socket, :filter, fn
%{^filter_column => _} -> Map.put(socket.assigns.filter, filter_column, "")
_ -> Map.put(socket.assigns.filter, filter_column, "")
end)
{:noreply, socket}
end
def handle_event(
"filter_change",
%{"header" => header_id, "value" => value},
socket
) do
filter_column = String.to_existing_atom(header_id)
socket =
update(socket, :filter, fn
state -> Map.put(state, filter_column, value)
end)
{:noreply, process_rows(socket)}
>>>>>>> f96a43f (WIP: basic filter support)
end
@impl true
def mount(socket) do
{:ok, socket}
end
@impl true
def update(%{meta: %{headers: []}}, _socket) do
raise ArgumentError, "meta.headers must not be empty"
end
def update(assigns, socket) do
socket
|> assign(assigns)
|> assign_new(:sort, fn -> nil end)
|> assign_new(:filter, fn -> %{} end)
|> assign_new(:class, fn -> "" end)
|> process_rows()
|> then(&{:ok, &1})
end
#
<<<<<<< HEAD
defp process_rows(%{assigns: %{rows: rows}} = socket) do
assign(socket, :processed_rows, rows |> sort_rows(socket))
||||||| parent of f96a43f (WIP: basic filter support)
defp update_rows(rows, nil, _meta) do
rows
=======
defp process_rows(%{assigns: %{rows: rows}} = socket) do
assign(socket, :processed_rows, rows |> filter_rows(socket) |> sort_rows(socket))
end
defp sort_rows(rows, %{assigns: %{sort: {column, order}, meta: %{headers: headers}}}) do
sorter = column_sorter(order, Enum.find(headers, &(&1.id == column)))
Enum.sort_by(rows, &Map.get(&1, column), sorter)
end
defp sort_rows(rows, _socket) do
rows
>>>>>>> f96a43f (WIP: basic filter support)
end
<<<<<<< HEAD
defp sort_rows(rows, %{assigns: %{sort: {column, order}, meta: %{headers: headers}}}) do
sorter = column_sorter(order, Enum.find(headers, &(&1.id == column)))
Enum.sort_by(rows, &Map.get(&1, column), sorter)
||||||| parent of f96a43f (WIP: basic filter support)
defp update_rows(rows, {column, order}, %{headers: headers}) do
sorter = column_sorter(order, Enum.find(headers, &(&1.id == column)))
Enum.sort_by(rows, &Map.get(&1, column), sorter)
=======
defp filter_rows(rows, %{assigns: %{filter: nil}}) do
rows
end
defp filter_rows(rows, %{assigns: %{filter: filter}}) do
Enum.filter(rows, fn row ->
Enum.all?(filter, fn {column, value} ->
String.contains?(to_string(Map.get(row, column)), value)
end)
end)
>>>>>>> f96a43f (WIP: basic filter support)
end
defp sort_rows(rows, _socket) do
rows
end
#
defp column_sorter(order, %{sort: sort}) when is_function(sort) do
if order == :asc, do: sort, else: &sort.(&2, &1)
end
defp column_sorter(order, %{sort: module}) when is_atom(module) do
{order, module}
end
defp column_sorter(order, _), do: if(order == :asc, do: &<=/2, else: &>=/2)
defp sort_arrow(nil, _column), do: "—"
defp sort_arrow({column, order}, column) when order == :asc, do: "▲"
defp sort_arrow({column, order}, column) when order == :desc, do: "▼"
defp sort_arrow(_, _), do: "—"
end