forked from shibao/cannery
		
	make ammo type show page and container show page also display ammo groups as table
This commit is contained in:
		@@ -35,7 +35,7 @@ defmodule CanneryWeb.Components.AmmoGroupCard do
 | 
			
		||||
      <div class="flex flex-col justify-center items-center">
 | 
			
		||||
        <span class="rounded-lg title text-lg">
 | 
			
		||||
          <%= gettext("Count:") %>
 | 
			
		||||
          <%= if @ammo_group.count == 0, do: "Empty", else: @ammo_group.count %>
 | 
			
		||||
          <%= if @ammo_group.count == 0, do: gettext("Empty"), else: @ammo_group.count %>
 | 
			
		||||
        </span>
 | 
			
		||||
 | 
			
		||||
        <%= if @ammo_group.notes do %>
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										222
									
								
								lib/cannery_web/components/ammo_group_table_component.ex
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										222
									
								
								lib/cannery_web/components/ammo_group_table_component.ex
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,222 @@
 | 
			
		||||
defmodule CanneryWeb.Components.AmmoGroupTableComponent do
 | 
			
		||||
  @moduledoc """
 | 
			
		||||
  A component that displays a list of ammo groups
 | 
			
		||||
  """
 | 
			
		||||
  use CanneryWeb, :live_component
 | 
			
		||||
  alias Cannery.{Accounts.User, Ammo, Ammo.AmmoGroup, Repo}
 | 
			
		||||
  alias Ecto.UUID
 | 
			
		||||
  alias Phoenix.LiveView.{Rendered, Socket}
 | 
			
		||||
 | 
			
		||||
  @impl true
 | 
			
		||||
  @spec update(
 | 
			
		||||
          %{
 | 
			
		||||
            required(:id) => UUID.t(),
 | 
			
		||||
            required(:current_user) => User.t(),
 | 
			
		||||
            required(:ammo_groups) => [AmmoGroup.t()],
 | 
			
		||||
            optional(:show_used) => boolean(),
 | 
			
		||||
            optional(:ammo_type) => Rendered.t(),
 | 
			
		||||
            optional(:range) => Rendered.t(),
 | 
			
		||||
            optional(:container) => Rendered.t(),
 | 
			
		||||
            optional(:actions) => Rendered.t(),
 | 
			
		||||
            optional(any()) => any()
 | 
			
		||||
          },
 | 
			
		||||
          Socket.t()
 | 
			
		||||
        ) :: {:ok, Socket.t()}
 | 
			
		||||
  def update(%{id: _id, ammo_groups: _ammo_group, current_user: _current_user} = assigns, socket) do
 | 
			
		||||
    socket =
 | 
			
		||||
      socket
 | 
			
		||||
      |> assign(assigns)
 | 
			
		||||
      |> assign_new(:show_used, fn -> false end)
 | 
			
		||||
      |> assign_new(:ammo_type, fn -> [] end)
 | 
			
		||||
      |> assign_new(:range, fn -> [] end)
 | 
			
		||||
      |> assign_new(:container, fn -> [] end)
 | 
			
		||||
      |> assign_new(:actions, fn -> [] end)
 | 
			
		||||
      |> display_ammo_groups()
 | 
			
		||||
 | 
			
		||||
    {:ok, socket}
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  defp display_ammo_groups(
 | 
			
		||||
         %{
 | 
			
		||||
           assigns: %{
 | 
			
		||||
             ammo_groups: ammo_groups,
 | 
			
		||||
             current_user: current_user,
 | 
			
		||||
             show_used: show_used,
 | 
			
		||||
             ammo_type: ammo_type,
 | 
			
		||||
             range: range,
 | 
			
		||||
             container: container,
 | 
			
		||||
             actions: actions
 | 
			
		||||
           }
 | 
			
		||||
         } = socket
 | 
			
		||||
       ) do
 | 
			
		||||
    columns =
 | 
			
		||||
      if actions == [] do
 | 
			
		||||
        []
 | 
			
		||||
      else
 | 
			
		||||
        [%{label: nil, key: :actions, sortable: false}]
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
    columns =
 | 
			
		||||
      if show_used do
 | 
			
		||||
        [%{label: gettext("Used up on"), key: :used_up_on} | columns]
 | 
			
		||||
      else
 | 
			
		||||
        columns
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
    columns = [%{label: gettext("Added on"), key: :added_on} | columns]
 | 
			
		||||
 | 
			
		||||
    columns =
 | 
			
		||||
      if container == [] do
 | 
			
		||||
        columns
 | 
			
		||||
      else
 | 
			
		||||
        [%{label: gettext("Container"), key: :container} | columns]
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
    columns =
 | 
			
		||||
      if range == [] do
 | 
			
		||||
        columns
 | 
			
		||||
      else
 | 
			
		||||
        [%{label: gettext("Range"), key: :range} | columns]
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
    columns = [
 | 
			
		||||
      %{label: gettext("Count"), key: :count},
 | 
			
		||||
      %{label: gettext("Price paid"), key: :price_paid},
 | 
			
		||||
      %{label: gettext("% left"), key: :remaining},
 | 
			
		||||
      %{label: gettext("Notes"), key: :notes}
 | 
			
		||||
      | columns
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
    columns =
 | 
			
		||||
      if ammo_type == [] do
 | 
			
		||||
        columns
 | 
			
		||||
      else
 | 
			
		||||
        [%{label: gettext("Ammo type"), key: :ammo_type} | columns]
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
    rows =
 | 
			
		||||
      ammo_groups
 | 
			
		||||
      |> Repo.preload([:ammo_type, :container])
 | 
			
		||||
      |> Enum.map(fn ammo_group ->
 | 
			
		||||
        ammo_group
 | 
			
		||||
        |> get_row_data_for_ammo_group(%{
 | 
			
		||||
          current_user: current_user,
 | 
			
		||||
          ammo_type: ammo_type,
 | 
			
		||||
          columns: columns,
 | 
			
		||||
          container: container,
 | 
			
		||||
          actions: actions,
 | 
			
		||||
          range: range
 | 
			
		||||
        })
 | 
			
		||||
      end)
 | 
			
		||||
 | 
			
		||||
    socket |> assign(columns: columns, rows: rows)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  @impl true
 | 
			
		||||
  def render(assigns) do
 | 
			
		||||
    ~H"""
 | 
			
		||||
    <div class="w-full">
 | 
			
		||||
      <.live_component
 | 
			
		||||
        module={CanneryWeb.Components.TableComponent}
 | 
			
		||||
        id={@id}
 | 
			
		||||
        columns={@columns}
 | 
			
		||||
        rows={@rows}
 | 
			
		||||
      />
 | 
			
		||||
    </div>
 | 
			
		||||
    """
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  @spec get_row_data_for_ammo_group(AmmoGroup.t(), additional_data :: map()) :: map()
 | 
			
		||||
  defp get_row_data_for_ammo_group(ammo_group, %{columns: columns} = additional_data) do
 | 
			
		||||
    ammo_group = ammo_group |> Repo.preload([:ammo_type, :container])
 | 
			
		||||
 | 
			
		||||
    columns
 | 
			
		||||
    |> Map.new(fn %{key: key} ->
 | 
			
		||||
      {key, get_value_for_key(key, ammo_group, additional_data)}
 | 
			
		||||
    end)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  @spec get_value_for_key(atom(), AmmoGroup.t(), additional_data :: map()) ::
 | 
			
		||||
          any() | {any(), Rendered.t()}
 | 
			
		||||
  defp get_value_for_key(
 | 
			
		||||
         :ammo_type,
 | 
			
		||||
         %{ammo_type: %{name: ammo_type_name} = ammo_type},
 | 
			
		||||
         %{ammo_type: ammo_type_block}
 | 
			
		||||
       ) do
 | 
			
		||||
    assigns = %{ammo_type: ammo_type, ammo_type_block: ammo_type_block}
 | 
			
		||||
 | 
			
		||||
    {ammo_type_name,
 | 
			
		||||
     ~H"""
 | 
			
		||||
     <%= render_slot(@ammo_type_block, @ammo_type) %>
 | 
			
		||||
     """}
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  defp get_value_for_key(:price_paid, %{price_paid: nil}, _additional_data), do: {"", nil}
 | 
			
		||||
 | 
			
		||||
  defp get_value_for_key(:price_paid, %{price_paid: price_paid}, _additional_data),
 | 
			
		||||
    do: gettext("$%{amount}", amount: price_paid |> :erlang.float_to_binary(decimals: 2))
 | 
			
		||||
 | 
			
		||||
  defp get_value_for_key(:added_on, %{inserted_at: inserted_at}, _additional_data) do
 | 
			
		||||
    assigns = %{inserted_at: inserted_at}
 | 
			
		||||
 | 
			
		||||
    {inserted_at,
 | 
			
		||||
     ~H"""
 | 
			
		||||
     <%= @inserted_at |> display_datetime() %>
 | 
			
		||||
     """}
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  defp get_value_for_key(:used_up_on, ammo_group, _additional_data) do
 | 
			
		||||
    last_shot_group_date =
 | 
			
		||||
      case ammo_group |> Ammo.get_last_used_shot_group() do
 | 
			
		||||
        %{date: last_shot_group_date} -> last_shot_group_date
 | 
			
		||||
        _no_shot_groups -> nil
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
    assigns = %{last_shot_group_date: last_shot_group_date}
 | 
			
		||||
 | 
			
		||||
    {last_shot_group_date,
 | 
			
		||||
     ~H"""
 | 
			
		||||
     <%= @last_shot_group_date |> display_date() %>
 | 
			
		||||
     """}
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  defp get_value_for_key(:range, %{staged: staged} = ammo_group, %{range: range}) do
 | 
			
		||||
    assigns = %{range: range, ammo_group: ammo_group}
 | 
			
		||||
 | 
			
		||||
    {staged,
 | 
			
		||||
     ~H"""
 | 
			
		||||
     <%= render_slot(@range, @ammo_group) %>
 | 
			
		||||
     """}
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  defp get_value_for_key(:remaining, ammo_group, _additional_data),
 | 
			
		||||
    do: gettext("%{percentage}%", percentage: ammo_group |> Ammo.get_percentage_remaining())
 | 
			
		||||
 | 
			
		||||
  defp get_value_for_key(:actions, ammo_group, %{actions: actions}) do
 | 
			
		||||
    assigns = %{actions: actions, ammo_group: ammo_group}
 | 
			
		||||
 | 
			
		||||
    ~H"""
 | 
			
		||||
    <%= render_slot(@actions, @ammo_group) %>
 | 
			
		||||
    """
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  defp get_value_for_key(:container, %{container: nil}, _additional_data), do: {nil, nil}
 | 
			
		||||
 | 
			
		||||
  defp get_value_for_key(
 | 
			
		||||
         :container,
 | 
			
		||||
         %{container: %{name: container_name}} = ammo_group,
 | 
			
		||||
         %{container: container}
 | 
			
		||||
       ) do
 | 
			
		||||
    assigns = %{container: container, ammo_group: ammo_group}
 | 
			
		||||
 | 
			
		||||
    {container_name,
 | 
			
		||||
     ~H"""
 | 
			
		||||
     <%= render_slot(@container, @ammo_group) %>
 | 
			
		||||
     """}
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  defp get_value_for_key(:count, %{count: count}, _additional_data),
 | 
			
		||||
    do: if(count == 0, do: gettext("Empty"), else: count)
 | 
			
		||||
 | 
			
		||||
  defp get_value_for_key(key, ammo_group, _additional_data), do: ammo_group |> Map.get(key)
 | 
			
		||||
end
 | 
			
		||||
@@ -106,7 +106,7 @@ defmodule CanneryWeb.Components.MoveAmmoGroupComponent do
 | 
			
		||||
    containers
 | 
			
		||||
    |> Enum.map(fn container ->
 | 
			
		||||
      columns
 | 
			
		||||
      |> Enum.into(%{}, fn %{key: key} -> {key, get_row_value_by_key(key, container, assigns)} end)
 | 
			
		||||
      |> Map.new(fn %{key: key} -> {key, get_row_value_by_key(key, container, assigns)} end)
 | 
			
		||||
    end)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -6,7 +6,7 @@
 | 
			
		||||
          <%= if column |> Map.get(:sortable, true) do %>
 | 
			
		||||
            <th class={"p-2 #{column[:class]}"}>
 | 
			
		||||
              <span
 | 
			
		||||
                class="cursor-pointer"
 | 
			
		||||
                class="cursor-pointer flex justify-center items-center space-x-2"
 | 
			
		||||
                phx-click="sort_by"
 | 
			
		||||
                phx-value-sort-key={key}
 | 
			
		||||
                phx-target={@myself}
 | 
			
		||||
 
 | 
			
		||||
@@ -95,183 +95,11 @@ defmodule CanneryWeb.AmmoGroupLive.Index do
 | 
			
		||||
    ammo_types_count = Ammo.get_ammo_types_count!(current_user)
 | 
			
		||||
    containers_count = Containers.get_containers_count!(current_user)
 | 
			
		||||
 | 
			
		||||
    columns = [
 | 
			
		||||
      %{label: gettext("Ammo type"), key: :ammo_type},
 | 
			
		||||
      %{label: gettext("Count"), key: :count},
 | 
			
		||||
      %{label: gettext("Price paid"), key: :price_paid},
 | 
			
		||||
      %{label: gettext("% left"), key: :remaining},
 | 
			
		||||
      %{label: gettext("Range"), key: :range},
 | 
			
		||||
      %{label: gettext("Container"), key: :container},
 | 
			
		||||
      %{label: gettext("Added on"), key: :added_on}
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
    columns =
 | 
			
		||||
      if show_used do
 | 
			
		||||
        columns ++ [%{label: gettext("Used up on"), key: :used_up_on}]
 | 
			
		||||
      else
 | 
			
		||||
        columns
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
    columns = columns ++ [%{label: nil, key: :actions, sortable: false}]
 | 
			
		||||
 | 
			
		||||
    rows =
 | 
			
		||||
      ammo_groups
 | 
			
		||||
      |> Enum.map(fn ammo_group -> ammo_group |> get_row_data_for_ammo_group(columns) end)
 | 
			
		||||
 | 
			
		||||
    socket
 | 
			
		||||
    |> assign(
 | 
			
		||||
      ammo_groups: ammo_groups,
 | 
			
		||||
      ammo_types_count: ammo_types_count,
 | 
			
		||||
      containers_count: containers_count,
 | 
			
		||||
      columns: columns,
 | 
			
		||||
      rows: rows
 | 
			
		||||
      containers_count: containers_count
 | 
			
		||||
    )
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  @spec get_row_data_for_ammo_group(AmmoGroup.t(), [map()]) :: [map()]
 | 
			
		||||
  defp get_row_data_for_ammo_group(ammo_group, columns) do
 | 
			
		||||
    ammo_group = ammo_group |> Repo.preload([:ammo_type, :container])
 | 
			
		||||
 | 
			
		||||
    columns
 | 
			
		||||
    |> Enum.into(%{}, fn %{key: key} -> {key, get_value_for_key(key, ammo_group)} end)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  @spec get_value_for_key(atom(), AmmoGroup.t()) :: any()
 | 
			
		||||
  defp get_value_for_key(:ammo_type, %{ammo_type: ammo_type}) do
 | 
			
		||||
    assigns = %{ammo_type: ammo_type}
 | 
			
		||||
 | 
			
		||||
    {ammo_type.name,
 | 
			
		||||
     ~H"""
 | 
			
		||||
     <.link navigate={Routes.ammo_type_show_path(Endpoint, :show, @ammo_type)} class="link">
 | 
			
		||||
       <%= @ammo_type.name %>
 | 
			
		||||
     </.link>
 | 
			
		||||
     """}
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  defp get_value_for_key(:price_paid, %{price_paid: nil}), do: {"a", nil}
 | 
			
		||||
 | 
			
		||||
  defp get_value_for_key(:price_paid, %{price_paid: price_paid}),
 | 
			
		||||
    do: gettext("$%{amount}", amount: price_paid |> :erlang.float_to_binary(decimals: 2))
 | 
			
		||||
 | 
			
		||||
  defp get_value_for_key(:added_on, %{inserted_at: inserted_at}) do
 | 
			
		||||
    assigns = %{inserted_at: inserted_at}
 | 
			
		||||
 | 
			
		||||
    {inserted_at,
 | 
			
		||||
     ~H"""
 | 
			
		||||
     <%= @inserted_at |> display_datetime() %>
 | 
			
		||||
     """}
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  defp get_value_for_key(:used_up_on, ammo_group) do
 | 
			
		||||
    last_shot_group_date =
 | 
			
		||||
      case ammo_group |> Ammo.get_last_used_shot_group() do
 | 
			
		||||
        %{date: last_shot_group_date} -> last_shot_group_date
 | 
			
		||||
        _no_shot_groups -> nil
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
    assigns = %{last_shot_group_date: last_shot_group_date}
 | 
			
		||||
 | 
			
		||||
    {last_shot_group_date,
 | 
			
		||||
     ~H"""
 | 
			
		||||
     <%= @last_shot_group_date |> display_date() %>
 | 
			
		||||
     """}
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  defp get_value_for_key(:range, %{staged: staged} = ammo_group) do
 | 
			
		||||
    assigns = %{ammo_group: ammo_group}
 | 
			
		||||
 | 
			
		||||
    {staged,
 | 
			
		||||
     ~H"""
 | 
			
		||||
     <div class="min-w-20 py-2 px-4 h-full flex flew-wrap justify-center items-center">
 | 
			
		||||
       <button
 | 
			
		||||
         type="button"
 | 
			
		||||
         class="mx-2 my-1 text-sm btn btn-primary"
 | 
			
		||||
         phx-click="toggle_staged"
 | 
			
		||||
         phx-value-ammo_group_id={@ammo_group.id}
 | 
			
		||||
       >
 | 
			
		||||
         <%= if @ammo_group.staged, do: gettext("Unstage"), else: gettext("Stage") %>
 | 
			
		||||
       </button>
 | 
			
		||||
 | 
			
		||||
       <.link
 | 
			
		||||
         patch={Routes.ammo_group_index_path(Endpoint, :add_shot_group, @ammo_group)}
 | 
			
		||||
         class="mx-2 my-1 text-sm btn btn-primary"
 | 
			
		||||
       >
 | 
			
		||||
         <%= dgettext("actions", "Record shots") %>
 | 
			
		||||
       </.link>
 | 
			
		||||
     </div>
 | 
			
		||||
     """}
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  defp get_value_for_key(:remaining, ammo_group),
 | 
			
		||||
    do: gettext("%{percentage}%", percentage: ammo_group |> Ammo.get_percentage_remaining())
 | 
			
		||||
 | 
			
		||||
  defp get_value_for_key(:actions, ammo_group) do
 | 
			
		||||
    assigns = %{ammo_group: ammo_group}
 | 
			
		||||
 | 
			
		||||
    ~H"""
 | 
			
		||||
    <div class="py-2 px-4 h-full space-x-4 flex justify-center items-center">
 | 
			
		||||
      <.link
 | 
			
		||||
        navigate={Routes.ammo_group_show_path(Endpoint, :show, @ammo_group)}
 | 
			
		||||
        class="text-primary-600 link"
 | 
			
		||||
        data-qa={"view-#{@ammo_group.id}"}
 | 
			
		||||
      >
 | 
			
		||||
        <i class="fa-fw fa-lg fas fa-eye"></i>
 | 
			
		||||
      </.link>
 | 
			
		||||
 | 
			
		||||
      <.link
 | 
			
		||||
        patch={Routes.ammo_group_index_path(Endpoint, :edit, @ammo_group)}
 | 
			
		||||
        class="text-primary-600 link"
 | 
			
		||||
        data-qa={"edit-#{@ammo_group.id}"}
 | 
			
		||||
      >
 | 
			
		||||
        <i class="fa-fw fa-lg fas fa-edit"></i>
 | 
			
		||||
      </.link>
 | 
			
		||||
 | 
			
		||||
      <.link
 | 
			
		||||
        patch={Routes.ammo_group_index_path(Endpoint, :clone, @ammo_group)}
 | 
			
		||||
        class="text-primary-600 link"
 | 
			
		||||
        data-qa={"clone-#{@ammo_group.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={@ammo_group.id}
 | 
			
		||||
        data-confirm={dgettext("prompts", "Are you sure you want to delete this ammo?")}
 | 
			
		||||
        data-qa={"delete-#{@ammo_group.id}"}
 | 
			
		||||
      >
 | 
			
		||||
        <i class="fa-fw fa-lg fas fa-trash"></i>
 | 
			
		||||
      </.link>
 | 
			
		||||
    </div>
 | 
			
		||||
    """
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  defp get_value_for_key(:container, %{container: nil}), do: {nil, nil}
 | 
			
		||||
 | 
			
		||||
  defp get_value_for_key(:container, %{container: %{name: container_name}} = ammo_group) do
 | 
			
		||||
    assigns = %{ammo_group: ammo_group}
 | 
			
		||||
 | 
			
		||||
    {container_name,
 | 
			
		||||
     ~H"""
 | 
			
		||||
     <div class="min-w-20 py-2 px-4 h-full flex flew-wrap justify-center items-center">
 | 
			
		||||
       <.link
 | 
			
		||||
         navigate={Routes.container_show_path(Endpoint, :show, @ammo_group.container)}
 | 
			
		||||
         class="mx-2 my-1 link"
 | 
			
		||||
       >
 | 
			
		||||
         <%= @ammo_group.container.name %>
 | 
			
		||||
       </.link>
 | 
			
		||||
 | 
			
		||||
       <.link
 | 
			
		||||
         patch={Routes.ammo_group_index_path(Endpoint, :move, @ammo_group)}
 | 
			
		||||
         class="mx-2 my-1 text-sm btn btn-primary"
 | 
			
		||||
       >
 | 
			
		||||
         <%= gettext("Move ammo") %>
 | 
			
		||||
       </.link>
 | 
			
		||||
     </div>
 | 
			
		||||
     """}
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  defp get_value_for_key(key, ammo_group), do: ammo_group |> Map.get(key)
 | 
			
		||||
end
 | 
			
		||||
 
 | 
			
		||||
@@ -42,7 +42,7 @@
 | 
			
		||||
  <% end %>
 | 
			
		||||
 | 
			
		||||
  <%= unless @ammo_groups |> Enum.empty?() do %>
 | 
			
		||||
    <div class="flex flex-col justify-center items-center">
 | 
			
		||||
    <div class="flex flex-col space-y-4 justify-center items-center">
 | 
			
		||||
      <.toggle_button action="toggle_show_used" value={@show_used}>
 | 
			
		||||
        <span class="title text-lg text-primary-600">
 | 
			
		||||
          <%= gettext("Show used") %>
 | 
			
		||||
@@ -51,12 +51,92 @@
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <.live_component
 | 
			
		||||
      module={CanneryWeb.Components.TableComponent}
 | 
			
		||||
      id="ammo_groups_index_table"
 | 
			
		||||
      action={@live_action}
 | 
			
		||||
      columns={@columns}
 | 
			
		||||
      rows={@rows}
 | 
			
		||||
    />
 | 
			
		||||
      module={CanneryWeb.Components.AmmoGroupTableComponent}
 | 
			
		||||
      id="ammo-group-index-table"
 | 
			
		||||
      ammo_groups={@ammo_groups}
 | 
			
		||||
      current_user={@current_user}
 | 
			
		||||
      show_used={@show_used}
 | 
			
		||||
    >
 | 
			
		||||
      <:ammo_type :let={%{name: ammo_type_name} = ammo_type}>
 | 
			
		||||
        <.link navigate={Routes.ammo_type_show_path(Endpoint, :show, ammo_type)} class="link">
 | 
			
		||||
          <%= ammo_type_name %>
 | 
			
		||||
        </.link>
 | 
			
		||||
      </:ammo_type>
 | 
			
		||||
      <:range :let={ammo_group}>
 | 
			
		||||
        <div class="min-w-20 py-2 px-4 h-full flex flew-wrap justify-center items-center">
 | 
			
		||||
          <button
 | 
			
		||||
            type="button"
 | 
			
		||||
            class="mx-2 my-1 text-sm btn btn-primary"
 | 
			
		||||
            phx-click="toggle_staged"
 | 
			
		||||
            phx-value-ammo_group_id={ammo_group.id}
 | 
			
		||||
          >
 | 
			
		||||
            <%= if ammo_group.staged, do: gettext("Unstage"), else: gettext("Stage") %>
 | 
			
		||||
          </button>
 | 
			
		||||
 | 
			
		||||
          <.link
 | 
			
		||||
            patch={Routes.ammo_group_index_path(Endpoint, :add_shot_group, ammo_group)}
 | 
			
		||||
            class="mx-2 my-1 text-sm btn btn-primary"
 | 
			
		||||
          >
 | 
			
		||||
            <%= dgettext("actions", "Record shots") %>
 | 
			
		||||
          </.link>
 | 
			
		||||
        </div>
 | 
			
		||||
      </:range>
 | 
			
		||||
      <:container :let={%{container: %{name: container_name} = container} = ammo_group}>
 | 
			
		||||
        <div class="min-w-20 py-2 px-4 h-full flex flew-wrap justify-center items-center">
 | 
			
		||||
          <.link
 | 
			
		||||
            navigate={Routes.container_show_path(Endpoint, :show, container)}
 | 
			
		||||
            class="mx-2 my-1 link"
 | 
			
		||||
          >
 | 
			
		||||
            <%= container_name %>
 | 
			
		||||
          </.link>
 | 
			
		||||
 | 
			
		||||
          <.link
 | 
			
		||||
            patch={Routes.ammo_group_index_path(Endpoint, :move, ammo_group)}
 | 
			
		||||
            class="mx-2 my-1 text-sm btn btn-primary"
 | 
			
		||||
          >
 | 
			
		||||
            <%= gettext("Move ammo") %>
 | 
			
		||||
          </.link>
 | 
			
		||||
        </div>
 | 
			
		||||
      </:container>
 | 
			
		||||
      <:actions :let={ammo_group}>
 | 
			
		||||
        <div class="py-2 px-4 h-full space-x-4 flex justify-center items-center">
 | 
			
		||||
          <.link
 | 
			
		||||
            navigate={Routes.ammo_group_show_path(Endpoint, :show, ammo_group)}
 | 
			
		||||
            class="text-primary-600 link"
 | 
			
		||||
            data-qa={"view-#{ammo_group.id}"}
 | 
			
		||||
          >
 | 
			
		||||
            <i class="fa-fw fa-lg fas fa-eye"></i>
 | 
			
		||||
          </.link>
 | 
			
		||||
 | 
			
		||||
          <.link
 | 
			
		||||
            patch={Routes.ammo_group_index_path(Endpoint, :edit, ammo_group)}
 | 
			
		||||
            class="text-primary-600 link"
 | 
			
		||||
            data-qa={"edit-#{ammo_group.id}"}
 | 
			
		||||
          >
 | 
			
		||||
            <i class="fa-fw fa-lg fas fa-edit"></i>
 | 
			
		||||
          </.link>
 | 
			
		||||
 | 
			
		||||
          <.link
 | 
			
		||||
            patch={Routes.ammo_group_index_path(Endpoint, :clone, ammo_group)}
 | 
			
		||||
            class="text-primary-600 link"
 | 
			
		||||
            data-qa={"clone-#{ammo_group.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={ammo_group.id}
 | 
			
		||||
            data-confirm={dgettext("prompts", "Are you sure you want to delete this ammo?")}
 | 
			
		||||
            data-qa={"delete-#{ammo_group.id}"}
 | 
			
		||||
          >
 | 
			
		||||
            <i class="fa-fw fa-lg fas fa-trash"></i>
 | 
			
		||||
          </.link>
 | 
			
		||||
        </div>
 | 
			
		||||
      </:actions>
 | 
			
		||||
    </.live_component>
 | 
			
		||||
  <% end %>
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -102,12 +102,12 @@ defmodule CanneryWeb.AmmoGroupLive.Show do
 | 
			
		||||
  defp display_ammo_group(%{assigns: %{current_user: current_user}} = socket, id),
 | 
			
		||||
    do: display_ammo_group(socket, Ammo.get_ammo_group!(id, current_user))
 | 
			
		||||
 | 
			
		||||
  @spec get_table_row_for_shot_group(AmmoGroup.t(), ShotGroup.t(), [map()]) :: [map()]
 | 
			
		||||
  @spec get_table_row_for_shot_group(AmmoGroup.t(), ShotGroup.t(), [map()]) :: map()
 | 
			
		||||
  defp get_table_row_for_shot_group(ammo_group, %{date: date} = shot_group, columns) do
 | 
			
		||||
    assigns = %{ammo_group: ammo_group, shot_group: shot_group}
 | 
			
		||||
 | 
			
		||||
    columns
 | 
			
		||||
    |> Enum.into(%{}, fn %{key: key} ->
 | 
			
		||||
    |> Map.new(fn %{key: key} ->
 | 
			
		||||
      value =
 | 
			
		||||
        case key do
 | 
			
		||||
          :date ->
 | 
			
		||||
 
 | 
			
		||||
@@ -134,7 +134,7 @@ defmodule CanneryWeb.AmmoTypeLive.Index do
 | 
			
		||||
        end
 | 
			
		||||
      )
 | 
			
		||||
      |> Kernel.++([
 | 
			
		||||
        %{label: gettext("Average Price paid"), key: :avg_price_paid, type: :avg_price_paid},
 | 
			
		||||
        %{label: gettext("Average CPR"), key: :avg_price_paid, type: :avg_price_paid},
 | 
			
		||||
        %{label: nil, key: "actions", type: :actions, sortable: false}
 | 
			
		||||
      ])
 | 
			
		||||
 | 
			
		||||
@@ -147,7 +147,7 @@ defmodule CanneryWeb.AmmoTypeLive.Index do
 | 
			
		||||
 | 
			
		||||
  defp get_ammo_type_values(ammo_type, columns, current_user) do
 | 
			
		||||
    columns
 | 
			
		||||
    |> Enum.into(%{}, fn %{key: key, type: type} ->
 | 
			
		||||
    |> Map.new(fn %{key: key, type: type} ->
 | 
			
		||||
      {key, get_ammo_type_value(type, key, ammo_type, current_user)}
 | 
			
		||||
    end)
 | 
			
		||||
  end
 | 
			
		||||
 
 | 
			
		||||
@@ -8,13 +8,41 @@ defmodule CanneryWeb.AmmoTypeLive.Show do
 | 
			
		||||
  alias Cannery.Ammo
 | 
			
		||||
  alias CanneryWeb.Endpoint
 | 
			
		||||
 | 
			
		||||
  @impl true
 | 
			
		||||
  def mount(_params, _session, socket), do: {:ok, socket |> assign(show_used: false)}
 | 
			
		||||
  @fields_list [
 | 
			
		||||
    %{label: gettext("Bullet type:"), key: :bullet_type, type: :string},
 | 
			
		||||
    %{label: gettext("Bullet core:"), key: :bullet_core, type: :string},
 | 
			
		||||
    %{label: gettext("Cartridge:"), key: :cartridge, type: :string},
 | 
			
		||||
    %{label: gettext("Caliber:"), key: :caliber, type: :string},
 | 
			
		||||
    %{label: gettext("Case material:"), key: :case_material, type: :string},
 | 
			
		||||
    %{label: gettext("Jacket type:"), key: :jacket_type, type: :string},
 | 
			
		||||
    %{label: gettext("Muzzle velocity:"), key: :muzzle_velocity, type: :string},
 | 
			
		||||
    %{label: gettext("Powder type:"), key: :powder_type, type: :string},
 | 
			
		||||
    %{label: gettext("Powder grains per charge:"), key: :powder_grains_per_charge, type: :string},
 | 
			
		||||
    %{label: gettext("Grains:"), key: :grains, type: :string},
 | 
			
		||||
    %{label: gettext("Pressure:"), key: :pressure, type: :string},
 | 
			
		||||
    %{label: gettext("Primer type:"), key: :primer_type, type: :string},
 | 
			
		||||
    %{label: gettext("Firing type:"), key: :firing_type, type: :string},
 | 
			
		||||
    %{label: gettext("Tracer:"), key: :tracer, type: :boolean},
 | 
			
		||||
    %{label: gettext("Incendiary:"), key: :incendiary, type: :boolean},
 | 
			
		||||
    %{label: gettext("Blank:"), key: :blank, type: :boolean},
 | 
			
		||||
    %{label: gettext("Corrosive:"), key: :corrosive, type: :boolean},
 | 
			
		||||
    %{label: gettext("Manufacturer:"), key: :manufacturer, type: :string},
 | 
			
		||||
    %{label: gettext("UPC:"), key: :upc, type: :string}
 | 
			
		||||
  ]
 | 
			
		||||
 | 
			
		||||
  @impl true
 | 
			
		||||
  def handle_params(%{"id" => id}, _params, %{assigns: %{current_user: current_user}} = socket) do
 | 
			
		||||
  def mount(_params, _session, socket),
 | 
			
		||||
    do: {:ok, socket |> assign(show_used: false, view_table: false)}
 | 
			
		||||
 | 
			
		||||
  @impl true
 | 
			
		||||
  def handle_params(
 | 
			
		||||
        %{"id" => id},
 | 
			
		||||
        _params,
 | 
			
		||||
        %{assigns: %{current_user: current_user, live_action: live_action}} = socket
 | 
			
		||||
      ) do
 | 
			
		||||
    ammo_type = Ammo.get_ammo_type!(id, current_user)
 | 
			
		||||
    {:noreply, socket |> display_ammo_type(ammo_type)}
 | 
			
		||||
    socket = socket |> assign(view_table: live_action == :table) |> display_ammo_type(ammo_type)
 | 
			
		||||
    {:noreply, socket}
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  @impl true
 | 
			
		||||
@@ -36,22 +64,45 @@ defmodule CanneryWeb.AmmoTypeLive.Show do
 | 
			
		||||
    {:noreply, socket |> assign(:show_used, !show_used) |> display_ammo_type()}
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  @impl true
 | 
			
		||||
  def handle_event(
 | 
			
		||||
        "toggle_table",
 | 
			
		||||
        _params,
 | 
			
		||||
        %{assigns: %{view_table: view_table, ammo_type: ammo_type}} = socket
 | 
			
		||||
      ) do
 | 
			
		||||
    new_path =
 | 
			
		||||
      if view_table,
 | 
			
		||||
        do: Routes.ammo_type_show_path(Endpoint, :show, ammo_type),
 | 
			
		||||
        else: Routes.ammo_type_show_path(Endpoint, :table, ammo_type)
 | 
			
		||||
 | 
			
		||||
    {:noreply, socket |> assign(view_table: !view_table) |> push_patch(to: new_path)}
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  defp display_ammo_type(
 | 
			
		||||
         %{
 | 
			
		||||
           assigns: %{
 | 
			
		||||
             live_action: live_action,
 | 
			
		||||
             current_user: current_user,
 | 
			
		||||
             show_used: show_used
 | 
			
		||||
           }
 | 
			
		||||
         } = socket,
 | 
			
		||||
         %{assigns: %{live_action: live_action, current_user: current_user, show_used: show_used}} =
 | 
			
		||||
           socket,
 | 
			
		||||
         ammo_type
 | 
			
		||||
       ) do
 | 
			
		||||
    fields_to_display =
 | 
			
		||||
      @fields_list
 | 
			
		||||
      |> Enum.any?(fn %{key: field, type: type} ->
 | 
			
		||||
        default_value =
 | 
			
		||||
          case type do
 | 
			
		||||
            :boolean -> false
 | 
			
		||||
            _other_type -> nil
 | 
			
		||||
          end
 | 
			
		||||
 | 
			
		||||
        ammo_type |> Map.get(field) != default_value
 | 
			
		||||
      end)
 | 
			
		||||
 | 
			
		||||
    socket
 | 
			
		||||
    |> assign(
 | 
			
		||||
      page_title: page_title(live_action),
 | 
			
		||||
      page_title: page_title(live_action, ammo_type),
 | 
			
		||||
      ammo_type: ammo_type,
 | 
			
		||||
      ammo_groups: ammo_type |> Ammo.list_ammo_groups_for_type(current_user, show_used),
 | 
			
		||||
      avg_cost_per_round: ammo_type |> Ammo.get_average_cost_for_ammo_type!(current_user)
 | 
			
		||||
      avg_cost_per_round: ammo_type |> Ammo.get_average_cost_for_ammo_type!(current_user),
 | 
			
		||||
      fields_list: @fields_list,
 | 
			
		||||
      fields_to_display: fields_to_display
 | 
			
		||||
    )
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
@@ -59,6 +110,9 @@ defmodule CanneryWeb.AmmoTypeLive.Show do
 | 
			
		||||
    socket |> display_ammo_type(ammo_type)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  defp page_title(:show), do: gettext("Show Ammo type")
 | 
			
		||||
  defp page_title(:edit), do: gettext("Edit Ammo type")
 | 
			
		||||
  defp page_title(action, %{name: ammo_type_name}) when action in [:show, :table],
 | 
			
		||||
    do: ammo_type_name
 | 
			
		||||
 | 
			
		||||
  defp page_title(:edit, %{name: ammo_type_name}),
 | 
			
		||||
    do: gettext("Edit %{ammo_type_name}", ammo_type_name: ammo_type_name)
 | 
			
		||||
end
 | 
			
		||||
 
 | 
			
		||||
@@ -39,44 +39,30 @@
 | 
			
		||||
 | 
			
		||||
  <hr class="hr" />
 | 
			
		||||
 | 
			
		||||
  <div class="grid sm:grid-cols-2 gap-4 text-center justify-center items-center">
 | 
			
		||||
    <%= for {field_name, field, type} <- [
 | 
			
		||||
          {gettext("Bullet type"), :bullet_type, :string},
 | 
			
		||||
          {gettext("Bullet core"), :bullet_core, :string},
 | 
			
		||||
          {gettext("Cartridge"), :cartridge, :string},
 | 
			
		||||
          {gettext("Caliber"), :caliber, :string},
 | 
			
		||||
          {gettext("Case material"), :case_material, :string},
 | 
			
		||||
          {gettext("Jacket type"), :jacket_type, :string},
 | 
			
		||||
          {gettext("Muzzle velocity"), :muzzle_velocity, :string},
 | 
			
		||||
          {gettext("Powder type"), :powder_type, :string},
 | 
			
		||||
          {gettext("Powder grains per charge"), :powder_grains_per_charge, :string},
 | 
			
		||||
          {gettext("Grains"), :grains, :string},
 | 
			
		||||
          {gettext("Pressure"), :pressure, :string},
 | 
			
		||||
          {gettext("Primer type"), :primer_type, :string},
 | 
			
		||||
          {gettext("Firing type"), :firing_type, :string},
 | 
			
		||||
          {gettext("Tracer"), :tracer, :boolean},
 | 
			
		||||
          {gettext("Incendiary"), :incendiary, :boolean},
 | 
			
		||||
          {gettext("Blank"), :blank, :boolean},
 | 
			
		||||
          {gettext("Corrosive"), :corrosive, :boolean},
 | 
			
		||||
          {gettext("Manufacturer"), :manufacturer, :string},
 | 
			
		||||
          {gettext("UPC"), :upc, :string}
 | 
			
		||||
        ] do %>
 | 
			
		||||
      <%= if @ammo_type |> Map.get(field) do %>
 | 
			
		||||
        <h3 class="title text-lg">
 | 
			
		||||
          <%= field_name %>:
 | 
			
		||||
        </h3>
 | 
			
		||||
  <%= if @fields_to_display do %>
 | 
			
		||||
    <div class="grid sm:grid-cols-2 gap-4 text-center justify-center items-center">
 | 
			
		||||
      <%= for %{label: label, key: key, type: type} <- @fields_list do %>
 | 
			
		||||
        <%= if @ammo_type |> Map.get(key) do %>
 | 
			
		||||
          <h3 class="title text-lg">
 | 
			
		||||
            <%= label %>
 | 
			
		||||
          </h3>
 | 
			
		||||
 | 
			
		||||
        <span class="text-primary-600">
 | 
			
		||||
          <%= case type do %>
 | 
			
		||||
            <% :boolean -> %>
 | 
			
		||||
              <%= @ammo_type |> Map.get(field) |> humanize() %>
 | 
			
		||||
            <% _ -> %>
 | 
			
		||||
              <%= @ammo_type |> Map.get(field) %>
 | 
			
		||||
          <% end %>
 | 
			
		||||
        </span>
 | 
			
		||||
          <span class="text-primary-600">
 | 
			
		||||
            <%= case type do %>
 | 
			
		||||
              <% :boolean -> %>
 | 
			
		||||
                <%= @ammo_type |> Map.get(key) |> humanize() %>
 | 
			
		||||
              <% _ -> %>
 | 
			
		||||
                <%= @ammo_type |> Map.get(key) %>
 | 
			
		||||
            <% end %>
 | 
			
		||||
          </span>
 | 
			
		||||
        <% end %>
 | 
			
		||||
      <% end %>
 | 
			
		||||
    <% end %>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <hr class="hr" />
 | 
			
		||||
  <% end %>
 | 
			
		||||
 | 
			
		||||
  <div class="grid sm:grid-cols-2 gap-4 text-center justify-center items-center">
 | 
			
		||||
    <h3 class="title text-lg">
 | 
			
		||||
      <%= gettext("Rounds:") %>
 | 
			
		||||
    </h3>
 | 
			
		||||
@@ -100,7 +86,11 @@
 | 
			
		||||
    <span class="text-primary-600">
 | 
			
		||||
      <%= @ammo_type |> Ammo.get_historical_count_for_ammo_type(@current_user) %>
 | 
			
		||||
    </span>
 | 
			
		||||
  </div>
 | 
			
		||||
 | 
			
		||||
  <hr class="hr" />
 | 
			
		||||
 | 
			
		||||
  <div class="grid sm:grid-cols-2 gap-4 text-center justify-center items-center">
 | 
			
		||||
    <h3 class="title text-lg">
 | 
			
		||||
      <%= gettext("Packs:") %>
 | 
			
		||||
    </h3>
 | 
			
		||||
@@ -124,7 +114,11 @@
 | 
			
		||||
    <span class="text-primary-600">
 | 
			
		||||
      <%= @ammo_type |> Ammo.get_ammo_groups_count_for_type(@current_user, true) %>
 | 
			
		||||
    </span>
 | 
			
		||||
  </div>
 | 
			
		||||
 | 
			
		||||
  <hr class="hr" />
 | 
			
		||||
 | 
			
		||||
  <div class="grid sm:grid-cols-2 gap-4 text-center justify-center items-center">
 | 
			
		||||
    <h3 class="title text-lg">
 | 
			
		||||
      <%= gettext("Added on:") %>
 | 
			
		||||
    </h3>
 | 
			
		||||
@@ -135,7 +129,7 @@
 | 
			
		||||
 | 
			
		||||
    <%= if @avg_cost_per_round do %>
 | 
			
		||||
      <h3 class="title text-lg">
 | 
			
		||||
        <%= gettext("Average Price paid") %>:
 | 
			
		||||
        <%= gettext("Average CPR") %>:
 | 
			
		||||
      </h3>
 | 
			
		||||
 | 
			
		||||
      <span class="text-primary-600">
 | 
			
		||||
@@ -152,26 +146,51 @@
 | 
			
		||||
 | 
			
		||||
  <hr class="hr" />
 | 
			
		||||
 | 
			
		||||
  <div class="flex flex-col justify-center items-center">
 | 
			
		||||
  <div class="flex justify-center items-center space-x-4">
 | 
			
		||||
    <.toggle_button action="toggle_show_used" value={@show_used}>
 | 
			
		||||
      <span class="title text-lg text-primary-600">
 | 
			
		||||
        <%= gettext("Show used") %>
 | 
			
		||||
      </span>
 | 
			
		||||
    </.toggle_button>
 | 
			
		||||
 | 
			
		||||
    <.toggle_button action="toggle_table" value={@view_table}>
 | 
			
		||||
      <span class="title text-lg text-primary-600">
 | 
			
		||||
        <%= gettext("View as table") %>
 | 
			
		||||
      </span>
 | 
			
		||||
    </.toggle_button>
 | 
			
		||||
  </div>
 | 
			
		||||
 | 
			
		||||
  <div>
 | 
			
		||||
  <div class="w-full p-4">
 | 
			
		||||
    <%= if @ammo_groups |> Enum.empty?() do %>
 | 
			
		||||
      <h2 class="mx-8 my-4 title text-lg text-primary-600">
 | 
			
		||||
      <h2 class="px-4 title text-lg text-primary-600">
 | 
			
		||||
        <%= gettext("No ammo for this type") %>
 | 
			
		||||
        <%= display_emoji("😔") %>
 | 
			
		||||
      </h2>
 | 
			
		||||
    <% else %>
 | 
			
		||||
      <div class="flex flex-wrap justify-center items-center">
 | 
			
		||||
        <%= for ammo_group <- @ammo_groups do %>
 | 
			
		||||
          <.ammo_group_card ammo_group={ammo_group} show_container={true} />
 | 
			
		||||
        <% end %>
 | 
			
		||||
      </div>
 | 
			
		||||
      <%= if @view_table do %>
 | 
			
		||||
        <.live_component
 | 
			
		||||
          module={CanneryWeb.Components.AmmoGroupTableComponent}
 | 
			
		||||
          id="ammo-type-show-table"
 | 
			
		||||
          ammo_groups={@ammo_groups}
 | 
			
		||||
          current_user={@current_user}
 | 
			
		||||
          show_used={@show_used}
 | 
			
		||||
        >
 | 
			
		||||
          <:container :let={%{container: %{name: container_name} = container}}>
 | 
			
		||||
            <.link
 | 
			
		||||
              navigate={Routes.container_show_path(Endpoint, :show, container)}
 | 
			
		||||
              class="mx-2 my-1 link"
 | 
			
		||||
            >
 | 
			
		||||
              <%= container_name %>
 | 
			
		||||
            </.link>
 | 
			
		||||
          </:container>
 | 
			
		||||
        </.live_component>
 | 
			
		||||
      <% else %>
 | 
			
		||||
        <div class="flex flex-wrap justify-center items-center">
 | 
			
		||||
          <%= for ammo_group <- @ammo_groups do %>
 | 
			
		||||
            <.ammo_group_card ammo_group={ammo_group} show_container={true} />
 | 
			
		||||
          <% end %>
 | 
			
		||||
        </div>
 | 
			
		||||
      <% end %>
 | 
			
		||||
    <% end %>
 | 
			
		||||
  </div>
 | 
			
		||||
</div>
 | 
			
		||||
 
 | 
			
		||||
@@ -153,12 +153,12 @@ defmodule CanneryWeb.ContainerLive.Index do
 | 
			
		||||
    )
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  @spec get_row_data_for_container(Container.t(), [map()]) :: [map()]
 | 
			
		||||
  @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
 | 
			
		||||
    |> Enum.into(%{}, fn %{key: key} -> {key, get_value_for_key(key, container)} end)
 | 
			
		||||
    |> Map.new(fn %{key: key} -> {key, get_value_for_key(key, container)} end)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  @spec get_value_for_key(atom(), Container.t()) :: any()
 | 
			
		||||
 
 | 
			
		||||
@@ -26,7 +26,7 @@
 | 
			
		||||
    </div>
 | 
			
		||||
  <% end %>
 | 
			
		||||
 | 
			
		||||
  <div class="max-w-full flex flex-row flex-wrap justify-center items-center">
 | 
			
		||||
  <div class="w-full flex flex-row flex-wrap justify-center items-center">
 | 
			
		||||
    <%= if @view_table do %>
 | 
			
		||||
      <.live_component
 | 
			
		||||
        module={CanneryWeb.Components.TableComponent}
 | 
			
		||||
 
 | 
			
		||||
@@ -11,15 +11,19 @@ defmodule CanneryWeb.ContainerLive.Show do
 | 
			
		||||
  alias Phoenix.LiveView.Socket
 | 
			
		||||
 | 
			
		||||
  @impl true
 | 
			
		||||
  def mount(_params, _session, socket), do: {:ok, socket |> assign(show_used: false)}
 | 
			
		||||
  def mount(_params, _session, socket),
 | 
			
		||||
    do: {:ok, socket |> assign(show_used: false, view_table: false)}
 | 
			
		||||
 | 
			
		||||
  @impl true
 | 
			
		||||
  def handle_params(
 | 
			
		||||
        %{"id" => id},
 | 
			
		||||
        _session,
 | 
			
		||||
        %{assigns: %{current_user: current_user}} = socket
 | 
			
		||||
        %{assigns: %{current_user: current_user, live_action: live_action}} = socket
 | 
			
		||||
      ) do
 | 
			
		||||
    {:noreply, socket |> render_container(id, current_user)}
 | 
			
		||||
    socket =
 | 
			
		||||
      socket |> assign(view_table: live_action == :table) |> render_container(id, current_user)
 | 
			
		||||
 | 
			
		||||
    {:noreply, socket}
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  @impl true
 | 
			
		||||
@@ -87,6 +91,20 @@ defmodule CanneryWeb.ContainerLive.Show do
 | 
			
		||||
    {:noreply, socket |> assign(:show_used, !show_used) |> render_container()}
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  @impl true
 | 
			
		||||
  def handle_event(
 | 
			
		||||
        "toggle_table",
 | 
			
		||||
        _params,
 | 
			
		||||
        %{assigns: %{view_table: view_table, container: container}} = socket
 | 
			
		||||
      ) do
 | 
			
		||||
    new_path =
 | 
			
		||||
      if view_table,
 | 
			
		||||
        do: Routes.container_show_path(Endpoint, :show, container),
 | 
			
		||||
        else: Routes.container_show_path(Endpoint, :table, container)
 | 
			
		||||
 | 
			
		||||
    {:noreply, socket |> assign(view_table: !view_table) |> push_patch(to: new_path)}
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  @spec render_container(Socket.t(), Container.id(), User.t()) :: Socket.t()
 | 
			
		||||
  defp render_container(
 | 
			
		||||
         %{assigns: %{live_action: live_action, show_used: show_used}} = socket,
 | 
			
		||||
@@ -102,7 +120,7 @@ defmodule CanneryWeb.ContainerLive.Show do
 | 
			
		||||
 | 
			
		||||
    page_title =
 | 
			
		||||
      case live_action do
 | 
			
		||||
        :show -> gettext("Show %{name}", name: container_name)
 | 
			
		||||
        action when action in [:show, :table] -> container_name
 | 
			
		||||
        :edit -> gettext("Edit %{name}", name: container_name)
 | 
			
		||||
        :edit_tags -> gettext("Edit %{name} tags", name: container_name)
 | 
			
		||||
      end
 | 
			
		||||
 
 | 
			
		||||
@@ -91,25 +91,47 @@
 | 
			
		||||
 | 
			
		||||
  <hr class="mb-4 hr" />
 | 
			
		||||
 | 
			
		||||
  <div class="flex flex-col justify-center items-center">
 | 
			
		||||
  <div class="flex justify-center items-center space-x-4">
 | 
			
		||||
    <.toggle_button action="toggle_show_used" value={@show_used}>
 | 
			
		||||
      <span class="title text-lg text-primary-600">
 | 
			
		||||
        <%= dgettext("actions", "Show used") %>
 | 
			
		||||
        <%= gettext("Show used") %>
 | 
			
		||||
      </span>
 | 
			
		||||
    </.toggle_button>
 | 
			
		||||
 | 
			
		||||
    <.toggle_button action="toggle_table" value={@view_table}>
 | 
			
		||||
      <span class="title text-lg text-primary-600">
 | 
			
		||||
        <%= gettext("View as table") %>
 | 
			
		||||
      </span>
 | 
			
		||||
    </.toggle_button>
 | 
			
		||||
  </div>
 | 
			
		||||
 | 
			
		||||
  <div>
 | 
			
		||||
  <div class="w-full p-4">
 | 
			
		||||
    <%= if @ammo_groups |> Enum.empty?() do %>
 | 
			
		||||
      <h2 class="mx-8 my-4 title text-lg text-primary-600">
 | 
			
		||||
      <h2 class="mx-4 title text-lg text-primary-600">
 | 
			
		||||
        <%= gettext("No ammo in this container") %>
 | 
			
		||||
      </h2>
 | 
			
		||||
    <% else %>
 | 
			
		||||
      <div class="flex flex-wrap justify-center items-center">
 | 
			
		||||
        <%= for ammo_group <- @ammo_groups do %>
 | 
			
		||||
          <.ammo_group_card ammo_group={ammo_group} />
 | 
			
		||||
        <% end %>
 | 
			
		||||
      </div>
 | 
			
		||||
      <%= if @view_table do %>
 | 
			
		||||
        <.live_component
 | 
			
		||||
          module={CanneryWeb.Components.AmmoGroupTableComponent}
 | 
			
		||||
          id="ammo-type-show-table"
 | 
			
		||||
          ammo_groups={@ammo_groups}
 | 
			
		||||
          current_user={@current_user}
 | 
			
		||||
          show_used={@show_used}
 | 
			
		||||
        >
 | 
			
		||||
          <:ammo_type :let={%{name: ammo_type_name} = ammo_type}>
 | 
			
		||||
            <.link navigate={Routes.ammo_type_show_path(Endpoint, :show, ammo_type)} class="link">
 | 
			
		||||
              <%= ammo_type_name %>
 | 
			
		||||
            </.link>
 | 
			
		||||
          </:ammo_type>
 | 
			
		||||
        </.live_component>
 | 
			
		||||
      <% else %>
 | 
			
		||||
        <div class="flex flex-wrap justify-center items-center">
 | 
			
		||||
          <%= for ammo_group <- @ammo_groups do %>
 | 
			
		||||
            <.ammo_group_card ammo_group={ammo_group} />
 | 
			
		||||
          <% end %>
 | 
			
		||||
        </div>
 | 
			
		||||
      <% end %>
 | 
			
		||||
    <% end %>
 | 
			
		||||
  </div>
 | 
			
		||||
</div>
 | 
			
		||||
 
 | 
			
		||||
@@ -71,8 +71,9 @@ defmodule CanneryWeb.Router do
 | 
			
		||||
    live "/catalog/:id/clone", AmmoTypeLive.Index, :clone
 | 
			
		||||
    live "/catalog/:id/edit", AmmoTypeLive.Index, :edit
 | 
			
		||||
 | 
			
		||||
    live "/catalog/:id", AmmoTypeLive.Show, :show
 | 
			
		||||
    live "/catalog/:id/show", AmmoTypeLive.Show, :show
 | 
			
		||||
    live "/catalog/:id/show/edit", AmmoTypeLive.Show, :edit
 | 
			
		||||
    live "/catalog/:id/show/table", AmmoTypeLive.Show, :table
 | 
			
		||||
 | 
			
		||||
    live "/containers", ContainerLive.Index, :index
 | 
			
		||||
    live "/containers/table", ContainerLive.Index, :table
 | 
			
		||||
@@ -81,7 +82,8 @@ defmodule CanneryWeb.Router do
 | 
			
		||||
    live "/containers/:id/clone", ContainerLive.Index, :clone
 | 
			
		||||
    live "/containers/:id/edit_tags", ContainerLive.Index, :edit_tags
 | 
			
		||||
 | 
			
		||||
    live "/containers/:id", ContainerLive.Show, :show
 | 
			
		||||
    live "/containers/:id/show", ContainerLive.Show, :show
 | 
			
		||||
    live "/containers/:id/show/table", ContainerLive.Show, :table
 | 
			
		||||
    live "/containers/:id/show/edit", ContainerLive.Show, :edit
 | 
			
		||||
    live "/containers/:id/show/edit_tags", ContainerLive.Show, :edit_tags
 | 
			
		||||
 | 
			
		||||
@@ -92,7 +94,7 @@ defmodule CanneryWeb.Router do
 | 
			
		||||
    live "/ammo/:id/add_shot_group", AmmoGroupLive.Index, :add_shot_group
 | 
			
		||||
    live "/ammo/:id/move", AmmoGroupLive.Index, :move
 | 
			
		||||
 | 
			
		||||
    live "/ammo/:id", AmmoGroupLive.Show, :show
 | 
			
		||||
    live "/ammo/:id/show", AmmoGroupLive.Show, :show
 | 
			
		||||
    live "/ammo/:id/show/edit", AmmoGroupLive.Show, :edit
 | 
			
		||||
    live "/ammo/:id/show/add_shot_group", AmmoGroupLive.Show, :add_shot_group
 | 
			
		||||
    live "/ammo/:id/show/move", AmmoGroupLive.Show, :move
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user