cannery/lib/cannery_web/components/container_table_component.ex

168 lines
4.8 KiB
Elixir
Raw Permalink Normal View History

2022-12-03 20:20:11 -05:00
defmodule CanneryWeb.Components.ContainerTableComponent do
@moduledoc """
A component that displays a list of containers
"""
use CanneryWeb, :live_component
alias Cannery.{Accounts.User, Ammo, Containers.Container}
2022-12-03 20:20:11 -05:00
alias Ecto.UUID
alias Phoenix.LiveView.{Rendered, Socket}
@impl true
@spec update(
%{
required(:id) => UUID.t(),
required(:current_user) => User.t(),
optional(:containers) => [Container.t()],
optional(:tag_actions) => Rendered.t(),
optional(:actions) => Rendered.t(),
optional(any()) => any()
},
Socket.t()
) :: {:ok, Socket.t()}
def update(%{id: _id, containers: _containers, current_user: _current_user} = assigns, socket) do
socket =
socket
|> assign(assigns)
|> assign_new(:tag_actions, fn -> [] end)
|> assign_new(:actions, fn -> [] end)
|> display_containers()
{:ok, socket}
end
defp display_containers(
%{
assigns: %{
containers: containers,
current_user: current_user,
tag_actions: tag_actions,
actions: actions
}
} = socket
) do
columns =
[
%{label: gettext("Name"), key: :name, type: :string},
%{label: gettext("Description"), key: :desc, type: :string},
%{label: gettext("Location"), key: :location, type: :string},
%{label: gettext("Type"), key: :type, type: :string}
2022-12-03 20:20:11 -05:00
]
|> Enum.filter(fn %{key: key, type: type} ->
# remove columns if all values match defaults
default_value =
case type do
:boolean -> false
_other_type -> nil
end
containers
|> Enum.any?(fn container ->
type in [:tags, :actions] or not (container |> Map.get(key) == default_value)
end)
end)
|> Enum.concat([
%{label: gettext("Packs"), key: :packs, type: :integer},
%{label: gettext("Rounds"), key: :rounds, type: :integer},
%{label: gettext("Tags"), key: :tags, type: :tags},
2023-03-19 12:35:26 -04:00
%{label: gettext("Actions"), key: :actions, sortable: false, type: :actions}
])
2022-12-03 20:20:11 -05:00
2022-12-03 21:41:54 -05:00
extra_data = %{
current_user: current_user,
tag_actions: tag_actions,
actions: actions,
2023-06-05 18:29:36 -04:00
pack_count:
2023-09-07 19:14:42 -04:00
Ammo.get_grouped_packs_count(current_user,
containers: containers,
group_by: :container_id
),
2023-06-05 22:08:42 -04:00
round_count:
2023-09-07 19:14:42 -04:00
Ammo.get_grouped_round_count(current_user,
containers: containers,
group_by: :container_id
)
2022-12-03 21:41:54 -05:00
}
2022-12-03 20:20:11 -05:00
rows =
containers
|> Enum.map(fn container ->
2022-12-03 21:41:54 -05:00
container |> get_row_data_for_container(columns, extra_data)
2022-12-03 20:20:11 -05:00
end)
socket
|> assign(
columns: columns,
rows: rows
)
end
@impl true
def render(assigns) do
~H"""
<div id={@id} class="w-full">
<.live_component
module={CanneryWeb.Components.TableComponent}
id={"table-#{@id}"}
columns={@columns}
rows={@rows}
/>
</div>
"""
end
@spec get_row_data_for_container(Container.t(), columns :: [map()], extra_data :: map) :: map()
defp get_row_data_for_container(container, columns, extra_data) do
columns
|> Map.new(fn %{key: key} -> {key, get_value_for_key(key, container, extra_data)} end)
end
@spec get_value_for_key(atom(), Container.t(), extra_data :: map) :: any()
2023-04-14 23:34:11 -04:00
defp get_value_for_key(:name, %{name: container_name} = assigns, _extra_data) do
2022-12-03 20:20:11 -05:00
{container_name,
~H"""
<div class="flex flex-wrap justify-center items-center">
2023-04-14 23:34:11 -04:00
<.link navigate={~p"/container/#{@id}"} class="link">
<%= @name %>
2022-12-03 20:20:11 -05:00
</.link>
</div>
"""}
end
defp get_value_for_key(:packs, %{id: container_id}, %{pack_count: pack_count}) do
pack_count |> Map.get(container_id, 0)
2022-12-03 20:20:11 -05:00
end
defp get_value_for_key(:rounds, %{id: container_id}, %{round_count: round_count}) do
round_count |> Map.get(container_id, 0)
2022-12-03 20:20:11 -05:00
end
defp get_value_for_key(:tags, container, %{tag_actions: tag_actions}) do
assigns = %{tag_actions: tag_actions, container: container}
tag_names =
container.tags
|> Enum.map(fn %{name: name} -> name end)
|> Enum.sort()
|> Enum.join(" ")
{tag_names,
2022-12-03 20:20:11 -05:00
~H"""
<div class="flex flex-wrap justify-center items-center">
2023-03-17 21:06:08 -04:00
<.simple_tag_card :for={tag <- @container.tags} :if={@container.tags} tag={tag} />
2022-12-03 20:20:11 -05:00
<%= render_slot(@tag_actions, @container) %>
</div>
"""}
end
defp get_value_for_key(:actions, container, %{actions: actions}) do
assigns = %{actions: actions, container: container}
~H"""
<%= render_slot(@actions, @container) %>
"""
end
defp get_value_for_key(key, container, _extra_data), do: container |> Map.get(key)
end