forked from shibao/cannery
		
	use container table component instead
This commit is contained in:
		
							
								
								
									
										157
									
								
								lib/cannery_web/components/container_table_component.ex
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										157
									
								
								lib/cannery_web/components/container_table_component.ex
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,157 @@
 | 
			
		||||
defmodule CanneryWeb.Components.ContainerTableComponent do
 | 
			
		||||
  @moduledoc """
 | 
			
		||||
  A component that displays a list of containers
 | 
			
		||||
  """
 | 
			
		||||
  use CanneryWeb, :live_component
 | 
			
		||||
  alias Cannery.{Accounts.User, Containers, Containers.Container, Repo}
 | 
			
		||||
  alias CanneryWeb.Components.TagCard
 | 
			
		||||
  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},
 | 
			
		||||
        %{label: gettext("Packs"), key: :packs, type: :integer},
 | 
			
		||||
        %{label: gettext("Rounds"), key: :rounds, type: :string},
 | 
			
		||||
        %{label: gettext("Tags"), key: :tags, type: :tags},
 | 
			
		||||
        %{label: nil, key: :actions, sortable: false, type: :actions}
 | 
			
		||||
      ]
 | 
			
		||||
      |> 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)
 | 
			
		||||
 | 
			
		||||
    rows =
 | 
			
		||||
      containers
 | 
			
		||||
      |> Enum.map(fn container ->
 | 
			
		||||
        container
 | 
			
		||||
        |> get_row_data_for_container(columns, %{
 | 
			
		||||
          current_user: current_user,
 | 
			
		||||
          tag_actions: tag_actions,
 | 
			
		||||
          actions: actions
 | 
			
		||||
        })
 | 
			
		||||
      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
 | 
			
		||||
    container = container |> Repo.preload([:ammo_groups, :tags])
 | 
			
		||||
 | 
			
		||||
    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()
 | 
			
		||||
  defp get_value_for_key(:name, %{id: id, name: container_name}, _extra_data) do
 | 
			
		||||
    assigns = %{id: id, container_name: container_name}
 | 
			
		||||
 | 
			
		||||
    {container_name,
 | 
			
		||||
     ~H"""
 | 
			
		||||
     <div class="flex flex-wrap justify-center items-center">
 | 
			
		||||
       <.link navigate={Routes.container_show_path(Endpoint, :show, @id)} class="link">
 | 
			
		||||
         <%= @container_name %>
 | 
			
		||||
       </.link>
 | 
			
		||||
     </div>
 | 
			
		||||
     """}
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  defp get_value_for_key(:packs, container, _extra_data) do
 | 
			
		||||
    container |> Containers.get_container_ammo_group_count!()
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  defp get_value_for_key(:rounds, container, _extra_data) do
 | 
			
		||||
    container |> Containers.get_container_rounds!()
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  defp get_value_for_key(:tags, container, %{tag_actions: tag_actions}) do
 | 
			
		||||
    assigns = %{tag_actions: tag_actions, container: container}
 | 
			
		||||
 | 
			
		||||
    {container.tags |> Enum.map(fn %{name: name} -> name end),
 | 
			
		||||
     ~H"""
 | 
			
		||||
     <div class="flex flex-wrap justify-center items-center">
 | 
			
		||||
       <%= unless @container.tags |> Enum.empty?() do %>
 | 
			
		||||
         <%= for tag <- @container.tags do %>
 | 
			
		||||
           <TagCard.simple_tag_card tag={tag} />
 | 
			
		||||
         <% end %>
 | 
			
		||||
       <% end %>
 | 
			
		||||
 | 
			
		||||
       <%= 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
 | 
			
		||||
@@ -6,7 +6,6 @@ defmodule CanneryWeb.ContainerLive.Index do
 | 
			
		||||
  use CanneryWeb, :live_view
 | 
			
		||||
  import CanneryWeb.Components.ContainerCard
 | 
			
		||||
  alias Cannery.{Containers, Containers.Container, Repo}
 | 
			
		||||
  alias CanneryWeb.{Components.TagCard, Endpoint}
 | 
			
		||||
  alias Ecto.Changeset
 | 
			
		||||
 | 
			
		||||
  @impl true
 | 
			
		||||
@@ -124,133 +123,9 @@ defmodule CanneryWeb.ContainerLive.Index do
 | 
			
		||||
 | 
			
		||||
  defp display_containers(%{assigns: %{search: search, current_user: current_user}} = socket) do
 | 
			
		||||
    containers =
 | 
			
		||||
      Containers.list_containers(search, current_user) |> Repo.preload([:tags, :ammo_groups])
 | 
			
		||||
      Containers.list_containers(search, current_user)
 | 
			
		||||
      |> Repo.preload([:tags, :ammo_groups])
 | 
			
		||||
 | 
			
		||||
    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},
 | 
			
		||||
        %{label: gettext("Packs"), key: :packs, type: :integer},
 | 
			
		||||
        %{label: gettext("Rounds"), key: :rounds, type: :string},
 | 
			
		||||
        %{label: gettext("Tags"), key: :tags, type: :tags},
 | 
			
		||||
        %{label: nil, key: :actions, sortable: false, type: :actions}
 | 
			
		||||
      ]
 | 
			
		||||
      |> 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)
 | 
			
		||||
 | 
			
		||||
    rows =
 | 
			
		||||
      containers
 | 
			
		||||
      |> Enum.map(fn container -> container |> get_row_data_for_container(columns) end)
 | 
			
		||||
 | 
			
		||||
    socket
 | 
			
		||||
    |> assign(
 | 
			
		||||
      containers: containers,
 | 
			
		||||
      columns: columns,
 | 
			
		||||
      rows: rows
 | 
			
		||||
    )
 | 
			
		||||
    socket |> assign(:containers, containers)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  @spec get_row_data_for_container(Container.t(), [map()]) :: map()
 | 
			
		||||
  defp get_row_data_for_container(container, columns) do
 | 
			
		||||
    container = container |> Repo.preload([:ammo_groups, :tags])
 | 
			
		||||
 | 
			
		||||
    columns
 | 
			
		||||
    |> Map.new(fn %{key: key} -> {key, get_value_for_key(key, container)} end)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  @spec get_value_for_key(atom(), Container.t()) :: any()
 | 
			
		||||
  defp get_value_for_key(:name, %{id: id, name: container_name}) do
 | 
			
		||||
    assigns = %{id: id, container_name: container_name}
 | 
			
		||||
 | 
			
		||||
    {container_name,
 | 
			
		||||
     ~H"""
 | 
			
		||||
     <div class="flex flex-wrap justify-center items-center">
 | 
			
		||||
       <.link navigate={Routes.container_show_path(Endpoint, :show, @id)} class="link">
 | 
			
		||||
         <%= @container_name %>
 | 
			
		||||
       </.link>
 | 
			
		||||
     </div>
 | 
			
		||||
     """}
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  defp get_value_for_key(:packs, container) do
 | 
			
		||||
    container |> Containers.get_container_ammo_group_count!()
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  defp get_value_for_key(:rounds, container) do
 | 
			
		||||
    container |> Containers.get_container_rounds!()
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  defp get_value_for_key(:tags, container) do
 | 
			
		||||
    assigns = %{container: container}
 | 
			
		||||
 | 
			
		||||
    {container.tags |> Enum.map(fn %{name: name} -> name end),
 | 
			
		||||
     ~H"""
 | 
			
		||||
     <div class="flex flex-wrap justify-center items-center">
 | 
			
		||||
       <%= unless @container.tags |> Enum.empty?() do %>
 | 
			
		||||
         <%= for tag <- @container.tags do %>
 | 
			
		||||
           <TagCard.simple_tag_card tag={tag} />
 | 
			
		||||
         <% end %>
 | 
			
		||||
       <% end %>
 | 
			
		||||
 | 
			
		||||
       <div class="mx-4 my-2">
 | 
			
		||||
         <.link
 | 
			
		||||
           patch={Routes.container_index_path(Endpoint, :edit_tags, @container)}
 | 
			
		||||
           class="text-primary-600 link"
 | 
			
		||||
         >
 | 
			
		||||
           <i class="fa-fw fa-lg fas fa-tags"></i>
 | 
			
		||||
         </.link>
 | 
			
		||||
       </div>
 | 
			
		||||
     </div>
 | 
			
		||||
     """}
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  defp get_value_for_key(:actions, container) do
 | 
			
		||||
    assigns = %{container: container}
 | 
			
		||||
 | 
			
		||||
    ~H"""
 | 
			
		||||
    <.link
 | 
			
		||||
      patch={Routes.container_index_path(Endpoint, :edit, @container)}
 | 
			
		||||
      class="text-primary-600 link"
 | 
			
		||||
      data-qa={"edit-#{@container.id}"}
 | 
			
		||||
    >
 | 
			
		||||
      <i class="fa-fw fa-lg fas fa-edit"></i>
 | 
			
		||||
    </.link>
 | 
			
		||||
 | 
			
		||||
    <.link
 | 
			
		||||
      patch={Routes.container_index_path(Endpoint, :clone, @container)}
 | 
			
		||||
      class="text-primary-600 link"
 | 
			
		||||
      data-qa={"clone-#{@container.id}"}
 | 
			
		||||
    >
 | 
			
		||||
      <i class="fa-fw fa-lg fas fa-copy"></i>
 | 
			
		||||
    </.link>
 | 
			
		||||
 | 
			
		||||
    <.link
 | 
			
		||||
      href="#"
 | 
			
		||||
      class="text-primary-600 link"
 | 
			
		||||
      phx-click="delete"
 | 
			
		||||
      phx-value-id={@container.id}
 | 
			
		||||
      data-confirm={
 | 
			
		||||
        dgettext("prompts", "Are you sure you want to delete %{name}?", name: @container.name)
 | 
			
		||||
      }
 | 
			
		||||
      data-qa={"delete-#{@container.id}"}
 | 
			
		||||
    >
 | 
			
		||||
      <i class="fa-fw fa-lg fas fa-trash"></i>
 | 
			
		||||
    </.link>
 | 
			
		||||
    """
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  defp get_value_for_key(key, container), do: container |> Map.get(key)
 | 
			
		||||
end
 | 
			
		||||
 
 | 
			
		||||
@@ -51,12 +51,55 @@
 | 
			
		||||
    <% else %>
 | 
			
		||||
      <%= if @view_table do %>
 | 
			
		||||
        <.live_component
 | 
			
		||||
          module={CanneryWeb.Components.TableComponent}
 | 
			
		||||
          module={CanneryWeb.Components.ContainerTableComponent}
 | 
			
		||||
          id="containers_index_table"
 | 
			
		||||
          action={@live_action}
 | 
			
		||||
          columns={@columns}
 | 
			
		||||
          rows={@rows}
 | 
			
		||||
        />
 | 
			
		||||
          containers={@containers}
 | 
			
		||||
          current_user={@current_user}
 | 
			
		||||
        >
 | 
			
		||||
          <:tag_actions :let={container}>
 | 
			
		||||
            <div class="mx-4 my-2">
 | 
			
		||||
              <.link
 | 
			
		||||
                patch={Routes.container_index_path(Endpoint, :edit_tags, container)}
 | 
			
		||||
                class="text-primary-600 link"
 | 
			
		||||
              >
 | 
			
		||||
                <i class="fa-fw fa-lg fas fa-tags"></i>
 | 
			
		||||
              </.link>
 | 
			
		||||
            </div>
 | 
			
		||||
          </:tag_actions>
 | 
			
		||||
          <:actions :let={container}>
 | 
			
		||||
            <.link
 | 
			
		||||
              patch={Routes.container_index_path(Endpoint, :edit, container)}
 | 
			
		||||
              class="text-primary-600 link"
 | 
			
		||||
              data-qa={"edit-#{container.id}"}
 | 
			
		||||
            >
 | 
			
		||||
              <i class="fa-fw fa-lg fas fa-edit"></i>
 | 
			
		||||
            </.link>
 | 
			
		||||
 | 
			
		||||
            <.link
 | 
			
		||||
              patch={Routes.container_index_path(Endpoint, :clone, container)}
 | 
			
		||||
              class="text-primary-600 link"
 | 
			
		||||
              data-qa={"clone-#{container.id}"}
 | 
			
		||||
            >
 | 
			
		||||
              <i class="fa-fw fa-lg fas fa-copy"></i>
 | 
			
		||||
            </.link>
 | 
			
		||||
 | 
			
		||||
            <.link
 | 
			
		||||
              href="#"
 | 
			
		||||
              class="text-primary-600 link"
 | 
			
		||||
              phx-click="delete"
 | 
			
		||||
              phx-value-id={container.id}
 | 
			
		||||
              data-confirm={
 | 
			
		||||
                dgettext("prompts", "Are you sure you want to delete %{name}?",
 | 
			
		||||
                  name: container.name
 | 
			
		||||
                )
 | 
			
		||||
              }
 | 
			
		||||
              data-qa={"delete-#{container.id}"}
 | 
			
		||||
            >
 | 
			
		||||
              <i class="fa-fw fa-lg fas fa-trash"></i>
 | 
			
		||||
            </.link>
 | 
			
		||||
          </:actions>
 | 
			
		||||
        </.live_component>
 | 
			
		||||
      <% else %>
 | 
			
		||||
        <%= for container <- @containers do %>
 | 
			
		||||
          <.container_card container={container}>
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user