forked from shibao/cannery
		
	Compare commits
	
		
			27 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 81f21a02c4 | |||
| 9a17d4ad24 | |||
| 9835fe3f5e | |||
| 4dee8808f3 | |||
| 65c70ca398 | |||
| 550f6a6420 | |||
| 88c3f15fc8 | |||
| c33f15603b | |||
| 98775359af | |||
| e0e7b25bc4 | |||
| bdddf65685 | |||
| 6f50702b11 | |||
| 5f8d1a917f | |||
| 32801828fa | |||
| 6ed3312ea8 | |||
| b122253b9b | |||
| a68a16bf06 | |||
| 4b6d0952f8 | |||
| 0544b58ab6 | |||
| 6d26103784 | |||
| 0cae7c2940 | |||
| 1e645b5bb8 | |||
| bab2b26c13 | |||
| 8c95536ffd | |||
| d9251c7e4c | |||
| fe4e4f4f17 | |||
| e5e5449e8b | 
							
								
								
									
										33
									
								
								CHANGELOG.md
									
									
									
									
									
								
							
							
						
						
									
										33
									
								
								CHANGELOG.md
									
									
									
									
									
								
							@@ -1,3 +1,22 @@
 | 
				
			|||||||
 | 
					# v0.9.2
 | 
				
			||||||
 | 
					- Add lot number to packs
 | 
				
			||||||
 | 
					- Don't show price paid and lot number columns when displaying packs if not used
 | 
				
			||||||
 | 
					- Fix additional shotgun fields not being exportable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# v0.9.1
 | 
				
			||||||
 | 
					- Rename ammo type's "type" to "class" to avoid confusion
 | 
				
			||||||
 | 
					- Rename "ammo type" to "type" to avoid confusion
 | 
				
			||||||
 | 
					- Fixes type search
 | 
				
			||||||
 | 
					- Fixes shot records table disappearing after selecting an empty ammo class
 | 
				
			||||||
 | 
					- Code quality improvements
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# v0.9.0
 | 
				
			||||||
 | 
					- Add length limits to all string fields
 | 
				
			||||||
 | 
					- Add selectable ammo types
 | 
				
			||||||
 | 
					- Improve onboarding experience slightly
 | 
				
			||||||
 | 
					- Remove show used view from a container since it doesn't really make that much
 | 
				
			||||||
 | 
					  sense
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# v0.8.6
 | 
					# v0.8.6
 | 
				
			||||||
- Fix duplicate entries showing up
 | 
					- Fix duplicate entries showing up
 | 
				
			||||||
- Show ammo packs under a type in a table by default
 | 
					- Show ammo packs under a type in a table by default
 | 
				
			||||||
@@ -44,7 +63,7 @@
 | 
				
			|||||||
# v0.8.0
 | 
					# v0.8.0
 | 
				
			||||||
- Add search to catalog, ammo, container, tag and range index pages
 | 
					- Add search to catalog, ammo, container, tag and range index pages
 | 
				
			||||||
- Tweak urls for catalog, ammo, containers, tags and shot records
 | 
					- Tweak urls for catalog, ammo, containers, tags and shot records
 | 
				
			||||||
- Fix bug with shot group chart not drawing lines between days correctly
 | 
					- Fix bug with shot record chart not drawing lines between days correctly
 | 
				
			||||||
- Improve cards across app (make them line up with each other)
 | 
					- Improve cards across app (make them line up with each other)
 | 
				
			||||||
- Update translations and add spanish!!! (thank you Brea and Hannah!)
 | 
					- Update translations and add spanish!!! (thank you Brea and Hannah!)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -56,7 +75,7 @@
 | 
				
			|||||||
- Fix toggle button styling
 | 
					- Fix toggle button styling
 | 
				
			||||||
- Miscellanous code improvements
 | 
					- Miscellanous code improvements
 | 
				
			||||||
- Improve container index table
 | 
					- Improve container index table
 | 
				
			||||||
- Fix bug with ammo not updating after deleting shot group
 | 
					- Fix bug with ammo not updating after deleting shot record
 | 
				
			||||||
- Replace ammo "added on" with "purchased on"
 | 
					- Replace ammo "added on" with "purchased on"
 | 
				
			||||||
- Miscellaneous wording improvements
 | 
					- Miscellaneous wording improvements
 | 
				
			||||||
- Update translations
 | 
					- Update translations
 | 
				
			||||||
@@ -65,8 +84,8 @@
 | 
				
			|||||||
- Add shading to table component
 | 
					- Add shading to table component
 | 
				
			||||||
- Fix chart to sum by day
 | 
					- Fix chart to sum by day
 | 
				
			||||||
- Fix whitespace when copying invite url
 | 
					- Fix whitespace when copying invite url
 | 
				
			||||||
- Make ammo type show page also display ammo groups as table
 | 
					- Make ammo type show page also display packs as table
 | 
				
			||||||
- Make container show page also display ammo groups as table
 | 
					- Make container show page also display packs as table
 | 
				
			||||||
- Display CPR for ammo packs
 | 
					- Display CPR for ammo packs
 | 
				
			||||||
- Add original count for ammo packs
 | 
					- Add original count for ammo packs
 | 
				
			||||||
- Add ammo pack CPR and original count to json export
 | 
					- Add ammo pack CPR and original count to json export
 | 
				
			||||||
@@ -90,7 +109,7 @@
 | 
				
			|||||||
- Add ammo type cloning
 | 
					- Add ammo type cloning
 | 
				
			||||||
- Add container cloning
 | 
					- Add container cloning
 | 
				
			||||||
- Fix bug with moving ammo packs between containers
 | 
					- Fix bug with moving ammo packs between containers
 | 
				
			||||||
- Add button to set rounds left to 0 when creating a shot group
 | 
					- Add button to set rounds left to 0 when creating a shot record
 | 
				
			||||||
- Update project dependencies
 | 
					- Update project dependencies
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# v0.5.4
 | 
					# v0.5.4
 | 
				
			||||||
@@ -142,8 +161,8 @@
 | 
				
			|||||||
# v0.3.0
 | 
					# v0.3.0
 | 
				
			||||||
- Fix ammo type counts not showing when count is 0
 | 
					- Fix ammo type counts not showing when count is 0
 | 
				
			||||||
- Add prompt to create first container before first ammo group
 | 
					- Add prompt to create first container before first ammo group
 | 
				
			||||||
- Edit and delete shot groups from ammo group show page
 | 
					- Edit and delete shot records from ammo group show page
 | 
				
			||||||
- Use today's date when adding new shot groups
 | 
					- Use today's date when adding new shot records
 | 
				
			||||||
- Create multiple ammo groups at one time
 | 
					- Create multiple ammo groups at one time
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# v0.2.3
 | 
					# v0.2.3
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,8 +17,8 @@ If you're multilingual, this project can use your translations! Visit
 | 
				
			|||||||
  functions as short as possible while keeping variable names descriptive! For
 | 
					  functions as short as possible while keeping variable names descriptive! For
 | 
				
			||||||
  instance, use inline `do:` blocks for short functions and make your aliases as
 | 
					  instance, use inline `do:` blocks for short functions and make your aliases as
 | 
				
			||||||
  short as possible without introducing ambiguity.
 | 
					  short as possible without introducing ambiguity.
 | 
				
			||||||
  - I.e. since there's only one `AmmoGroup` in the app, please alias
 | 
					  - I.e. since there's only one `Pack` in the app, please alias
 | 
				
			||||||
    `AmmoGroup.t()` instead of using `Cannery.Ammo.AmmoGroup.t()`
 | 
					    `Pack.t()` instead of using `Cannery.Ammo.Pack.t()`
 | 
				
			||||||
- Use pipelines when possible. If only calling a single method, a pipeline isn't
 | 
					- Use pipelines when possible. If only calling a single method, a pipeline isn't
 | 
				
			||||||
  strictly necessary but still encouraged for future modification.
 | 
					  strictly necessary but still encouraged for future modification.
 | 
				
			||||||
- Please add typespecs to your functions! Even your private functions may be
 | 
					- Please add typespecs to your functions! Even your private functions may be
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -13,8 +13,8 @@ The self-hosted firearm tracker website.
 | 
				
			|||||||
# Features
 | 
					# Features
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- Create containers to store your ammunition, and tag them with custom tags
 | 
					- Create containers to store your ammunition, and tag them with custom tags
 | 
				
			||||||
- Add ammunition types to Cannery, and then ammunition groups to your containers
 | 
					- Add ammunition types to Cannery, and then ammo packs to your containers
 | 
				
			||||||
- Stage groups of ammo for range day and record your ammo usage
 | 
					- Stage ammo packs for range day and track your usage with shot records
 | 
				
			||||||
- Invitations via invite tokens or public registration
 | 
					- Invitations via invite tokens or public registration
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Installation
 | 
					# Installation
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -45,7 +45,7 @@ module.exports = (env, options) => {
 | 
				
			|||||||
        {
 | 
					        {
 | 
				
			||||||
          test: /\.(woff(2)?|ttf|eot|svg|otf)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
 | 
					          test: /\.(woff(2)?|ttf|eot|svg|otf)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
 | 
				
			||||||
          type: 'asset/resource',
 | 
					          type: 'asset/resource',
 | 
				
			||||||
          generator: { filename: 'fonts/[name][ext]' }
 | 
					          generator: { filename: 'fonts/[name].[ext]' }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      ]
 | 
					      ]
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -48,8 +48,9 @@ defmodule Cannery.Accounts.Invite do
 | 
				
			|||||||
    %__MODULE__{}
 | 
					    %__MODULE__{}
 | 
				
			||||||
    |> change(token: token, created_by_id: user_id)
 | 
					    |> change(token: token, created_by_id: user_id)
 | 
				
			||||||
    |> cast(attrs, [:name, :uses_left, :disabled_at])
 | 
					    |> cast(attrs, [:name, :uses_left, :disabled_at])
 | 
				
			||||||
    |> validate_required([:name, :token, :created_by_id])
 | 
					    |> validate_length(:name, max: 255)
 | 
				
			||||||
    |> validate_number(:uses_left, greater_than_or_equal_to: 0)
 | 
					    |> validate_number(:uses_left, greater_than_or_equal_to: 0)
 | 
				
			||||||
 | 
					    |> validate_required([:name, :token, :created_by_id])
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @doc false
 | 
					  @doc false
 | 
				
			||||||
@@ -57,7 +58,8 @@ defmodule Cannery.Accounts.Invite do
 | 
				
			|||||||
  def update_changeset(invite, attrs) do
 | 
					  def update_changeset(invite, attrs) do
 | 
				
			||||||
    invite
 | 
					    invite
 | 
				
			||||||
    |> cast(attrs, [:name, :uses_left, :disabled_at])
 | 
					    |> cast(attrs, [:name, :uses_left, :disabled_at])
 | 
				
			||||||
    |> validate_required([:name])
 | 
					    |> validate_length(:name, max: 255)
 | 
				
			||||||
    |> validate_number(:uses_left, greater_than_or_equal_to: 0)
 | 
					    |> validate_number(:uses_left, greater_than_or_equal_to: 0)
 | 
				
			||||||
 | 
					    |> validate_required([:name])
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -79,6 +79,7 @@ defmodule Cannery.Accounts.User do
 | 
				
			|||||||
    %User{}
 | 
					    %User{}
 | 
				
			||||||
    |> cast(attrs, [:email, :password, :locale])
 | 
					    |> cast(attrs, [:email, :password, :locale])
 | 
				
			||||||
    |> put_change(:invite_id, if(invite, do: invite.id))
 | 
					    |> put_change(:invite_id, if(invite, do: invite.id))
 | 
				
			||||||
 | 
					    |> validate_length(:locale, max: 255)
 | 
				
			||||||
    |> validate_email()
 | 
					    |> validate_email()
 | 
				
			||||||
    |> validate_password(opts)
 | 
					    |> validate_password(opts)
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
@@ -209,6 +210,7 @@ defmodule Cannery.Accounts.User do
 | 
				
			|||||||
  def locale_changeset(user_or_changeset, locale) do
 | 
					  def locale_changeset(user_or_changeset, locale) do
 | 
				
			||||||
    user_or_changeset
 | 
					    user_or_changeset
 | 
				
			||||||
    |> cast(%{"locale" => locale}, [:locale])
 | 
					    |> cast(%{"locale" => locale}, [:locale])
 | 
				
			||||||
 | 
					    |> validate_length(:locale, max: 255)
 | 
				
			||||||
    |> validate_required(:locale)
 | 
					    |> validate_required(:locale)
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,97 +4,143 @@ defmodule Cannery.ActivityLog do
 | 
				
			|||||||
  """
 | 
					  """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  import Ecto.Query, warn: false
 | 
					  import Ecto.Query, warn: false
 | 
				
			||||||
  alias Cannery.Ammo.{AmmoGroup, AmmoType}
 | 
					  alias Cannery.Ammo.{Pack, Type}
 | 
				
			||||||
  alias Cannery.{Accounts.User, ActivityLog.ShotGroup, Repo}
 | 
					  alias Cannery.{Accounts.User, ActivityLog.ShotRecord, Repo}
 | 
				
			||||||
  alias Ecto.Multi
 | 
					  alias Ecto.{Multi, Queryable}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @doc """
 | 
					  @doc """
 | 
				
			||||||
  Returns the list of shot_groups.
 | 
					  Returns the list of shot_records.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  ## Examples
 | 
					  ## Examples
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      iex> list_shot_groups(%User{id: 123})
 | 
					      iex> list_shot_records(:all, %User{id: 123})
 | 
				
			||||||
      [%ShotGroup{}, ...]
 | 
					      [%ShotRecord{}, ...]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      iex> list_shot_groups("cool", %User{id: 123})
 | 
					      iex> list_shot_records("cool", :all, %User{id: 123})
 | 
				
			||||||
      [%ShotGroup{notes: "My cool shot group"}, ...]
 | 
					      [%ShotRecord{notes: "My cool shot record"}, ...]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      iex> list_shot_records("cool", :rifle, %User{id: 123})
 | 
				
			||||||
 | 
					      [%ShotRecord{notes: "Shot some rifle rounds"}, ...]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  """
 | 
					  """
 | 
				
			||||||
  @spec list_shot_groups(User.t()) :: [ShotGroup.t()]
 | 
					  @spec list_shot_records(Type.class() | :all, User.t()) :: [ShotRecord.t()]
 | 
				
			||||||
  @spec list_shot_groups(search :: nil | String.t(), User.t()) :: [ShotGroup.t()]
 | 
					  @spec list_shot_records(search :: nil | String.t(), Type.class() | :all, User.t()) ::
 | 
				
			||||||
  def list_shot_groups(search \\ nil, user)
 | 
					          [ShotRecord.t()]
 | 
				
			||||||
 | 
					  def list_shot_records(search \\ nil, type, %{id: user_id}) do
 | 
				
			||||||
  def list_shot_groups(search, %{id: user_id}) when search |> is_nil() or search == "",
 | 
					    from(sg in ShotRecord,
 | 
				
			||||||
    do: Repo.all(from sg in ShotGroup, where: sg.user_id == ^user_id)
 | 
					      as: :sg,
 | 
				
			||||||
 | 
					      left_join: ag in Pack,
 | 
				
			||||||
  def list_shot_groups(search, %{id: user_id}) when search |> is_binary() do
 | 
					      as: :ag,
 | 
				
			||||||
    trimmed_search = String.trim(search)
 | 
					      on: sg.pack_id == ag.id,
 | 
				
			||||||
 | 
					      left_join: at in Type,
 | 
				
			||||||
    Repo.all(
 | 
					      as: :at,
 | 
				
			||||||
      from sg in ShotGroup,
 | 
					      on: ag.type_id == at.id,
 | 
				
			||||||
        left_join: ag in AmmoGroup,
 | 
					      where: sg.user_id == ^user_id,
 | 
				
			||||||
        on: sg.ammo_group_id == ag.id,
 | 
					      distinct: sg.id
 | 
				
			||||||
        left_join: at in AmmoType,
 | 
					 | 
				
			||||||
        on: ag.ammo_type_id == at.id,
 | 
					 | 
				
			||||||
        where: sg.user_id == ^user_id,
 | 
					 | 
				
			||||||
        where:
 | 
					 | 
				
			||||||
          fragment(
 | 
					 | 
				
			||||||
            "? @@ websearch_to_tsquery('english', ?)",
 | 
					 | 
				
			||||||
            sg.search,
 | 
					 | 
				
			||||||
            ^trimmed_search
 | 
					 | 
				
			||||||
          ) or
 | 
					 | 
				
			||||||
            fragment(
 | 
					 | 
				
			||||||
              "? @@ websearch_to_tsquery('english', ?)",
 | 
					 | 
				
			||||||
              ag.search,
 | 
					 | 
				
			||||||
              ^trimmed_search
 | 
					 | 
				
			||||||
            ) or
 | 
					 | 
				
			||||||
            fragment(
 | 
					 | 
				
			||||||
              "? @@ websearch_to_tsquery('english', ?)",
 | 
					 | 
				
			||||||
              at.search,
 | 
					 | 
				
			||||||
              ^trimmed_search
 | 
					 | 
				
			||||||
            ),
 | 
					 | 
				
			||||||
        order_by: {
 | 
					 | 
				
			||||||
          :desc,
 | 
					 | 
				
			||||||
          fragment(
 | 
					 | 
				
			||||||
            "ts_rank_cd(?, websearch_to_tsquery('english', ?), 4)",
 | 
					 | 
				
			||||||
            sg.search,
 | 
					 | 
				
			||||||
            ^trimmed_search
 | 
					 | 
				
			||||||
          )
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
        distinct: sg.id
 | 
					 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 | 
					    |> list_shot_records_search(search)
 | 
				
			||||||
 | 
					    |> list_shot_records_filter_type(type)
 | 
				
			||||||
 | 
					    |> Repo.all()
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @spec list_shot_groups_for_ammo_group(AmmoGroup.t(), User.t()) :: [ShotGroup.t()]
 | 
					  @spec list_shot_records_search(Queryable.t(), search :: String.t() | nil) ::
 | 
				
			||||||
  def list_shot_groups_for_ammo_group(
 | 
					          Queryable.t()
 | 
				
			||||||
        %AmmoGroup{id: ammo_group_id, user_id: user_id},
 | 
					  defp list_shot_records_search(query, search) when search in ["", nil], do: query
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  defp list_shot_records_search(query, search) when search |> is_binary() do
 | 
				
			||||||
 | 
					    trimmed_search = String.trim(search)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    query
 | 
				
			||||||
 | 
					    |> where(
 | 
				
			||||||
 | 
					      [sg: sg, ag: ag, at: at],
 | 
				
			||||||
 | 
					      fragment(
 | 
				
			||||||
 | 
					        "? @@ websearch_to_tsquery('english', ?)",
 | 
				
			||||||
 | 
					        sg.search,
 | 
				
			||||||
 | 
					        ^trimmed_search
 | 
				
			||||||
 | 
					      ) or
 | 
				
			||||||
 | 
					        fragment(
 | 
				
			||||||
 | 
					          "? @@ websearch_to_tsquery('english', ?)",
 | 
				
			||||||
 | 
					          ag.search,
 | 
				
			||||||
 | 
					          ^trimmed_search
 | 
				
			||||||
 | 
					        ) or
 | 
				
			||||||
 | 
					        fragment(
 | 
				
			||||||
 | 
					          "? @@ websearch_to_tsquery('english', ?)",
 | 
				
			||||||
 | 
					          at.search,
 | 
				
			||||||
 | 
					          ^trimmed_search
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    |> order_by([sg: sg], {
 | 
				
			||||||
 | 
					      :desc,
 | 
				
			||||||
 | 
					      fragment(
 | 
				
			||||||
 | 
					        "ts_rank_cd(?, websearch_to_tsquery('english', ?), 4)",
 | 
				
			||||||
 | 
					        sg.search,
 | 
				
			||||||
 | 
					        ^trimmed_search
 | 
				
			||||||
 | 
					      )
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @spec list_shot_records_filter_type(Queryable.t(), Type.class() | :all) ::
 | 
				
			||||||
 | 
					          Queryable.t()
 | 
				
			||||||
 | 
					  defp list_shot_records_filter_type(query, :rifle),
 | 
				
			||||||
 | 
					    do: query |> where([at: at], at.class == :rifle)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  defp list_shot_records_filter_type(query, :pistol),
 | 
				
			||||||
 | 
					    do: query |> where([at: at], at.class == :pistol)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  defp list_shot_records_filter_type(query, :shotgun),
 | 
				
			||||||
 | 
					    do: query |> where([at: at], at.class == :shotgun)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  defp list_shot_records_filter_type(query, _all), do: query
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @doc """
 | 
				
			||||||
 | 
					  Returns a count of shot records.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ## Examples
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      iex> get_shot_record_count!(%User{id: 123})
 | 
				
			||||||
 | 
					      3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  """
 | 
				
			||||||
 | 
					  @spec get_shot_record_count!(User.t()) :: integer()
 | 
				
			||||||
 | 
					  def get_shot_record_count!(%User{id: user_id}) do
 | 
				
			||||||
 | 
					    Repo.one(
 | 
				
			||||||
 | 
					      from sg in ShotRecord,
 | 
				
			||||||
 | 
					        where: sg.user_id == ^user_id,
 | 
				
			||||||
 | 
					        select: count(sg.id),
 | 
				
			||||||
 | 
					        distinct: true
 | 
				
			||||||
 | 
					    ) || 0
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @spec list_shot_records_for_pack(Pack.t(), User.t()) :: [ShotRecord.t()]
 | 
				
			||||||
 | 
					  def list_shot_records_for_pack(
 | 
				
			||||||
 | 
					        %Pack{id: pack_id, user_id: user_id},
 | 
				
			||||||
        %User{id: user_id}
 | 
					        %User{id: user_id}
 | 
				
			||||||
      ) do
 | 
					      ) do
 | 
				
			||||||
    Repo.all(
 | 
					    Repo.all(
 | 
				
			||||||
      from sg in ShotGroup,
 | 
					      from sg in ShotRecord,
 | 
				
			||||||
        where: sg.ammo_group_id == ^ammo_group_id,
 | 
					        where: sg.pack_id == ^pack_id,
 | 
				
			||||||
        where: sg.user_id == ^user_id
 | 
					        where: sg.user_id == ^user_id
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @doc """
 | 
					  @doc """
 | 
				
			||||||
  Gets a single shot_group.
 | 
					  Gets a single shot_record.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  Raises `Ecto.NoResultsError` if the Shot group does not exist.
 | 
					  Raises `Ecto.NoResultsError` if the shot record does not exist.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  ## Examples
 | 
					  ## Examples
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      iex> get_shot_group!(123, %User{id: 123})
 | 
					      iex> get_shot_record!(123, %User{id: 123})
 | 
				
			||||||
      %ShotGroup{}
 | 
					      %ShotRecord{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      iex> get_shot_group!(456, %User{id: 123})
 | 
					      iex> get_shot_record!(456, %User{id: 123})
 | 
				
			||||||
      ** (Ecto.NoResultsError)
 | 
					      ** (Ecto.NoResultsError)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  """
 | 
					  """
 | 
				
			||||||
  @spec get_shot_group!(ShotGroup.id(), User.t()) :: ShotGroup.t()
 | 
					  @spec get_shot_record!(ShotRecord.id(), User.t()) :: ShotRecord.t()
 | 
				
			||||||
  def get_shot_group!(id, %User{id: user_id}) do
 | 
					  def get_shot_record!(id, %User{id: user_id}) do
 | 
				
			||||||
    Repo.one!(
 | 
					    Repo.one!(
 | 
				
			||||||
      from sg in ShotGroup,
 | 
					      from sg in ShotRecord,
 | 
				
			||||||
        where: sg.id == ^id,
 | 
					        where: sg.id == ^id,
 | 
				
			||||||
        where: sg.user_id == ^user_id,
 | 
					        where: sg.user_id == ^user_id,
 | 
				
			||||||
        order_by: sg.date
 | 
					        order_by: sg.date
 | 
				
			||||||
@@ -102,251 +148,249 @@ defmodule Cannery.ActivityLog do
 | 
				
			|||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @doc """
 | 
					  @doc """
 | 
				
			||||||
  Creates a shot_group.
 | 
					  Creates a shot_record.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  ## Examples
 | 
					  ## Examples
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      iex> create_shot_group(%{field: value}, %User{id: 123})
 | 
					      iex> create_shot_record(%{field: value}, %User{id: 123})
 | 
				
			||||||
      {:ok, %ShotGroup{}}
 | 
					      {:ok, %ShotRecord{}}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      iex> create_shot_group(%{field: bad_value}, %User{id: 123})
 | 
					      iex> create_shot_record(%{field: bad_value}, %User{id: 123})
 | 
				
			||||||
      {:error, %Ecto.Changeset{}}
 | 
					      {:error, %Ecto.Changeset{}}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  """
 | 
					  """
 | 
				
			||||||
  @spec create_shot_group(attrs :: map(), User.t(), AmmoGroup.t()) ::
 | 
					  @spec create_shot_record(attrs :: map(), User.t(), Pack.t()) ::
 | 
				
			||||||
          {:ok, ShotGroup.t()} | {:error, ShotGroup.changeset() | nil}
 | 
					          {:ok, ShotRecord.t()} | {:error, ShotRecord.changeset() | nil}
 | 
				
			||||||
  def create_shot_group(attrs, user, ammo_group) do
 | 
					  def create_shot_record(attrs, user, pack) do
 | 
				
			||||||
    Multi.new()
 | 
					    Multi.new()
 | 
				
			||||||
    |> Multi.insert(
 | 
					    |> Multi.insert(
 | 
				
			||||||
      :create_shot_group,
 | 
					      :create_shot_record,
 | 
				
			||||||
      %ShotGroup{} |> ShotGroup.create_changeset(user, ammo_group, attrs)
 | 
					      %ShotRecord{} |> ShotRecord.create_changeset(user, pack, attrs)
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
    |> Multi.run(
 | 
					    |> Multi.run(
 | 
				
			||||||
      :ammo_group,
 | 
					      :pack,
 | 
				
			||||||
      fn _repo, %{create_shot_group: %{ammo_group_id: ammo_group_id, user_id: user_id}} ->
 | 
					      fn _repo, %{create_shot_record: %{pack_id: pack_id, user_id: user_id}} ->
 | 
				
			||||||
        ammo_group =
 | 
					        pack =
 | 
				
			||||||
          Repo.one(
 | 
					          Repo.one(
 | 
				
			||||||
            from ag in AmmoGroup,
 | 
					            from ag in Pack,
 | 
				
			||||||
              where: ag.id == ^ammo_group_id,
 | 
					              where: ag.id == ^pack_id,
 | 
				
			||||||
              where: ag.user_id == ^user_id
 | 
					              where: ag.user_id == ^user_id
 | 
				
			||||||
          )
 | 
					          )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        {:ok, ammo_group}
 | 
					        {:ok, pack}
 | 
				
			||||||
      end
 | 
					      end
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
    |> Multi.update(
 | 
					    |> Multi.update(
 | 
				
			||||||
      :update_ammo_group,
 | 
					      :update_pack,
 | 
				
			||||||
      fn %{create_shot_group: %{count: shot_group_count}, ammo_group: %{count: ammo_group_count}} ->
 | 
					      fn %{create_shot_record: %{count: shot_record_count}, pack: %{count: pack_count}} ->
 | 
				
			||||||
        ammo_group |> AmmoGroup.range_changeset(%{"count" => ammo_group_count - shot_group_count})
 | 
					        pack |> Pack.range_changeset(%{"count" => pack_count - shot_record_count})
 | 
				
			||||||
      end
 | 
					      end
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
    |> Repo.transaction()
 | 
					    |> Repo.transaction()
 | 
				
			||||||
    |> case do
 | 
					    |> case do
 | 
				
			||||||
      {:ok, %{create_shot_group: shot_group}} -> {:ok, shot_group}
 | 
					      {:ok, %{create_shot_record: shot_record}} -> {:ok, shot_record}
 | 
				
			||||||
      {:error, :create_shot_group, changeset, _changes_so_far} -> {:error, changeset}
 | 
					      {:error, :create_shot_record, changeset, _changes_so_far} -> {:error, changeset}
 | 
				
			||||||
      {:error, _other_transaction, _value, _changes_so_far} -> {:error, nil}
 | 
					      {:error, _other_transaction, _value, _changes_so_far} -> {:error, nil}
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @doc """
 | 
					  @doc """
 | 
				
			||||||
  Updates a shot_group.
 | 
					  Updates a shot_record.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  ## Examples
 | 
					  ## Examples
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      iex> update_shot_group(shot_group, %{field: new_value}, %User{id: 123})
 | 
					      iex> update_shot_record(shot_record, %{field: new_value}, %User{id: 123})
 | 
				
			||||||
      {:ok, %ShotGroup{}}
 | 
					      {:ok, %ShotRecord{}}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      iex> update_shot_group(shot_group, %{field: bad_value}, %User{id: 123})
 | 
					      iex> update_shot_record(shot_record, %{field: bad_value}, %User{id: 123})
 | 
				
			||||||
      {:error, %Ecto.Changeset{}}
 | 
					      {:error, %Ecto.Changeset{}}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  """
 | 
					  """
 | 
				
			||||||
  @spec update_shot_group(ShotGroup.t(), attrs :: map(), User.t()) ::
 | 
					  @spec update_shot_record(ShotRecord.t(), attrs :: map(), User.t()) ::
 | 
				
			||||||
          {:ok, ShotGroup.t()} | {:error, ShotGroup.changeset() | nil}
 | 
					          {:ok, ShotRecord.t()} | {:error, ShotRecord.changeset() | nil}
 | 
				
			||||||
  def update_shot_group(
 | 
					  def update_shot_record(
 | 
				
			||||||
        %ShotGroup{count: count, user_id: user_id} = shot_group,
 | 
					        %ShotRecord{count: count, user_id: user_id} = shot_record,
 | 
				
			||||||
        attrs,
 | 
					        attrs,
 | 
				
			||||||
        %User{id: user_id} = user
 | 
					        %User{id: user_id} = user
 | 
				
			||||||
      ) do
 | 
					      ) do
 | 
				
			||||||
    Multi.new()
 | 
					    Multi.new()
 | 
				
			||||||
    |> Multi.update(
 | 
					    |> Multi.update(
 | 
				
			||||||
      :update_shot_group,
 | 
					      :update_shot_record,
 | 
				
			||||||
      shot_group |> ShotGroup.update_changeset(user, attrs)
 | 
					      shot_record |> ShotRecord.update_changeset(user, attrs)
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
    |> Multi.run(
 | 
					    |> Multi.run(
 | 
				
			||||||
      :ammo_group,
 | 
					      :pack,
 | 
				
			||||||
      fn repo, %{update_shot_group: %{ammo_group_id: ammo_group_id, user_id: user_id}} ->
 | 
					      fn repo, %{update_shot_record: %{pack_id: pack_id, user_id: user_id}} ->
 | 
				
			||||||
        {:ok,
 | 
					        {:ok, repo.one(from ag in Pack, where: ag.id == ^pack_id and ag.user_id == ^user_id)}
 | 
				
			||||||
         repo.one(from ag in AmmoGroup, where: ag.id == ^ammo_group_id and ag.user_id == ^user_id)}
 | 
					 | 
				
			||||||
      end
 | 
					      end
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
    |> Multi.update(
 | 
					    |> Multi.update(
 | 
				
			||||||
      :update_ammo_group,
 | 
					      :update_pack,
 | 
				
			||||||
      fn %{
 | 
					      fn %{
 | 
				
			||||||
           update_shot_group: %{count: new_count},
 | 
					           update_shot_record: %{count: new_count},
 | 
				
			||||||
           ammo_group: %{count: ammo_group_count} = ammo_group
 | 
					           pack: %{count: pack_count} = pack
 | 
				
			||||||
         } ->
 | 
					         } ->
 | 
				
			||||||
        shot_diff_to_add = new_count - count
 | 
					        shot_diff_to_add = new_count - count
 | 
				
			||||||
        new_ammo_group_count = ammo_group_count - shot_diff_to_add
 | 
					        new_pack_count = pack_count - shot_diff_to_add
 | 
				
			||||||
        ammo_group |> AmmoGroup.range_changeset(%{"count" => new_ammo_group_count})
 | 
					        pack |> Pack.range_changeset(%{"count" => new_pack_count})
 | 
				
			||||||
      end
 | 
					      end
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
    |> Repo.transaction()
 | 
					    |> Repo.transaction()
 | 
				
			||||||
    |> case do
 | 
					    |> case do
 | 
				
			||||||
      {:ok, %{update_shot_group: shot_group}} -> {:ok, shot_group}
 | 
					      {:ok, %{update_shot_record: shot_record}} -> {:ok, shot_record}
 | 
				
			||||||
      {:error, :update_shot_group, changeset, _changes_so_far} -> {:error, changeset}
 | 
					      {:error, :update_shot_record, changeset, _changes_so_far} -> {:error, changeset}
 | 
				
			||||||
      {:error, _other_transaction, _value, _changes_so_far} -> {:error, nil}
 | 
					      {:error, _other_transaction, _value, _changes_so_far} -> {:error, nil}
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @doc """
 | 
					  @doc """
 | 
				
			||||||
  Deletes a shot_group.
 | 
					  Deletes a shot_record.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  ## Examples
 | 
					  ## Examples
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      iex> delete_shot_group(shot_group, %User{id: 123})
 | 
					      iex> delete_shot_record(shot_record, %User{id: 123})
 | 
				
			||||||
      {:ok, %ShotGroup{}}
 | 
					      {:ok, %ShotRecord{}}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      iex> delete_shot_group(shot_group, %User{id: 123})
 | 
					      iex> delete_shot_record(shot_record, %User{id: 123})
 | 
				
			||||||
      {:error, %Ecto.Changeset{}}
 | 
					      {:error, %Ecto.Changeset{}}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  """
 | 
					  """
 | 
				
			||||||
  @spec delete_shot_group(ShotGroup.t(), User.t()) ::
 | 
					  @spec delete_shot_record(ShotRecord.t(), User.t()) ::
 | 
				
			||||||
          {:ok, ShotGroup.t()} | {:error, ShotGroup.changeset()}
 | 
					          {:ok, ShotRecord.t()} | {:error, ShotRecord.changeset()}
 | 
				
			||||||
  def delete_shot_group(
 | 
					  def delete_shot_record(
 | 
				
			||||||
        %ShotGroup{user_id: user_id} = shot_group,
 | 
					        %ShotRecord{user_id: user_id} = shot_record,
 | 
				
			||||||
        %User{id: user_id}
 | 
					        %User{id: user_id}
 | 
				
			||||||
      ) do
 | 
					      ) do
 | 
				
			||||||
    Multi.new()
 | 
					    Multi.new()
 | 
				
			||||||
    |> Multi.delete(:delete_shot_group, shot_group)
 | 
					    |> Multi.delete(:delete_shot_record, shot_record)
 | 
				
			||||||
    |> Multi.run(
 | 
					    |> Multi.run(
 | 
				
			||||||
      :ammo_group,
 | 
					      :pack,
 | 
				
			||||||
      fn repo, %{delete_shot_group: %{ammo_group_id: ammo_group_id, user_id: user_id}} ->
 | 
					      fn repo, %{delete_shot_record: %{pack_id: pack_id, user_id: user_id}} ->
 | 
				
			||||||
        {:ok,
 | 
					        {:ok, repo.one(from ag in Pack, where: ag.id == ^pack_id and ag.user_id == ^user_id)}
 | 
				
			||||||
         repo.one(from ag in AmmoGroup, where: ag.id == ^ammo_group_id and ag.user_id == ^user_id)}
 | 
					 | 
				
			||||||
      end
 | 
					      end
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
    |> Multi.update(
 | 
					    |> Multi.update(
 | 
				
			||||||
      :update_ammo_group,
 | 
					      :update_pack,
 | 
				
			||||||
      fn %{
 | 
					      fn %{
 | 
				
			||||||
           delete_shot_group: %{count: count},
 | 
					           delete_shot_record: %{count: count},
 | 
				
			||||||
           ammo_group: %{count: ammo_group_count} = ammo_group
 | 
					           pack: %{count: pack_count} = pack
 | 
				
			||||||
         } ->
 | 
					         } ->
 | 
				
			||||||
        new_ammo_group_count = ammo_group_count + count
 | 
					        new_pack_count = pack_count + count
 | 
				
			||||||
        ammo_group |> AmmoGroup.range_changeset(%{"count" => new_ammo_group_count})
 | 
					        pack |> Pack.range_changeset(%{"count" => new_pack_count})
 | 
				
			||||||
      end
 | 
					      end
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
    |> Repo.transaction()
 | 
					    |> Repo.transaction()
 | 
				
			||||||
    |> case do
 | 
					    |> case do
 | 
				
			||||||
      {:ok, %{delete_shot_group: shot_group}} -> {:ok, shot_group}
 | 
					      {:ok, %{delete_shot_record: shot_record}} -> {:ok, shot_record}
 | 
				
			||||||
      {:error, :delete_shot_group, changeset, _changes_so_far} -> {:error, changeset}
 | 
					      {:error, :delete_shot_record, changeset, _changes_so_far} -> {:error, changeset}
 | 
				
			||||||
      {:error, _other_transaction, _value, _changes_so_far} -> {:error, nil}
 | 
					      {:error, _other_transaction, _value, _changes_so_far} -> {:error, nil}
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @doc """
 | 
					  @doc """
 | 
				
			||||||
  Returns the number of shot rounds for an ammo group
 | 
					  Returns the number of shot rounds for a pack
 | 
				
			||||||
  """
 | 
					  """
 | 
				
			||||||
  @spec get_used_count(AmmoGroup.t(), User.t()) :: non_neg_integer()
 | 
					  @spec get_used_count(Pack.t(), User.t()) :: non_neg_integer()
 | 
				
			||||||
  def get_used_count(%AmmoGroup{id: ammo_group_id} = ammo_group, user) do
 | 
					  def get_used_count(%Pack{id: pack_id} = pack, user) do
 | 
				
			||||||
    [ammo_group]
 | 
					    [pack]
 | 
				
			||||||
    |> get_used_counts(user)
 | 
					    |> get_used_counts(user)
 | 
				
			||||||
    |> Map.get(ammo_group_id, 0)
 | 
					    |> Map.get(pack_id, 0)
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @doc """
 | 
					  @doc """
 | 
				
			||||||
  Returns the number of shot rounds for multiple ammo groups
 | 
					  Returns the number of shot rounds for multiple packs
 | 
				
			||||||
  """
 | 
					  """
 | 
				
			||||||
  @spec get_used_counts([AmmoGroup.t()], User.t()) ::
 | 
					  @spec get_used_counts([Pack.t()], User.t()) ::
 | 
				
			||||||
          %{optional(AmmoGroup.id()) => non_neg_integer()}
 | 
					          %{optional(Pack.id()) => non_neg_integer()}
 | 
				
			||||||
  def get_used_counts(ammo_groups, %User{id: user_id}) do
 | 
					  def get_used_counts(packs, %User{id: user_id}) do
 | 
				
			||||||
    ammo_group_ids =
 | 
					    pack_ids =
 | 
				
			||||||
      ammo_groups
 | 
					      packs
 | 
				
			||||||
      |> Enum.map(fn %{id: ammo_group_id} -> ammo_group_id end)
 | 
					      |> Enum.map(fn %{id: pack_id} -> pack_id end)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Repo.all(
 | 
					    Repo.all(
 | 
				
			||||||
      from sg in ShotGroup,
 | 
					      from sg in ShotRecord,
 | 
				
			||||||
        where: sg.ammo_group_id in ^ammo_group_ids,
 | 
					        where: sg.pack_id in ^pack_ids,
 | 
				
			||||||
        where: sg.user_id == ^user_id,
 | 
					        where: sg.user_id == ^user_id,
 | 
				
			||||||
        group_by: sg.ammo_group_id,
 | 
					        group_by: sg.pack_id,
 | 
				
			||||||
        select: {sg.ammo_group_id, sum(sg.count)}
 | 
					        select: {sg.pack_id, sum(sg.count)}
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
    |> Map.new()
 | 
					    |> Map.new()
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @doc """
 | 
					  @doc """
 | 
				
			||||||
  Returns the last entered shot group date for an ammo group
 | 
					  Returns the last entered shot record date for a pack
 | 
				
			||||||
  """
 | 
					  """
 | 
				
			||||||
  @spec get_last_used_date(AmmoGroup.t(), User.t()) :: Date.t() | nil
 | 
					  @spec get_last_used_date(Pack.t(), User.t()) :: Date.t() | nil
 | 
				
			||||||
  def get_last_used_date(%AmmoGroup{id: ammo_group_id} = ammo_group, user) do
 | 
					  def get_last_used_date(%Pack{id: pack_id} = pack, user) do
 | 
				
			||||||
    [ammo_group]
 | 
					    [pack]
 | 
				
			||||||
    |> get_last_used_dates(user)
 | 
					    |> get_last_used_dates(user)
 | 
				
			||||||
    |> Map.get(ammo_group_id)
 | 
					    |> Map.get(pack_id)
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @doc """
 | 
					  @doc """
 | 
				
			||||||
  Returns the last entered shot group date for an ammo group
 | 
					  Returns the last entered shot record date for a pack
 | 
				
			||||||
  """
 | 
					  """
 | 
				
			||||||
  @spec get_last_used_dates([AmmoGroup.t()], User.t()) :: %{optional(AmmoGroup.id()) => Date.t()}
 | 
					  @spec get_last_used_dates([Pack.t()], User.t()) :: %{optional(Pack.id()) => Date.t()}
 | 
				
			||||||
  def get_last_used_dates(ammo_groups, %User{id: user_id}) do
 | 
					  def get_last_used_dates(packs, %User{id: user_id}) do
 | 
				
			||||||
    ammo_group_ids =
 | 
					    pack_ids =
 | 
				
			||||||
      ammo_groups
 | 
					      packs
 | 
				
			||||||
      |> Enum.map(fn %AmmoGroup{id: ammo_group_id, user_id: ^user_id} -> ammo_group_id end)
 | 
					      |> Enum.map(fn %Pack{id: pack_id, user_id: ^user_id} -> pack_id end)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Repo.all(
 | 
					    Repo.all(
 | 
				
			||||||
      from sg in ShotGroup,
 | 
					      from sg in ShotRecord,
 | 
				
			||||||
        where: sg.ammo_group_id in ^ammo_group_ids,
 | 
					        where: sg.pack_id in ^pack_ids,
 | 
				
			||||||
        where: sg.user_id == ^user_id,
 | 
					        where: sg.user_id == ^user_id,
 | 
				
			||||||
        group_by: sg.ammo_group_id,
 | 
					        group_by: sg.pack_id,
 | 
				
			||||||
        select: {sg.ammo_group_id, max(sg.date)}
 | 
					        select: {sg.pack_id, max(sg.date)}
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
    |> Map.new()
 | 
					    |> Map.new()
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @doc """
 | 
					  @doc """
 | 
				
			||||||
  Gets the total number of rounds shot for an ammo type
 | 
					  Gets the total number of rounds shot for a type
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  Raises `Ecto.NoResultsError` if the Ammo type does not exist.
 | 
					  Raises `Ecto.NoResultsError` if the type does not exist.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  ## Examples
 | 
					  ## Examples
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      iex> get_used_count_for_ammo_type(123, %User{id: 123})
 | 
					      iex> get_used_count_for_type(123, %User{id: 123})
 | 
				
			||||||
      35
 | 
					      35
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      iex> get_used_count_for_ammo_type(456, %User{id: 123})
 | 
					      iex> get_used_count_for_type(456, %User{id: 123})
 | 
				
			||||||
      ** (Ecto.NoResultsError)
 | 
					      ** (Ecto.NoResultsError)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  """
 | 
					  """
 | 
				
			||||||
  @spec get_used_count_for_ammo_type(AmmoType.t(), User.t()) :: non_neg_integer()
 | 
					  @spec get_used_count_for_type(Type.t(), User.t()) :: non_neg_integer()
 | 
				
			||||||
  def get_used_count_for_ammo_type(%AmmoType{id: ammo_type_id} = ammo_type, user) do
 | 
					  def get_used_count_for_type(%Type{id: type_id} = type, user) do
 | 
				
			||||||
    [ammo_type]
 | 
					    [type]
 | 
				
			||||||
    |> get_used_count_for_ammo_types(user)
 | 
					    |> get_used_count_for_types(user)
 | 
				
			||||||
    |> Map.get(ammo_type_id, 0)
 | 
					    |> Map.get(type_id, 0)
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @doc """
 | 
					  @doc """
 | 
				
			||||||
  Gets the total number of rounds shot for multiple ammo types
 | 
					  Gets the total number of rounds shot for multiple types
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  ## Examples
 | 
					  ## Examples
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      iex> get_used_count_for_ammo_types(123, %User{id: 123})
 | 
					      iex> get_used_count_for_types(123, %User{id: 123})
 | 
				
			||||||
      35
 | 
					      35
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  """
 | 
					  """
 | 
				
			||||||
  @spec get_used_count_for_ammo_types([AmmoType.t()], User.t()) ::
 | 
					  @spec get_used_count_for_types([Type.t()], User.t()) ::
 | 
				
			||||||
          %{optional(AmmoType.id()) => non_neg_integer()}
 | 
					          %{optional(Type.id()) => non_neg_integer()}
 | 
				
			||||||
  def get_used_count_for_ammo_types(ammo_types, %User{id: user_id}) do
 | 
					  def get_used_count_for_types(types, %User{id: user_id}) do
 | 
				
			||||||
    ammo_type_ids =
 | 
					    type_ids =
 | 
				
			||||||
      ammo_types
 | 
					      types
 | 
				
			||||||
      |> Enum.map(fn %AmmoType{id: ammo_type_id, user_id: ^user_id} -> ammo_type_id end)
 | 
					      |> Enum.map(fn %Type{id: type_id, user_id: ^user_id} -> type_id end)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Repo.all(
 | 
					    Repo.all(
 | 
				
			||||||
      from ag in AmmoGroup,
 | 
					      from ag in Pack,
 | 
				
			||||||
        left_join: sg in ShotGroup,
 | 
					        left_join: sg in ShotRecord,
 | 
				
			||||||
        on: ag.id == sg.ammo_group_id,
 | 
					        on: ag.id == sg.pack_id,
 | 
				
			||||||
        where: ag.ammo_type_id in ^ammo_type_ids,
 | 
					        where: ag.type_id in ^type_ids,
 | 
				
			||||||
        where: not (sg.count |> is_nil()),
 | 
					        where: not (sg.count |> is_nil()),
 | 
				
			||||||
        group_by: ag.ammo_type_id,
 | 
					        group_by: ag.type_id,
 | 
				
			||||||
        select: {ag.ammo_type_id, sum(sg.count)}
 | 
					        select: {ag.type_id, sum(sg.count)}
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
    |> Map.new()
 | 
					    |> Map.new()
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,12 +1,12 @@
 | 
				
			|||||||
defmodule Cannery.ActivityLog.ShotGroup do
 | 
					defmodule Cannery.ActivityLog.ShotRecord do
 | 
				
			||||||
  @moduledoc """
 | 
					  @moduledoc """
 | 
				
			||||||
  A shot group records a group of ammo shot during a range trip
 | 
					  A shot record records a group of ammo shot during a range trip
 | 
				
			||||||
  """
 | 
					  """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  use Ecto.Schema
 | 
					  use Ecto.Schema
 | 
				
			||||||
  import CanneryWeb.Gettext
 | 
					  import CanneryWeb.Gettext
 | 
				
			||||||
  import Ecto.Changeset
 | 
					  import Ecto.Changeset
 | 
				
			||||||
  alias Cannery.{Accounts.User, Ammo, Ammo.AmmoGroup}
 | 
					  alias Cannery.{Accounts.User, Ammo, Ammo.Pack}
 | 
				
			||||||
  alias Ecto.{Changeset, UUID}
 | 
					  alias Ecto.{Changeset, UUID}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @derive {Jason.Encoder,
 | 
					  @derive {Jason.Encoder,
 | 
				
			||||||
@@ -15,17 +15,17 @@ defmodule Cannery.ActivityLog.ShotGroup do
 | 
				
			|||||||
             :count,
 | 
					             :count,
 | 
				
			||||||
             :date,
 | 
					             :date,
 | 
				
			||||||
             :notes,
 | 
					             :notes,
 | 
				
			||||||
             :ammo_group_id
 | 
					             :pack_id
 | 
				
			||||||
           ]}
 | 
					           ]}
 | 
				
			||||||
  @primary_key {:id, :binary_id, autogenerate: true}
 | 
					  @primary_key {:id, :binary_id, autogenerate: true}
 | 
				
			||||||
  @foreign_key_type :binary_id
 | 
					  @foreign_key_type :binary_id
 | 
				
			||||||
  schema "shot_groups" do
 | 
					  schema "shot_records" do
 | 
				
			||||||
    field :count, :integer
 | 
					    field :count, :integer
 | 
				
			||||||
    field :date, :date
 | 
					    field :date, :date
 | 
				
			||||||
    field :notes, :string
 | 
					    field :notes, :string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    field :user_id, :binary_id
 | 
					    field :user_id, :binary_id
 | 
				
			||||||
    field :ammo_group_id, :binary_id
 | 
					    field :pack_id, :binary_id
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    timestamps()
 | 
					    timestamps()
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
@@ -35,57 +35,57 @@ defmodule Cannery.ActivityLog.ShotGroup do
 | 
				
			|||||||
          count: integer,
 | 
					          count: integer,
 | 
				
			||||||
          notes: String.t() | nil,
 | 
					          notes: String.t() | nil,
 | 
				
			||||||
          date: Date.t() | nil,
 | 
					          date: Date.t() | nil,
 | 
				
			||||||
          ammo_group_id: AmmoGroup.id(),
 | 
					          pack_id: Pack.id(),
 | 
				
			||||||
          user_id: User.id(),
 | 
					          user_id: User.id(),
 | 
				
			||||||
          inserted_at: NaiveDateTime.t(),
 | 
					          inserted_at: NaiveDateTime.t(),
 | 
				
			||||||
          updated_at: NaiveDateTime.t()
 | 
					          updated_at: NaiveDateTime.t()
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
  @type new_shot_group :: %__MODULE__{}
 | 
					  @type new_shot_record :: %__MODULE__{}
 | 
				
			||||||
  @type id :: UUID.t()
 | 
					  @type id :: UUID.t()
 | 
				
			||||||
  @type changeset :: Changeset.t(t() | new_shot_group())
 | 
					  @type changeset :: Changeset.t(t() | new_shot_record())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @doc false
 | 
					  @doc false
 | 
				
			||||||
  @spec create_changeset(
 | 
					  @spec create_changeset(
 | 
				
			||||||
          new_shot_group(),
 | 
					          new_shot_record(),
 | 
				
			||||||
          User.t() | any(),
 | 
					          User.t() | any(),
 | 
				
			||||||
          AmmoGroup.t() | any(),
 | 
					          Pack.t() | any(),
 | 
				
			||||||
          attrs :: map()
 | 
					          attrs :: map()
 | 
				
			||||||
        ) :: changeset()
 | 
					        ) :: changeset()
 | 
				
			||||||
  def create_changeset(
 | 
					  def create_changeset(
 | 
				
			||||||
        shot_group,
 | 
					        shot_record,
 | 
				
			||||||
        %User{id: user_id},
 | 
					        %User{id: user_id},
 | 
				
			||||||
        %AmmoGroup{id: ammo_group_id, user_id: user_id} = ammo_group,
 | 
					        %Pack{id: pack_id, user_id: user_id} = pack,
 | 
				
			||||||
        attrs
 | 
					        attrs
 | 
				
			||||||
      ) do
 | 
					      ) do
 | 
				
			||||||
    shot_group
 | 
					    shot_record
 | 
				
			||||||
    |> change(user_id: user_id)
 | 
					    |> change(user_id: user_id)
 | 
				
			||||||
    |> change(ammo_group_id: ammo_group_id)
 | 
					    |> change(pack_id: pack_id)
 | 
				
			||||||
    |> cast(attrs, [:count, :notes, :date])
 | 
					    |> cast(attrs, [:count, :notes, :date])
 | 
				
			||||||
    |> validate_create_shot_group_count(ammo_group)
 | 
					    |> validate_length(:notes, max: 255)
 | 
				
			||||||
    |> validate_required([:date, :ammo_group_id, :user_id])
 | 
					    |> validate_create_shot_record_count(pack)
 | 
				
			||||||
 | 
					    |> validate_required([:date, :pack_id, :user_id])
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def create_changeset(shot_group, _invalid_user, _invalid_ammo_group, attrs) do
 | 
					  def create_changeset(shot_record, _invalid_user, _invalid_pack, attrs) do
 | 
				
			||||||
    shot_group
 | 
					    shot_record
 | 
				
			||||||
    |> cast(attrs, [:count, :notes, :date])
 | 
					    |> cast(attrs, [:count, :notes, :date])
 | 
				
			||||||
    |> validate_required([:ammo_group_id, :user_id])
 | 
					    |> validate_length(:notes, max: 255)
 | 
				
			||||||
 | 
					    |> validate_required([:pack_id, :user_id])
 | 
				
			||||||
    |> add_error(:invalid, dgettext("errors", "Please select a valid user and ammo pack"))
 | 
					    |> add_error(:invalid, dgettext("errors", "Please select a valid user and ammo pack"))
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  defp validate_create_shot_group_count(changeset, %AmmoGroup{count: ammo_group_count}) do
 | 
					  defp validate_create_shot_record_count(changeset, %Pack{count: pack_count}) do
 | 
				
			||||||
    case changeset |> Changeset.get_field(:count) do
 | 
					    case changeset |> Changeset.get_field(:count) do
 | 
				
			||||||
      nil ->
 | 
					      nil ->
 | 
				
			||||||
        changeset |> Changeset.add_error(:ammo_left, dgettext("errors", "can't be blank"))
 | 
					        changeset |> Changeset.add_error(:ammo_left, dgettext("errors", "can't be blank"))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      count when count > ammo_group_count ->
 | 
					      count when count > pack_count ->
 | 
				
			||||||
        changeset
 | 
					        changeset
 | 
				
			||||||
        |> Changeset.add_error(:ammo_left, dgettext("errors", "Ammo left must be at least 0"))
 | 
					        |> Changeset.add_error(:ammo_left, dgettext("errors", "Ammo left must be at least 0"))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      count when count <= 0 ->
 | 
					      count when count <= 0 ->
 | 
				
			||||||
        error =
 | 
					        error =
 | 
				
			||||||
          dgettext("errors", "Ammo left can be at most %{count} rounds",
 | 
					          dgettext("errors", "Ammo left can be at most %{count} rounds", count: pack_count - 1)
 | 
				
			||||||
            count: ammo_group_count - 1
 | 
					 | 
				
			||||||
          )
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        changeset |> Changeset.add_error(:ammo_left, error)
 | 
					        changeset |> Changeset.add_error(:ammo_left, error)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -95,28 +95,28 @@ defmodule Cannery.ActivityLog.ShotGroup do
 | 
				
			|||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @doc false
 | 
					  @doc false
 | 
				
			||||||
  @spec update_changeset(t() | new_shot_group(), User.t(), attrs :: map()) :: changeset()
 | 
					  @spec update_changeset(t() | new_shot_record(), User.t(), attrs :: map()) :: changeset()
 | 
				
			||||||
  def update_changeset(%__MODULE__{} = shot_group, user, attrs) do
 | 
					  def update_changeset(%__MODULE__{} = shot_record, user, attrs) do
 | 
				
			||||||
    shot_group
 | 
					    shot_record
 | 
				
			||||||
    |> cast(attrs, [:count, :notes, :date])
 | 
					    |> cast(attrs, [:count, :notes, :date])
 | 
				
			||||||
 | 
					    |> validate_length(:notes, max: 255)
 | 
				
			||||||
    |> validate_number(:count, greater_than: 0)
 | 
					    |> validate_number(:count, greater_than: 0)
 | 
				
			||||||
    |> validate_required([:count, :date])
 | 
					    |> validate_required([:count, :date])
 | 
				
			||||||
    |> validate_update_shot_group_count(shot_group, user)
 | 
					    |> validate_update_shot_record_count(shot_record, user)
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  defp validate_update_shot_group_count(
 | 
					  defp validate_update_shot_record_count(
 | 
				
			||||||
         changeset,
 | 
					         changeset,
 | 
				
			||||||
         %__MODULE__{ammo_group_id: ammo_group_id, count: count},
 | 
					         %__MODULE__{pack_id: pack_id, count: count},
 | 
				
			||||||
         user
 | 
					         user
 | 
				
			||||||
       ) do
 | 
					       ) do
 | 
				
			||||||
    %{count: ammo_group_count} = Ammo.get_ammo_group!(ammo_group_id, user)
 | 
					    %{count: pack_count} = Ammo.get_pack!(pack_id, user)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    new_shot_group_count = changeset |> Changeset.get_field(:count)
 | 
					    new_shot_record_count = changeset |> Changeset.get_field(:count)
 | 
				
			||||||
    shot_diff_to_add = new_shot_group_count - count
 | 
					    shot_diff_to_add = new_shot_record_count - count
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if shot_diff_to_add > ammo_group_count do
 | 
					    if shot_diff_to_add > pack_count do
 | 
				
			||||||
      error =
 | 
					      error = dgettext("errors", "Count can be at most %{count} shots", count: pack_count + count)
 | 
				
			||||||
        dgettext("errors", "Count can be at most %{count} shots", count: ammo_group_count + count)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
      changeset |> Changeset.add_error(:count, error)
 | 
					      changeset |> Changeset.add_error(:count, error)
 | 
				
			||||||
    else
 | 
					    else
 | 
				
			||||||
							
								
								
									
										1088
									
								
								lib/cannery/ammo.ex
									
									
									
									
									
								
							
							
						
						
									
										1088
									
								
								lib/cannery/ammo.ex
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -1,4 +1,4 @@
 | 
				
			|||||||
defmodule Cannery.Ammo.AmmoGroup do
 | 
					defmodule Cannery.Ammo.Pack do
 | 
				
			||||||
  @moduledoc """
 | 
					  @moduledoc """
 | 
				
			||||||
  A group of a certain ammunition type.
 | 
					  A group of a certain ammunition type.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -9,7 +9,7 @@ defmodule Cannery.Ammo.AmmoGroup do
 | 
				
			|||||||
  use Ecto.Schema
 | 
					  use Ecto.Schema
 | 
				
			||||||
  import CanneryWeb.Gettext
 | 
					  import CanneryWeb.Gettext
 | 
				
			||||||
  import Ecto.Changeset
 | 
					  import Ecto.Changeset
 | 
				
			||||||
  alias Cannery.Ammo.AmmoType
 | 
					  alias Cannery.Ammo.Type
 | 
				
			||||||
  alias Cannery.{Accounts.User, Containers, Containers.Container}
 | 
					  alias Cannery.{Accounts.User, Containers, Containers.Container}
 | 
				
			||||||
  alias Ecto.{Changeset, UUID}
 | 
					  alias Ecto.{Changeset, UUID}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -19,20 +19,22 @@ defmodule Cannery.Ammo.AmmoGroup do
 | 
				
			|||||||
             :count,
 | 
					             :count,
 | 
				
			||||||
             :notes,
 | 
					             :notes,
 | 
				
			||||||
             :price_paid,
 | 
					             :price_paid,
 | 
				
			||||||
 | 
					             :lot_number,
 | 
				
			||||||
             :staged,
 | 
					             :staged,
 | 
				
			||||||
             :ammo_type_id,
 | 
					             :type_id,
 | 
				
			||||||
             :container_id
 | 
					             :container_id
 | 
				
			||||||
           ]}
 | 
					           ]}
 | 
				
			||||||
  @primary_key {:id, :binary_id, autogenerate: true}
 | 
					  @primary_key {:id, :binary_id, autogenerate: true}
 | 
				
			||||||
  @foreign_key_type :binary_id
 | 
					  @foreign_key_type :binary_id
 | 
				
			||||||
  schema "ammo_groups" do
 | 
					  schema "packs" do
 | 
				
			||||||
    field :count, :integer
 | 
					    field :count, :integer
 | 
				
			||||||
    field :notes, :string
 | 
					    field :notes, :string
 | 
				
			||||||
    field :price_paid, :float
 | 
					    field :price_paid, :float
 | 
				
			||||||
    field :staged, :boolean, default: false
 | 
					    field :staged, :boolean, default: false
 | 
				
			||||||
 | 
					    field :lot_number, :string
 | 
				
			||||||
    field :purchased_on, :date
 | 
					    field :purchased_on, :date
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    belongs_to :ammo_type, AmmoType
 | 
					    belongs_to :type, Type
 | 
				
			||||||
    field :container_id, :binary_id
 | 
					    field :container_id, :binary_id
 | 
				
			||||||
    field :user_id, :binary_id
 | 
					    field :user_id, :binary_id
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -45,60 +47,76 @@ defmodule Cannery.Ammo.AmmoGroup do
 | 
				
			|||||||
          notes: String.t() | nil,
 | 
					          notes: String.t() | nil,
 | 
				
			||||||
          price_paid: float() | nil,
 | 
					          price_paid: float() | nil,
 | 
				
			||||||
          staged: boolean(),
 | 
					          staged: boolean(),
 | 
				
			||||||
 | 
					          lot_number: String.t() | nil,
 | 
				
			||||||
          purchased_on: Date.t(),
 | 
					          purchased_on: Date.t(),
 | 
				
			||||||
          ammo_type: AmmoType.t() | nil,
 | 
					          type: Type.t() | nil,
 | 
				
			||||||
          ammo_type_id: AmmoType.id(),
 | 
					          type_id: Type.id(),
 | 
				
			||||||
          container_id: Container.id(),
 | 
					          container_id: Container.id(),
 | 
				
			||||||
          user_id: User.id(),
 | 
					          user_id: User.id(),
 | 
				
			||||||
          inserted_at: NaiveDateTime.t(),
 | 
					          inserted_at: NaiveDateTime.t(),
 | 
				
			||||||
          updated_at: NaiveDateTime.t()
 | 
					          updated_at: NaiveDateTime.t()
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
  @type new_ammo_group :: %__MODULE__{}
 | 
					  @type new_pack :: %__MODULE__{}
 | 
				
			||||||
  @type id :: UUID.t()
 | 
					  @type id :: UUID.t()
 | 
				
			||||||
  @type changeset :: Changeset.t(t() | new_ammo_group())
 | 
					  @type changeset :: Changeset.t(t() | new_pack())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @doc false
 | 
					  @doc false
 | 
				
			||||||
  @spec create_changeset(
 | 
					  @spec create_changeset(
 | 
				
			||||||
          new_ammo_group(),
 | 
					          new_pack(),
 | 
				
			||||||
          AmmoType.t() | nil,
 | 
					          Type.t() | nil,
 | 
				
			||||||
          Container.t() | nil,
 | 
					          Container.t() | nil,
 | 
				
			||||||
          User.t(),
 | 
					          User.t(),
 | 
				
			||||||
          attrs :: map()
 | 
					          attrs :: map()
 | 
				
			||||||
        ) :: changeset()
 | 
					        ) :: changeset()
 | 
				
			||||||
  def create_changeset(
 | 
					  def create_changeset(
 | 
				
			||||||
        ammo_group,
 | 
					        pack,
 | 
				
			||||||
        %AmmoType{id: ammo_type_id},
 | 
					        %Type{id: type_id},
 | 
				
			||||||
        %Container{id: container_id, user_id: user_id},
 | 
					        %Container{id: container_id, user_id: user_id},
 | 
				
			||||||
        %User{id: user_id},
 | 
					        %User{id: user_id},
 | 
				
			||||||
        attrs
 | 
					        attrs
 | 
				
			||||||
      )
 | 
					      )
 | 
				
			||||||
      when is_binary(ammo_type_id) and is_binary(container_id) and is_binary(user_id) do
 | 
					      when is_binary(type_id) and is_binary(container_id) and is_binary(user_id) do
 | 
				
			||||||
    ammo_group
 | 
					    pack
 | 
				
			||||||
    |> change(ammo_type_id: ammo_type_id)
 | 
					    |> change(type_id: type_id)
 | 
				
			||||||
    |> change(user_id: user_id)
 | 
					    |> change(user_id: user_id)
 | 
				
			||||||
    |> change(container_id: container_id)
 | 
					    |> change(container_id: container_id)
 | 
				
			||||||
    |> cast(attrs, [:count, :price_paid, :notes, :staged, :purchased_on])
 | 
					    |> cast(attrs, [:count, :price_paid, :notes, :staged, :purchased_on, :lot_number])
 | 
				
			||||||
    |> validate_number(:count, greater_than: 0)
 | 
					    |> validate_number(:count, greater_than: 0)
 | 
				
			||||||
    |> validate_required([:count, :staged, :purchased_on, :ammo_type_id, :container_id, :user_id])
 | 
					    |> validate_number(:price_paid, greater_than_or_equal_to: 0)
 | 
				
			||||||
 | 
					    |> validate_length(:lot_number, max: 255)
 | 
				
			||||||
 | 
					    |> validate_required([:count, :staged, :purchased_on, :type_id, :container_id, :user_id])
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @doc """
 | 
					  @doc """
 | 
				
			||||||
  Invalid changeset, used to prompt user to select ammo type and container
 | 
					  Invalid changeset, used to prompt user to select type and container
 | 
				
			||||||
  """
 | 
					  """
 | 
				
			||||||
  def create_changeset(ammo_group, _invalid_ammo_type, _invalid_container, _invalid_user, attrs) do
 | 
					  def create_changeset(pack, _invalid_type, _invalid_container, _invalid_user, attrs) do
 | 
				
			||||||
    ammo_group
 | 
					    pack
 | 
				
			||||||
    |> cast(attrs, [:ammo_type_id, :container_id])
 | 
					    |> cast(attrs, [:type_id, :container_id])
 | 
				
			||||||
    |> validate_required([:ammo_type_id, :container_id])
 | 
					    |> validate_required([:type_id, :container_id])
 | 
				
			||||||
    |> add_error(:invalid, dgettext("errors", "Please select an ammo type and container"))
 | 
					    |> validate_number(:count, greater_than: 0)
 | 
				
			||||||
 | 
					    |> validate_number(:price_paid, greater_than_or_equal_to: 0)
 | 
				
			||||||
 | 
					    |> validate_length(:lot_number, max: 255)
 | 
				
			||||||
 | 
					    |> add_error(:invalid, dgettext("errors", "Please select a type and container"))
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @doc false
 | 
					  @doc false
 | 
				
			||||||
  @spec update_changeset(t() | new_ammo_group(), attrs :: map(), User.t()) :: changeset()
 | 
					  @spec update_changeset(t() | new_pack(), attrs :: map(), User.t()) :: changeset()
 | 
				
			||||||
  def update_changeset(ammo_group, attrs, user) do
 | 
					  def update_changeset(pack, attrs, user) do
 | 
				
			||||||
    ammo_group
 | 
					    pack
 | 
				
			||||||
    |> cast(attrs, [:count, :price_paid, :notes, :staged, :purchased_on, :container_id])
 | 
					    |> cast(attrs, [
 | 
				
			||||||
 | 
					      :count,
 | 
				
			||||||
 | 
					      :price_paid,
 | 
				
			||||||
 | 
					      :notes,
 | 
				
			||||||
 | 
					      :staged,
 | 
				
			||||||
 | 
					      :purchased_on,
 | 
				
			||||||
 | 
					      :lot_number,
 | 
				
			||||||
 | 
					      :container_id
 | 
				
			||||||
 | 
					    ])
 | 
				
			||||||
    |> validate_number(:count, greater_than_or_equal_to: 0)
 | 
					    |> validate_number(:count, greater_than_or_equal_to: 0)
 | 
				
			||||||
 | 
					    |> validate_number(:price_paid, greater_than_or_equal_to: 0)
 | 
				
			||||||
    |> validate_container_id(user)
 | 
					    |> validate_container_id(user)
 | 
				
			||||||
 | 
					    |> validate_length(:lot_number, max: 255)
 | 
				
			||||||
    |> validate_required([:count, :staged, :purchased_on, :container_id])
 | 
					    |> validate_required([:count, :staged, :purchased_on, :container_id])
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -113,12 +131,12 @@ defmodule Cannery.Ammo.AmmoGroup do
 | 
				
			|||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @doc """
 | 
					  @doc """
 | 
				
			||||||
  This range changeset is used when "using up" ammo groups, and allows for
 | 
					  This range changeset is used when "using up" packs, and allows for
 | 
				
			||||||
  updating the count to 0
 | 
					  updating the count to 0
 | 
				
			||||||
  """
 | 
					  """
 | 
				
			||||||
  @spec range_changeset(t() | new_ammo_group(), attrs :: map()) :: changeset()
 | 
					  @spec range_changeset(t() | new_pack(), attrs :: map()) :: changeset()
 | 
				
			||||||
  def range_changeset(ammo_group, attrs) do
 | 
					  def range_changeset(pack, attrs) do
 | 
				
			||||||
    ammo_group
 | 
					    pack
 | 
				
			||||||
    |> cast(attrs, [:count, :staged])
 | 
					    |> cast(attrs, [:count, :staged])
 | 
				
			||||||
    |> validate_required([:count, :staged])
 | 
					    |> validate_required([:count, :staged])
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
@@ -1,4 +1,4 @@
 | 
				
			|||||||
defmodule Cannery.Ammo.AmmoType do
 | 
					defmodule Cannery.Ammo.Type do
 | 
				
			||||||
  @moduledoc """
 | 
					  @moduledoc """
 | 
				
			||||||
  An ammunition type.
 | 
					  An ammunition type.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -8,65 +8,92 @@ defmodule Cannery.Ammo.AmmoType do
 | 
				
			|||||||
  use Ecto.Schema
 | 
					  use Ecto.Schema
 | 
				
			||||||
  import Ecto.Changeset
 | 
					  import Ecto.Changeset
 | 
				
			||||||
  alias Cannery.Accounts.User
 | 
					  alias Cannery.Accounts.User
 | 
				
			||||||
  alias Cannery.Ammo.AmmoGroup
 | 
					  alias Cannery.Ammo.Pack
 | 
				
			||||||
  alias Ecto.{Changeset, UUID}
 | 
					  alias Ecto.{Changeset, UUID}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @derive {Jason.Encoder,
 | 
					  @derive {Jason.Encoder,
 | 
				
			||||||
           only: [
 | 
					           only: [
 | 
				
			||||||
             :id,
 | 
					 | 
				
			||||||
             :name,
 | 
					             :name,
 | 
				
			||||||
             :desc,
 | 
					             :desc,
 | 
				
			||||||
 | 
					             :class,
 | 
				
			||||||
             :bullet_type,
 | 
					             :bullet_type,
 | 
				
			||||||
             :bullet_core,
 | 
					             :bullet_core,
 | 
				
			||||||
             :cartridge,
 | 
					 | 
				
			||||||
             :caliber,
 | 
					             :caliber,
 | 
				
			||||||
             :case_material,
 | 
					             :case_material,
 | 
				
			||||||
             :jacket_type,
 | 
					 | 
				
			||||||
             :muzzle_velocity,
 | 
					 | 
				
			||||||
             :powder_type,
 | 
					             :powder_type,
 | 
				
			||||||
             :powder_grains_per_charge,
 | 
					 | 
				
			||||||
             :grains,
 | 
					             :grains,
 | 
				
			||||||
             :pressure,
 | 
					             :pressure,
 | 
				
			||||||
             :primer_type,
 | 
					             :primer_type,
 | 
				
			||||||
             :firing_type,
 | 
					             :firing_type,
 | 
				
			||||||
 | 
					             :manufacturer,
 | 
				
			||||||
 | 
					             :upc,
 | 
				
			||||||
             :tracer,
 | 
					             :tracer,
 | 
				
			||||||
             :incendiary,
 | 
					             :incendiary,
 | 
				
			||||||
             :blank,
 | 
					             :blank,
 | 
				
			||||||
             :corrosive,
 | 
					             :corrosive,
 | 
				
			||||||
             :manufacturer,
 | 
					             :cartridge,
 | 
				
			||||||
             :upc
 | 
					             :jacket_type,
 | 
				
			||||||
 | 
					             :powder_grains_per_charge,
 | 
				
			||||||
 | 
					             :muzzle_velocity,
 | 
				
			||||||
 | 
					             :wadding,
 | 
				
			||||||
 | 
					             :shot_type,
 | 
				
			||||||
 | 
					             :shot_material,
 | 
				
			||||||
 | 
					             :shot_size,
 | 
				
			||||||
 | 
					             :unfired_length,
 | 
				
			||||||
 | 
					             :brass_height,
 | 
				
			||||||
 | 
					             :chamber_size,
 | 
				
			||||||
 | 
					             :load_grains,
 | 
				
			||||||
 | 
					             :shot_charge_weight,
 | 
				
			||||||
 | 
					             :dram_equivalent
 | 
				
			||||||
           ]}
 | 
					           ]}
 | 
				
			||||||
  @primary_key {:id, :binary_id, autogenerate: true}
 | 
					  @primary_key {:id, :binary_id, autogenerate: true}
 | 
				
			||||||
  @foreign_key_type :binary_id
 | 
					  @foreign_key_type :binary_id
 | 
				
			||||||
  schema "ammo_types" do
 | 
					  schema "types" do
 | 
				
			||||||
    field :name, :string
 | 
					    field :name, :string
 | 
				
			||||||
    field :desc, :string
 | 
					    field :desc, :string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # https://en.wikipedia.org/wiki/Bullet#Abbreviations
 | 
					    field :class, Ecto.Enum, values: [:rifle, :shotgun, :pistol]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # common fields
 | 
				
			||||||
 | 
					    # https://shootersreference.com/reloadingdata/bullet_abbreviations/
 | 
				
			||||||
    field :bullet_type, :string
 | 
					    field :bullet_type, :string
 | 
				
			||||||
    field :bullet_core, :string
 | 
					    field :bullet_core, :string
 | 
				
			||||||
    field :cartridge, :string
 | 
					    # also gauge for shotguns
 | 
				
			||||||
    field :caliber, :string
 | 
					    field :caliber, :string
 | 
				
			||||||
    field :case_material, :string
 | 
					    field :case_material, :string
 | 
				
			||||||
    field :jacket_type, :string
 | 
					 | 
				
			||||||
    field :muzzle_velocity, :integer
 | 
					 | 
				
			||||||
    field :powder_type, :string
 | 
					    field :powder_type, :string
 | 
				
			||||||
    field :powder_grains_per_charge, :integer
 | 
					 | 
				
			||||||
    field :grains, :integer
 | 
					    field :grains, :integer
 | 
				
			||||||
    field :pressure, :string
 | 
					    field :pressure, :string
 | 
				
			||||||
    field :primer_type, :string
 | 
					    field :primer_type, :string
 | 
				
			||||||
    field :firing_type, :string
 | 
					    field :firing_type, :string
 | 
				
			||||||
 | 
					    field :manufacturer, :string
 | 
				
			||||||
 | 
					    field :upc, :string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    field :tracer, :boolean, default: false
 | 
					    field :tracer, :boolean, default: false
 | 
				
			||||||
    field :incendiary, :boolean, default: false
 | 
					    field :incendiary, :boolean, default: false
 | 
				
			||||||
    field :blank, :boolean, default: false
 | 
					    field :blank, :boolean, default: false
 | 
				
			||||||
    field :corrosive, :boolean, default: false
 | 
					    field :corrosive, :boolean, default: false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    field :manufacturer, :string
 | 
					    # rifle/pistol fields
 | 
				
			||||||
    field :upc, :string
 | 
					    field :cartridge, :string
 | 
				
			||||||
 | 
					    field :jacket_type, :string
 | 
				
			||||||
 | 
					    field :powder_grains_per_charge, :integer
 | 
				
			||||||
 | 
					    field :muzzle_velocity, :integer
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # shotgun fields
 | 
				
			||||||
 | 
					    field :wadding, :string
 | 
				
			||||||
 | 
					    field :shot_type, :string
 | 
				
			||||||
 | 
					    field :shot_material, :string
 | 
				
			||||||
 | 
					    field :shot_size, :string
 | 
				
			||||||
 | 
					    field :unfired_length, :string
 | 
				
			||||||
 | 
					    field :brass_height, :string
 | 
				
			||||||
 | 
					    field :chamber_size, :string
 | 
				
			||||||
 | 
					    field :load_grains, :integer
 | 
				
			||||||
 | 
					    field :shot_charge_weight, :string
 | 
				
			||||||
 | 
					    field :dram_equivalent, :string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    field :user_id, :binary_id
 | 
					    field :user_id, :binary_id
 | 
				
			||||||
 | 
					    has_many :packs, Pack
 | 
				
			||||||
    has_many :ammo_groups, AmmoGroup
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    timestamps()
 | 
					    timestamps()
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
@@ -75,74 +102,133 @@ defmodule Cannery.Ammo.AmmoType do
 | 
				
			|||||||
          id: id(),
 | 
					          id: id(),
 | 
				
			||||||
          name: String.t(),
 | 
					          name: String.t(),
 | 
				
			||||||
          desc: String.t() | nil,
 | 
					          desc: String.t() | nil,
 | 
				
			||||||
 | 
					          class: class(),
 | 
				
			||||||
          bullet_type: String.t() | nil,
 | 
					          bullet_type: String.t() | nil,
 | 
				
			||||||
          bullet_core: String.t() | nil,
 | 
					          bullet_core: String.t() | nil,
 | 
				
			||||||
          cartridge: String.t() | nil,
 | 
					 | 
				
			||||||
          caliber: String.t() | nil,
 | 
					          caliber: String.t() | nil,
 | 
				
			||||||
          case_material: String.t() | nil,
 | 
					          case_material: String.t() | nil,
 | 
				
			||||||
          jacket_type: String.t() | nil,
 | 
					 | 
				
			||||||
          muzzle_velocity: integer() | nil,
 | 
					 | 
				
			||||||
          powder_type: String.t() | nil,
 | 
					          powder_type: String.t() | nil,
 | 
				
			||||||
          powder_grains_per_charge: integer() | nil,
 | 
					 | 
				
			||||||
          grains: integer() | nil,
 | 
					          grains: integer() | nil,
 | 
				
			||||||
          pressure: String.t() | nil,
 | 
					          pressure: String.t() | nil,
 | 
				
			||||||
          primer_type: String.t() | nil,
 | 
					          primer_type: String.t() | nil,
 | 
				
			||||||
          firing_type: String.t() | nil,
 | 
					          firing_type: String.t() | nil,
 | 
				
			||||||
 | 
					          manufacturer: String.t() | nil,
 | 
				
			||||||
 | 
					          upc: String.t() | nil,
 | 
				
			||||||
          tracer: boolean(),
 | 
					          tracer: boolean(),
 | 
				
			||||||
          incendiary: boolean(),
 | 
					          incendiary: boolean(),
 | 
				
			||||||
          blank: boolean(),
 | 
					          blank: boolean(),
 | 
				
			||||||
          corrosive: boolean(),
 | 
					          corrosive: boolean(),
 | 
				
			||||||
          manufacturer: String.t() | nil,
 | 
					          cartridge: String.t() | nil,
 | 
				
			||||||
          upc: String.t() | nil,
 | 
					          jacket_type: String.t() | nil,
 | 
				
			||||||
 | 
					          powder_grains_per_charge: integer() | nil,
 | 
				
			||||||
 | 
					          muzzle_velocity: integer() | nil,
 | 
				
			||||||
 | 
					          wadding: String.t() | nil,
 | 
				
			||||||
 | 
					          shot_type: String.t() | nil,
 | 
				
			||||||
 | 
					          shot_material: String.t() | nil,
 | 
				
			||||||
 | 
					          shot_size: String.t() | nil,
 | 
				
			||||||
 | 
					          unfired_length: String.t() | nil,
 | 
				
			||||||
 | 
					          brass_height: String.t() | nil,
 | 
				
			||||||
 | 
					          chamber_size: String.t() | nil,
 | 
				
			||||||
 | 
					          load_grains: integer() | nil,
 | 
				
			||||||
 | 
					          shot_charge_weight: String.t() | nil,
 | 
				
			||||||
 | 
					          dram_equivalent: String.t() | nil,
 | 
				
			||||||
          user_id: User.id(),
 | 
					          user_id: User.id(),
 | 
				
			||||||
          ammo_groups: [AmmoGroup.t()] | nil,
 | 
					          packs: [Pack.t()] | nil,
 | 
				
			||||||
          inserted_at: NaiveDateTime.t(),
 | 
					          inserted_at: NaiveDateTime.t(),
 | 
				
			||||||
          updated_at: NaiveDateTime.t()
 | 
					          updated_at: NaiveDateTime.t()
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
  @type new_ammo_type :: %__MODULE__{}
 | 
					  @type new_type :: %__MODULE__{}
 | 
				
			||||||
  @type id :: UUID.t()
 | 
					  @type id :: UUID.t()
 | 
				
			||||||
  @type changeset :: Changeset.t(t() | new_ammo_type())
 | 
					  @type changeset :: Changeset.t(t() | new_type())
 | 
				
			||||||
 | 
					  @type class :: :rifle | :shotgun | :pistol | nil
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @spec changeset_fields() :: [atom()]
 | 
					  @spec changeset_fields() :: [atom()]
 | 
				
			||||||
  defp changeset_fields,
 | 
					  defp changeset_fields,
 | 
				
			||||||
    do: [
 | 
					    do: [
 | 
				
			||||||
      :name,
 | 
					      :name,
 | 
				
			||||||
      :desc,
 | 
					      :desc,
 | 
				
			||||||
 | 
					      :class,
 | 
				
			||||||
      :bullet_type,
 | 
					      :bullet_type,
 | 
				
			||||||
      :bullet_core,
 | 
					      :bullet_core,
 | 
				
			||||||
      :cartridge,
 | 
					 | 
				
			||||||
      :caliber,
 | 
					      :caliber,
 | 
				
			||||||
      :case_material,
 | 
					      :case_material,
 | 
				
			||||||
      :jacket_type,
 | 
					 | 
				
			||||||
      :muzzle_velocity,
 | 
					 | 
				
			||||||
      :powder_type,
 | 
					      :powder_type,
 | 
				
			||||||
      :powder_grains_per_charge,
 | 
					 | 
				
			||||||
      :grains,
 | 
					      :grains,
 | 
				
			||||||
      :pressure,
 | 
					      :pressure,
 | 
				
			||||||
      :primer_type,
 | 
					      :primer_type,
 | 
				
			||||||
      :firing_type,
 | 
					      :firing_type,
 | 
				
			||||||
 | 
					      :manufacturer,
 | 
				
			||||||
 | 
					      :upc,
 | 
				
			||||||
      :tracer,
 | 
					      :tracer,
 | 
				
			||||||
      :incendiary,
 | 
					      :incendiary,
 | 
				
			||||||
      :blank,
 | 
					      :blank,
 | 
				
			||||||
      :corrosive,
 | 
					      :corrosive,
 | 
				
			||||||
 | 
					      :cartridge,
 | 
				
			||||||
 | 
					      :jacket_type,
 | 
				
			||||||
 | 
					      :powder_grains_per_charge,
 | 
				
			||||||
 | 
					      :muzzle_velocity,
 | 
				
			||||||
 | 
					      :wadding,
 | 
				
			||||||
 | 
					      :shot_type,
 | 
				
			||||||
 | 
					      :shot_material,
 | 
				
			||||||
 | 
					      :shot_size,
 | 
				
			||||||
 | 
					      :unfired_length,
 | 
				
			||||||
 | 
					      :brass_height,
 | 
				
			||||||
 | 
					      :chamber_size,
 | 
				
			||||||
 | 
					      :load_grains,
 | 
				
			||||||
 | 
					      :shot_charge_weight,
 | 
				
			||||||
 | 
					      :dram_equivalent
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @spec string_fields() :: [atom()]
 | 
				
			||||||
 | 
					  defp string_fields,
 | 
				
			||||||
 | 
					    do: [
 | 
				
			||||||
 | 
					      :name,
 | 
				
			||||||
 | 
					      :desc,
 | 
				
			||||||
 | 
					      :bullet_type,
 | 
				
			||||||
 | 
					      :bullet_core,
 | 
				
			||||||
 | 
					      :caliber,
 | 
				
			||||||
 | 
					      :case_material,
 | 
				
			||||||
 | 
					      :powder_type,
 | 
				
			||||||
 | 
					      :pressure,
 | 
				
			||||||
 | 
					      :primer_type,
 | 
				
			||||||
 | 
					      :firing_type,
 | 
				
			||||||
      :manufacturer,
 | 
					      :manufacturer,
 | 
				
			||||||
      :upc
 | 
					      :upc,
 | 
				
			||||||
 | 
					      :cartridge,
 | 
				
			||||||
 | 
					      :jacket_type,
 | 
				
			||||||
 | 
					      :wadding,
 | 
				
			||||||
 | 
					      :shot_type,
 | 
				
			||||||
 | 
					      :shot_material,
 | 
				
			||||||
 | 
					      :shot_size,
 | 
				
			||||||
 | 
					      :unfired_length,
 | 
				
			||||||
 | 
					      :brass_height,
 | 
				
			||||||
 | 
					      :chamber_size,
 | 
				
			||||||
 | 
					      :shot_charge_weight,
 | 
				
			||||||
 | 
					      :dram_equivalent
 | 
				
			||||||
    ]
 | 
					    ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @doc false
 | 
					  @doc false
 | 
				
			||||||
  @spec create_changeset(new_ammo_type(), User.t(), attrs :: map()) :: changeset()
 | 
					  @spec create_changeset(new_type(), User.t(), attrs :: map()) :: changeset()
 | 
				
			||||||
  def create_changeset(ammo_type, %User{id: user_id}, attrs) do
 | 
					  def create_changeset(type, %User{id: user_id}, attrs) do
 | 
				
			||||||
    ammo_type
 | 
					    changeset =
 | 
				
			||||||
    |> change(user_id: user_id)
 | 
					      type
 | 
				
			||||||
    |> cast(attrs, changeset_fields())
 | 
					      |> change(user_id: user_id)
 | 
				
			||||||
 | 
					      |> cast(attrs, changeset_fields())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    string_fields()
 | 
				
			||||||
 | 
					    |> Enum.reduce(changeset, fn field, acc -> acc |> validate_length(field, max: 255) end)
 | 
				
			||||||
    |> validate_required([:name, :user_id])
 | 
					    |> validate_required([:name, :user_id])
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @doc false
 | 
					  @doc false
 | 
				
			||||||
  @spec update_changeset(t() | new_ammo_type(), attrs :: map()) :: changeset()
 | 
					  @spec update_changeset(t() | new_type(), attrs :: map()) :: changeset()
 | 
				
			||||||
  def update_changeset(ammo_type, attrs) do
 | 
					  def update_changeset(type, attrs) do
 | 
				
			||||||
    ammo_type
 | 
					    changeset =
 | 
				
			||||||
    |> cast(attrs, changeset_fields())
 | 
					      type
 | 
				
			||||||
 | 
					      |> cast(attrs, changeset_fields())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    string_fields()
 | 
				
			||||||
 | 
					    |> Enum.reduce(changeset, fn field, acc -> acc |> validate_length(field, max: 255) end)
 | 
				
			||||||
    |> validate_required(:name)
 | 
					    |> validate_required(:name)
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
@@ -5,7 +5,7 @@ defmodule Cannery.Containers do
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  import CanneryWeb.Gettext
 | 
					  import CanneryWeb.Gettext
 | 
				
			||||||
  import Ecto.Query, warn: false
 | 
					  import Ecto.Query, warn: false
 | 
				
			||||||
  alias Cannery.{Accounts.User, Ammo.AmmoGroup, Repo}
 | 
					  alias Cannery.{Accounts.User, Ammo.Pack, Repo}
 | 
				
			||||||
  alias Cannery.Containers.{Container, ContainerTag, Tag}
 | 
					  alias Cannery.Containers.{Container, ContainerTag, Tag}
 | 
				
			||||||
  alias Ecto.Changeset
 | 
					  alias Ecto.Changeset
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -203,7 +203,7 @@ defmodule Cannery.Containers do
 | 
				
			|||||||
          {:ok, Container.t()} | {:error, Container.changeset()}
 | 
					          {:ok, Container.t()} | {:error, Container.changeset()}
 | 
				
			||||||
  def delete_container(%Container{user_id: user_id} = container, %User{id: user_id}) do
 | 
					  def delete_container(%Container{user_id: user_id} = container, %User{id: user_id}) do
 | 
				
			||||||
    Repo.one(
 | 
					    Repo.one(
 | 
				
			||||||
      from ag in AmmoGroup,
 | 
					      from ag in Pack,
 | 
				
			||||||
        where: ag.container_id == ^container.id,
 | 
					        where: ag.container_id == ^container.id,
 | 
				
			||||||
        select: count(ag.id)
 | 
					        select: count(ag.id)
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
@@ -221,7 +221,7 @@ defmodule Cannery.Containers do
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        container
 | 
					        container
 | 
				
			||||||
        |> Container.update_changeset(%{})
 | 
					        |> Container.update_changeset(%{})
 | 
				
			||||||
        |> Changeset.add_error(:ammo_groups, error)
 | 
					        |> Changeset.add_error(:packs, error)
 | 
				
			||||||
        |> Changeset.apply_action(:delete)
 | 
					        |> Changeset.apply_action(:delete)
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -53,6 +53,8 @@ defmodule Cannery.Containers.Container do
 | 
				
			|||||||
    container
 | 
					    container
 | 
				
			||||||
    |> change(user_id: user_id)
 | 
					    |> change(user_id: user_id)
 | 
				
			||||||
    |> cast(attrs, [:name, :desc, :type, :location])
 | 
					    |> cast(attrs, [:name, :desc, :type, :location])
 | 
				
			||||||
 | 
					    |> validate_length(:name, max: 255)
 | 
				
			||||||
 | 
					    |> validate_length(:type, max: 255)
 | 
				
			||||||
    |> validate_required([:name, :type, :user_id])
 | 
					    |> validate_required([:name, :type, :user_id])
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -61,6 +63,8 @@ defmodule Cannery.Containers.Container do
 | 
				
			|||||||
  def update_changeset(container, attrs) do
 | 
					  def update_changeset(container, attrs) do
 | 
				
			||||||
    container
 | 
					    container
 | 
				
			||||||
    |> cast(attrs, [:name, :desc, :type, :location])
 | 
					    |> cast(attrs, [:name, :desc, :type, :location])
 | 
				
			||||||
 | 
					    |> validate_length(:name, max: 255)
 | 
				
			||||||
 | 
					    |> validate_length(:type, max: 255)
 | 
				
			||||||
    |> validate_required([:name, :type])
 | 
					    |> validate_required([:name, :type])
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -47,6 +47,9 @@ defmodule Cannery.Containers.Tag do
 | 
				
			|||||||
    tag
 | 
					    tag
 | 
				
			||||||
    |> change(user_id: user_id)
 | 
					    |> change(user_id: user_id)
 | 
				
			||||||
    |> cast(attrs, [:name, :bg_color, :text_color])
 | 
					    |> cast(attrs, [:name, :bg_color, :text_color])
 | 
				
			||||||
 | 
					    |> validate_length(:name, max: 255)
 | 
				
			||||||
 | 
					    |> validate_length(:bg_color, max: 12)
 | 
				
			||||||
 | 
					    |> validate_length(:text_color, max: 12)
 | 
				
			||||||
    |> validate_required([:name, :bg_color, :text_color, :user_id])
 | 
					    |> validate_required([:name, :bg_color, :text_color, :user_id])
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -55,6 +58,9 @@ defmodule Cannery.Containers.Tag do
 | 
				
			|||||||
  def update_changeset(tag, attrs) do
 | 
					  def update_changeset(tag, attrs) do
 | 
				
			||||||
    tag
 | 
					    tag
 | 
				
			||||||
    |> cast(attrs, [:name, :bg_color, :text_color])
 | 
					    |> cast(attrs, [:name, :bg_color, :text_color])
 | 
				
			||||||
 | 
					    |> validate_length(:name, max: 255)
 | 
				
			||||||
 | 
					    |> validate_length(:bg_color, max: 12)
 | 
				
			||||||
 | 
					    |> validate_length(:text_color, max: 12)
 | 
				
			||||||
    |> validate_required([:name, :bg_color, :text_color])
 | 
					    |> validate_required([:name, :bg_color, :text_color])
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,10 +1,10 @@
 | 
				
			|||||||
defmodule CanneryWeb.Components.AddShotGroupComponent do
 | 
					defmodule CanneryWeb.Components.AddShotRecordComponent do
 | 
				
			||||||
  @moduledoc """
 | 
					  @moduledoc """
 | 
				
			||||||
  Livecomponent that can create a ShotGroup
 | 
					  Livecomponent that can create a ShotRecord
 | 
				
			||||||
  """
 | 
					  """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  use CanneryWeb, :live_component
 | 
					  use CanneryWeb, :live_component
 | 
				
			||||||
  alias Cannery.{Accounts.User, ActivityLog, ActivityLog.ShotGroup, Ammo.AmmoGroup}
 | 
					  alias Cannery.{Accounts.User, ActivityLog, ActivityLog.ShotRecord, Ammo.Pack}
 | 
				
			||||||
  alias Ecto.Changeset
 | 
					  alias Ecto.Changeset
 | 
				
			||||||
  alias Phoenix.LiveView.{JS, Socket}
 | 
					  alias Phoenix.LiveView.{JS, Socket}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -12,15 +12,15 @@ defmodule CanneryWeb.Components.AddShotGroupComponent do
 | 
				
			|||||||
  @spec update(
 | 
					  @spec update(
 | 
				
			||||||
          %{
 | 
					          %{
 | 
				
			||||||
            required(:current_user) => User.t(),
 | 
					            required(:current_user) => User.t(),
 | 
				
			||||||
            required(:ammo_group) => AmmoGroup.t(),
 | 
					            required(:pack) => Pack.t(),
 | 
				
			||||||
            optional(any()) => any()
 | 
					            optional(any()) => any()
 | 
				
			||||||
          },
 | 
					          },
 | 
				
			||||||
          Socket.t()
 | 
					          Socket.t()
 | 
				
			||||||
        ) :: {:ok, Socket.t()}
 | 
					        ) :: {:ok, Socket.t()}
 | 
				
			||||||
  def update(%{ammo_group: ammo_group, current_user: current_user} = assigns, socket) do
 | 
					  def update(%{pack: pack, current_user: current_user} = assigns, socket) do
 | 
				
			||||||
    changeset =
 | 
					    changeset =
 | 
				
			||||||
      %ShotGroup{date: Date.utc_today()}
 | 
					      %ShotRecord{date: Date.utc_today()}
 | 
				
			||||||
      |> ShotGroup.create_changeset(current_user, ammo_group, %{})
 | 
					      |> ShotRecord.create_changeset(current_user, pack, %{})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    {:ok, socket |> assign(assigns) |> assign(:changeset, changeset)}
 | 
					    {:ok, socket |> assign(assigns) |> assign(:changeset, changeset)}
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
@@ -28,12 +28,12 @@ defmodule CanneryWeb.Components.AddShotGroupComponent do
 | 
				
			|||||||
  @impl true
 | 
					  @impl true
 | 
				
			||||||
  def handle_event(
 | 
					  def handle_event(
 | 
				
			||||||
        "validate",
 | 
					        "validate",
 | 
				
			||||||
        %{"shot_group" => shot_group_params},
 | 
					        %{"shot_record" => shot_record_params},
 | 
				
			||||||
        %{assigns: %{ammo_group: ammo_group, current_user: current_user}} = socket
 | 
					        %{assigns: %{pack: pack, current_user: current_user}} = socket
 | 
				
			||||||
      ) do
 | 
					      ) do
 | 
				
			||||||
    params = shot_group_params |> process_params(ammo_group)
 | 
					    params = shot_record_params |> process_params(pack)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    changeset = %ShotGroup{} |> ShotGroup.create_changeset(current_user, ammo_group, params)
 | 
					    changeset = %ShotRecord{} |> ShotRecord.create_changeset(current_user, pack, params)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    changeset =
 | 
					    changeset =
 | 
				
			||||||
      case changeset |> Changeset.apply_action(:validate) do
 | 
					      case changeset |> Changeset.apply_action(:validate) do
 | 
				
			||||||
@@ -46,17 +46,17 @@ defmodule CanneryWeb.Components.AddShotGroupComponent do
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  def handle_event(
 | 
					  def handle_event(
 | 
				
			||||||
        "save",
 | 
					        "save",
 | 
				
			||||||
        %{"shot_group" => shot_group_params},
 | 
					        %{"shot_record" => shot_record_params},
 | 
				
			||||||
        %{
 | 
					        %{
 | 
				
			||||||
          assigns: %{ammo_group: ammo_group, current_user: current_user, return_to: return_to}
 | 
					          assigns: %{pack: pack, current_user: current_user, return_to: return_to}
 | 
				
			||||||
        } = socket
 | 
					        } = socket
 | 
				
			||||||
      ) do
 | 
					      ) do
 | 
				
			||||||
    socket =
 | 
					    socket =
 | 
				
			||||||
      shot_group_params
 | 
					      shot_record_params
 | 
				
			||||||
      |> process_params(ammo_group)
 | 
					      |> process_params(pack)
 | 
				
			||||||
      |> ActivityLog.create_shot_group(current_user, ammo_group)
 | 
					      |> ActivityLog.create_shot_record(current_user, pack)
 | 
				
			||||||
      |> case do
 | 
					      |> case do
 | 
				
			||||||
        {:ok, _shot_group} ->
 | 
					        {:ok, _shot_record} ->
 | 
				
			||||||
          prompt = dgettext("prompts", "Shots recorded successfully")
 | 
					          prompt = dgettext("prompts", "Shots recorded successfully")
 | 
				
			||||||
          socket |> put_flash(:info, prompt) |> push_navigate(to: return_to)
 | 
					          socket |> put_flash(:info, prompt) |> push_navigate(to: return_to)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -68,8 +68,8 @@ defmodule CanneryWeb.Components.AddShotGroupComponent do
 | 
				
			|||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  # calculate count from shots left
 | 
					  # calculate count from shots left
 | 
				
			||||||
  defp process_params(params, %AmmoGroup{count: count}) do
 | 
					  defp process_params(params, %Pack{count: count}) do
 | 
				
			||||||
    shot_group_count =
 | 
					    shot_record_count =
 | 
				
			||||||
      if params |> Map.get("ammo_left", "") == "" do
 | 
					      if params |> Map.get("ammo_left", "") == "" do
 | 
				
			||||||
        nil
 | 
					        nil
 | 
				
			||||||
      else
 | 
					      else
 | 
				
			||||||
@@ -77,6 +77,6 @@ defmodule CanneryWeb.Components.AddShotGroupComponent do
 | 
				
			|||||||
        count - new_count
 | 
					        count - new_count
 | 
				
			||||||
      end
 | 
					      end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    params |> Map.put("count", shot_group_count)
 | 
					    params |> Map.put("count", shot_record_count)
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
@@ -6,7 +6,7 @@
 | 
				
			|||||||
  <.form
 | 
					  <.form
 | 
				
			||||||
    :let={f}
 | 
					    :let={f}
 | 
				
			||||||
    for={@changeset}
 | 
					    for={@changeset}
 | 
				
			||||||
    id="shot-group-form"
 | 
					    id="shot-record-form"
 | 
				
			||||||
    class="flex flex-col space-y-4 sm:space-y-0 sm:grid sm:grid-cols-3 sm:gap-4 justify-center items-center"
 | 
					    class="flex flex-col space-y-4 sm:space-y-0 sm:grid sm:grid-cols-3 sm:gap-4 justify-center items-center"
 | 
				
			||||||
    phx-target={@myself}
 | 
					    phx-target={@myself}
 | 
				
			||||||
    phx-change="validate"
 | 
					    phx-change="validate"
 | 
				
			||||||
@@ -22,14 +22,14 @@
 | 
				
			|||||||
    <%= label(f, :ammo_left, gettext("Rounds left"), class: "title text-lg text-primary-600") %>
 | 
					    <%= label(f, :ammo_left, gettext("Rounds left"), class: "title text-lg text-primary-600") %>
 | 
				
			||||||
    <%= number_input(f, :ammo_left,
 | 
					    <%= number_input(f, :ammo_left,
 | 
				
			||||||
      min: 0,
 | 
					      min: 0,
 | 
				
			||||||
      max: @ammo_group.count - 1,
 | 
					      max: @pack.count - 1,
 | 
				
			||||||
      placeholder: gettext("Rounds left"),
 | 
					      placeholder: gettext("Rounds left"),
 | 
				
			||||||
      class: "input input-primary"
 | 
					      class: "input input-primary"
 | 
				
			||||||
    ) %>
 | 
					    ) %>
 | 
				
			||||||
    <button
 | 
					    <button
 | 
				
			||||||
      type="button"
 | 
					      type="button"
 | 
				
			||||||
      class="mx-2 my-1 text-sm btn btn-primary"
 | 
					      class="mx-2 my-1 text-sm btn btn-primary"
 | 
				
			||||||
      phx-click={JS.dispatch("cannery:set-zero", to: "#shot-group-form_ammo_left")}
 | 
					      phx-click={JS.dispatch("cannery:set-zero", to: "#shot-record-form_ammo_left")}
 | 
				
			||||||
    >
 | 
					    >
 | 
				
			||||||
      <%= gettext("Used up!") %>
 | 
					      <%= gettext("Used up!") %>
 | 
				
			||||||
    </button>
 | 
					    </button>
 | 
				
			||||||
@@ -37,8 +37,9 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    <%= label(f, :notes, gettext("Notes"), class: "title text-lg text-primary-600") %>
 | 
					    <%= label(f, :notes, gettext("Notes"), class: "title text-lg text-primary-600") %>
 | 
				
			||||||
    <%= textarea(f, :notes,
 | 
					    <%= textarea(f, :notes,
 | 
				
			||||||
      id: "add-shot-group-form-notes",
 | 
					      id: "add-shot-record-form-notes",
 | 
				
			||||||
      class: "input input-primary col-span-2",
 | 
					      class: "input input-primary col-span-2",
 | 
				
			||||||
 | 
					      maxlength: 255,
 | 
				
			||||||
      placeholder: gettext("Really great weather"),
 | 
					      placeholder: gettext("Really great weather"),
 | 
				
			||||||
      phx_hook: "MaintainAttrs",
 | 
					      phx_hook: "MaintainAttrs",
 | 
				
			||||||
      phx_update: "ignore"
 | 
					      phx_update: "ignore"
 | 
				
			||||||
@@ -1,273 +0,0 @@
 | 
				
			|||||||
defmodule CanneryWeb.Components.AmmoGroupTableComponent do
 | 
					 | 
				
			||||||
  @moduledoc """
 | 
					 | 
				
			||||||
  A component that displays a list of ammo groups
 | 
					 | 
				
			||||||
  """
 | 
					 | 
				
			||||||
  use CanneryWeb, :live_component
 | 
					 | 
				
			||||||
  alias Cannery.{Accounts.User, Ammo.AmmoGroup, ComparableDate}
 | 
					 | 
				
			||||||
  alias Cannery.{ActivityLog, Ammo, Containers}
 | 
					 | 
				
			||||||
  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()],
 | 
					 | 
				
			||||||
            required(: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, show_used: _show_used} =
 | 
					 | 
				
			||||||
          assigns,
 | 
					 | 
				
			||||||
        socket
 | 
					 | 
				
			||||||
      ) do
 | 
					 | 
				
			||||||
    socket =
 | 
					 | 
				
			||||||
      socket
 | 
					 | 
				
			||||||
      |> assign(assigns)
 | 
					 | 
				
			||||||
      |> 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,
 | 
					 | 
				
			||||||
             ammo_type: ammo_type,
 | 
					 | 
				
			||||||
             range: range,
 | 
					 | 
				
			||||||
             container: container,
 | 
					 | 
				
			||||||
             actions: actions,
 | 
					 | 
				
			||||||
             show_used: show_used
 | 
					 | 
				
			||||||
           }
 | 
					 | 
				
			||||||
         } = socket
 | 
					 | 
				
			||||||
       ) do
 | 
					 | 
				
			||||||
    columns =
 | 
					 | 
				
			||||||
      if actions == [] do
 | 
					 | 
				
			||||||
        []
 | 
					 | 
				
			||||||
      else
 | 
					 | 
				
			||||||
        [%{label: gettext("Actions"), key: :actions, sortable: false}]
 | 
					 | 
				
			||||||
      end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    columns = [
 | 
					 | 
				
			||||||
      %{label: gettext("Purchased on"), key: :purchased_on, type: ComparableDate},
 | 
					 | 
				
			||||||
      %{label: gettext("Last used on"), key: :used_up_on, type: ComparableDate} | 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("Price paid"), key: :price_paid},
 | 
					 | 
				
			||||||
      %{label: gettext("CPR"), key: :cpr}
 | 
					 | 
				
			||||||
      | columns
 | 
					 | 
				
			||||||
    ]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    columns =
 | 
					 | 
				
			||||||
      if show_used do
 | 
					 | 
				
			||||||
        [
 | 
					 | 
				
			||||||
          %{label: gettext("Original Count"), key: :original_count},
 | 
					 | 
				
			||||||
          %{label: gettext("% left"), key: :remaining}
 | 
					 | 
				
			||||||
          | columns
 | 
					 | 
				
			||||||
        ]
 | 
					 | 
				
			||||||
      else
 | 
					 | 
				
			||||||
        columns
 | 
					 | 
				
			||||||
      end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    columns = [
 | 
					 | 
				
			||||||
      %{label: if(show_used, do: gettext("Current Count"), else: gettext("Count")), key: :count}
 | 
					 | 
				
			||||||
      | columns
 | 
					 | 
				
			||||||
    ]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    columns =
 | 
					 | 
				
			||||||
      if ammo_type == [] do
 | 
					 | 
				
			||||||
        columns
 | 
					 | 
				
			||||||
      else
 | 
					 | 
				
			||||||
        [%{label: gettext("Ammo type"), key: :ammo_type} | columns]
 | 
					 | 
				
			||||||
      end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    containers =
 | 
					 | 
				
			||||||
      ammo_groups
 | 
					 | 
				
			||||||
      |> Enum.map(fn %{container_id: container_id} -> container_id end)
 | 
					 | 
				
			||||||
      |> Containers.get_containers(current_user)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    extra_data = %{
 | 
					 | 
				
			||||||
      current_user: current_user,
 | 
					 | 
				
			||||||
      ammo_type: ammo_type,
 | 
					 | 
				
			||||||
      columns: columns,
 | 
					 | 
				
			||||||
      container: container,
 | 
					 | 
				
			||||||
      containers: containers,
 | 
					 | 
				
			||||||
      original_counts: Ammo.get_original_counts(ammo_groups, current_user),
 | 
					 | 
				
			||||||
      cprs: Ammo.get_cprs(ammo_groups, current_user),
 | 
					 | 
				
			||||||
      last_used_dates: ActivityLog.get_last_used_dates(ammo_groups, current_user),
 | 
					 | 
				
			||||||
      percentages_remaining: Ammo.get_percentages_remaining(ammo_groups, current_user),
 | 
					 | 
				
			||||||
      actions: actions,
 | 
					 | 
				
			||||||
      range: range
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    rows =
 | 
					 | 
				
			||||||
      ammo_groups
 | 
					 | 
				
			||||||
      |> Enum.map(fn ammo_group ->
 | 
					 | 
				
			||||||
        ammo_group |> get_row_data_for_ammo_group(extra_data)
 | 
					 | 
				
			||||||
      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_ammo_group(AmmoGroup.t(), additional_data :: map()) :: map()
 | 
					 | 
				
			||||||
  defp get_row_data_for_ammo_group(ammo_group, %{columns: columns} = additional_data) do
 | 
					 | 
				
			||||||
    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: {0, gettext("No cost information")}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  defp get_value_for_key(:price_paid, %{price_paid: price_paid}, _additional_data),
 | 
					 | 
				
			||||||
    do: {price_paid, gettext("$%{amount}", amount: display_currency(price_paid))}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  defp get_value_for_key(:purchased_on, %{purchased_on: purchased_on} = assigns, _additional_data) do
 | 
					 | 
				
			||||||
    {purchased_on,
 | 
					 | 
				
			||||||
     ~H"""
 | 
					 | 
				
			||||||
     <.date id={"#{@id}-purchased-on"} date={@purchased_on} />
 | 
					 | 
				
			||||||
     """}
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  defp get_value_for_key(:used_up_on, %{id: ammo_group_id}, %{last_used_dates: last_used_dates}) do
 | 
					 | 
				
			||||||
    last_used_date = last_used_dates |> Map.get(ammo_group_id)
 | 
					 | 
				
			||||||
    assigns = %{id: ammo_group_id, last_used_date: last_used_date}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    {last_used_date,
 | 
					 | 
				
			||||||
     ~H"""
 | 
					 | 
				
			||||||
     <%= if @last_used_date do %>
 | 
					 | 
				
			||||||
       <.date id={"#{@id}-last-used-date"} date={@last_used_date} />
 | 
					 | 
				
			||||||
     <% else %>
 | 
					 | 
				
			||||||
       <%= gettext("Never used") %>
 | 
					 | 
				
			||||||
     <% end %>
 | 
					 | 
				
			||||||
     """}
 | 
					 | 
				
			||||||
  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,
 | 
					 | 
				
			||||||
         %{id: ammo_group_id},
 | 
					 | 
				
			||||||
         %{percentages_remaining: percentages_remaining}
 | 
					 | 
				
			||||||
       ) do
 | 
					 | 
				
			||||||
    percentage = Map.fetch!(percentages_remaining, ammo_group_id)
 | 
					 | 
				
			||||||
    {percentage, gettext("%{percentage}%", percentage: percentage)}
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  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_id: container_id} = ammo_group,
 | 
					 | 
				
			||||||
         %{container: container_block, containers: containers}
 | 
					 | 
				
			||||||
       ) do
 | 
					 | 
				
			||||||
    container = %{name: container_name} = Map.fetch!(containers, container_id)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    assigns = %{
 | 
					 | 
				
			||||||
      container: container,
 | 
					 | 
				
			||||||
      container_block: container_block,
 | 
					 | 
				
			||||||
      ammo_group: ammo_group
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    {container_name,
 | 
					 | 
				
			||||||
     ~H"""
 | 
					 | 
				
			||||||
     <%= render_slot(@container_block, {@ammo_group, @container}) %>
 | 
					 | 
				
			||||||
     """}
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  defp get_value_for_key(
 | 
					 | 
				
			||||||
         :original_count,
 | 
					 | 
				
			||||||
         %{id: ammo_group_id},
 | 
					 | 
				
			||||||
         %{original_counts: original_counts}
 | 
					 | 
				
			||||||
       ) do
 | 
					 | 
				
			||||||
    Map.fetch!(original_counts, ammo_group_id)
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  defp get_value_for_key(:cpr, %{price_paid: nil}, _additional_data),
 | 
					 | 
				
			||||||
    do: {0, gettext("No cost information")}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  defp get_value_for_key(:cpr, %{id: ammo_group_id}, %{cprs: cprs}) do
 | 
					 | 
				
			||||||
    amount = Map.fetch!(cprs, ammo_group_id)
 | 
					 | 
				
			||||||
    {amount, gettext("$%{amount}", amount: display_currency(amount))}
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  defp get_value_for_key(:count, %{count: count}, _additional_data),
 | 
					 | 
				
			||||||
    do: if(count == 0, do: {0, gettext("Empty")}, else: count)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  defp get_value_for_key(key, ammo_group, _additional_data), do: ammo_group |> Map.get(key)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  @spec display_currency(float()) :: String.t()
 | 
					 | 
				
			||||||
  defp display_currency(float), do: :erlang.float_to_binary(float, decimals: 2)
 | 
					 | 
				
			||||||
end
 | 
					 | 
				
			||||||
@@ -1,264 +0,0 @@
 | 
				
			|||||||
defmodule CanneryWeb.Components.AmmoTypeTableComponent do
 | 
					 | 
				
			||||||
  @moduledoc """
 | 
					 | 
				
			||||||
  A component that displays a list of ammo type
 | 
					 | 
				
			||||||
  """
 | 
					 | 
				
			||||||
  use CanneryWeb, :live_component
 | 
					 | 
				
			||||||
  alias Cannery.{Accounts.User, ActivityLog, Ammo, Ammo.AmmoType}
 | 
					 | 
				
			||||||
  alias Ecto.UUID
 | 
					 | 
				
			||||||
  alias Phoenix.LiveView.{Rendered, Socket}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  @impl true
 | 
					 | 
				
			||||||
  @spec update(
 | 
					 | 
				
			||||||
          %{
 | 
					 | 
				
			||||||
            required(:id) => UUID.t(),
 | 
					 | 
				
			||||||
            required(:current_user) => User.t(),
 | 
					 | 
				
			||||||
            optional(:show_used) => boolean(),
 | 
					 | 
				
			||||||
            optional(:ammo_types) => [AmmoType.t()],
 | 
					 | 
				
			||||||
            optional(:actions) => Rendered.t(),
 | 
					 | 
				
			||||||
            optional(any()) => any()
 | 
					 | 
				
			||||||
          },
 | 
					 | 
				
			||||||
          Socket.t()
 | 
					 | 
				
			||||||
        ) :: {:ok, Socket.t()}
 | 
					 | 
				
			||||||
  def update(%{id: _id, ammo_types: _ammo_types, current_user: _current_user} = assigns, socket) do
 | 
					 | 
				
			||||||
    socket =
 | 
					 | 
				
			||||||
      socket
 | 
					 | 
				
			||||||
      |> assign(assigns)
 | 
					 | 
				
			||||||
      |> assign_new(:show_used, fn -> false end)
 | 
					 | 
				
			||||||
      |> assign_new(:actions, fn -> [] end)
 | 
					 | 
				
			||||||
      |> display_ammo_types()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    {:ok, socket}
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  defp display_ammo_types(
 | 
					 | 
				
			||||||
         %{
 | 
					 | 
				
			||||||
           assigns: %{
 | 
					 | 
				
			||||||
             ammo_types: ammo_types,
 | 
					 | 
				
			||||||
             current_user: current_user,
 | 
					 | 
				
			||||||
             show_used: show_used,
 | 
					 | 
				
			||||||
             actions: actions
 | 
					 | 
				
			||||||
           }
 | 
					 | 
				
			||||||
         } = socket
 | 
					 | 
				
			||||||
       ) do
 | 
					 | 
				
			||||||
    columns =
 | 
					 | 
				
			||||||
      [
 | 
					 | 
				
			||||||
        %{label: gettext("Name"), key: :name, type: :name},
 | 
					 | 
				
			||||||
        %{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}
 | 
					 | 
				
			||||||
      ]
 | 
					 | 
				
			||||||
      |> Enum.filter(fn %{key: key, type: type} ->
 | 
					 | 
				
			||||||
        # remove columns if all values match defaults
 | 
					 | 
				
			||||||
        default_value = if type == :boolean, do: false, else: nil
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        ammo_types
 | 
					 | 
				
			||||||
        |> Enum.any?(fn ammo_type ->
 | 
					 | 
				
			||||||
          not (ammo_type |> Map.get(key) == default_value)
 | 
					 | 
				
			||||||
        end)
 | 
					 | 
				
			||||||
      end)
 | 
					 | 
				
			||||||
      |> Kernel.++([
 | 
					 | 
				
			||||||
        %{label: gettext("Rounds"), key: :round_count, type: :round_count}
 | 
					 | 
				
			||||||
      ])
 | 
					 | 
				
			||||||
      |> Kernel.++(
 | 
					 | 
				
			||||||
        if show_used do
 | 
					 | 
				
			||||||
          [
 | 
					 | 
				
			||||||
            %{
 | 
					 | 
				
			||||||
              label: gettext("Used rounds"),
 | 
					 | 
				
			||||||
              key: :used_round_count,
 | 
					 | 
				
			||||||
              type: :used_round_count
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
            %{
 | 
					 | 
				
			||||||
              label: gettext("Total ever rounds"),
 | 
					 | 
				
			||||||
              key: :historical_round_count,
 | 
					 | 
				
			||||||
              type: :historical_round_count
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
          ]
 | 
					 | 
				
			||||||
        else
 | 
					 | 
				
			||||||
          []
 | 
					 | 
				
			||||||
        end
 | 
					 | 
				
			||||||
      )
 | 
					 | 
				
			||||||
      |> Kernel.++([%{label: gettext("Packs"), key: :ammo_count, type: :ammo_count}])
 | 
					 | 
				
			||||||
      |> Kernel.++(
 | 
					 | 
				
			||||||
        if show_used do
 | 
					 | 
				
			||||||
          [
 | 
					 | 
				
			||||||
            %{
 | 
					 | 
				
			||||||
              label: gettext("Used packs"),
 | 
					 | 
				
			||||||
              key: :used_pack_count,
 | 
					 | 
				
			||||||
              type: :used_pack_count
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
            %{
 | 
					 | 
				
			||||||
              label: gettext("Total ever packs"),
 | 
					 | 
				
			||||||
              key: :historical_pack_count,
 | 
					 | 
				
			||||||
              type: :historical_pack_count
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
          ]
 | 
					 | 
				
			||||||
        else
 | 
					 | 
				
			||||||
          []
 | 
					 | 
				
			||||||
        end
 | 
					 | 
				
			||||||
      )
 | 
					 | 
				
			||||||
      |> Kernel.++([
 | 
					 | 
				
			||||||
        %{label: gettext("Average CPR"), key: :avg_price_paid, type: :avg_price_paid},
 | 
					 | 
				
			||||||
        %{label: gettext("Actions"), key: "actions", type: :actions, sortable: false}
 | 
					 | 
				
			||||||
      ])
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    round_counts = ammo_types |> Ammo.get_round_count_for_ammo_types(current_user)
 | 
					 | 
				
			||||||
    packs_count = ammo_types |> Ammo.get_ammo_groups_count_for_types(current_user)
 | 
					 | 
				
			||||||
    average_costs = ammo_types |> Ammo.get_average_cost_for_ammo_types(current_user)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    [used_counts, historical_round_counts, historical_pack_counts, used_pack_counts] =
 | 
					 | 
				
			||||||
      if show_used do
 | 
					 | 
				
			||||||
        [
 | 
					 | 
				
			||||||
          ammo_types |> ActivityLog.get_used_count_for_ammo_types(current_user),
 | 
					 | 
				
			||||||
          ammo_types |> Ammo.get_historical_count_for_ammo_types(current_user),
 | 
					 | 
				
			||||||
          ammo_types |> Ammo.get_ammo_groups_count_for_types(current_user, true),
 | 
					 | 
				
			||||||
          ammo_types |> Ammo.get_used_ammo_groups_count_for_types(current_user)
 | 
					 | 
				
			||||||
        ]
 | 
					 | 
				
			||||||
      else
 | 
					 | 
				
			||||||
        [nil, nil, nil, nil]
 | 
					 | 
				
			||||||
      end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    extra_data = %{
 | 
					 | 
				
			||||||
      actions: actions,
 | 
					 | 
				
			||||||
      current_user: current_user,
 | 
					 | 
				
			||||||
      used_counts: used_counts,
 | 
					 | 
				
			||||||
      round_counts: round_counts,
 | 
					 | 
				
			||||||
      historical_round_counts: historical_round_counts,
 | 
					 | 
				
			||||||
      packs_count: packs_count,
 | 
					 | 
				
			||||||
      used_pack_counts: used_pack_counts,
 | 
					 | 
				
			||||||
      historical_pack_counts: historical_pack_counts,
 | 
					 | 
				
			||||||
      average_costs: average_costs
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    rows =
 | 
					 | 
				
			||||||
      ammo_types
 | 
					 | 
				
			||||||
      |> Enum.map(fn ammo_type ->
 | 
					 | 
				
			||||||
        ammo_type |> get_ammo_type_values(columns, extra_data)
 | 
					 | 
				
			||||||
      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
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  defp get_ammo_type_values(ammo_type, columns, extra_data) do
 | 
					 | 
				
			||||||
    columns
 | 
					 | 
				
			||||||
    |> Map.new(fn %{key: key, type: type} ->
 | 
					 | 
				
			||||||
      {key, get_ammo_type_value(type, key, ammo_type, extra_data)}
 | 
					 | 
				
			||||||
    end)
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  defp get_ammo_type_value(:boolean, key, ammo_type, _other_data),
 | 
					 | 
				
			||||||
    do: ammo_type |> Map.get(key) |> humanize()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  defp get_ammo_type_value(:round_count, _key, %{id: ammo_type_id}, %{round_counts: round_counts}),
 | 
					 | 
				
			||||||
    do: Map.get(round_counts, ammo_type_id, 0)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  defp get_ammo_type_value(
 | 
					 | 
				
			||||||
         :historical_round_count,
 | 
					 | 
				
			||||||
         _key,
 | 
					 | 
				
			||||||
         %{id: ammo_type_id},
 | 
					 | 
				
			||||||
         %{historical_round_counts: historical_round_counts}
 | 
					 | 
				
			||||||
       ) do
 | 
					 | 
				
			||||||
    Map.get(historical_round_counts, ammo_type_id, 0)
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  defp get_ammo_type_value(
 | 
					 | 
				
			||||||
         :used_round_count,
 | 
					 | 
				
			||||||
         _key,
 | 
					 | 
				
			||||||
         %{id: ammo_type_id},
 | 
					 | 
				
			||||||
         %{used_counts: used_counts}
 | 
					 | 
				
			||||||
       ) do
 | 
					 | 
				
			||||||
    Map.get(used_counts, ammo_type_id, 0)
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  defp get_ammo_type_value(
 | 
					 | 
				
			||||||
         :historical_pack_count,
 | 
					 | 
				
			||||||
         _key,
 | 
					 | 
				
			||||||
         %{id: ammo_type_id},
 | 
					 | 
				
			||||||
         %{historical_pack_counts: historical_pack_counts}
 | 
					 | 
				
			||||||
       ) do
 | 
					 | 
				
			||||||
    Map.get(historical_pack_counts, ammo_type_id, 0)
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  defp get_ammo_type_value(
 | 
					 | 
				
			||||||
         :used_pack_count,
 | 
					 | 
				
			||||||
         _key,
 | 
					 | 
				
			||||||
         %{id: ammo_type_id},
 | 
					 | 
				
			||||||
         %{used_pack_counts: used_pack_counts}
 | 
					 | 
				
			||||||
       ) do
 | 
					 | 
				
			||||||
    Map.get(used_pack_counts, ammo_type_id, 0)
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  defp get_ammo_type_value(:ammo_count, _key, %{id: ammo_type_id}, %{packs_count: packs_count}),
 | 
					 | 
				
			||||||
    do: Map.get(packs_count, ammo_type_id)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  defp get_ammo_type_value(
 | 
					 | 
				
			||||||
         :avg_price_paid,
 | 
					 | 
				
			||||||
         _key,
 | 
					 | 
				
			||||||
         %{id: ammo_type_id},
 | 
					 | 
				
			||||||
         %{average_costs: average_costs}
 | 
					 | 
				
			||||||
       ) do
 | 
					 | 
				
			||||||
    case Map.get(average_costs, ammo_type_id) do
 | 
					 | 
				
			||||||
      nil -> {0, gettext("No cost information")}
 | 
					 | 
				
			||||||
      count -> {count, gettext("$%{amount}", amount: display_currency(count))}
 | 
					 | 
				
			||||||
    end
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  defp get_ammo_type_value(:name, _key, %{name: ammo_type_name} = ammo_type, _other_data) 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_ammo_type_value(:actions, _key, ammo_type, %{actions: actions}) do
 | 
					 | 
				
			||||||
    assigns = %{actions: actions, ammo_type: ammo_type}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    ~H"""
 | 
					 | 
				
			||||||
    <%= render_slot(@actions, @ammo_type) %>
 | 
					 | 
				
			||||||
    """
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  defp get_ammo_type_value(nil, _key, _ammo_type, _other_data), do: nil
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  defp get_ammo_type_value(_other, key, ammo_type, _other_data), do: ammo_type |> Map.get(key)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  @spec display_currency(float()) :: String.t()
 | 
					 | 
				
			||||||
  defp display_currency(float), do: :erlang.float_to_binary(float, decimals: 2)
 | 
					 | 
				
			||||||
end
 | 
					 | 
				
			||||||
@@ -71,7 +71,7 @@ defmodule CanneryWeb.Components.ContainerTableComponent do
 | 
				
			|||||||
      current_user: current_user,
 | 
					      current_user: current_user,
 | 
				
			||||||
      tag_actions: tag_actions,
 | 
					      tag_actions: tag_actions,
 | 
				
			||||||
      actions: actions,
 | 
					      actions: actions,
 | 
				
			||||||
      pack_count: Ammo.get_ammo_groups_count_for_containers(containers, current_user),
 | 
					      pack_count: Ammo.get_packs_count_for_containers(containers, current_user),
 | 
				
			||||||
      round_count: Ammo.get_round_count_for_containers(containers, current_user)
 | 
					      round_count: Ammo.get_round_count_for_containers(containers, current_user)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,7 +5,7 @@ defmodule CanneryWeb.CoreComponents do
 | 
				
			|||||||
  use Phoenix.Component
 | 
					  use Phoenix.Component
 | 
				
			||||||
  import CanneryWeb.{Gettext, ViewHelpers}
 | 
					  import CanneryWeb.{Gettext, ViewHelpers}
 | 
				
			||||||
  alias Cannery.{Accounts, Accounts.Invite, Accounts.User}
 | 
					  alias Cannery.{Accounts, Accounts.Invite, Accounts.User}
 | 
				
			||||||
  alias Cannery.{Ammo, Ammo.AmmoGroup}
 | 
					  alias Cannery.{Ammo, Ammo.Pack}
 | 
				
			||||||
  alias Cannery.{Containers.Container, Containers.Tag}
 | 
					  alias Cannery.{Containers.Container, Containers.Tag}
 | 
				
			||||||
  alias CanneryWeb.{Endpoint, HomeLive}
 | 
					  alias CanneryWeb.{Endpoint, HomeLive}
 | 
				
			||||||
  alias CanneryWeb.Router.Helpers, as: Routes
 | 
					  alias CanneryWeb.Router.Helpers, as: Routes
 | 
				
			||||||
@@ -86,7 +86,7 @@ defmodule CanneryWeb.CoreComponents do
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  def simple_tag_card(assigns)
 | 
					  def simple_tag_card(assigns)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  attr :ammo_group, AmmoGroup, required: true
 | 
					  attr :pack, Pack, required: true
 | 
				
			||||||
  attr :current_user, User, required: true
 | 
					  attr :current_user, User, required: true
 | 
				
			||||||
  attr :original_count, :integer, default: nil
 | 
					  attr :original_count, :integer, default: nil
 | 
				
			||||||
  attr :cpr, :integer, default: nil
 | 
					  attr :cpr, :integer, default: nil
 | 
				
			||||||
@@ -94,7 +94,7 @@ defmodule CanneryWeb.CoreComponents do
 | 
				
			|||||||
  attr :container, Container, default: nil
 | 
					  attr :container, Container, default: nil
 | 
				
			||||||
  slot(:inner_block)
 | 
					  slot(:inner_block)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def ammo_group_card(assigns)
 | 
					  def pack_card(assigns)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @spec display_currency(float()) :: String.t()
 | 
					  @spec display_currency(float()) :: String.t()
 | 
				
			||||||
  defp display_currency(float), do: :erlang.float_to_binary(float, decimals: 2)
 | 
					  defp display_currency(float), do: :erlang.float_to_binary(float, decimals: 2)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -27,10 +27,10 @@
 | 
				
			|||||||
      <%= @container.location %>
 | 
					      <%= @container.location %>
 | 
				
			||||||
    </span>
 | 
					    </span>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <%= if @container |> Ammo.get_ammo_groups_count_for_container!(@current_user) != 0 do %>
 | 
					    <%= if @container |> Ammo.get_packs_count_for_container!(@current_user) != 0 do %>
 | 
				
			||||||
      <span class="rounded-lg title text-lg">
 | 
					      <span class="rounded-lg title text-lg">
 | 
				
			||||||
        <%= gettext("Packs:") %>
 | 
					        <%= gettext("Packs:") %>
 | 
				
			||||||
        <%= @container |> Ammo.get_ammo_groups_count_for_container!(@current_user) %>
 | 
					        <%= @container |> Ammo.get_packs_count_for_container!(@current_user) %>
 | 
				
			||||||
      </span>
 | 
					      </span>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      <span class="rounded-lg title text-lg">
 | 
					      <span class="rounded-lg title text-lg">
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,6 +6,7 @@
 | 
				
			|||||||
    p-8 flex flex-col justify-center items-center cursor-auto"
 | 
					    p-8 flex flex-col justify-center items-center cursor-auto"
 | 
				
			||||||
  style="background-color: rgba(0,0,0,0.4);"
 | 
					  style="background-color: rgba(0,0,0,0.4);"
 | 
				
			||||||
  phx-remove={hide_modal()}
 | 
					  phx-remove={hide_modal()}
 | 
				
			||||||
 | 
					  aria-label={gettext("Close modal")}
 | 
				
			||||||
>
 | 
					>
 | 
				
			||||||
  <span class="hidden"></span>
 | 
					  <span class="hidden"></span>
 | 
				
			||||||
</.link>
 | 
					</.link>
 | 
				
			||||||
@@ -31,6 +32,7 @@
 | 
				
			|||||||
        text-gray-500 hover:text-gray-800
 | 
					        text-gray-500 hover:text-gray-800
 | 
				
			||||||
        transition-all duration-500 ease-in-out"
 | 
					        transition-all duration-500 ease-in-out"
 | 
				
			||||||
      phx-remove={hide_modal()}
 | 
					      phx-remove={hide_modal()}
 | 
				
			||||||
 | 
					      aria-label={gettext("Close modal")}
 | 
				
			||||||
    >
 | 
					    >
 | 
				
			||||||
      <i class="fa-fw fa-lg fas fa-times"></i>
 | 
					      <i class="fa-fw fa-lg fas fa-times"></i>
 | 
				
			||||||
    </.link>
 | 
					    </.link>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,48 +1,45 @@
 | 
				
			|||||||
<div
 | 
					<div
 | 
				
			||||||
  id={"ammo_group-#{@ammo_group.id}"}
 | 
					  id={"pack-#{@pack.id}"}
 | 
				
			||||||
  class="mx-4 my-2 px-8 py-4
 | 
					  class="mx-4 my-2 px-8 py-4
 | 
				
			||||||
    flex flex-col justify-center items-center
 | 
					    flex flex-col justify-center items-center
 | 
				
			||||||
    border border-gray-400 rounded-lg shadow-lg hover:shadow-md
 | 
					    border border-gray-400 rounded-lg shadow-lg hover:shadow-md
 | 
				
			||||||
    transition-all duration-300 ease-in-out"
 | 
					    transition-all duration-300 ease-in-out"
 | 
				
			||||||
>
 | 
					>
 | 
				
			||||||
  <.link navigate={Routes.ammo_group_show_path(Endpoint, :show, @ammo_group)} class="mb-2 link">
 | 
					  <.link navigate={Routes.pack_show_path(Endpoint, :show, @pack)} class="mb-2 link">
 | 
				
			||||||
    <h1 class="title text-xl title-primary-500">
 | 
					    <h1 class="title text-xl title-primary-500">
 | 
				
			||||||
      <%= @ammo_group.ammo_type.name %>
 | 
					      <%= @pack.type.name %>
 | 
				
			||||||
    </h1>
 | 
					    </h1>
 | 
				
			||||||
  </.link>
 | 
					  </.link>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  <div class="flex flex-col justify-center items-center">
 | 
					  <div class="flex flex-col justify-center items-center">
 | 
				
			||||||
    <span class="rounded-lg title text-lg">
 | 
					    <span class="rounded-lg title text-lg">
 | 
				
			||||||
      <%= gettext("Count:") %>
 | 
					      <%= gettext("Count:") %>
 | 
				
			||||||
      <%= if @ammo_group.count == 0, do: gettext("Empty"), else: @ammo_group.count %>
 | 
					      <%= if @pack.count == 0, do: gettext("Empty"), else: @pack.count %>
 | 
				
			||||||
    </span>
 | 
					    </span>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <span
 | 
					    <span :if={@original_count && @original_count != @pack.count} class="rounded-lg title text-lg">
 | 
				
			||||||
      :if={@original_count && @original_count != @ammo_group.count}
 | 
					 | 
				
			||||||
      class="rounded-lg title text-lg"
 | 
					 | 
				
			||||||
    >
 | 
					 | 
				
			||||||
      <%= gettext("Original Count:") %>
 | 
					      <%= gettext("Original Count:") %>
 | 
				
			||||||
      <%= @original_count %>
 | 
					      <%= @original_count %>
 | 
				
			||||||
    </span>
 | 
					    </span>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <span :if={@ammo_group.notes} class="rounded-lg title text-lg">
 | 
					    <span :if={@pack.notes} class="rounded-lg title text-lg">
 | 
				
			||||||
      <%= gettext("Notes:") %>
 | 
					      <%= gettext("Notes:") %>
 | 
				
			||||||
      <%= @ammo_group.notes %>
 | 
					      <%= @pack.notes %>
 | 
				
			||||||
    </span>
 | 
					    </span>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <span :if={@ammo_group.purchased_on} class="rounded-lg title text-lg">
 | 
					    <span :if={@pack.purchased_on} class="rounded-lg title text-lg">
 | 
				
			||||||
      <%= gettext("Purchased on:") %>
 | 
					      <%= gettext("Purchased on:") %>
 | 
				
			||||||
      <.date id={"#{@ammo_group.id}-purchased-on"} date={@ammo_group.purchased_on} />
 | 
					      <.date id={"#{@pack.id}-purchased-on"} date={@pack.purchased_on} />
 | 
				
			||||||
    </span>
 | 
					    </span>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <span :if={@last_used_date} class="rounded-lg title text-lg">
 | 
					    <span :if={@last_used_date} class="rounded-lg title text-lg">
 | 
				
			||||||
      <%= gettext("Last used on:") %>
 | 
					      <%= gettext("Last used on:") %>
 | 
				
			||||||
      <.date id={"#{@ammo_group.id}-last-used-on"} date={@last_used_date} />
 | 
					      <.date id={"#{@pack.id}-last-used-on"} date={@last_used_date} />
 | 
				
			||||||
    </span>
 | 
					    </span>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <span :if={@ammo_group.price_paid} class="rounded-lg title text-lg">
 | 
					    <span :if={@pack.price_paid} class="rounded-lg title text-lg">
 | 
				
			||||||
      <%= gettext("Price paid:") %>
 | 
					      <%= gettext("Price paid:") %>
 | 
				
			||||||
      <%= gettext("$%{amount}", amount: display_currency(@ammo_group.price_paid)) %>
 | 
					      <%= gettext("$%{amount}", amount: display_currency(@pack.price_paid)) %>
 | 
				
			||||||
    </span>
 | 
					    </span>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <span :if={@cpr} class="rounded-lg title text-lg">
 | 
					    <span :if={@cpr} class="rounded-lg title text-lg">
 | 
				
			||||||
@@ -50,6 +47,11 @@
 | 
				
			|||||||
      <%= gettext("$%{amount}", amount: display_currency(@cpr)) %>
 | 
					      <%= gettext("$%{amount}", amount: display_currency(@cpr)) %>
 | 
				
			||||||
    </span>
 | 
					    </span>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <span :if={@pack.lot_number} class="rounded-lg title text-lg">
 | 
				
			||||||
 | 
					      <%= gettext("Lot number:") %>
 | 
				
			||||||
 | 
					      <%= @pack.lot_number %>
 | 
				
			||||||
 | 
					    </span>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <span :if={@container} class="rounded-lg title text-lg">
 | 
					    <span :if={@container} class="rounded-lg title text-lg">
 | 
				
			||||||
      <%= gettext("Container:") %>
 | 
					      <%= gettext("Container:") %>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1,4 +1,4 @@
 | 
				
			|||||||
<label for={@id || @action} class="inline-flex relative items-center cursor-pointer">
 | 
					<label for={@id || @action} class="relative inline-flex items-center cursor-pointer">
 | 
				
			||||||
  <input
 | 
					  <input
 | 
				
			||||||
    id={@id || @action}
 | 
					    id={@id || @action}
 | 
				
			||||||
    type="checkbox"
 | 
					    type="checkbox"
 | 
				
			||||||
@@ -23,7 +23,7 @@
 | 
				
			|||||||
  </div>
 | 
					  </div>
 | 
				
			||||||
  <span
 | 
					  <span
 | 
				
			||||||
    id={"#{@id || @action}-label"}
 | 
					    id={"#{@id || @action}-label"}
 | 
				
			||||||
    class="ml-3 text-sm font-medium text-gray-900 dark:text-gray-300"
 | 
					    class="ml-3 text-sm font-medium text-gray-900 dark:text-gray-300 whitespace-nowrap"
 | 
				
			||||||
  >
 | 
					  >
 | 
				
			||||||
    <%= render_slot(@inner_block) %>
 | 
					    <%= render_slot(@inner_block) %>
 | 
				
			||||||
  </span>
 | 
					  </span>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -44,7 +44,7 @@
 | 
				
			|||||||
        </li>
 | 
					        </li>
 | 
				
			||||||
        <li class="mx-2 my-1">
 | 
					        <li class="mx-2 my-1">
 | 
				
			||||||
          <.link
 | 
					          <.link
 | 
				
			||||||
            navigate={Routes.ammo_type_index_path(Endpoint, :index)}
 | 
					            navigate={Routes.type_index_path(Endpoint, :index)}
 | 
				
			||||||
            class="text-white hover:underline"
 | 
					            class="text-white hover:underline"
 | 
				
			||||||
          >
 | 
					          >
 | 
				
			||||||
            <%= gettext("Catalog") %>
 | 
					            <%= gettext("Catalog") %>
 | 
				
			||||||
@@ -52,7 +52,7 @@
 | 
				
			|||||||
        </li>
 | 
					        </li>
 | 
				
			||||||
        <li class="mx-2 my-1">
 | 
					        <li class="mx-2 my-1">
 | 
				
			||||||
          <.link
 | 
					          <.link
 | 
				
			||||||
            navigate={Routes.ammo_group_index_path(Endpoint, :index)}
 | 
					            navigate={Routes.pack_index_path(Endpoint, :index)}
 | 
				
			||||||
            class="text-white hover:underline"
 | 
					            class="text-white hover:underline"
 | 
				
			||||||
          >
 | 
					          >
 | 
				
			||||||
            <%= gettext("Ammo") %>
 | 
					            <%= gettext("Ammo") %>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,10 +1,10 @@
 | 
				
			|||||||
defmodule CanneryWeb.Components.MoveAmmoGroupComponent do
 | 
					defmodule CanneryWeb.Components.MovePackComponent do
 | 
				
			||||||
  @moduledoc """
 | 
					  @moduledoc """
 | 
				
			||||||
  Livecomponent that can move an ammo group to another container
 | 
					  Livecomponent that can move a pack to another container
 | 
				
			||||||
  """
 | 
					  """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  use CanneryWeb, :live_component
 | 
					  use CanneryWeb, :live_component
 | 
				
			||||||
  alias Cannery.{Accounts.User, Ammo, Ammo.AmmoGroup, Containers, Containers.Container}
 | 
					  alias Cannery.{Accounts.User, Ammo, Ammo.Pack, Containers, Containers.Container}
 | 
				
			||||||
  alias CanneryWeb.Endpoint
 | 
					  alias CanneryWeb.Endpoint
 | 
				
			||||||
  alias Ecto.Changeset
 | 
					  alias Ecto.Changeset
 | 
				
			||||||
  alias Phoenix.LiveView.Socket
 | 
					  alias Phoenix.LiveView.Socket
 | 
				
			||||||
@@ -13,17 +13,16 @@ defmodule CanneryWeb.Components.MoveAmmoGroupComponent do
 | 
				
			|||||||
  @spec update(
 | 
					  @spec update(
 | 
				
			||||||
          %{
 | 
					          %{
 | 
				
			||||||
            required(:current_user) => User.t(),
 | 
					            required(:current_user) => User.t(),
 | 
				
			||||||
            required(:ammo_group) => AmmoGroup.t(),
 | 
					            required(:pack) => Pack.t(),
 | 
				
			||||||
            optional(any()) => any()
 | 
					            optional(any()) => any()
 | 
				
			||||||
          },
 | 
					          },
 | 
				
			||||||
          Socket.t()
 | 
					          Socket.t()
 | 
				
			||||||
        ) :: {:ok, Socket.t()}
 | 
					        ) :: {:ok, Socket.t()}
 | 
				
			||||||
  def update(
 | 
					  def update(
 | 
				
			||||||
        %{ammo_group: %{container_id: container_id} = ammo_group, current_user: current_user} =
 | 
					        %{pack: %{container_id: container_id} = pack, current_user: current_user} = assigns,
 | 
				
			||||||
          assigns,
 | 
					 | 
				
			||||||
        socket
 | 
					        socket
 | 
				
			||||||
      ) do
 | 
					      ) do
 | 
				
			||||||
    changeset = ammo_group |> AmmoGroup.update_changeset(%{}, current_user)
 | 
					    changeset = pack |> Pack.update_changeset(%{}, current_user)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    containers =
 | 
					    containers =
 | 
				
			||||||
      Containers.list_containers(current_user)
 | 
					      Containers.list_containers(current_user)
 | 
				
			||||||
@@ -41,16 +40,15 @@ defmodule CanneryWeb.Components.MoveAmmoGroupComponent do
 | 
				
			|||||||
  def handle_event(
 | 
					  def handle_event(
 | 
				
			||||||
        "move",
 | 
					        "move",
 | 
				
			||||||
        %{"container_id" => container_id},
 | 
					        %{"container_id" => container_id},
 | 
				
			||||||
        %{assigns: %{ammo_group: ammo_group, current_user: current_user, return_to: return_to}} =
 | 
					        %{assigns: %{pack: pack, current_user: current_user, return_to: return_to}} = socket
 | 
				
			||||||
          socket
 | 
					 | 
				
			||||||
      ) do
 | 
					      ) do
 | 
				
			||||||
    %{name: container_name} = Containers.get_container!(container_id, current_user)
 | 
					    %{name: container_name} = Containers.get_container!(container_id, current_user)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    socket =
 | 
					    socket =
 | 
				
			||||||
      ammo_group
 | 
					      pack
 | 
				
			||||||
      |> Ammo.update_ammo_group(%{"container_id" => container_id}, current_user)
 | 
					      |> Ammo.update_pack(%{"container_id" => container_id}, current_user)
 | 
				
			||||||
      |> case do
 | 
					      |> case do
 | 
				
			||||||
        {:ok, _ammo_group} ->
 | 
					        {:ok, _pack} ->
 | 
				
			||||||
          prompt = dgettext("prompts", "Ammo moved to %{name} successfully", name: container_name)
 | 
					          prompt = dgettext("prompts", "Ammo moved to %{name} successfully", name: container_name)
 | 
				
			||||||
          socket |> put_flash(:info, prompt) |> push_navigate(to: return_to)
 | 
					          socket |> put_flash(:info, prompt) |> push_navigate(to: return_to)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -92,7 +90,7 @@ defmodule CanneryWeb.Components.MoveAmmoGroupComponent do
 | 
				
			|||||||
      <% else %>
 | 
					      <% else %>
 | 
				
			||||||
        <.live_component
 | 
					        <.live_component
 | 
				
			||||||
          module={CanneryWeb.Components.TableComponent}
 | 
					          module={CanneryWeb.Components.TableComponent}
 | 
				
			||||||
          id="move_ammo_group_table"
 | 
					          id="move_pack_table"
 | 
				
			||||||
          columns={@columns}
 | 
					          columns={@columns}
 | 
				
			||||||
          rows={@rows}
 | 
					          rows={@rows}
 | 
				
			||||||
        />
 | 
					        />
 | 
				
			||||||
							
								
								
									
										269
									
								
								lib/cannery_web/components/pack_table_component.ex
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										269
									
								
								lib/cannery_web/components/pack_table_component.ex
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,269 @@
 | 
				
			|||||||
 | 
					defmodule CanneryWeb.Components.PackTableComponent do
 | 
				
			||||||
 | 
					  @moduledoc """
 | 
				
			||||||
 | 
					  A component that displays a list of packs
 | 
				
			||||||
 | 
					  """
 | 
				
			||||||
 | 
					  use CanneryWeb, :live_component
 | 
				
			||||||
 | 
					  alias Cannery.{Accounts.User, Ammo.Pack, ComparableDate}
 | 
				
			||||||
 | 
					  alias Cannery.{ActivityLog, Ammo, Containers}
 | 
				
			||||||
 | 
					  alias CanneryWeb.Components.TableComponent
 | 
				
			||||||
 | 
					  alias Ecto.UUID
 | 
				
			||||||
 | 
					  alias Phoenix.LiveView.{Rendered, Socket}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @impl true
 | 
				
			||||||
 | 
					  @spec update(
 | 
				
			||||||
 | 
					          %{
 | 
				
			||||||
 | 
					            required(:id) => UUID.t(),
 | 
				
			||||||
 | 
					            required(:current_user) => User.t(),
 | 
				
			||||||
 | 
					            required(:packs) => [Pack.t()],
 | 
				
			||||||
 | 
					            required(:show_used) => boolean(),
 | 
				
			||||||
 | 
					            optional(: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, packs: _pack, current_user: _current_user, show_used: _show_used} = assigns,
 | 
				
			||||||
 | 
					        socket
 | 
				
			||||||
 | 
					      ) do
 | 
				
			||||||
 | 
					    socket =
 | 
				
			||||||
 | 
					      socket
 | 
				
			||||||
 | 
					      |> assign(assigns)
 | 
				
			||||||
 | 
					      |> assign_new(:type, fn -> [] end)
 | 
				
			||||||
 | 
					      |> assign_new(:range, fn -> [] end)
 | 
				
			||||||
 | 
					      |> assign_new(:container, fn -> [] end)
 | 
				
			||||||
 | 
					      |> assign_new(:actions, fn -> [] end)
 | 
				
			||||||
 | 
					      |> display_packs()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    {:ok, socket}
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  defp display_packs(
 | 
				
			||||||
 | 
					         %{
 | 
				
			||||||
 | 
					           assigns: %{
 | 
				
			||||||
 | 
					             packs: packs,
 | 
				
			||||||
 | 
					             current_user: current_user,
 | 
				
			||||||
 | 
					             type: type,
 | 
				
			||||||
 | 
					             range: range,
 | 
				
			||||||
 | 
					             container: container,
 | 
				
			||||||
 | 
					             actions: actions,
 | 
				
			||||||
 | 
					             show_used: show_used
 | 
				
			||||||
 | 
					           }
 | 
				
			||||||
 | 
					         } = socket
 | 
				
			||||||
 | 
					       ) do
 | 
				
			||||||
 | 
					    lot_number_used = packs |> Enum.any?(fn %{lot_number: lot_number} -> !!lot_number end)
 | 
				
			||||||
 | 
					    price_paid_used = packs |> Enum.any?(fn %{price_paid: price_paid} -> !!price_paid end)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    columns =
 | 
				
			||||||
 | 
					      []
 | 
				
			||||||
 | 
					      |> TableComponent.maybe_compose_columns(
 | 
				
			||||||
 | 
					        %{label: gettext("Actions"), key: :actions, sortable: false},
 | 
				
			||||||
 | 
					        actions != []
 | 
				
			||||||
 | 
					      )
 | 
				
			||||||
 | 
					      |> TableComponent.maybe_compose_columns(%{
 | 
				
			||||||
 | 
					        label: gettext("Last used on"),
 | 
				
			||||||
 | 
					        key: :used_up_on,
 | 
				
			||||||
 | 
					        type: ComparableDate
 | 
				
			||||||
 | 
					      })
 | 
				
			||||||
 | 
					      |> TableComponent.maybe_compose_columns(%{
 | 
				
			||||||
 | 
					        label: gettext("Purchased on"),
 | 
				
			||||||
 | 
					        key: :purchased_on,
 | 
				
			||||||
 | 
					        type: ComparableDate
 | 
				
			||||||
 | 
					      })
 | 
				
			||||||
 | 
					      |> TableComponent.maybe_compose_columns(
 | 
				
			||||||
 | 
					        %{label: gettext("Container"), key: :container},
 | 
				
			||||||
 | 
					        container != []
 | 
				
			||||||
 | 
					      )
 | 
				
			||||||
 | 
					      |> TableComponent.maybe_compose_columns(
 | 
				
			||||||
 | 
					        %{label: gettext("Range"), key: :range},
 | 
				
			||||||
 | 
					        range != []
 | 
				
			||||||
 | 
					      )
 | 
				
			||||||
 | 
					      |> TableComponent.maybe_compose_columns(
 | 
				
			||||||
 | 
					        %{label: gettext("Lot number"), key: :lot_number},
 | 
				
			||||||
 | 
					        lot_number_used
 | 
				
			||||||
 | 
					      )
 | 
				
			||||||
 | 
					      |> TableComponent.maybe_compose_columns(
 | 
				
			||||||
 | 
					        %{label: gettext("CPR"), key: :cpr},
 | 
				
			||||||
 | 
					        price_paid_used
 | 
				
			||||||
 | 
					      )
 | 
				
			||||||
 | 
					      |> TableComponent.maybe_compose_columns(
 | 
				
			||||||
 | 
					        %{label: gettext("Price paid"), key: :price_paid},
 | 
				
			||||||
 | 
					        price_paid_used
 | 
				
			||||||
 | 
					      )
 | 
				
			||||||
 | 
					      |> TableComponent.maybe_compose_columns(
 | 
				
			||||||
 | 
					        %{label: gettext("% left"), key: :remaining},
 | 
				
			||||||
 | 
					        show_used
 | 
				
			||||||
 | 
					      )
 | 
				
			||||||
 | 
					      |> TableComponent.maybe_compose_columns(
 | 
				
			||||||
 | 
					        %{label: gettext("Original Count"), key: :original_count},
 | 
				
			||||||
 | 
					        show_used
 | 
				
			||||||
 | 
					      )
 | 
				
			||||||
 | 
					      |> TableComponent.maybe_compose_columns(%{
 | 
				
			||||||
 | 
					        label: if(show_used, do: gettext("Current Count"), else: gettext("Count")),
 | 
				
			||||||
 | 
					        key: :count
 | 
				
			||||||
 | 
					      })
 | 
				
			||||||
 | 
					      |> TableComponent.maybe_compose_columns(
 | 
				
			||||||
 | 
					        %{label: gettext("Type"), key: :type},
 | 
				
			||||||
 | 
					        type != []
 | 
				
			||||||
 | 
					      )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    containers =
 | 
				
			||||||
 | 
					      packs
 | 
				
			||||||
 | 
					      |> Enum.map(fn %{container_id: container_id} -> container_id end)
 | 
				
			||||||
 | 
					      |> Containers.get_containers(current_user)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    extra_data = %{
 | 
				
			||||||
 | 
					      current_user: current_user,
 | 
				
			||||||
 | 
					      type: type,
 | 
				
			||||||
 | 
					      columns: columns,
 | 
				
			||||||
 | 
					      container: container,
 | 
				
			||||||
 | 
					      containers: containers,
 | 
				
			||||||
 | 
					      original_counts: Ammo.get_original_counts(packs, current_user),
 | 
				
			||||||
 | 
					      cprs: Ammo.get_cprs(packs, current_user),
 | 
				
			||||||
 | 
					      last_used_dates: ActivityLog.get_last_used_dates(packs, current_user),
 | 
				
			||||||
 | 
					      percentages_remaining: Ammo.get_percentages_remaining(packs, current_user),
 | 
				
			||||||
 | 
					      actions: actions,
 | 
				
			||||||
 | 
					      range: range
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    rows =
 | 
				
			||||||
 | 
					      packs
 | 
				
			||||||
 | 
					      |> Enum.map(fn pack ->
 | 
				
			||||||
 | 
					        pack |> get_row_data_for_pack(extra_data)
 | 
				
			||||||
 | 
					      end)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    socket |> assign(columns: columns, rows: rows)
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @impl true
 | 
				
			||||||
 | 
					  def render(assigns) do
 | 
				
			||||||
 | 
					    ~H"""
 | 
				
			||||||
 | 
					    <div id={@id} class="w-full">
 | 
				
			||||||
 | 
					      <.live_component module={TableComponent} id={"table-#{@id}"} columns={@columns} rows={@rows} />
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @spec get_row_data_for_pack(Pack.t(), additional_data :: map()) :: map()
 | 
				
			||||||
 | 
					  defp get_row_data_for_pack(pack, %{columns: columns} = additional_data) do
 | 
				
			||||||
 | 
					    columns
 | 
				
			||||||
 | 
					    |> Map.new(fn %{key: key} ->
 | 
				
			||||||
 | 
					      {key, get_value_for_key(key, pack, additional_data)}
 | 
				
			||||||
 | 
					    end)
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @spec get_value_for_key(atom(), Pack.t(), additional_data :: map()) ::
 | 
				
			||||||
 | 
					          any() | {any(), Rendered.t()}
 | 
				
			||||||
 | 
					  defp get_value_for_key(
 | 
				
			||||||
 | 
					         :type,
 | 
				
			||||||
 | 
					         %{type: %{name: type_name} = type},
 | 
				
			||||||
 | 
					         %{type: type_block}
 | 
				
			||||||
 | 
					       ) do
 | 
				
			||||||
 | 
					    assigns = %{type: type, type_block: type_block}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    {type_name,
 | 
				
			||||||
 | 
					     ~H"""
 | 
				
			||||||
 | 
					     <%= render_slot(@type_block, @type) %>
 | 
				
			||||||
 | 
					     """}
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  defp get_value_for_key(:price_paid, %{price_paid: nil}, _additional_data),
 | 
				
			||||||
 | 
					    do: {0, gettext("No cost information")}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  defp get_value_for_key(:price_paid, %{price_paid: price_paid}, _additional_data),
 | 
				
			||||||
 | 
					    do: {price_paid, gettext("$%{amount}", amount: display_currency(price_paid))}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  defp get_value_for_key(:purchased_on, %{purchased_on: purchased_on} = assigns, _additional_data) do
 | 
				
			||||||
 | 
					    {purchased_on,
 | 
				
			||||||
 | 
					     ~H"""
 | 
				
			||||||
 | 
					     <.date id={"#{@id}-purchased-on"} date={@purchased_on} />
 | 
				
			||||||
 | 
					     """}
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  defp get_value_for_key(:used_up_on, %{id: pack_id}, %{last_used_dates: last_used_dates}) do
 | 
				
			||||||
 | 
					    last_used_date = last_used_dates |> Map.get(pack_id)
 | 
				
			||||||
 | 
					    assigns = %{id: pack_id, last_used_date: last_used_date}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    {last_used_date,
 | 
				
			||||||
 | 
					     ~H"""
 | 
				
			||||||
 | 
					     <%= if @last_used_date do %>
 | 
				
			||||||
 | 
					       <.date id={"#{@id}-last-used-date"} date={@last_used_date} />
 | 
				
			||||||
 | 
					     <% else %>
 | 
				
			||||||
 | 
					       <%= gettext("Never used") %>
 | 
				
			||||||
 | 
					     <% end %>
 | 
				
			||||||
 | 
					     """}
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  defp get_value_for_key(:range, %{staged: staged} = pack, %{range: range}) do
 | 
				
			||||||
 | 
					    assigns = %{range: range, pack: pack}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    {staged,
 | 
				
			||||||
 | 
					     ~H"""
 | 
				
			||||||
 | 
					     <%= render_slot(@range, @pack) %>
 | 
				
			||||||
 | 
					     """}
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  defp get_value_for_key(
 | 
				
			||||||
 | 
					         :remaining,
 | 
				
			||||||
 | 
					         %{id: pack_id},
 | 
				
			||||||
 | 
					         %{percentages_remaining: percentages_remaining}
 | 
				
			||||||
 | 
					       ) do
 | 
				
			||||||
 | 
					    percentage = Map.fetch!(percentages_remaining, pack_id)
 | 
				
			||||||
 | 
					    {percentage, gettext("%{percentage}%", percentage: percentage)}
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  defp get_value_for_key(:actions, pack, %{actions: actions}) do
 | 
				
			||||||
 | 
					    assigns = %{actions: actions, pack: pack}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ~H"""
 | 
				
			||||||
 | 
					    <%= render_slot(@actions, @pack) %>
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  defp get_value_for_key(:container, %{container: nil}, _additional_data), do: {nil, nil}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  defp get_value_for_key(
 | 
				
			||||||
 | 
					         :container,
 | 
				
			||||||
 | 
					         %{container_id: container_id} = pack,
 | 
				
			||||||
 | 
					         %{container: container_block, containers: containers}
 | 
				
			||||||
 | 
					       ) do
 | 
				
			||||||
 | 
					    container = %{name: container_name} = Map.fetch!(containers, container_id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    assigns = %{
 | 
				
			||||||
 | 
					      container: container,
 | 
				
			||||||
 | 
					      container_block: container_block,
 | 
				
			||||||
 | 
					      pack: pack
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    {container_name,
 | 
				
			||||||
 | 
					     ~H"""
 | 
				
			||||||
 | 
					     <%= render_slot(@container_block, {@pack, @container}) %>
 | 
				
			||||||
 | 
					     """}
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  defp get_value_for_key(
 | 
				
			||||||
 | 
					         :original_count,
 | 
				
			||||||
 | 
					         %{id: pack_id},
 | 
				
			||||||
 | 
					         %{original_counts: original_counts}
 | 
				
			||||||
 | 
					       ) do
 | 
				
			||||||
 | 
					    Map.fetch!(original_counts, pack_id)
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  defp get_value_for_key(:cpr, %{price_paid: nil}, _additional_data),
 | 
				
			||||||
 | 
					    do: {0, gettext("No cost information")}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  defp get_value_for_key(:cpr, %{id: pack_id}, %{cprs: cprs}) do
 | 
				
			||||||
 | 
					    amount = Map.fetch!(cprs, pack_id)
 | 
				
			||||||
 | 
					    {amount, gettext("$%{amount}", amount: display_currency(amount))}
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  defp get_value_for_key(:count, %{count: count}, _additional_data),
 | 
				
			||||||
 | 
					    do: if(count == 0, do: {0, gettext("Empty")}, else: count)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  defp get_value_for_key(key, pack, _additional_data), do: pack |> Map.get(key)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @spec display_currency(float()) :: String.t()
 | 
				
			||||||
 | 
					  defp display_currency(float), do: :erlang.float_to_binary(float, decimals: 2)
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
@@ -1,9 +1,9 @@
 | 
				
			|||||||
defmodule CanneryWeb.Components.ShotGroupTableComponent do
 | 
					defmodule CanneryWeb.Components.ShotRecordTableComponent do
 | 
				
			||||||
  @moduledoc """
 | 
					  @moduledoc """
 | 
				
			||||||
  A component that displays a list of shot groups
 | 
					  A component that displays a list of shot records
 | 
				
			||||||
  """
 | 
					  """
 | 
				
			||||||
  use CanneryWeb, :live_component
 | 
					  use CanneryWeb, :live_component
 | 
				
			||||||
  alias Cannery.{Accounts.User, ActivityLog.ShotGroup, Ammo, ComparableDate}
 | 
					  alias Cannery.{Accounts.User, ActivityLog.ShotRecord, Ammo, ComparableDate}
 | 
				
			||||||
  alias Ecto.UUID
 | 
					  alias Ecto.UUID
 | 
				
			||||||
  alias Phoenix.LiveView.{Rendered, Socket}
 | 
					  alias Phoenix.LiveView.{Rendered, Socket}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -12,26 +12,29 @@ defmodule CanneryWeb.Components.ShotGroupTableComponent do
 | 
				
			|||||||
          %{
 | 
					          %{
 | 
				
			||||||
            required(:id) => UUID.t(),
 | 
					            required(:id) => UUID.t(),
 | 
				
			||||||
            required(:current_user) => User.t(),
 | 
					            required(:current_user) => User.t(),
 | 
				
			||||||
            optional(:shot_groups) => [ShotGroup.t()],
 | 
					            optional(:shot_records) => [ShotRecord.t()],
 | 
				
			||||||
            optional(:actions) => Rendered.t(),
 | 
					            optional(:actions) => Rendered.t(),
 | 
				
			||||||
            optional(any()) => any()
 | 
					            optional(any()) => any()
 | 
				
			||||||
          },
 | 
					          },
 | 
				
			||||||
          Socket.t()
 | 
					          Socket.t()
 | 
				
			||||||
        ) :: {:ok, Socket.t()}
 | 
					        ) :: {:ok, Socket.t()}
 | 
				
			||||||
  def update(%{id: _id, shot_groups: _shot_groups, current_user: _current_user} = assigns, socket) do
 | 
					  def update(
 | 
				
			||||||
 | 
					        %{id: _id, shot_records: _shot_records, current_user: _current_user} = assigns,
 | 
				
			||||||
 | 
					        socket
 | 
				
			||||||
 | 
					      ) do
 | 
				
			||||||
    socket =
 | 
					    socket =
 | 
				
			||||||
      socket
 | 
					      socket
 | 
				
			||||||
      |> assign(assigns)
 | 
					      |> assign(assigns)
 | 
				
			||||||
      |> assign_new(:actions, fn -> [] end)
 | 
					      |> assign_new(:actions, fn -> [] end)
 | 
				
			||||||
      |> display_shot_groups()
 | 
					      |> display_shot_records()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    {:ok, socket}
 | 
					    {:ok, socket}
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  defp display_shot_groups(
 | 
					  defp display_shot_records(
 | 
				
			||||||
         %{
 | 
					         %{
 | 
				
			||||||
           assigns: %{
 | 
					           assigns: %{
 | 
				
			||||||
             shot_groups: shot_groups,
 | 
					             shot_records: shot_records,
 | 
				
			||||||
             current_user: current_user,
 | 
					             current_user: current_user,
 | 
				
			||||||
             actions: actions
 | 
					             actions: actions
 | 
				
			||||||
           }
 | 
					           }
 | 
				
			||||||
@@ -45,17 +48,17 @@ defmodule CanneryWeb.Components.ShotGroupTableComponent do
 | 
				
			|||||||
      %{label: gettext("Actions"), key: :actions, sortable: false}
 | 
					      %{label: gettext("Actions"), key: :actions, sortable: false}
 | 
				
			||||||
    ]
 | 
					    ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ammo_groups =
 | 
					    packs =
 | 
				
			||||||
      shot_groups
 | 
					      shot_records
 | 
				
			||||||
      |> Enum.map(fn %{ammo_group_id: ammo_group_id} -> ammo_group_id end)
 | 
					      |> Enum.map(fn %{pack_id: pack_id} -> pack_id end)
 | 
				
			||||||
      |> Ammo.get_ammo_groups(current_user)
 | 
					      |> Ammo.get_packs(current_user)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    extra_data = %{current_user: current_user, actions: actions, ammo_groups: ammo_groups}
 | 
					    extra_data = %{current_user: current_user, actions: actions, packs: packs}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    rows =
 | 
					    rows =
 | 
				
			||||||
      shot_groups
 | 
					      shot_records
 | 
				
			||||||
      |> Enum.map(fn shot_group ->
 | 
					      |> Enum.map(fn shot_record ->
 | 
				
			||||||
        shot_group |> get_row_data_for_shot_group(columns, extra_data)
 | 
					        shot_record |> get_row_data_for_shot_record(columns, extra_data)
 | 
				
			||||||
      end)
 | 
					      end)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    socket
 | 
					    socket
 | 
				
			||||||
@@ -81,22 +84,22 @@ defmodule CanneryWeb.Components.ShotGroupTableComponent do
 | 
				
			|||||||
    """
 | 
					    """
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @spec get_row_data_for_shot_group(ShotGroup.t(), columns :: [map()], extra_data :: map()) ::
 | 
					  @spec get_row_data_for_shot_record(ShotRecord.t(), columns :: [map()], extra_data :: map()) ::
 | 
				
			||||||
          map()
 | 
					          map()
 | 
				
			||||||
  defp get_row_data_for_shot_group(shot_group, columns, extra_data) do
 | 
					  defp get_row_data_for_shot_record(shot_record, columns, extra_data) do
 | 
				
			||||||
    columns
 | 
					    columns
 | 
				
			||||||
    |> Map.new(fn %{key: key} ->
 | 
					    |> Map.new(fn %{key: key} ->
 | 
				
			||||||
      {key, get_row_value(key, shot_group, extra_data)}
 | 
					      {key, get_row_value(key, shot_record, extra_data)}
 | 
				
			||||||
    end)
 | 
					    end)
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  defp get_row_value(:name, %{ammo_group_id: ammo_group_id}, %{ammo_groups: ammo_groups}) do
 | 
					  defp get_row_value(:name, %{pack_id: pack_id}, %{packs: packs}) do
 | 
				
			||||||
    assigns = %{ammo_group: ammo_group = Map.fetch!(ammo_groups, ammo_group_id)}
 | 
					    assigns = %{pack: pack = Map.fetch!(packs, pack_id)}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    {ammo_group.ammo_type.name,
 | 
					    {pack.type.name,
 | 
				
			||||||
     ~H"""
 | 
					     ~H"""
 | 
				
			||||||
     <.link navigate={Routes.ammo_group_show_path(Endpoint, :show, @ammo_group)} class="link">
 | 
					     <.link navigate={Routes.pack_show_path(Endpoint, :show, @pack)} class="link">
 | 
				
			||||||
       <%= @ammo_group.ammo_type.name %>
 | 
					       <%= @pack.type.name %>
 | 
				
			||||||
     </.link>
 | 
					     </.link>
 | 
				
			||||||
     """}
 | 
					     """}
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
@@ -108,13 +111,13 @@ defmodule CanneryWeb.Components.ShotGroupTableComponent do
 | 
				
			|||||||
     """}
 | 
					     """}
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  defp get_row_value(:actions, shot_group, %{actions: actions}) do
 | 
					  defp get_row_value(:actions, shot_record, %{actions: actions}) do
 | 
				
			||||||
    assigns = %{actions: actions, shot_group: shot_group}
 | 
					    assigns = %{actions: actions, shot_record: shot_record}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ~H"""
 | 
					    ~H"""
 | 
				
			||||||
    <%= render_slot(@actions, @shot_group) %>
 | 
					    <%= render_slot(@actions, @shot_record) %>
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  defp get_row_value(key, shot_group, _extra_data), do: shot_group |> Map.get(key)
 | 
					  defp get_row_value(key, shot_record, _extra_data), do: shot_record |> Map.get(key)
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
@@ -135,4 +135,25 @@ defmodule CanneryWeb.Components.TableComponent do
 | 
				
			|||||||
      sort_mode
 | 
					      sort_mode
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @doc """
 | 
				
			||||||
 | 
					  Conditionally composes elements into the columns list, supports maps and
 | 
				
			||||||
 | 
					  lists. Works tail to front in order for efficiency
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      iex> []
 | 
				
			||||||
 | 
					      ...> |> maybe_compose_columns(%{label: "Column 3"}, true)
 | 
				
			||||||
 | 
					      ...> |> maybe_compose_columns(%{label: "Column 2"}, false)
 | 
				
			||||||
 | 
					      ...> |> maybe_compose_columns(%{label: "Column 1"})
 | 
				
			||||||
 | 
					      [%{label: "Column 1"}, %{label: "Column 3"}]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  """
 | 
				
			||||||
 | 
					  @spec maybe_compose_columns(list(), element_to_add :: list() | map()) :: list()
 | 
				
			||||||
 | 
					  @spec maybe_compose_columns(list(), element_to_add :: list() | map(), boolean()) :: list()
 | 
				
			||||||
 | 
					  def maybe_compose_columns(columns, element_or_elements, add? \\ true)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def maybe_compose_columns(columns, elements, true) when is_list(elements),
 | 
				
			||||||
 | 
					    do: Enum.concat(elements, columns)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def maybe_compose_columns(columns, element, true) when is_map(element), do: [element | columns]
 | 
				
			||||||
 | 
					  def maybe_compose_columns(columns, _element_or_elements, false), do: columns
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										290
									
								
								lib/cannery_web/components/type_table_component.ex
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										290
									
								
								lib/cannery_web/components/type_table_component.ex
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,290 @@
 | 
				
			|||||||
 | 
					defmodule CanneryWeb.Components.TypeTableComponent do
 | 
				
			||||||
 | 
					  @moduledoc """
 | 
				
			||||||
 | 
					  A component that displays a list of types
 | 
				
			||||||
 | 
					  """
 | 
				
			||||||
 | 
					  use CanneryWeb, :live_component
 | 
				
			||||||
 | 
					  alias Cannery.{Accounts.User, ActivityLog, Ammo, Ammo.Type}
 | 
				
			||||||
 | 
					  alias CanneryWeb.Components.TableComponent
 | 
				
			||||||
 | 
					  alias Ecto.UUID
 | 
				
			||||||
 | 
					  alias Phoenix.LiveView.{Rendered, Socket}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @impl true
 | 
				
			||||||
 | 
					  @spec update(
 | 
				
			||||||
 | 
					          %{
 | 
				
			||||||
 | 
					            required(:id) => UUID.t(),
 | 
				
			||||||
 | 
					            required(:current_user) => User.t(),
 | 
				
			||||||
 | 
					            optional(:class) => Type.class() | nil,
 | 
				
			||||||
 | 
					            optional(:show_used) => boolean(),
 | 
				
			||||||
 | 
					            optional(:types) => [Type.t()],
 | 
				
			||||||
 | 
					            optional(:actions) => Rendered.t(),
 | 
				
			||||||
 | 
					            optional(any()) => any()
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          Socket.t()
 | 
				
			||||||
 | 
					        ) :: {:ok, Socket.t()}
 | 
				
			||||||
 | 
					  def update(%{id: _id, types: _types, current_user: _current_user} = assigns, socket) do
 | 
				
			||||||
 | 
					    socket =
 | 
				
			||||||
 | 
					      socket
 | 
				
			||||||
 | 
					      |> assign(assigns)
 | 
				
			||||||
 | 
					      |> assign_new(:show_used, fn -> false end)
 | 
				
			||||||
 | 
					      |> assign_new(:class, fn -> :all end)
 | 
				
			||||||
 | 
					      |> assign_new(:actions, fn -> [] end)
 | 
				
			||||||
 | 
					      |> display_types()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    {:ok, socket}
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  defp display_types(
 | 
				
			||||||
 | 
					         %{
 | 
				
			||||||
 | 
					           assigns: %{
 | 
				
			||||||
 | 
					             types: types,
 | 
				
			||||||
 | 
					             current_user: current_user,
 | 
				
			||||||
 | 
					             show_used: show_used,
 | 
				
			||||||
 | 
					             class: class,
 | 
				
			||||||
 | 
					             actions: actions
 | 
				
			||||||
 | 
					           }
 | 
				
			||||||
 | 
					         } = socket
 | 
				
			||||||
 | 
					       ) do
 | 
				
			||||||
 | 
					    filtered_columns =
 | 
				
			||||||
 | 
					      [
 | 
				
			||||||
 | 
					        %{label: gettext("Cartridge"), key: :cartridge, type: :string},
 | 
				
			||||||
 | 
					        %{
 | 
				
			||||||
 | 
					          label: if(class == :shotgun, do: gettext("Gauge"), else: gettext("Caliber")),
 | 
				
			||||||
 | 
					          key: :caliber,
 | 
				
			||||||
 | 
					          type: :string
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        %{label: gettext("Unfired shell length"), key: :unfired_length, type: :string},
 | 
				
			||||||
 | 
					        %{label: gettext("Brass height"), key: :brass_height, type: :string},
 | 
				
			||||||
 | 
					        %{label: gettext("Chamber size"), key: :chamber_size, type: :string},
 | 
				
			||||||
 | 
					        %{label: gettext("Chamber size"), key: :chamber_size, type: :string},
 | 
				
			||||||
 | 
					        %{label: gettext("Grains"), key: :grains, type: :string},
 | 
				
			||||||
 | 
					        %{label: gettext("Bullet type"), key: :bullet_type, type: :string},
 | 
				
			||||||
 | 
					        %{
 | 
				
			||||||
 | 
					          label: if(class == :shotgun, do: gettext("Slug core"), else: gettext("Bullet core")),
 | 
				
			||||||
 | 
					          key: :bullet_core,
 | 
				
			||||||
 | 
					          type: :string
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        %{label: gettext("Jacket type"), key: :jacket_type, type: :string},
 | 
				
			||||||
 | 
					        %{label: gettext("Case material"), key: :case_material, type: :string},
 | 
				
			||||||
 | 
					        %{label: gettext("Wadding"), key: :wadding, type: :string},
 | 
				
			||||||
 | 
					        %{label: gettext("Shot type"), key: :shot_type, type: :string},
 | 
				
			||||||
 | 
					        %{label: gettext("Shot material"), key: :shot_material, type: :string},
 | 
				
			||||||
 | 
					        %{label: gettext("Shot size"), key: :shot_size, type: :string},
 | 
				
			||||||
 | 
					        %{label: gettext("Load grains"), key: :load_grains, type: :string},
 | 
				
			||||||
 | 
					        %{label: gettext("Shot charge weight"), key: :shot_charge_weight, 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("Pressure"), key: :pressure, type: :string},
 | 
				
			||||||
 | 
					        %{label: gettext("Dram equivalent"), key: :dram_equivalent, type: :string},
 | 
				
			||||||
 | 
					        %{label: gettext("Muzzle velocity"), key: :muzzle_velocity, 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: :atom},
 | 
				
			||||||
 | 
					        %{label: gettext("Incendiary"), key: :incendiary, type: :atom},
 | 
				
			||||||
 | 
					        %{label: gettext("Blank"), key: :blank, type: :atom},
 | 
				
			||||||
 | 
					        %{label: gettext("Corrosive"), key: :corrosive, type: :atom},
 | 
				
			||||||
 | 
					        %{label: gettext("Manufacturer"), key: :manufacturer, type: :string}
 | 
				
			||||||
 | 
					      ]
 | 
				
			||||||
 | 
					      |> Enum.filter(fn %{key: key, type: type} ->
 | 
				
			||||||
 | 
					        # remove columns if all values match defaults
 | 
				
			||||||
 | 
					        default_value = if type == :atom, do: false, else: nil
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        types
 | 
				
			||||||
 | 
					        |> Enum.any?(fn type -> Map.get(type, key, default_value) != default_value end)
 | 
				
			||||||
 | 
					      end)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    columns =
 | 
				
			||||||
 | 
					      [%{label: gettext("Actions"), key: "actions", type: :actions, sortable: false}]
 | 
				
			||||||
 | 
					      |> TableComponent.maybe_compose_columns(%{
 | 
				
			||||||
 | 
					        label: gettext("Average CPR"),
 | 
				
			||||||
 | 
					        key: :avg_price_paid,
 | 
				
			||||||
 | 
					        type: :avg_price_paid
 | 
				
			||||||
 | 
					      })
 | 
				
			||||||
 | 
					      |> TableComponent.maybe_compose_columns(
 | 
				
			||||||
 | 
					        %{
 | 
				
			||||||
 | 
					          label: gettext("Total ever packs"),
 | 
				
			||||||
 | 
					          key: :historical_pack_count,
 | 
				
			||||||
 | 
					          type: :historical_pack_count
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        show_used
 | 
				
			||||||
 | 
					      )
 | 
				
			||||||
 | 
					      |> TableComponent.maybe_compose_columns(
 | 
				
			||||||
 | 
					        %{
 | 
				
			||||||
 | 
					          label: gettext("Used packs"),
 | 
				
			||||||
 | 
					          key: :used_pack_count,
 | 
				
			||||||
 | 
					          type: :used_pack_count
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        show_used
 | 
				
			||||||
 | 
					      )
 | 
				
			||||||
 | 
					      |> TableComponent.maybe_compose_columns(%{
 | 
				
			||||||
 | 
					        label: gettext("Packs"),
 | 
				
			||||||
 | 
					        key: :ammo_count,
 | 
				
			||||||
 | 
					        type: :ammo_count
 | 
				
			||||||
 | 
					      })
 | 
				
			||||||
 | 
					      |> TableComponent.maybe_compose_columns(
 | 
				
			||||||
 | 
					        %{
 | 
				
			||||||
 | 
					          label: gettext("Total ever rounds"),
 | 
				
			||||||
 | 
					          key: :historical_round_count,
 | 
				
			||||||
 | 
					          type: :historical_round_count
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        show_used
 | 
				
			||||||
 | 
					      )
 | 
				
			||||||
 | 
					      |> TableComponent.maybe_compose_columns(
 | 
				
			||||||
 | 
					        %{
 | 
				
			||||||
 | 
					          label: gettext("Used rounds"),
 | 
				
			||||||
 | 
					          key: :used_round_count,
 | 
				
			||||||
 | 
					          type: :used_round_count
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        show_used
 | 
				
			||||||
 | 
					      )
 | 
				
			||||||
 | 
					      |> TableComponent.maybe_compose_columns(%{
 | 
				
			||||||
 | 
					        label: gettext("Rounds"),
 | 
				
			||||||
 | 
					        key: :round_count,
 | 
				
			||||||
 | 
					        type: :round_count
 | 
				
			||||||
 | 
					      })
 | 
				
			||||||
 | 
					      |> TableComponent.maybe_compose_columns(filtered_columns)
 | 
				
			||||||
 | 
					      |> TableComponent.maybe_compose_columns(
 | 
				
			||||||
 | 
					        %{label: gettext("Class"), key: :class, type: :atom},
 | 
				
			||||||
 | 
					        class in [:all, nil]
 | 
				
			||||||
 | 
					      )
 | 
				
			||||||
 | 
					      |> TableComponent.maybe_compose_columns(%{label: gettext("Name"), key: :name, type: :name})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    round_counts = types |> Ammo.get_round_count_for_types(current_user)
 | 
				
			||||||
 | 
					    packs_count = types |> Ammo.get_packs_count_for_types(current_user)
 | 
				
			||||||
 | 
					    average_costs = types |> Ammo.get_average_cost_for_types(current_user)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    [used_counts, historical_round_counts, historical_pack_counts, used_pack_counts] =
 | 
				
			||||||
 | 
					      if show_used do
 | 
				
			||||||
 | 
					        [
 | 
				
			||||||
 | 
					          types |> ActivityLog.get_used_count_for_types(current_user),
 | 
				
			||||||
 | 
					          types |> Ammo.get_historical_count_for_types(current_user),
 | 
				
			||||||
 | 
					          types |> Ammo.get_packs_count_for_types(current_user, true),
 | 
				
			||||||
 | 
					          types |> Ammo.get_used_packs_count_for_types(current_user)
 | 
				
			||||||
 | 
					        ]
 | 
				
			||||||
 | 
					      else
 | 
				
			||||||
 | 
					        [nil, nil, nil, nil]
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    extra_data = %{
 | 
				
			||||||
 | 
					      actions: actions,
 | 
				
			||||||
 | 
					      current_user: current_user,
 | 
				
			||||||
 | 
					      used_counts: used_counts,
 | 
				
			||||||
 | 
					      round_counts: round_counts,
 | 
				
			||||||
 | 
					      historical_round_counts: historical_round_counts,
 | 
				
			||||||
 | 
					      packs_count: packs_count,
 | 
				
			||||||
 | 
					      used_pack_counts: used_pack_counts,
 | 
				
			||||||
 | 
					      historical_pack_counts: historical_pack_counts,
 | 
				
			||||||
 | 
					      average_costs: average_costs
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    rows =
 | 
				
			||||||
 | 
					      types
 | 
				
			||||||
 | 
					      |> Enum.map(fn type ->
 | 
				
			||||||
 | 
					        type |> get_type_values(columns, extra_data)
 | 
				
			||||||
 | 
					      end)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    socket |> assign(columns: columns, rows: rows)
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @impl true
 | 
				
			||||||
 | 
					  def render(assigns) do
 | 
				
			||||||
 | 
					    ~H"""
 | 
				
			||||||
 | 
					    <div id={@id} class="w-full">
 | 
				
			||||||
 | 
					      <.live_component module={TableComponent} id={"table-#{@id}"} columns={@columns} rows={@rows} />
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  defp get_type_values(type, columns, extra_data) do
 | 
				
			||||||
 | 
					    columns
 | 
				
			||||||
 | 
					    |> Map.new(fn %{key: key, type: column_type} ->
 | 
				
			||||||
 | 
					      {key, get_type_value(column_type, key, type, extra_data)}
 | 
				
			||||||
 | 
					    end)
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  defp get_type_value(:atom, key, type, _other_data),
 | 
				
			||||||
 | 
					    do: type |> Map.get(key) |> humanize()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  defp get_type_value(:round_count, _key, %{id: type_id}, %{round_counts: round_counts}),
 | 
				
			||||||
 | 
					    do: Map.get(round_counts, type_id, 0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  defp get_type_value(
 | 
				
			||||||
 | 
					         :historical_round_count,
 | 
				
			||||||
 | 
					         _key,
 | 
				
			||||||
 | 
					         %{id: type_id},
 | 
				
			||||||
 | 
					         %{historical_round_counts: historical_round_counts}
 | 
				
			||||||
 | 
					       ) do
 | 
				
			||||||
 | 
					    Map.get(historical_round_counts, type_id, 0)
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  defp get_type_value(
 | 
				
			||||||
 | 
					         :used_round_count,
 | 
				
			||||||
 | 
					         _key,
 | 
				
			||||||
 | 
					         %{id: type_id},
 | 
				
			||||||
 | 
					         %{used_counts: used_counts}
 | 
				
			||||||
 | 
					       ) do
 | 
				
			||||||
 | 
					    Map.get(used_counts, type_id, 0)
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  defp get_type_value(
 | 
				
			||||||
 | 
					         :historical_pack_count,
 | 
				
			||||||
 | 
					         _key,
 | 
				
			||||||
 | 
					         %{id: type_id},
 | 
				
			||||||
 | 
					         %{historical_pack_counts: historical_pack_counts}
 | 
				
			||||||
 | 
					       ) do
 | 
				
			||||||
 | 
					    Map.get(historical_pack_counts, type_id, 0)
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  defp get_type_value(
 | 
				
			||||||
 | 
					         :used_pack_count,
 | 
				
			||||||
 | 
					         _key,
 | 
				
			||||||
 | 
					         %{id: type_id},
 | 
				
			||||||
 | 
					         %{used_pack_counts: used_pack_counts}
 | 
				
			||||||
 | 
					       ) do
 | 
				
			||||||
 | 
					    Map.get(used_pack_counts, type_id, 0)
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  defp get_type_value(:ammo_count, _key, %{id: type_id}, %{packs_count: packs_count}),
 | 
				
			||||||
 | 
					    do: Map.get(packs_count, type_id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  defp get_type_value(
 | 
				
			||||||
 | 
					         :avg_price_paid,
 | 
				
			||||||
 | 
					         _key,
 | 
				
			||||||
 | 
					         %{id: type_id},
 | 
				
			||||||
 | 
					         %{average_costs: average_costs}
 | 
				
			||||||
 | 
					       ) do
 | 
				
			||||||
 | 
					    case Map.get(average_costs, type_id) do
 | 
				
			||||||
 | 
					      nil -> {0, gettext("No cost information")}
 | 
				
			||||||
 | 
					      count -> {count, gettext("$%{amount}", amount: display_currency(count))}
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  defp get_type_value(:name, _key, %{name: type_name} = type, _other_data) do
 | 
				
			||||||
 | 
					    assigns = %{type: type}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    {type_name,
 | 
				
			||||||
 | 
					     ~H"""
 | 
				
			||||||
 | 
					     <.link navigate={Routes.type_show_path(Endpoint, :show, @type)} class="link">
 | 
				
			||||||
 | 
					       <%= @type.name %>
 | 
				
			||||||
 | 
					     </.link>
 | 
				
			||||||
 | 
					     """}
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  defp get_type_value(:actions, _key, type, %{actions: actions}) do
 | 
				
			||||||
 | 
					    assigns = %{actions: actions, type: type}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ~H"""
 | 
				
			||||||
 | 
					    <%= render_slot(@actions, @type) %>
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  defp get_type_value(nil, _key, _type, _other_data), do: nil
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  defp get_type_value(_other, key, type, _other_data), do: type |> Map.get(key)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @spec display_currency(float()) :: String.t()
 | 
				
			||||||
 | 
					  defp display_currency(float), do: :erlang.float_to_binary(float, decimals: 2)
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
@@ -3,73 +3,72 @@ defmodule CanneryWeb.ExportController do
 | 
				
			|||||||
  alias Cannery.{ActivityLog, Ammo, Containers}
 | 
					  alias Cannery.{ActivityLog, Ammo, Containers}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def export(%{assigns: %{current_user: current_user}} = conn, %{"mode" => "json"}) do
 | 
					  def export(%{assigns: %{current_user: current_user}} = conn, %{"mode" => "json"}) do
 | 
				
			||||||
    ammo_types = Ammo.list_ammo_types(current_user)
 | 
					    types = Ammo.list_types(current_user, :all)
 | 
				
			||||||
    used_counts = ammo_types |> ActivityLog.get_used_count_for_ammo_types(current_user)
 | 
					    used_counts = types |> ActivityLog.get_used_count_for_types(current_user)
 | 
				
			||||||
    round_counts = ammo_types |> Ammo.get_round_count_for_ammo_types(current_user)
 | 
					    round_counts = types |> Ammo.get_round_count_for_types(current_user)
 | 
				
			||||||
    ammo_group_counts = ammo_types |> Ammo.get_ammo_groups_count_for_types(current_user)
 | 
					    pack_counts = types |> Ammo.get_packs_count_for_types(current_user)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    total_ammo_group_counts =
 | 
					    total_pack_counts = types |> Ammo.get_packs_count_for_types(current_user, true)
 | 
				
			||||||
      ammo_types |> Ammo.get_ammo_groups_count_for_types(current_user, true)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    average_costs = ammo_types |> Ammo.get_average_cost_for_ammo_types(current_user)
 | 
					    average_costs = types |> Ammo.get_average_cost_for_types(current_user)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ammo_types =
 | 
					    types =
 | 
				
			||||||
      ammo_types
 | 
					      types
 | 
				
			||||||
      |> Enum.map(fn %{id: ammo_type_id} = ammo_type ->
 | 
					      |> Enum.map(fn %{id: type_id} = type ->
 | 
				
			||||||
        ammo_type
 | 
					        type
 | 
				
			||||||
        |> Jason.encode!()
 | 
					        |> Jason.encode!()
 | 
				
			||||||
        |> Jason.decode!()
 | 
					        |> Jason.decode!()
 | 
				
			||||||
        |> Map.merge(%{
 | 
					        |> Map.merge(%{
 | 
				
			||||||
          "average_cost" => Map.get(average_costs, ammo_type_id),
 | 
					          "average_cost" => Map.get(average_costs, type_id),
 | 
				
			||||||
          "round_count" => Map.get(round_counts, ammo_type_id, 0),
 | 
					          "round_count" => Map.get(round_counts, type_id, 0),
 | 
				
			||||||
          "used_count" => Map.get(used_counts, ammo_type_id, 0),
 | 
					          "used_count" => Map.get(used_counts, type_id, 0),
 | 
				
			||||||
          "ammo_group_count" => Map.get(ammo_group_counts, ammo_type_id, 0),
 | 
					          "pack_count" => Map.get(pack_counts, type_id, 0),
 | 
				
			||||||
          "total_ammo_group_count" => Map.get(total_ammo_group_counts, ammo_type_id, 0)
 | 
					          "total_pack_count" => Map.get(total_pack_counts, type_id, 0)
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
      end)
 | 
					      end)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ammo_groups = Ammo.list_ammo_groups(nil, true, current_user)
 | 
					    packs = Ammo.list_packs(nil, :all, current_user, true)
 | 
				
			||||||
    used_counts = ammo_groups |> ActivityLog.get_used_counts(current_user)
 | 
					    used_counts = packs |> ActivityLog.get_used_counts(current_user)
 | 
				
			||||||
    original_counts = ammo_groups |> Ammo.get_original_counts(current_user)
 | 
					    original_counts = packs |> Ammo.get_original_counts(current_user)
 | 
				
			||||||
    cprs = ammo_groups |> Ammo.get_cprs(current_user)
 | 
					    cprs = packs |> Ammo.get_cprs(current_user)
 | 
				
			||||||
    percentages_remaining = ammo_groups |> Ammo.get_percentages_remaining(current_user)
 | 
					    percentages_remaining = packs |> Ammo.get_percentages_remaining(current_user)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ammo_groups =
 | 
					    packs =
 | 
				
			||||||
      ammo_groups
 | 
					      packs
 | 
				
			||||||
      |> Enum.map(fn %{id: ammo_group_id} = ammo_group ->
 | 
					      |> Enum.map(fn %{id: pack_id} = pack ->
 | 
				
			||||||
        ammo_group
 | 
					        pack
 | 
				
			||||||
        |> Jason.encode!()
 | 
					        |> Jason.encode!()
 | 
				
			||||||
        |> Jason.decode!()
 | 
					        |> Jason.decode!()
 | 
				
			||||||
        |> Map.merge(%{
 | 
					        |> Map.merge(%{
 | 
				
			||||||
          "used_count" => Map.get(used_counts, ammo_group_id),
 | 
					          "used_count" => Map.get(used_counts, pack_id),
 | 
				
			||||||
          "percentage_remaining" => Map.fetch!(percentages_remaining, ammo_group_id),
 | 
					          "percentage_remaining" => Map.fetch!(percentages_remaining, pack_id),
 | 
				
			||||||
          "original_count" => Map.get(original_counts, ammo_group_id),
 | 
					          "original_count" => Map.get(original_counts, pack_id),
 | 
				
			||||||
          "cpr" => Map.get(cprs, ammo_group_id)
 | 
					          "cpr" => Map.get(cprs, pack_id)
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
      end)
 | 
					      end)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    shot_groups = ActivityLog.list_shot_groups(current_user)
 | 
					    shot_records = ActivityLog.list_shot_records(:all, current_user)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    containers =
 | 
					    containers =
 | 
				
			||||||
      Containers.list_containers(current_user)
 | 
					      Containers.list_containers(current_user)
 | 
				
			||||||
      |> Enum.map(fn container ->
 | 
					      |> Enum.map(fn container ->
 | 
				
			||||||
        ammo_group_count = container |> Ammo.get_ammo_groups_count_for_container!(current_user)
 | 
					        pack_count = container |> Ammo.get_packs_count_for_container!(current_user)
 | 
				
			||||||
        round_count = container |> Ammo.get_round_count_for_container!(current_user)
 | 
					        round_count = container |> Ammo.get_round_count_for_container!(current_user)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        container
 | 
					        container
 | 
				
			||||||
        |> Jason.encode!()
 | 
					        |> Jason.encode!()
 | 
				
			||||||
        |> Jason.decode!()
 | 
					        |> Jason.decode!()
 | 
				
			||||||
        |> Map.merge(%{
 | 
					        |> Map.merge(%{
 | 
				
			||||||
          "ammo_group_count" => ammo_group_count,
 | 
					          "pack_count" => pack_count,
 | 
				
			||||||
          "round_count" => round_count
 | 
					          "round_count" => round_count
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
      end)
 | 
					      end)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    json(conn, %{
 | 
					    json(conn, %{
 | 
				
			||||||
      user: current_user,
 | 
					      user: current_user,
 | 
				
			||||||
      ammo_types: ammo_types,
 | 
					      types: types,
 | 
				
			||||||
      ammo_groups: ammo_groups,
 | 
					      packs: packs,
 | 
				
			||||||
      shot_groups: shot_groups,
 | 
					      shot_records: shot_records,
 | 
				
			||||||
      containers: containers
 | 
					      containers: containers
 | 
				
			||||||
    })
 | 
					    })
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,222 +0,0 @@
 | 
				
			|||||||
<div class="flex flex-col space-y-8 justify-center items-center">
 | 
					 | 
				
			||||||
  <h1 class="title text-2xl title-primary-500">
 | 
					 | 
				
			||||||
    <%= gettext("Ammo") %>
 | 
					 | 
				
			||||||
  </h1>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  <h2
 | 
					 | 
				
			||||||
    :if={@ammo_groups |> Enum.empty?() and @search |> is_nil()}
 | 
					 | 
				
			||||||
    class="title text-xl text-primary-600"
 | 
					 | 
				
			||||||
  >
 | 
					 | 
				
			||||||
    <%= gettext("No Ammo") %>
 | 
					 | 
				
			||||||
    <%= display_emoji("😔") %>
 | 
					 | 
				
			||||||
  </h2>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  <%= cond do %>
 | 
					 | 
				
			||||||
    <% @containers_count == 0 -> %>
 | 
					 | 
				
			||||||
      <div class="flex justify-center items-center">
 | 
					 | 
				
			||||||
        <h2 class="m-2 title text-md text-primary-600">
 | 
					 | 
				
			||||||
          <%= dgettext("prompts", "You'll need to") %>
 | 
					 | 
				
			||||||
        </h2>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        <.link navigate={Routes.container_index_path(Endpoint, :new)} class="btn btn-primary">
 | 
					 | 
				
			||||||
          <%= dgettext("actions", "add a container first") %>
 | 
					 | 
				
			||||||
        </.link>
 | 
					 | 
				
			||||||
      </div>
 | 
					 | 
				
			||||||
    <% @ammo_types_count == 0 -> %>
 | 
					 | 
				
			||||||
      <div class="flex justify-center items-center">
 | 
					 | 
				
			||||||
        <h2 class="m-2 title text-md text-primary-600">
 | 
					 | 
				
			||||||
          <%= dgettext("prompts", "You'll need to") %>
 | 
					 | 
				
			||||||
        </h2>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        <.link navigate={Routes.ammo_type_index_path(Endpoint, :new)} class="btn btn-primary">
 | 
					 | 
				
			||||||
          <%= dgettext("actions", "add an ammo type first") %>
 | 
					 | 
				
			||||||
        </.link>
 | 
					 | 
				
			||||||
      </div>
 | 
					 | 
				
			||||||
    <% @ammo_groups |> Enum.empty?() and @search |> is_nil() -> %>
 | 
					 | 
				
			||||||
      <.link patch={Routes.ammo_group_index_path(Endpoint, :new)} class="btn btn-primary">
 | 
					 | 
				
			||||||
        <%= dgettext("actions", "Add your first box!") %>
 | 
					 | 
				
			||||||
      </.link>
 | 
					 | 
				
			||||||
    <% true -> %>
 | 
					 | 
				
			||||||
      <.link patch={Routes.ammo_group_index_path(Endpoint, :new)} class="btn btn-primary">
 | 
					 | 
				
			||||||
        <%= dgettext("actions", "Add Ammo") %>
 | 
					 | 
				
			||||||
      </.link>
 | 
					 | 
				
			||||||
  <% end %>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  <div class="w-full flex flex-col sm:flex-row justify-center items-center space-y-4 sm:space-y-0 sm:space-x-4 max-w-xl">
 | 
					 | 
				
			||||||
    <.form
 | 
					 | 
				
			||||||
      :let={f}
 | 
					 | 
				
			||||||
      for={%{}}
 | 
					 | 
				
			||||||
      as={:search}
 | 
					 | 
				
			||||||
      phx-change="search"
 | 
					 | 
				
			||||||
      phx-submit="search"
 | 
					 | 
				
			||||||
      class="grow self-stretch flex flex-col items-stretch"
 | 
					 | 
				
			||||||
    >
 | 
					 | 
				
			||||||
      <%= text_input(f, :search_term,
 | 
					 | 
				
			||||||
        class: "input input-primary",
 | 
					 | 
				
			||||||
        value: @search,
 | 
					 | 
				
			||||||
        role: "search",
 | 
					 | 
				
			||||||
        phx_debounce: 300,
 | 
					 | 
				
			||||||
        placeholder: gettext("Search ammo")
 | 
					 | 
				
			||||||
      ) %>
 | 
					 | 
				
			||||||
    </.form>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    <.toggle_button action="toggle_show_used" value={@show_used}>
 | 
					 | 
				
			||||||
      <span class="title text-lg text-primary-600">
 | 
					 | 
				
			||||||
        <%= gettext("Show used") %>
 | 
					 | 
				
			||||||
      </span>
 | 
					 | 
				
			||||||
    </.toggle_button>
 | 
					 | 
				
			||||||
  </div>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  <%= if @ammo_groups |> Enum.empty?() do %>
 | 
					 | 
				
			||||||
    <h2 class="title text-xl text-primary-600">
 | 
					 | 
				
			||||||
      <%= gettext("No Ammo") %>
 | 
					 | 
				
			||||||
      <%= display_emoji("😔") %>
 | 
					 | 
				
			||||||
    </h2>
 | 
					 | 
				
			||||||
  <% else %>
 | 
					 | 
				
			||||||
    <.live_component
 | 
					 | 
				
			||||||
      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: dgettext("actions", "Unstage"),
 | 
					 | 
				
			||||||
              else: dgettext("actions", "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={{ammo_group, %{name: container_name} = container}}>
 | 
					 | 
				
			||||||
        <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"
 | 
					 | 
				
			||||||
          >
 | 
					 | 
				
			||||||
            <%= dgettext("actions", "Move ammo") %>
 | 
					 | 
				
			||||||
          </.link>
 | 
					 | 
				
			||||||
        </div>
 | 
					 | 
				
			||||||
      </:container>
 | 
					 | 
				
			||||||
      <:actions :let={%{count: ammo_group_count} = 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"
 | 
					 | 
				
			||||||
            aria-label={
 | 
					 | 
				
			||||||
              dgettext("actions", "View ammo group of %{ammo_group_count} bullets",
 | 
					 | 
				
			||||||
                ammo_group_count: ammo_group_count
 | 
					 | 
				
			||||||
              )
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
          >
 | 
					 | 
				
			||||||
            <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"
 | 
					 | 
				
			||||||
            aria-label={
 | 
					 | 
				
			||||||
              dgettext("actions", "Edit ammo group of %{ammo_group_count} bullets",
 | 
					 | 
				
			||||||
                ammo_group_count: ammo_group_count
 | 
					 | 
				
			||||||
              )
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
          >
 | 
					 | 
				
			||||||
            <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"
 | 
					 | 
				
			||||||
            aria-label={
 | 
					 | 
				
			||||||
              dgettext("actions", "Clone ammo group of %{ammo_group_count} bullets",
 | 
					 | 
				
			||||||
                ammo_group_count: ammo_group_count
 | 
					 | 
				
			||||||
              )
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
          >
 | 
					 | 
				
			||||||
            <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?")}
 | 
					 | 
				
			||||||
            aria-label={
 | 
					 | 
				
			||||||
              dgettext("actions", "Delete ammo group of %{ammo_group_count} bullets",
 | 
					 | 
				
			||||||
                ammo_group_count: ammo_group_count
 | 
					 | 
				
			||||||
              )
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
          >
 | 
					 | 
				
			||||||
            <i class="fa-fw fa-lg fas fa-trash"></i>
 | 
					 | 
				
			||||||
          </.link>
 | 
					 | 
				
			||||||
        </div>
 | 
					 | 
				
			||||||
      </:actions>
 | 
					 | 
				
			||||||
    </.live_component>
 | 
					 | 
				
			||||||
  <% end %>
 | 
					 | 
				
			||||||
</div>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
<%= case @live_action do %>
 | 
					 | 
				
			||||||
  <% create when create in [:new, :edit, :clone] -> %>
 | 
					 | 
				
			||||||
    <.modal return_to={Routes.ammo_group_index_path(Endpoint, :index)}>
 | 
					 | 
				
			||||||
      <.live_component
 | 
					 | 
				
			||||||
        module={CanneryWeb.AmmoGroupLive.FormComponent}
 | 
					 | 
				
			||||||
        id={@ammo_group.id || :new}
 | 
					 | 
				
			||||||
        title={@page_title}
 | 
					 | 
				
			||||||
        action={@live_action}
 | 
					 | 
				
			||||||
        ammo_group={@ammo_group}
 | 
					 | 
				
			||||||
        return_to={Routes.ammo_group_index_path(Endpoint, :index)}
 | 
					 | 
				
			||||||
        current_user={@current_user}
 | 
					 | 
				
			||||||
      />
 | 
					 | 
				
			||||||
    </.modal>
 | 
					 | 
				
			||||||
  <% :add_shot_group -> %>
 | 
					 | 
				
			||||||
    <.modal return_to={Routes.ammo_group_index_path(Endpoint, :index)}>
 | 
					 | 
				
			||||||
      <.live_component
 | 
					 | 
				
			||||||
        module={CanneryWeb.Components.AddShotGroupComponent}
 | 
					 | 
				
			||||||
        id={:new}
 | 
					 | 
				
			||||||
        title={@page_title}
 | 
					 | 
				
			||||||
        action={@live_action}
 | 
					 | 
				
			||||||
        ammo_group={@ammo_group}
 | 
					 | 
				
			||||||
        return_to={Routes.ammo_group_index_path(Endpoint, :index)}
 | 
					 | 
				
			||||||
        current_user={@current_user}
 | 
					 | 
				
			||||||
      />
 | 
					 | 
				
			||||||
    </.modal>
 | 
					 | 
				
			||||||
  <% :move -> %>
 | 
					 | 
				
			||||||
    <.modal return_to={Routes.ammo_group_index_path(Endpoint, :index)}>
 | 
					 | 
				
			||||||
      <.live_component
 | 
					 | 
				
			||||||
        module={CanneryWeb.Components.MoveAmmoGroupComponent}
 | 
					 | 
				
			||||||
        id={@ammo_group.id}
 | 
					 | 
				
			||||||
        title={@page_title}
 | 
					 | 
				
			||||||
        action={@live_action}
 | 
					 | 
				
			||||||
        ammo_group={@ammo_group}
 | 
					 | 
				
			||||||
        return_to={Routes.ammo_group_index_path(Endpoint, :index)}
 | 
					 | 
				
			||||||
        current_user={@current_user}
 | 
					 | 
				
			||||||
      />
 | 
					 | 
				
			||||||
    </.modal>
 | 
					 | 
				
			||||||
  <% _ -> %>
 | 
					 | 
				
			||||||
<% end %>
 | 
					 | 
				
			||||||
@@ -1,164 +0,0 @@
 | 
				
			|||||||
<div>
 | 
					 | 
				
			||||||
  <h2 class="mb-8 text-center title text-xl text-primary-600">
 | 
					 | 
				
			||||||
    <%= @title %>
 | 
					 | 
				
			||||||
  </h2>
 | 
					 | 
				
			||||||
  <.form
 | 
					 | 
				
			||||||
    :let={f}
 | 
					 | 
				
			||||||
    for={@changeset}
 | 
					 | 
				
			||||||
    id="ammo_type-form"
 | 
					 | 
				
			||||||
    phx-target={@myself}
 | 
					 | 
				
			||||||
    phx-change="validate"
 | 
					 | 
				
			||||||
    phx-submit="save"
 | 
					 | 
				
			||||||
    class="flex flex-col space-y-4 sm:space-y-0 sm:grid sm:grid-cols-3 sm:gap-4 justify-center items-center"
 | 
					 | 
				
			||||||
  >
 | 
					 | 
				
			||||||
    <div
 | 
					 | 
				
			||||||
      :if={@changeset.action && not @changeset.valid?()}
 | 
					 | 
				
			||||||
      class="invalid-feedback col-span-3 text-center"
 | 
					 | 
				
			||||||
    >
 | 
					 | 
				
			||||||
      <%= changeset_errors(@changeset) %>
 | 
					 | 
				
			||||||
    </div>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    <%= label(f, :name, gettext("Name"), class: "title text-lg text-primary-600") %>
 | 
					 | 
				
			||||||
    <%= text_input(f, :name, class: "text-center col-span-2 input input-primary") %>
 | 
					 | 
				
			||||||
    <%= error_tag(f, :name, "col-span-3 text-center") %>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    <%= label(f, :desc, gettext("Description"), class: "title text-lg text-primary-600") %>
 | 
					 | 
				
			||||||
    <%= textarea(f, :desc,
 | 
					 | 
				
			||||||
      id: "ammo-type-form-desc",
 | 
					 | 
				
			||||||
      class: "text-center col-span-2 input input-primary",
 | 
					 | 
				
			||||||
      phx_hook: "MaintainAttrs",
 | 
					 | 
				
			||||||
      phx_update: "ignore"
 | 
					 | 
				
			||||||
    ) %>
 | 
					 | 
				
			||||||
    <%= error_tag(f, :desc, "col-span-3 text-center") %>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    <.link
 | 
					 | 
				
			||||||
      href="https://shootersreference.com/reloadingdata/bullet_abbreviations/"
 | 
					 | 
				
			||||||
      class="col-span-3 text-center link title text-md text-primary-600"
 | 
					 | 
				
			||||||
    >
 | 
					 | 
				
			||||||
      <%= gettext("Example bullet type abbreviations") %>
 | 
					 | 
				
			||||||
    </.link>
 | 
					 | 
				
			||||||
    <%= label(f, :bullet_type, gettext("Bullet type"), class: "title text-lg text-primary-600") %>
 | 
					 | 
				
			||||||
    <%= text_input(f, :bullet_type,
 | 
					 | 
				
			||||||
      class: "text-center col-span-2 input input-primary",
 | 
					 | 
				
			||||||
      placeholder: gettext("FMJ")
 | 
					 | 
				
			||||||
    ) %>
 | 
					 | 
				
			||||||
    <%= error_tag(f, :bullet_type, "col-span-3 text-center") %>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    <%= label(f, :bullet_core, gettext("Bullet core"), class: "title text-lg text-primary-600") %>
 | 
					 | 
				
			||||||
    <%= text_input(f, :bullet_core,
 | 
					 | 
				
			||||||
      class: "text-center col-span-2 input input-primary",
 | 
					 | 
				
			||||||
      placeholder: gettext("Steel")
 | 
					 | 
				
			||||||
    ) %>
 | 
					 | 
				
			||||||
    <%= error_tag(f, :bullet_core, "col-span-3 text-center") %>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    <%= label(f, :cartridge, gettext("Cartridge"), class: "title text-lg text-primary-600") %>
 | 
					 | 
				
			||||||
    <%= text_input(f, :cartridge,
 | 
					 | 
				
			||||||
      class: "text-center col-span-2 input input-primary",
 | 
					 | 
				
			||||||
      placeholder: gettext("5.56x46mm NATO")
 | 
					 | 
				
			||||||
    ) %>
 | 
					 | 
				
			||||||
    <%= error_tag(f, :cartridge, "col-span-3 text-center") %>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    <%= label(f, :caliber, gettext("Caliber"), class: "title text-lg text-primary-600") %>
 | 
					 | 
				
			||||||
    <%= text_input(f, :caliber,
 | 
					 | 
				
			||||||
      class: "text-center col-span-2 input input-primary",
 | 
					 | 
				
			||||||
      placeholder: gettext(".223")
 | 
					 | 
				
			||||||
    ) %>
 | 
					 | 
				
			||||||
    <%= error_tag(f, :caliber, "col-span-3 text-center") %>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    <%= label(f, :case_material, gettext("Case material"), class: "title text-lg text-primary-600") %>
 | 
					 | 
				
			||||||
    <%= text_input(f, :case_material,
 | 
					 | 
				
			||||||
      class: "text-center col-span-2 input input-primary",
 | 
					 | 
				
			||||||
      placeholder: gettext("Brass")
 | 
					 | 
				
			||||||
    ) %>
 | 
					 | 
				
			||||||
    <%= error_tag(f, :case_material, "col-span-3 text-center") %>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    <%= label(f, :jacket_type, gettext("Jacket type"), class: "title text-lg text-primary-600") %>
 | 
					 | 
				
			||||||
    <%= text_input(f, :jacket_type,
 | 
					 | 
				
			||||||
      class: "text-center col-span-2 input input-primary",
 | 
					 | 
				
			||||||
      placeholder: gettext("Bimetal")
 | 
					 | 
				
			||||||
    ) %>
 | 
					 | 
				
			||||||
    <%= error_tag(f, :case_material, "col-span-3 text-center") %>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    <%= label(f, :muzzle_velocity, gettext("Muzzle velocity"),
 | 
					 | 
				
			||||||
      class: "title text-lg text-primary-600"
 | 
					 | 
				
			||||||
    ) %>
 | 
					 | 
				
			||||||
    <%= number_input(f, :muzzle_velocity,
 | 
					 | 
				
			||||||
      step: "1",
 | 
					 | 
				
			||||||
      class: "text-center col-span-2 input input-primary",
 | 
					 | 
				
			||||||
      min: 1
 | 
					 | 
				
			||||||
    ) %>
 | 
					 | 
				
			||||||
    <%= error_tag(f, :muzzle_velocity, "col-span-3 text-center") %>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    <%= label(f, :powder_type, gettext("Powder type"), class: "title text-lg text-primary-600") %>
 | 
					 | 
				
			||||||
    <%= text_input(f, :powder_type, class: "text-center col-span-2 input input-primary") %>
 | 
					 | 
				
			||||||
    <%= error_tag(f, :powder_type, "col-span-3 text-center") %>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    <%= label(f, :powder_grains_per_charge, gettext("Powder grains per charge"),
 | 
					 | 
				
			||||||
      class: "title text-lg text-primary-600"
 | 
					 | 
				
			||||||
    ) %>
 | 
					 | 
				
			||||||
    <%= number_input(f, :powder_grains_per_charge,
 | 
					 | 
				
			||||||
      step: "1",
 | 
					 | 
				
			||||||
      class: "text-center col-span-2 input input-primary",
 | 
					 | 
				
			||||||
      min: 1
 | 
					 | 
				
			||||||
    ) %>
 | 
					 | 
				
			||||||
    <%= error_tag(f, :powder_grains_per_charge, "col-span-3 text-center") %>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    <%= label(f, :grains, gettext("Grains"), class: "title text-lg text-primary-600") %>
 | 
					 | 
				
			||||||
    <%= number_input(f, :grains,
 | 
					 | 
				
			||||||
      step: "1",
 | 
					 | 
				
			||||||
      class: "text-center col-span-2 input input-primary",
 | 
					 | 
				
			||||||
      min: 1
 | 
					 | 
				
			||||||
    ) %>
 | 
					 | 
				
			||||||
    <%= error_tag(f, :grains, "col-span-3 text-center") %>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    <%= label(f, :pressure, gettext("Pressure"), class: "title text-lg text-primary-600") %>
 | 
					 | 
				
			||||||
    <%= text_input(f, :pressure,
 | 
					 | 
				
			||||||
      class: "text-center col-span-2 input input-primary",
 | 
					 | 
				
			||||||
      placeholder: gettext("+P")
 | 
					 | 
				
			||||||
    ) %>
 | 
					 | 
				
			||||||
    <%= error_tag(f, :pressure, "col-span-3 text-center") %>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    <%= label(f, :primer_type, gettext("Primer type"), class: "title text-lg text-primary-600") %>
 | 
					 | 
				
			||||||
    <%= text_input(f, :primer_type,
 | 
					 | 
				
			||||||
      class: "text-center col-span-2 input input-primary",
 | 
					 | 
				
			||||||
      placeholder: gettext("Boxer")
 | 
					 | 
				
			||||||
    ) %>
 | 
					 | 
				
			||||||
    <%= error_tag(f, :primer_type, "col-span-3 text-center") %>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    <%= label(f, :firing_type, gettext("Firing type"), class: "title text-lg text-primary-600") %>
 | 
					 | 
				
			||||||
    <%= text_input(f, :firing_type,
 | 
					 | 
				
			||||||
      class: "text-center col-span-2 input input-primary",
 | 
					 | 
				
			||||||
      placeholder: gettext("Centerfire")
 | 
					 | 
				
			||||||
    ) %>
 | 
					 | 
				
			||||||
    <%= error_tag(f, :firing_type, "col-span-3 text-center") %>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    <%= label(f, :tracer, gettext("Tracer"), class: "title text-lg text-primary-600") %>
 | 
					 | 
				
			||||||
    <%= checkbox(f, :tracer, class: "text-center col-span-2 checkbox") %>
 | 
					 | 
				
			||||||
    <%= error_tag(f, :tracer, "col-span-3 text-center") %>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    <%= label(f, :incendiary, gettext("Incendiary"), class: "title text-lg text-primary-600") %>
 | 
					 | 
				
			||||||
    <%= checkbox(f, :incendiary, class: "text-center col-span-2 checkbox") %>
 | 
					 | 
				
			||||||
    <%= error_tag(f, :incendiary, "col-span-3 text-center") %>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    <%= label(f, :blank, gettext("Blank"), class: "title text-lg text-primary-600") %>
 | 
					 | 
				
			||||||
    <%= checkbox(f, :blank, class: "text-center col-span-2 checkbox") %>
 | 
					 | 
				
			||||||
    <%= error_tag(f, :blank, "col-span-3 text-center") %>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    <%= label(f, :corrosive, gettext("Corrosive"), class: "title text-lg text-primary-600") %>
 | 
					 | 
				
			||||||
    <%= checkbox(f, :corrosive, class: "text-center col-span-2 checkbox") %>
 | 
					 | 
				
			||||||
    <%= error_tag(f, :corrosive, "col-span-3 text-center") %>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    <%= label(f, :manufacturer, gettext("Manufacturer"), class: "title text-lg text-primary-600") %>
 | 
					 | 
				
			||||||
    <%= text_input(f, :manufacturer, class: "text-center col-span-2 input input-primary") %>
 | 
					 | 
				
			||||||
    <%= error_tag(f, :manufacturer, "col-span-3 text-center") %>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    <%= label(f, :upc, gettext("UPC"), class: "title text-lg text-primary-600") %>
 | 
					 | 
				
			||||||
    <%= text_input(f, :upc, class: "text-center col-span-2 input input-primary") %>
 | 
					 | 
				
			||||||
    <%= error_tag(f, :upc, "col-span-3 text-center") %>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    <%= submit(dgettext("actions", "Save"),
 | 
					 | 
				
			||||||
      phx_disable_with: dgettext("prompts", "Saving..."),
 | 
					 | 
				
			||||||
      class: "mx-auto col-span-3 btn btn-primary"
 | 
					 | 
				
			||||||
    ) %>
 | 
					 | 
				
			||||||
  </.form>
 | 
					 | 
				
			||||||
</div>
 | 
					 | 
				
			||||||
@@ -1,92 +0,0 @@
 | 
				
			|||||||
defmodule CanneryWeb.AmmoTypeLive.Index do
 | 
					 | 
				
			||||||
  @moduledoc """
 | 
					 | 
				
			||||||
  Liveview for showing a Cannery.Ammo.AmmoType index
 | 
					 | 
				
			||||||
  """
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  use CanneryWeb, :live_view
 | 
					 | 
				
			||||||
  alias Cannery.{Ammo, Ammo.AmmoType}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  @impl true
 | 
					 | 
				
			||||||
  def mount(%{"search" => search}, _session, socket) do
 | 
					 | 
				
			||||||
    {:ok, socket |> assign(show_used: false, search: search) |> list_ammo_types()}
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  def mount(_params, _session, socket) do
 | 
					 | 
				
			||||||
    {:ok, socket |> assign(show_used: false, search: nil) |> list_ammo_types()}
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  @impl true
 | 
					 | 
				
			||||||
  def handle_params(params, _url, %{assigns: %{live_action: live_action}} = socket) do
 | 
					 | 
				
			||||||
    {:noreply, apply_action(socket, live_action, params)}
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  defp apply_action(%{assigns: %{current_user: current_user}} = socket, :edit, %{"id" => id}) do
 | 
					 | 
				
			||||||
    %{name: ammo_type_name} = ammo_type = Ammo.get_ammo_type!(id, current_user)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    socket
 | 
					 | 
				
			||||||
    |> assign(
 | 
					 | 
				
			||||||
      page_title: gettext("Edit %{ammo_type_name}", ammo_type_name: ammo_type_name),
 | 
					 | 
				
			||||||
      ammo_type: ammo_type
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  defp apply_action(%{assigns: %{current_user: current_user}} = socket, :clone, %{"id" => id}) do
 | 
					 | 
				
			||||||
    socket
 | 
					 | 
				
			||||||
    |> assign(
 | 
					 | 
				
			||||||
      page_title: gettext("New Ammo type"),
 | 
					 | 
				
			||||||
      ammo_type: %{Ammo.get_ammo_type!(id, current_user) | id: nil}
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  defp apply_action(socket, :new, _params) do
 | 
					 | 
				
			||||||
    socket
 | 
					 | 
				
			||||||
    |> assign(
 | 
					 | 
				
			||||||
      page_title: gettext("New Ammo type"),
 | 
					 | 
				
			||||||
      ammo_type: %AmmoType{}
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  defp apply_action(socket, :index, _params) do
 | 
					 | 
				
			||||||
    socket
 | 
					 | 
				
			||||||
    |> assign(
 | 
					 | 
				
			||||||
      page_title: gettext("Catalog"),
 | 
					 | 
				
			||||||
      search: nil,
 | 
					 | 
				
			||||||
      ammo_type: nil
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
    |> list_ammo_types()
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  defp apply_action(socket, :search, %{"search" => search}) do
 | 
					 | 
				
			||||||
    socket
 | 
					 | 
				
			||||||
    |> assign(
 | 
					 | 
				
			||||||
      page_title: gettext("Catalog"),
 | 
					 | 
				
			||||||
      search: search,
 | 
					 | 
				
			||||||
      ammo_type: nil
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
    |> list_ammo_types()
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  @impl true
 | 
					 | 
				
			||||||
  def handle_event("delete", %{"id" => id}, %{assigns: %{current_user: current_user}} = socket) do
 | 
					 | 
				
			||||||
    %{name: name} = Ammo.get_ammo_type!(id, current_user) |> Ammo.delete_ammo_type!(current_user)
 | 
					 | 
				
			||||||
    prompt = dgettext("prompts", "%{name} deleted succesfully", name: name)
 | 
					 | 
				
			||||||
    {:noreply, socket |> put_flash(:info, prompt) |> list_ammo_types()}
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  def handle_event("toggle_show_used", _params, %{assigns: %{show_used: show_used}} = socket) do
 | 
					 | 
				
			||||||
    {:noreply, socket |> assign(:show_used, !show_used) |> list_ammo_types()}
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  def handle_event("search", %{"search" => %{"search_term" => ""}}, socket) do
 | 
					 | 
				
			||||||
    {:noreply, socket |> push_patch(to: Routes.ammo_type_index_path(Endpoint, :index))}
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  def handle_event("search", %{"search" => %{"search_term" => search_term}}, socket) do
 | 
					 | 
				
			||||||
    search_path = Routes.ammo_type_index_path(Endpoint, :search, search_term)
 | 
					 | 
				
			||||||
    {:noreply, socket |> push_patch(to: search_path)}
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  defp list_ammo_types(%{assigns: %{search: search, current_user: current_user}} = socket) do
 | 
					 | 
				
			||||||
    socket |> assign(ammo_types: Ammo.list_ammo_types(search, current_user))
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
end
 | 
					 | 
				
			||||||
@@ -1,143 +0,0 @@
 | 
				
			|||||||
defmodule CanneryWeb.AmmoTypeLive.Show do
 | 
					 | 
				
			||||||
  @moduledoc """
 | 
					 | 
				
			||||||
  Liveview for showing and editing an Cannery.Ammo.AmmoType
 | 
					 | 
				
			||||||
  """
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  use CanneryWeb, :live_view
 | 
					 | 
				
			||||||
  alias Cannery.{ActivityLog, Ammo, Ammo.AmmoType, Containers}
 | 
					 | 
				
			||||||
  alias CanneryWeb.Endpoint
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  @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 mount(_params, _session, socket),
 | 
					 | 
				
			||||||
    do: {:ok, socket |> assign(show_used: false, view_table: true)}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  @impl true
 | 
					 | 
				
			||||||
  def handle_params(%{"id" => id}, _params, socket) do
 | 
					 | 
				
			||||||
    {:noreply, socket |> display_ammo_type(id)}
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  @impl true
 | 
					 | 
				
			||||||
  def handle_event(
 | 
					 | 
				
			||||||
        "delete",
 | 
					 | 
				
			||||||
        _params,
 | 
					 | 
				
			||||||
        %{assigns: %{ammo_type: ammo_type, current_user: current_user}} = socket
 | 
					 | 
				
			||||||
      ) do
 | 
					 | 
				
			||||||
    %{name: ammo_type_name} = ammo_type |> Ammo.delete_ammo_type!(current_user)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    prompt = dgettext("prompts", "%{name} deleted succesfully", name: ammo_type_name)
 | 
					 | 
				
			||||||
    redirect_to = Routes.ammo_type_index_path(socket, :index)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    {:noreply, socket |> put_flash(:info, prompt) |> push_navigate(to: redirect_to)}
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  def handle_event("toggle_show_used", _params, %{assigns: %{show_used: show_used}} = socket) do
 | 
					 | 
				
			||||||
    {:noreply, socket |> assign(:show_used, !show_used) |> display_ammo_type()}
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  def handle_event("toggle_table", _params, %{assigns: %{view_table: view_table}} = socket) do
 | 
					 | 
				
			||||||
    {:noreply, socket |> assign(:view_table, !view_table)}
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  defp display_ammo_type(
 | 
					 | 
				
			||||||
         %{assigns: %{live_action: live_action, current_user: current_user, show_used: show_used}} =
 | 
					 | 
				
			||||||
           socket,
 | 
					 | 
				
			||||||
         %AmmoType{name: ammo_type_name} = 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)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    ammo_groups = ammo_type |> Ammo.list_ammo_groups_for_type(current_user, show_used)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    [
 | 
					 | 
				
			||||||
      original_counts,
 | 
					 | 
				
			||||||
      used_packs_count,
 | 
					 | 
				
			||||||
      historical_packs_count,
 | 
					 | 
				
			||||||
      used_rounds,
 | 
					 | 
				
			||||||
      historical_round_count
 | 
					 | 
				
			||||||
    ] =
 | 
					 | 
				
			||||||
      if show_used do
 | 
					 | 
				
			||||||
        [
 | 
					 | 
				
			||||||
          ammo_groups |> Ammo.get_original_counts(current_user),
 | 
					 | 
				
			||||||
          ammo_type |> Ammo.get_used_ammo_groups_count_for_type(current_user),
 | 
					 | 
				
			||||||
          ammo_type |> Ammo.get_ammo_groups_count_for_type(current_user, true),
 | 
					 | 
				
			||||||
          ammo_type |> ActivityLog.get_used_count_for_ammo_type(current_user),
 | 
					 | 
				
			||||||
          ammo_type |> Ammo.get_historical_count_for_ammo_type(current_user)
 | 
					 | 
				
			||||||
        ]
 | 
					 | 
				
			||||||
      else
 | 
					 | 
				
			||||||
        [nil, nil, nil, nil, nil]
 | 
					 | 
				
			||||||
      end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    page_title =
 | 
					 | 
				
			||||||
      case live_action do
 | 
					 | 
				
			||||||
        :show -> ammo_type_name
 | 
					 | 
				
			||||||
        :edit -> gettext("Edit %{ammo_type_name}", ammo_type_name: ammo_type_name)
 | 
					 | 
				
			||||||
      end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    containers =
 | 
					 | 
				
			||||||
      ammo_groups
 | 
					 | 
				
			||||||
      |> Enum.map(fn %{container_id: container_id} -> container_id end)
 | 
					 | 
				
			||||||
      |> Containers.get_containers(current_user)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    socket
 | 
					 | 
				
			||||||
    |> assign(
 | 
					 | 
				
			||||||
      page_title: page_title,
 | 
					 | 
				
			||||||
      ammo_type: ammo_type,
 | 
					 | 
				
			||||||
      ammo_groups: ammo_groups,
 | 
					 | 
				
			||||||
      containers: containers,
 | 
					 | 
				
			||||||
      cprs: ammo_groups |> Ammo.get_cprs(current_user),
 | 
					 | 
				
			||||||
      last_used_dates: ammo_groups |> ActivityLog.get_last_used_dates(current_user),
 | 
					 | 
				
			||||||
      avg_cost_per_round: ammo_type |> Ammo.get_average_cost_for_ammo_type(current_user),
 | 
					 | 
				
			||||||
      rounds: ammo_type |> Ammo.get_round_count_for_ammo_type(current_user),
 | 
					 | 
				
			||||||
      original_counts: original_counts,
 | 
					 | 
				
			||||||
      used_rounds: used_rounds,
 | 
					 | 
				
			||||||
      historical_round_count: historical_round_count,
 | 
					 | 
				
			||||||
      packs_count: ammo_type |> Ammo.get_ammo_groups_count_for_type(current_user),
 | 
					 | 
				
			||||||
      used_packs_count: used_packs_count,
 | 
					 | 
				
			||||||
      historical_packs_count: historical_packs_count,
 | 
					 | 
				
			||||||
      fields_list: @fields_list,
 | 
					 | 
				
			||||||
      fields_to_display: fields_to_display
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  defp display_ammo_type(%{assigns: %{current_user: current_user}} = socket, ammo_type_id) do
 | 
					 | 
				
			||||||
    socket |> display_ammo_type(Ammo.get_ammo_type!(ammo_type_id, current_user))
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  defp display_ammo_type(%{assigns: %{ammo_type: ammo_type}} = socket) do
 | 
					 | 
				
			||||||
    socket |> display_ammo_type(ammo_type)
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  @spec display_currency(float()) :: String.t()
 | 
					 | 
				
			||||||
  defp display_currency(float), do: :erlang.float_to_binary(float, decimals: 2)
 | 
					 | 
				
			||||||
end
 | 
					 | 
				
			||||||
@@ -21,7 +21,8 @@
 | 
				
			|||||||
    <%= label(f, :name, gettext("Name"), class: "title text-lg text-primary-600") %>
 | 
					    <%= label(f, :name, gettext("Name"), class: "title text-lg text-primary-600") %>
 | 
				
			||||||
    <%= text_input(f, :name,
 | 
					    <%= text_input(f, :name,
 | 
				
			||||||
      class: "input input-primary col-span-2",
 | 
					      class: "input input-primary col-span-2",
 | 
				
			||||||
      placeholder: gettext("My cool ammo can")
 | 
					      placeholder: gettext("My cool ammo can"),
 | 
				
			||||||
 | 
					      maxlength: 255
 | 
				
			||||||
    ) %>
 | 
					    ) %>
 | 
				
			||||||
    <%= error_tag(f, :name, "col-span-3 text-center") %>
 | 
					    <%= error_tag(f, :name, "col-span-3 text-center") %>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -38,7 +39,8 @@
 | 
				
			|||||||
    <%= label(f, :type, gettext("Type"), class: "title text-lg text-primary-600") %>
 | 
					    <%= label(f, :type, gettext("Type"), class: "title text-lg text-primary-600") %>
 | 
				
			||||||
    <%= text_input(f, :type,
 | 
					    <%= text_input(f, :type,
 | 
				
			||||||
      class: "input input-primary col-span-2",
 | 
					      class: "input input-primary col-span-2",
 | 
				
			||||||
      placeholder: gettext("Magazine, Clip, Ammo Box, etc")
 | 
					      placeholder: gettext("Magazine, Clip, Ammo Box, etc"),
 | 
				
			||||||
 | 
					      maxlength: 255
 | 
				
			||||||
    ) %>
 | 
					    ) %>
 | 
				
			||||||
    <%= error_tag(f, :type, "col-span-3 text-center") %>
 | 
					    <%= error_tag(f, :type, "col-span-3 text-center") %>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -79,15 +79,15 @@ defmodule CanneryWeb.ContainerLive.Index do
 | 
				
			|||||||
              prompt = dgettext("prompts", "%{name} has been deleted", name: container_name)
 | 
					              prompt = dgettext("prompts", "%{name} has been deleted", name: container_name)
 | 
				
			||||||
              socket |> put_flash(:info, prompt) |> display_containers()
 | 
					              socket |> put_flash(:info, prompt) |> display_containers()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            {:error, %{action: :delete, errors: [ammo_groups: _error], valid?: false} = changeset} ->
 | 
					            {:error, %{action: :delete, errors: [packs: _error], valid?: false} = changeset} ->
 | 
				
			||||||
              ammo_groups_error = changeset |> changeset_errors(:ammo_groups) |> Enum.join(", ")
 | 
					              packs_error = changeset |> changeset_errors(:packs) |> Enum.join(", ")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
              prompt =
 | 
					              prompt =
 | 
				
			||||||
                dgettext(
 | 
					                dgettext(
 | 
				
			||||||
                  "errors",
 | 
					                  "errors",
 | 
				
			||||||
                  "Could not delete %{name}: %{error}",
 | 
					                  "Could not delete %{name}: %{error}",
 | 
				
			||||||
                  name: changeset |> Changeset.get_field(:name, "container"),
 | 
					                  name: changeset |> Changeset.get_field(:name, "container"),
 | 
				
			||||||
                  error: ammo_groups_error
 | 
					                  error: packs_error
 | 
				
			||||||
                )
 | 
					                )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
              socket |> put_flash(:error, prompt)
 | 
					              socket |> put_flash(:error, prompt)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,17 +17,17 @@
 | 
				
			|||||||
      <%= dgettext("actions", "New Container") %>
 | 
					      <%= dgettext("actions", "New Container") %>
 | 
				
			||||||
    </.link>
 | 
					    </.link>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <div class="w-full flex flex-col sm:flex-row justify-center items-center space-y-4 sm:space-y-0 sm:space-x-4 max-w-xl">
 | 
					    <div class="w-full flex flex-col sm:flex-row justify-center items-center space-y-4 sm:space-y-0 sm:space-x-4 max-w-2xl">
 | 
				
			||||||
      <.form
 | 
					      <.form
 | 
				
			||||||
        :let={f}
 | 
					        :let={f}
 | 
				
			||||||
        for={%{}}
 | 
					        for={%{}}
 | 
				
			||||||
        as={:search}
 | 
					        as={:search}
 | 
				
			||||||
        phx-change="search"
 | 
					        phx-change="search"
 | 
				
			||||||
        phx-submit="search"
 | 
					        phx-submit="search"
 | 
				
			||||||
        class="grow self-stretch flex flex-col items-stretch"
 | 
					        class="grow flex items-center"
 | 
				
			||||||
      >
 | 
					      >
 | 
				
			||||||
        <%= text_input(f, :search_term,
 | 
					        <%= text_input(f, :search_term,
 | 
				
			||||||
          class: "input input-primary",
 | 
					          class: "grow input input-primary",
 | 
				
			||||||
          value: @search,
 | 
					          value: @search,
 | 
				
			||||||
          role: "search",
 | 
					          role: "search",
 | 
				
			||||||
          phx_debounce: 300,
 | 
					          phx_debounce: 300,
 | 
				
			||||||
@@ -41,80 +41,22 @@
 | 
				
			|||||||
        </span>
 | 
					        </span>
 | 
				
			||||||
      </.toggle_button>
 | 
					      </.toggle_button>
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
  <% end %>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  <%= if @containers |> Enum.empty?() do %>
 | 
					    <%= if @containers |> Enum.empty?() do %>
 | 
				
			||||||
    <h2 class="title text-xl text-primary-600">
 | 
					      <h2 class="title text-xl text-primary-600">
 | 
				
			||||||
      <%= gettext("No containers") %>
 | 
					        <%= gettext("No containers") %>
 | 
				
			||||||
      <%= display_emoji("😔") %>
 | 
					        <%= display_emoji("😔") %>
 | 
				
			||||||
    </h2>
 | 
					      </h2>
 | 
				
			||||||
  <% else %>
 | 
					 | 
				
			||||||
    <%= if @view_table do %>
 | 
					 | 
				
			||||||
      <.live_component
 | 
					 | 
				
			||||||
        module={CanneryWeb.Components.ContainerTableComponent}
 | 
					 | 
				
			||||||
        id="containers_index_table"
 | 
					 | 
				
			||||||
        action={@live_action}
 | 
					 | 
				
			||||||
        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"
 | 
					 | 
				
			||||||
              aria-label={
 | 
					 | 
				
			||||||
                dgettext("actions", "Tag %{container_name}", container_name: container.name)
 | 
					 | 
				
			||||||
              }
 | 
					 | 
				
			||||||
            >
 | 
					 | 
				
			||||||
              <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"
 | 
					 | 
				
			||||||
            aria-label={
 | 
					 | 
				
			||||||
              dgettext("actions", "Edit %{container_name}", container_name: container.name)
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
          >
 | 
					 | 
				
			||||||
            <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"
 | 
					 | 
				
			||||||
            aria-label={
 | 
					 | 
				
			||||||
              dgettext("actions", "Clone %{container_name}", container_name: container.name)
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
          >
 | 
					 | 
				
			||||||
            <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)
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            aria-label={
 | 
					 | 
				
			||||||
              dgettext("actions", "Delete %{container_name}", container_name: container.name)
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
          >
 | 
					 | 
				
			||||||
            <i class="fa-fw fa-lg fas fa-trash"></i>
 | 
					 | 
				
			||||||
          </.link>
 | 
					 | 
				
			||||||
        </:actions>
 | 
					 | 
				
			||||||
      </.live_component>
 | 
					 | 
				
			||||||
    <% else %>
 | 
					    <% else %>
 | 
				
			||||||
      <div class="w-full flex flex-row flex-wrap justify-center items-stretch">
 | 
					      <%= if @view_table do %>
 | 
				
			||||||
        <.container_card
 | 
					        <.live_component
 | 
				
			||||||
          :for={container <- @containers}
 | 
					          module={CanneryWeb.Components.ContainerTableComponent}
 | 
				
			||||||
          container={container}
 | 
					          id="containers_index_table"
 | 
				
			||||||
 | 
					          action={@live_action}
 | 
				
			||||||
 | 
					          containers={@containers}
 | 
				
			||||||
          current_user={@current_user}
 | 
					          current_user={@current_user}
 | 
				
			||||||
        >
 | 
					        >
 | 
				
			||||||
          <:tag_actions>
 | 
					          <:tag_actions :let={container}>
 | 
				
			||||||
            <div class="mx-4 my-2">
 | 
					            <div class="mx-4 my-2">
 | 
				
			||||||
              <.link
 | 
					              <.link
 | 
				
			||||||
                patch={Routes.container_index_path(Endpoint, :edit_tags, container)}
 | 
					                patch={Routes.container_index_path(Endpoint, :edit_tags, container)}
 | 
				
			||||||
@@ -127,42 +69,104 @@
 | 
				
			|||||||
              </.link>
 | 
					              </.link>
 | 
				
			||||||
            </div>
 | 
					            </div>
 | 
				
			||||||
          </:tag_actions>
 | 
					          </:tag_actions>
 | 
				
			||||||
          <.link
 | 
					          <:actions :let={container}>
 | 
				
			||||||
            patch={Routes.container_index_path(Endpoint, :edit, container)}
 | 
					            <.link
 | 
				
			||||||
            class="text-primary-600 link"
 | 
					              patch={Routes.container_index_path(Endpoint, :edit, container)}
 | 
				
			||||||
            aria-label={
 | 
					              class="text-primary-600 link"
 | 
				
			||||||
              dgettext("actions", "Edit %{container_name}", container_name: container.name)
 | 
					              aria-label={
 | 
				
			||||||
            }
 | 
					                dgettext("actions", "Edit %{container_name}", container_name: container.name)
 | 
				
			||||||
          >
 | 
					              }
 | 
				
			||||||
            <i class="fa-fw fa-lg fas fa-edit"></i>
 | 
					            >
 | 
				
			||||||
          </.link>
 | 
					              <i class="fa-fw fa-lg fas fa-edit"></i>
 | 
				
			||||||
 | 
					            </.link>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          <.link
 | 
					            <.link
 | 
				
			||||||
            patch={Routes.container_index_path(Endpoint, :clone, container)}
 | 
					              patch={Routes.container_index_path(Endpoint, :clone, container)}
 | 
				
			||||||
            class="text-primary-600 link"
 | 
					              class="text-primary-600 link"
 | 
				
			||||||
            aria-label={
 | 
					              aria-label={
 | 
				
			||||||
              dgettext("actions", "Clone %{container_name}", container_name: container.name)
 | 
					                dgettext("actions", "Clone %{container_name}", container_name: container.name)
 | 
				
			||||||
            }
 | 
					              }
 | 
				
			||||||
          >
 | 
					            >
 | 
				
			||||||
            <i class="fa-fw fa-lg fas fa-copy"></i>
 | 
					              <i class="fa-fw fa-lg fas fa-copy"></i>
 | 
				
			||||||
          </.link>
 | 
					            </.link>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          <.link
 | 
					            <.link
 | 
				
			||||||
            href="#"
 | 
					              href="#"
 | 
				
			||||||
            class="text-primary-600 link"
 | 
					              class="text-primary-600 link"
 | 
				
			||||||
            phx-click="delete"
 | 
					              phx-click="delete"
 | 
				
			||||||
            phx-value-id={container.id}
 | 
					              phx-value-id={container.id}
 | 
				
			||||||
            data-confirm={
 | 
					              data-confirm={
 | 
				
			||||||
              dgettext("prompts", "Are you sure you want to delete %{name}?", name: container.name)
 | 
					                dgettext("prompts", "Are you sure you want to delete %{name}?",
 | 
				
			||||||
            }
 | 
					                  name: container.name
 | 
				
			||||||
            aria-label={
 | 
					                )
 | 
				
			||||||
              dgettext("actions", "Delete %{container_name}", container_name: container.name)
 | 
					              }
 | 
				
			||||||
            }
 | 
					              aria-label={
 | 
				
			||||||
 | 
					                dgettext("actions", "Delete %{container_name}", container_name: container.name)
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					            >
 | 
				
			||||||
 | 
					              <i class="fa-fw fa-lg fas fa-trash"></i>
 | 
				
			||||||
 | 
					            </.link>
 | 
				
			||||||
 | 
					          </:actions>
 | 
				
			||||||
 | 
					        </.live_component>
 | 
				
			||||||
 | 
					      <% else %>
 | 
				
			||||||
 | 
					        <div class="w-full flex flex-row flex-wrap justify-center items-stretch">
 | 
				
			||||||
 | 
					          <.container_card
 | 
				
			||||||
 | 
					            :for={container <- @containers}
 | 
				
			||||||
 | 
					            container={container}
 | 
				
			||||||
 | 
					            current_user={@current_user}
 | 
				
			||||||
          >
 | 
					          >
 | 
				
			||||||
            <i class="fa-fw fa-lg fas fa-trash"></i>
 | 
					            <:tag_actions>
 | 
				
			||||||
          </.link>
 | 
					              <div class="mx-4 my-2">
 | 
				
			||||||
        </.container_card>
 | 
					                <.link
 | 
				
			||||||
      </div>
 | 
					                  patch={Routes.container_index_path(Endpoint, :edit_tags, container)}
 | 
				
			||||||
 | 
					                  class="text-primary-600 link"
 | 
				
			||||||
 | 
					                  aria-label={
 | 
				
			||||||
 | 
					                    dgettext("actions", "Tag %{container_name}", container_name: container.name)
 | 
				
			||||||
 | 
					                  }
 | 
				
			||||||
 | 
					                >
 | 
				
			||||||
 | 
					                  <i class="fa-fw fa-lg fas fa-tags"></i>
 | 
				
			||||||
 | 
					                </.link>
 | 
				
			||||||
 | 
					              </div>
 | 
				
			||||||
 | 
					            </:tag_actions>
 | 
				
			||||||
 | 
					            <.link
 | 
				
			||||||
 | 
					              patch={Routes.container_index_path(Endpoint, :edit, container)}
 | 
				
			||||||
 | 
					              class="text-primary-600 link"
 | 
				
			||||||
 | 
					              aria-label={
 | 
				
			||||||
 | 
					                dgettext("actions", "Edit %{container_name}", container_name: container.name)
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					            >
 | 
				
			||||||
 | 
					              <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"
 | 
				
			||||||
 | 
					              aria-label={
 | 
				
			||||||
 | 
					                dgettext("actions", "Clone %{container_name}", container_name: container.name)
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					            >
 | 
				
			||||||
 | 
					              <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
 | 
				
			||||||
 | 
					                )
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					              aria-label={
 | 
				
			||||||
 | 
					                dgettext("actions", "Delete %{container_name}", container_name: container.name)
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					            >
 | 
				
			||||||
 | 
					              <i class="fa-fw fa-lg fas fa-trash"></i>
 | 
				
			||||||
 | 
					            </.link>
 | 
				
			||||||
 | 
					          </.container_card>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					      <% end %>
 | 
				
			||||||
    <% end %>
 | 
					    <% end %>
 | 
				
			||||||
  <% end %>
 | 
					  <% end %>
 | 
				
			||||||
</div>
 | 
					</div>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -11,13 +11,13 @@ defmodule CanneryWeb.ContainerLive.Show do
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  @impl true
 | 
					  @impl true
 | 
				
			||||||
  def mount(_params, _session, socket),
 | 
					  def mount(_params, _session, socket),
 | 
				
			||||||
    do: {:ok, socket |> assign(show_used: false, view_table: true)}
 | 
					    do: {:ok, socket |> assign(class: :all, view_table: true)}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @impl true
 | 
					  @impl true
 | 
				
			||||||
  def handle_params(%{"id" => id}, _session, %{assigns: %{current_user: current_user}} = socket) do
 | 
					  def handle_params(%{"id" => id}, _session, %{assigns: %{current_user: current_user}} = socket) do
 | 
				
			||||||
    socket =
 | 
					    socket =
 | 
				
			||||||
      socket
 | 
					      socket
 | 
				
			||||||
      |> assign(view_table: true)
 | 
					      |> assign(:view_table, true)
 | 
				
			||||||
      |> render_container(id, current_user)
 | 
					      |> render_container(id, current_user)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    {:noreply, socket}
 | 
					    {:noreply, socket}
 | 
				
			||||||
@@ -64,13 +64,13 @@ defmodule CanneryWeb.ContainerLive.Show do
 | 
				
			|||||||
          |> put_flash(:info, prompt)
 | 
					          |> put_flash(:info, prompt)
 | 
				
			||||||
          |> push_navigate(to: Routes.container_index_path(socket, :index))
 | 
					          |> push_navigate(to: Routes.container_index_path(socket, :index))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        {:error, %{action: :delete, errors: [ammo_groups: _error], valid?: false} = changeset} ->
 | 
					        {:error, %{action: :delete, errors: [packs: _error], valid?: false} = changeset} ->
 | 
				
			||||||
          ammo_groups_error = changeset |> changeset_errors(:ammo_groups) |> Enum.join(", ")
 | 
					          packs_error = changeset |> changeset_errors(:packs) |> Enum.join(", ")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          prompt =
 | 
					          prompt =
 | 
				
			||||||
            dgettext("errors", "Could not delete %{name}: %{error}",
 | 
					            dgettext("errors", "Could not delete %{name}: %{error}",
 | 
				
			||||||
              name: changeset |> Changeset.get_field(:name, "container"),
 | 
					              name: changeset |> Changeset.get_field(:name, "container"),
 | 
				
			||||||
              error: ammo_groups_error
 | 
					              error: packs_error
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          socket |> put_flash(:error, prompt)
 | 
					          socket |> put_flash(:error, prompt)
 | 
				
			||||||
@@ -82,25 +82,37 @@ defmodule CanneryWeb.ContainerLive.Show do
 | 
				
			|||||||
    {:noreply, socket}
 | 
					    {:noreply, socket}
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def handle_event("toggle_show_used", _params, %{assigns: %{show_used: show_used}} = socket) do
 | 
					 | 
				
			||||||
    {:noreply, socket |> assign(:show_used, !show_used) |> render_container()}
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  def handle_event("toggle_table", _params, %{assigns: %{view_table: view_table}} = socket) do
 | 
					  def handle_event("toggle_table", _params, %{assigns: %{view_table: view_table}} = socket) do
 | 
				
			||||||
    {:noreply, socket |> assign(:view_table, !view_table) |> render_container()}
 | 
					    {:noreply, socket |> assign(:view_table, !view_table) |> render_container()}
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def handle_event("change_class", %{"type" => %{"class" => "rifle"}}, socket) do
 | 
				
			||||||
 | 
					    {:noreply, socket |> assign(:class, :rifle) |> render_container()}
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def handle_event("change_class", %{"type" => %{"class" => "shotgun"}}, socket) do
 | 
				
			||||||
 | 
					    {:noreply, socket |> assign(:class, :shotgun) |> render_container()}
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def handle_event("change_class", %{"type" => %{"class" => "pistol"}}, socket) do
 | 
				
			||||||
 | 
					    {:noreply, socket |> assign(:class, :pistol) |> render_container()}
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def handle_event("change_class", %{"type" => %{"class" => _all}}, socket) do
 | 
				
			||||||
 | 
					    {:noreply, socket |> assign(:class, :all) |> render_container()}
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @spec render_container(Socket.t(), Container.id(), User.t()) :: Socket.t()
 | 
					  @spec render_container(Socket.t(), Container.id(), User.t()) :: Socket.t()
 | 
				
			||||||
  defp render_container(
 | 
					  defp render_container(
 | 
				
			||||||
         %{assigns: %{live_action: live_action, show_used: show_used}} = socket,
 | 
					         %{assigns: %{class: class, live_action: live_action}} = socket,
 | 
				
			||||||
         id,
 | 
					         id,
 | 
				
			||||||
         current_user
 | 
					         current_user
 | 
				
			||||||
       ) do
 | 
					       ) do
 | 
				
			||||||
    %{name: container_name} = container = Containers.get_container!(id, current_user)
 | 
					    %{name: container_name} = container = Containers.get_container!(id, current_user)
 | 
				
			||||||
    ammo_groups = Ammo.list_ammo_groups_for_container(container, current_user, show_used)
 | 
					    packs = Ammo.list_packs_for_container(container, class, current_user)
 | 
				
			||||||
    original_counts = ammo_groups |> Ammo.get_original_counts(current_user)
 | 
					    original_counts = packs |> Ammo.get_original_counts(current_user)
 | 
				
			||||||
    cprs = ammo_groups |> Ammo.get_cprs(current_user)
 | 
					    cprs = packs |> Ammo.get_cprs(current_user)
 | 
				
			||||||
    last_used_dates = ammo_groups |> ActivityLog.get_last_used_dates(current_user)
 | 
					    last_used_dates = packs |> ActivityLog.get_last_used_dates(current_user)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    page_title =
 | 
					    page_title =
 | 
				
			||||||
      case live_action do
 | 
					      case live_action do
 | 
				
			||||||
@@ -113,7 +125,8 @@ defmodule CanneryWeb.ContainerLive.Show do
 | 
				
			|||||||
    |> assign(
 | 
					    |> assign(
 | 
				
			||||||
      container: container,
 | 
					      container: container,
 | 
				
			||||||
      round_count: Ammo.get_round_count_for_container!(container, current_user),
 | 
					      round_count: Ammo.get_round_count_for_container!(container, current_user),
 | 
				
			||||||
      ammo_groups: ammo_groups,
 | 
					      packs_count: Ammo.get_packs_count_for_container!(container, current_user),
 | 
				
			||||||
 | 
					      packs: packs,
 | 
				
			||||||
      original_counts: original_counts,
 | 
					      original_counts: original_counts,
 | 
				
			||||||
      cprs: cprs,
 | 
					      cprs: cprs,
 | 
				
			||||||
      last_used_dates: last_used_dates,
 | 
					      last_used_dates: last_used_dates,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,22 +18,15 @@
 | 
				
			|||||||
    <%= @container.location %>
 | 
					    <%= @container.location %>
 | 
				
			||||||
  </span>
 | 
					  </span>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  <%= unless @ammo_groups |> Enum.empty?() do %>
 | 
					  <span class="rounded-lg title text-lg">
 | 
				
			||||||
    <span class="rounded-lg title text-lg">
 | 
					    <%= gettext("Packs:") %>
 | 
				
			||||||
      <%= gettext("Packs:") %>
 | 
					    <%= @packs_count %>
 | 
				
			||||||
      <%= @ammo_groups |> Enum.reject(fn %{count: count} -> count in [0, nil] end) |> Enum.count() %>
 | 
					  </span>
 | 
				
			||||||
    </span>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <span :if={@show_used} class="rounded-lg title text-lg">
 | 
					  <span class="rounded-lg title text-lg">
 | 
				
			||||||
      <%= gettext("Total packs:") %>
 | 
					    <%= gettext("Rounds:") %>
 | 
				
			||||||
      <%= Enum.count(@ammo_groups) %>
 | 
					    <%= @round_count %>
 | 
				
			||||||
    </span>
 | 
					  </span>
 | 
				
			||||||
 | 
					 | 
				
			||||||
    <span class="rounded-lg title text-lg">
 | 
					 | 
				
			||||||
      <%= gettext("Rounds:") %>
 | 
					 | 
				
			||||||
      <%= @round_count %>
 | 
					 | 
				
			||||||
    </span>
 | 
					 | 
				
			||||||
  <% end %>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  <div class="flex space-x-4 justify-center items-center text-primary-600">
 | 
					  <div class="flex space-x-4 justify-center items-center text-primary-600">
 | 
				
			||||||
    <.link
 | 
					    <.link
 | 
				
			||||||
@@ -93,11 +86,29 @@
 | 
				
			|||||||
  <hr class="mb-4 hr" />
 | 
					  <hr class="mb-4 hr" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  <div class="flex justify-center items-center space-x-4">
 | 
					  <div class="flex justify-center items-center space-x-4">
 | 
				
			||||||
    <.toggle_button action="toggle_show_used" value={@show_used}>
 | 
					    <.form
 | 
				
			||||||
      <span class="title text-lg text-primary-600">
 | 
					      :let={f}
 | 
				
			||||||
        <%= gettext("Show used") %>
 | 
					      for={%{}}
 | 
				
			||||||
      </span>
 | 
					      as={:type}
 | 
				
			||||||
    </.toggle_button>
 | 
					      phx-change="change_class"
 | 
				
			||||||
 | 
					      phx-submit="change_class"
 | 
				
			||||||
 | 
					      class="flex items-center"
 | 
				
			||||||
 | 
					    >
 | 
				
			||||||
 | 
					      <%= label(f, :class, gettext("Class"), class: "title text-primary-600 text-lg text-center") %>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      <%= select(
 | 
				
			||||||
 | 
					        f,
 | 
				
			||||||
 | 
					        :class,
 | 
				
			||||||
 | 
					        [
 | 
				
			||||||
 | 
					          {gettext("All"), :all},
 | 
				
			||||||
 | 
					          {gettext("Rifle"), :rifle},
 | 
				
			||||||
 | 
					          {gettext("Shotgun"), :shotgun},
 | 
				
			||||||
 | 
					          {gettext("Pistol"), :pistol}
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					        class: "mx-2 my-1 min-w-md input input-primary",
 | 
				
			||||||
 | 
					        value: @class
 | 
				
			||||||
 | 
					      ) %>
 | 
				
			||||||
 | 
					    </.form>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <.toggle_button action="toggle_table" value={@view_table}>
 | 
					    <.toggle_button action="toggle_table" value={@view_table}>
 | 
				
			||||||
      <span class="title text-lg text-primary-600">
 | 
					      <span class="title text-lg text-primary-600">
 | 
				
			||||||
@@ -107,33 +118,33 @@
 | 
				
			|||||||
  </div>
 | 
					  </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  <div class="w-full p-4">
 | 
					  <div class="w-full p-4">
 | 
				
			||||||
    <%= if @ammo_groups |> Enum.empty?() do %>
 | 
					    <%= if @packs |> Enum.empty?() do %>
 | 
				
			||||||
      <h2 class="mx-4 title text-lg text-primary-600 text-center">
 | 
					      <h2 class="mx-4 title text-lg text-primary-600 text-center">
 | 
				
			||||||
        <%= gettext("No ammo in this container") %>
 | 
					        <%= gettext("No ammo in this container") %>
 | 
				
			||||||
      </h2>
 | 
					      </h2>
 | 
				
			||||||
    <% else %>
 | 
					    <% else %>
 | 
				
			||||||
      <%= if @view_table do %>
 | 
					      <%= if @view_table do %>
 | 
				
			||||||
        <.live_component
 | 
					        <.live_component
 | 
				
			||||||
          module={CanneryWeb.Components.AmmoGroupTableComponent}
 | 
					          module={CanneryWeb.Components.PackTableComponent}
 | 
				
			||||||
          id="ammo-type-show-table"
 | 
					          id="type-show-table"
 | 
				
			||||||
          ammo_groups={@ammo_groups}
 | 
					          packs={@packs}
 | 
				
			||||||
          current_user={@current_user}
 | 
					          current_user={@current_user}
 | 
				
			||||||
          show_used={@show_used}
 | 
					          show_used={false}
 | 
				
			||||||
        >
 | 
					        >
 | 
				
			||||||
          <:ammo_type :let={%{name: ammo_type_name} = ammo_type}>
 | 
					          <:type :let={%{name: type_name} = type}>
 | 
				
			||||||
            <.link navigate={Routes.ammo_type_show_path(Endpoint, :show, ammo_type)} class="link">
 | 
					            <.link navigate={Routes.type_show_path(Endpoint, :show, type)} class="link">
 | 
				
			||||||
              <%= ammo_type_name %>
 | 
					              <%= type_name %>
 | 
				
			||||||
            </.link>
 | 
					            </.link>
 | 
				
			||||||
          </:ammo_type>
 | 
					          </:type>
 | 
				
			||||||
        </.live_component>
 | 
					        </.live_component>
 | 
				
			||||||
      <% else %>
 | 
					      <% else %>
 | 
				
			||||||
        <div class="flex flex-wrap justify-center items-stretch">
 | 
					        <div class="flex flex-wrap justify-center items-stretch">
 | 
				
			||||||
          <.ammo_group_card
 | 
					          <.pack_card
 | 
				
			||||||
            :for={%{id: ammo_group_id} = ammo_group <- @ammo_groups}
 | 
					            :for={%{id: pack_id} = pack <- @packs}
 | 
				
			||||||
            ammo_group={ammo_group}
 | 
					            pack={pack}
 | 
				
			||||||
            original_count={Map.fetch!(@original_counts, ammo_group_id)}
 | 
					            original_count={Map.fetch!(@original_counts, pack_id)}
 | 
				
			||||||
            cpr={Map.get(@cprs, ammo_group_id)}
 | 
					            cpr={Map.get(@cprs, pack_id)}
 | 
				
			||||||
            last_used_date={Map.get(@last_used_dates, ammo_group_id)}
 | 
					            last_used_date={Map.get(@last_used_dates, pack_id)}
 | 
				
			||||||
            current_user={@current_user}
 | 
					            current_user={@current_user}
 | 
				
			||||||
          />
 | 
					          />
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,7 +18,10 @@
 | 
				
			|||||||
      <%= changeset_errors(@changeset) %>
 | 
					      <%= changeset_errors(@changeset) %>
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <%= label(f, :name, gettext("Name"), class: "title text-lg text-primary-600") %>
 | 
					    <%= label(f, :name, gettext("Name"),
 | 
				
			||||||
 | 
					      class: "title text-lg text-primary-600",
 | 
				
			||||||
 | 
					      maxlength: 255
 | 
				
			||||||
 | 
					    ) %>
 | 
				
			||||||
    <%= text_input(f, :name, class: "input input-primary col-span-2") %>
 | 
					    <%= text_input(f, :name, class: "input input-primary col-span-2") %>
 | 
				
			||||||
    <%= error_tag(f, :name, "col-span-3") %>
 | 
					    <%= error_tag(f, :name, "col-span-3") %>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,38 +1,38 @@
 | 
				
			|||||||
defmodule CanneryWeb.AmmoGroupLive.FormComponent do
 | 
					defmodule CanneryWeb.PackLive.FormComponent do
 | 
				
			||||||
  @moduledoc """
 | 
					  @moduledoc """
 | 
				
			||||||
  Livecomponent that can update or create an Cannery.Ammo.AmmoGroup
 | 
					  Livecomponent that can update or create an Cannery.Ammo.Pack
 | 
				
			||||||
  """
 | 
					  """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  use CanneryWeb, :live_component
 | 
					  use CanneryWeb, :live_component
 | 
				
			||||||
  alias Cannery.Ammo.{AmmoGroup, AmmoType}
 | 
					  alias Cannery.Ammo.{Pack, Type}
 | 
				
			||||||
  alias Cannery.{Accounts.User, Ammo, Containers, Containers.Container}
 | 
					  alias Cannery.{Accounts.User, Ammo, Containers, Containers.Container}
 | 
				
			||||||
  alias Ecto.Changeset
 | 
					  alias Ecto.Changeset
 | 
				
			||||||
  alias Phoenix.LiveView.Socket
 | 
					  alias Phoenix.LiveView.Socket
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @ammo_group_create_limit 10_000
 | 
					  @pack_create_limit 10_000
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @impl true
 | 
					  @impl true
 | 
				
			||||||
  @spec update(
 | 
					  @spec update(
 | 
				
			||||||
          %{:ammo_group => AmmoGroup.t(), :current_user => User.t(), optional(any) => any},
 | 
					          %{:pack => Pack.t(), :current_user => User.t(), optional(any) => any},
 | 
				
			||||||
          Socket.t()
 | 
					          Socket.t()
 | 
				
			||||||
        ) :: {:ok, Socket.t()}
 | 
					        ) :: {:ok, Socket.t()}
 | 
				
			||||||
  def update(%{ammo_group: _ammo_group} = assigns, socket) do
 | 
					  def update(%{pack: _pack} = assigns, socket) do
 | 
				
			||||||
    socket |> assign(assigns) |> update()
 | 
					    socket |> assign(assigns) |> update()
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @spec update(Socket.t()) :: {:ok, Socket.t()}
 | 
					  @spec update(Socket.t()) :: {:ok, Socket.t()}
 | 
				
			||||||
  def update(%{assigns: %{current_user: current_user}} = socket) do
 | 
					  def update(%{assigns: %{current_user: current_user}} = socket) do
 | 
				
			||||||
    %{assigns: %{ammo_types: ammo_types, containers: containers}} =
 | 
					    %{assigns: %{types: types, containers: containers}} =
 | 
				
			||||||
      socket =
 | 
					      socket =
 | 
				
			||||||
      socket
 | 
					      socket
 | 
				
			||||||
      |> assign(:ammo_group_create_limit, @ammo_group_create_limit)
 | 
					      |> assign(:pack_create_limit, @pack_create_limit)
 | 
				
			||||||
      |> assign(:ammo_types, Ammo.list_ammo_types(current_user))
 | 
					      |> assign(:types, Ammo.list_types(current_user, :all))
 | 
				
			||||||
      |> assign_new(:containers, fn -> Containers.list_containers(current_user) end)
 | 
					      |> assign_new(:containers, fn -> Containers.list_containers(current_user) end)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    params =
 | 
					    params =
 | 
				
			||||||
      if ammo_types |> List.first() |> is_nil(),
 | 
					      if types |> List.first() |> is_nil(),
 | 
				
			||||||
        do: %{},
 | 
					        do: %{},
 | 
				
			||||||
        else: %{} |> Map.put("ammo_type_id", ammo_types |> List.first() |> Map.get(:id))
 | 
					        else: %{} |> Map.put("type_id", types |> List.first() |> Map.get(:id))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    params =
 | 
					    params =
 | 
				
			||||||
      if containers |> List.first() |> is_nil(),
 | 
					      if containers |> List.first() |> is_nil(),
 | 
				
			||||||
@@ -43,16 +43,16 @@ defmodule CanneryWeb.AmmoGroupLive.FormComponent do
 | 
				
			|||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @impl true
 | 
					  @impl true
 | 
				
			||||||
  def handle_event("validate", %{"ammo_group" => ammo_group_params}, socket) do
 | 
					  def handle_event("validate", %{"pack" => pack_params}, socket) do
 | 
				
			||||||
    {:noreply, socket |> assign_changeset(ammo_group_params, :validate)}
 | 
					    {:noreply, socket |> assign_changeset(pack_params, :validate)}
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def handle_event(
 | 
					  def handle_event(
 | 
				
			||||||
        "save",
 | 
					        "save",
 | 
				
			||||||
        %{"ammo_group" => ammo_group_params},
 | 
					        %{"pack" => pack_params},
 | 
				
			||||||
        %{assigns: %{action: action}} = socket
 | 
					        %{assigns: %{action: action}} = socket
 | 
				
			||||||
      ) do
 | 
					      ) do
 | 
				
			||||||
    save_ammo_group(socket, action, ammo_group_params)
 | 
					    save_pack(socket, action, pack_params)
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  # HTML Helpers
 | 
					  # HTML Helpers
 | 
				
			||||||
@@ -62,16 +62,16 @@ defmodule CanneryWeb.AmmoGroupLive.FormComponent do
 | 
				
			|||||||
    containers |> Enum.map(fn %{id: id, name: name} -> {name, id} end)
 | 
					    containers |> Enum.map(fn %{id: id, name: name} -> {name, id} end)
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @spec ammo_type_options([AmmoType.t()]) :: [{String.t(), AmmoType.id()}]
 | 
					  @spec type_options([Type.t()]) :: [{String.t(), Type.id()}]
 | 
				
			||||||
  defp ammo_type_options(ammo_types) do
 | 
					  defp type_options(types) do
 | 
				
			||||||
    ammo_types |> Enum.map(fn %{id: id, name: name} -> {name, id} end)
 | 
					    types |> Enum.map(fn %{id: id, name: name} -> {name, id} end)
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  # Save Helpers
 | 
					  # Save Helpers
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  defp assign_changeset(
 | 
					  defp assign_changeset(
 | 
				
			||||||
         %{assigns: %{action: action, ammo_group: ammo_group, current_user: user}} = socket,
 | 
					         %{assigns: %{action: action, pack: pack, current_user: user}} = socket,
 | 
				
			||||||
         ammo_group_params,
 | 
					         pack_params,
 | 
				
			||||||
         changeset_action \\ nil
 | 
					         changeset_action \\ nil
 | 
				
			||||||
       ) do
 | 
					       ) do
 | 
				
			||||||
    default_action =
 | 
					    default_action =
 | 
				
			||||||
@@ -83,12 +83,12 @@ defmodule CanneryWeb.AmmoGroupLive.FormComponent do
 | 
				
			|||||||
    changeset =
 | 
					    changeset =
 | 
				
			||||||
      case default_action do
 | 
					      case default_action do
 | 
				
			||||||
        :insert ->
 | 
					        :insert ->
 | 
				
			||||||
          ammo_type = maybe_get_ammo_type(ammo_group_params, user)
 | 
					          type = maybe_get_type(pack_params, user)
 | 
				
			||||||
          container = maybe_get_container(ammo_group_params, user)
 | 
					          container = maybe_get_container(pack_params, user)
 | 
				
			||||||
          ammo_group |> AmmoGroup.create_changeset(ammo_type, container, user, ammo_group_params)
 | 
					          pack |> Pack.create_changeset(type, container, user, pack_params)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        :update ->
 | 
					        :update ->
 | 
				
			||||||
          ammo_group |> AmmoGroup.update_changeset(ammo_group_params, user)
 | 
					          pack |> Pack.update_changeset(pack_params, user)
 | 
				
			||||||
      end
 | 
					      end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    changeset =
 | 
					    changeset =
 | 
				
			||||||
@@ -107,22 +107,21 @@ defmodule CanneryWeb.AmmoGroupLive.FormComponent do
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  defp maybe_get_container(_params_not_found, _user), do: nil
 | 
					  defp maybe_get_container(_params_not_found, _user), do: nil
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  defp maybe_get_ammo_type(%{"ammo_type_id" => ammo_type_id}, user)
 | 
					  defp maybe_get_type(%{"type_id" => type_id}, user)
 | 
				
			||||||
       when is_binary(ammo_type_id) do
 | 
					       when is_binary(type_id) do
 | 
				
			||||||
    ammo_type_id |> Ammo.get_ammo_type!(user)
 | 
					    type_id |> Ammo.get_type!(user)
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  defp maybe_get_ammo_type(_params_not_found, _user), do: nil
 | 
					  defp maybe_get_type(_params_not_found, _user), do: nil
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  defp save_ammo_group(
 | 
					  defp save_pack(
 | 
				
			||||||
         %{assigns: %{ammo_group: ammo_group, current_user: current_user, return_to: return_to}} =
 | 
					         %{assigns: %{pack: pack, current_user: current_user, return_to: return_to}} = socket,
 | 
				
			||||||
           socket,
 | 
					 | 
				
			||||||
         :edit,
 | 
					         :edit,
 | 
				
			||||||
         ammo_group_params
 | 
					         pack_params
 | 
				
			||||||
       ) do
 | 
					       ) do
 | 
				
			||||||
    socket =
 | 
					    socket =
 | 
				
			||||||
      case Ammo.update_ammo_group(ammo_group, ammo_group_params, current_user) do
 | 
					      case Ammo.update_pack(pack, pack_params, current_user) do
 | 
				
			||||||
        {:ok, _ammo_group} ->
 | 
					        {:ok, _pack} ->
 | 
				
			||||||
          prompt = dgettext("prompts", "Ammo updated successfully")
 | 
					          prompt = dgettext("prompts", "Ammo updated successfully")
 | 
				
			||||||
          socket |> put_flash(:info, prompt) |> push_navigate(to: return_to)
 | 
					          socket |> put_flash(:info, prompt) |> push_navigate(to: return_to)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -133,24 +132,24 @@ defmodule CanneryWeb.AmmoGroupLive.FormComponent do
 | 
				
			|||||||
    {:noreply, socket}
 | 
					    {:noreply, socket}
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  defp save_ammo_group(
 | 
					  defp save_pack(
 | 
				
			||||||
         %{assigns: %{changeset: changeset}} = socket,
 | 
					         %{assigns: %{changeset: changeset}} = socket,
 | 
				
			||||||
         action,
 | 
					         action,
 | 
				
			||||||
         %{"multiplier" => multiplier_str} = ammo_group_params
 | 
					         %{"multiplier" => multiplier_str} = pack_params
 | 
				
			||||||
       )
 | 
					       )
 | 
				
			||||||
       when action in [:new, :clone] do
 | 
					       when action in [:new, :clone] do
 | 
				
			||||||
    socket =
 | 
					    socket =
 | 
				
			||||||
      case multiplier_str |> Integer.parse() do
 | 
					      case multiplier_str |> Integer.parse() do
 | 
				
			||||||
        {multiplier, _remainder}
 | 
					        {multiplier, _remainder}
 | 
				
			||||||
        when multiplier >= 1 and multiplier <= @ammo_group_create_limit ->
 | 
					        when multiplier >= 1 and multiplier <= @pack_create_limit ->
 | 
				
			||||||
          socket |> create_multiple(ammo_group_params, multiplier)
 | 
					          socket |> create_multiple(pack_params, multiplier)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        {multiplier, _remainder} ->
 | 
					        {multiplier, _remainder} ->
 | 
				
			||||||
          error_msg =
 | 
					          error_msg =
 | 
				
			||||||
            dgettext(
 | 
					            dgettext(
 | 
				
			||||||
              "errors",
 | 
					              "errors",
 | 
				
			||||||
              "Invalid number of copies, must be between 1 and %{max}. Was %{multiplier}",
 | 
					              "Invalid number of copies, must be between 1 and %{max}. Was %{multiplier}",
 | 
				
			||||||
              max: @ammo_group_create_limit,
 | 
					              max: @pack_create_limit,
 | 
				
			||||||
              multiplier: multiplier
 | 
					              multiplier: multiplier
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -176,11 +175,11 @@ defmodule CanneryWeb.AmmoGroupLive.FormComponent do
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  defp create_multiple(
 | 
					  defp create_multiple(
 | 
				
			||||||
         %{assigns: %{current_user: current_user, return_to: return_to}} = socket,
 | 
					         %{assigns: %{current_user: current_user, return_to: return_to}} = socket,
 | 
				
			||||||
         ammo_group_params,
 | 
					         pack_params,
 | 
				
			||||||
         multiplier
 | 
					         multiplier
 | 
				
			||||||
       ) do
 | 
					       ) do
 | 
				
			||||||
    case Ammo.create_ammo_groups(ammo_group_params, multiplier, current_user) do
 | 
					    case Ammo.create_packs(pack_params, multiplier, current_user) do
 | 
				
			||||||
      {:ok, {count, _ammo_groups}} ->
 | 
					      {:ok, {count, _packs}} ->
 | 
				
			||||||
        prompt =
 | 
					        prompt =
 | 
				
			||||||
          dngettext(
 | 
					          dngettext(
 | 
				
			||||||
            "prompts",
 | 
					            "prompts",
 | 
				
			||||||
@@ -6,7 +6,7 @@
 | 
				
			|||||||
  <.form
 | 
					  <.form
 | 
				
			||||||
    :let={f}
 | 
					    :let={f}
 | 
				
			||||||
    for={@changeset}
 | 
					    for={@changeset}
 | 
				
			||||||
    id="ammo_group-form"
 | 
					    id="pack-form"
 | 
				
			||||||
    phx-target={@myself}
 | 
					    phx-target={@myself}
 | 
				
			||||||
    phx-change="validate"
 | 
					    phx-change="validate"
 | 
				
			||||||
    phx-submit="save"
 | 
					    phx-submit="save"
 | 
				
			||||||
@@ -19,11 +19,11 @@
 | 
				
			|||||||
      <%= changeset_errors(@changeset) %>
 | 
					      <%= changeset_errors(@changeset) %>
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <%= label(f, :ammo_type_id, gettext("Ammo type"), class: "title text-lg text-primary-600") %>
 | 
					    <%= label(f, :type_id, gettext("Type"), class: "title text-lg text-primary-600") %>
 | 
				
			||||||
    <%= select(f, :ammo_type_id, ammo_type_options(@ammo_types),
 | 
					    <%= select(f, :type_id, type_options(@types),
 | 
				
			||||||
      class: "text-center col-span-2 input input-primary"
 | 
					      class: "text-center col-span-2 input input-primary"
 | 
				
			||||||
    ) %>
 | 
					    ) %>
 | 
				
			||||||
    <%= error_tag(f, :ammo_type_id, "col-span-3 text-center") %>
 | 
					    <%= error_tag(f, :type_id, "col-span-3 text-center") %>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <%= label(f, :count, gettext("Count"), class: "title text-lg text-primary-600") %>
 | 
					    <%= label(f, :count, gettext("Count"), class: "title text-lg text-primary-600") %>
 | 
				
			||||||
    <%= number_input(f, :count,
 | 
					    <%= number_input(f, :count,
 | 
				
			||||||
@@ -39,6 +39,13 @@
 | 
				
			|||||||
    ) %>
 | 
					    ) %>
 | 
				
			||||||
    <%= error_tag(f, :price_paid, "col-span-3 text-center") %>
 | 
					    <%= error_tag(f, :price_paid, "col-span-3 text-center") %>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <%= label(f, :lot_number, gettext("Lot number"), class: "title text-lg text-primary-600") %>
 | 
				
			||||||
 | 
					    <%= text_input(f, :lot_number,
 | 
				
			||||||
 | 
					      class: "text-center col-span-2 input input-primary",
 | 
				
			||||||
 | 
					      maxlength: 255
 | 
				
			||||||
 | 
					    ) %>
 | 
				
			||||||
 | 
					    <%= error_tag(f, :price_paid, "col-span-3 text-center") %>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <%= label(f, :purchased_on, gettext("Purchased on"), class: "title text-lg text-primary-600") %>
 | 
					    <%= label(f, :purchased_on, gettext("Purchased on"), class: "title text-lg text-primary-600") %>
 | 
				
			||||||
    <%= date_input(f, :purchased_on,
 | 
					    <%= date_input(f, :purchased_on,
 | 
				
			||||||
      class: "input input-primary col-span-2",
 | 
					      class: "input input-primary col-span-2",
 | 
				
			||||||
@@ -49,7 +56,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    <%= label(f, :notes, gettext("Notes"), class: "title text-lg text-primary-600") %>
 | 
					    <%= label(f, :notes, gettext("Notes"), class: "title text-lg text-primary-600") %>
 | 
				
			||||||
    <%= textarea(f, :notes,
 | 
					    <%= textarea(f, :notes,
 | 
				
			||||||
      id: "ammo-group-form-notes",
 | 
					      id: "pack-form-notes",
 | 
				
			||||||
      class: "text-center col-span-2 input input-primary",
 | 
					      class: "text-center col-span-2 input input-primary",
 | 
				
			||||||
      phx_hook: "MaintainAttrs",
 | 
					      phx_hook: "MaintainAttrs",
 | 
				
			||||||
      phx_update: "ignore"
 | 
					      phx_update: "ignore"
 | 
				
			||||||
@@ -68,7 +75,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        <%= label(f, :multiplier, gettext("Copies"), class: "title text-lg text-primary-600") %>
 | 
					        <%= label(f, :multiplier, gettext("Copies"), class: "title text-lg text-primary-600") %>
 | 
				
			||||||
        <%= number_input(f, :multiplier,
 | 
					        <%= number_input(f, :multiplier,
 | 
				
			||||||
          max: @ammo_group_create_limit,
 | 
					          max: @pack_create_limit,
 | 
				
			||||||
          class: "text-center input input-primary",
 | 
					          class: "text-center input input-primary",
 | 
				
			||||||
          value: 1,
 | 
					          value: 1,
 | 
				
			||||||
          phx_update: "ignore"
 | 
					          phx_update: "ignore"
 | 
				
			||||||
@@ -1,34 +1,39 @@
 | 
				
			|||||||
defmodule CanneryWeb.AmmoGroupLive.Index do
 | 
					defmodule CanneryWeb.PackLive.Index do
 | 
				
			||||||
  @moduledoc """
 | 
					  @moduledoc """
 | 
				
			||||||
  Liveview to show a Cannery.Ammo.AmmoGroup index
 | 
					  Liveview to show a Cannery.Ammo.Pack index
 | 
				
			||||||
  """
 | 
					  """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  use CanneryWeb, :live_view
 | 
					  use CanneryWeb, :live_view
 | 
				
			||||||
  alias Cannery.{Ammo, Ammo.AmmoGroup, Containers}
 | 
					  alias Cannery.{Ammo, Ammo.Pack, Containers}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @impl true
 | 
					  @impl true
 | 
				
			||||||
  def mount(%{"search" => search}, _session, socket) do
 | 
					  def mount(%{"search" => search}, _session, socket) do
 | 
				
			||||||
    {:ok, socket |> assign(show_used: false, search: search) |> display_ammo_groups()}
 | 
					    socket =
 | 
				
			||||||
 | 
					      socket
 | 
				
			||||||
 | 
					      |> assign(class: :all, show_used: false, search: search)
 | 
				
			||||||
 | 
					      |> display_packs()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    {:ok, socket}
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def mount(_params, _session, socket) do
 | 
					  def mount(_params, _session, socket) do
 | 
				
			||||||
    {:ok, socket |> assign(show_used: false, search: nil) |> display_ammo_groups()}
 | 
					    {:ok, socket |> assign(class: :all, show_used: false, search: nil) |> display_packs()}
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @impl true
 | 
					  @impl true
 | 
				
			||||||
  def handle_params(params, _url, %{assigns: %{live_action: live_action}} = socket) do
 | 
					  def handle_params(params, _url, %{assigns: %{live_action: live_action}} = socket) do
 | 
				
			||||||
    {:noreply, apply_action(socket, live_action, params) |> display_ammo_groups()}
 | 
					    {:noreply, apply_action(socket, live_action, params) |> display_packs()}
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  defp apply_action(
 | 
					  defp apply_action(
 | 
				
			||||||
         %{assigns: %{current_user: current_user}} = socket,
 | 
					         %{assigns: %{current_user: current_user}} = socket,
 | 
				
			||||||
         :add_shot_group,
 | 
					         :add_shot_record,
 | 
				
			||||||
         %{"id" => id}
 | 
					         %{"id" => id}
 | 
				
			||||||
       ) do
 | 
					       ) do
 | 
				
			||||||
    socket
 | 
					    socket
 | 
				
			||||||
    |> assign(
 | 
					    |> assign(
 | 
				
			||||||
      page_title: gettext("Record shots"),
 | 
					      page_title: gettext("Record shots"),
 | 
				
			||||||
      ammo_group: Ammo.get_ammo_group!(id, current_user)
 | 
					      pack: Ammo.get_pack!(id, current_user)
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -36,7 +41,7 @@ defmodule CanneryWeb.AmmoGroupLive.Index do
 | 
				
			|||||||
    socket
 | 
					    socket
 | 
				
			||||||
    |> assign(
 | 
					    |> assign(
 | 
				
			||||||
      page_title: gettext("Move ammo"),
 | 
					      page_title: gettext("Move ammo"),
 | 
				
			||||||
      ammo_group: Ammo.get_ammo_group!(id, current_user)
 | 
					      pack: Ammo.get_pack!(id, current_user)
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -44,7 +49,7 @@ defmodule CanneryWeb.AmmoGroupLive.Index do
 | 
				
			|||||||
    socket
 | 
					    socket
 | 
				
			||||||
    |> assign(
 | 
					    |> assign(
 | 
				
			||||||
      page_title: gettext("Edit ammo"),
 | 
					      page_title: gettext("Edit ammo"),
 | 
				
			||||||
      ammo_group: Ammo.get_ammo_group!(id, current_user)
 | 
					      pack: Ammo.get_pack!(id, current_user)
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -52,7 +57,7 @@ defmodule CanneryWeb.AmmoGroupLive.Index do
 | 
				
			|||||||
    socket
 | 
					    socket
 | 
				
			||||||
    |> assign(
 | 
					    |> assign(
 | 
				
			||||||
      page_title: dgettext("actions", "Add Ammo"),
 | 
					      page_title: dgettext("actions", "Add Ammo"),
 | 
				
			||||||
      ammo_group: %{Ammo.get_ammo_group!(id, current_user) | id: nil}
 | 
					      pack: %{Ammo.get_pack!(id, current_user) | id: nil}
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -60,7 +65,7 @@ defmodule CanneryWeb.AmmoGroupLive.Index do
 | 
				
			|||||||
    socket
 | 
					    socket
 | 
				
			||||||
    |> assign(
 | 
					    |> assign(
 | 
				
			||||||
      page_title: dgettext("actions", "Add Ammo"),
 | 
					      page_title: dgettext("actions", "Add Ammo"),
 | 
				
			||||||
      ammo_group: %AmmoGroup{}
 | 
					      pack: %Pack{}
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -69,7 +74,7 @@ defmodule CanneryWeb.AmmoGroupLive.Index do
 | 
				
			|||||||
    |> assign(
 | 
					    |> assign(
 | 
				
			||||||
      page_title: gettext("Ammo"),
 | 
					      page_title: gettext("Ammo"),
 | 
				
			||||||
      search: nil,
 | 
					      search: nil,
 | 
				
			||||||
      ammo_group: nil
 | 
					      pack: nil
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -78,59 +83,84 @@ defmodule CanneryWeb.AmmoGroupLive.Index do
 | 
				
			|||||||
    |> assign(
 | 
					    |> assign(
 | 
				
			||||||
      page_title: gettext("Ammo"),
 | 
					      page_title: gettext("Ammo"),
 | 
				
			||||||
      search: search,
 | 
					      search: search,
 | 
				
			||||||
      ammo_group: nil
 | 
					      pack: nil
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @impl true
 | 
					  @impl true
 | 
				
			||||||
  def handle_event("delete", %{"id" => id}, %{assigns: %{current_user: current_user}} = socket) do
 | 
					  def handle_event("delete", %{"id" => id}, %{assigns: %{current_user: current_user}} = socket) do
 | 
				
			||||||
    Ammo.get_ammo_group!(id, current_user) |> Ammo.delete_ammo_group!(current_user)
 | 
					    Ammo.get_pack!(id, current_user) |> Ammo.delete_pack!(current_user)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    prompt = dgettext("prompts", "Ammo deleted succesfully")
 | 
					    prompt = dgettext("prompts", "Ammo deleted succesfully")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    {:noreply, socket |> put_flash(:info, prompt) |> display_ammo_groups()}
 | 
					    {:noreply, socket |> put_flash(:info, prompt) |> display_packs()}
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def handle_event(
 | 
					  def handle_event(
 | 
				
			||||||
        "toggle_staged",
 | 
					        "toggle_staged",
 | 
				
			||||||
        %{"ammo_group_id" => id},
 | 
					        %{"pack_id" => id},
 | 
				
			||||||
        %{assigns: %{current_user: current_user}} = socket
 | 
					        %{assigns: %{current_user: current_user}} = socket
 | 
				
			||||||
      ) do
 | 
					      ) do
 | 
				
			||||||
    ammo_group = Ammo.get_ammo_group!(id, current_user)
 | 
					    pack = Ammo.get_pack!(id, current_user)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    {:ok, _ammo_group} =
 | 
					    {:ok, _pack} = pack |> Ammo.update_pack(%{"staged" => !pack.staged}, current_user)
 | 
				
			||||||
      ammo_group |> Ammo.update_ammo_group(%{"staged" => !ammo_group.staged}, current_user)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    {:noreply, socket |> display_ammo_groups()}
 | 
					    {:noreply, socket |> display_packs()}
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def handle_event("toggle_show_used", _params, %{assigns: %{show_used: show_used}} = socket) do
 | 
					  def handle_event("toggle_show_used", _params, %{assigns: %{show_used: show_used}} = socket) do
 | 
				
			||||||
    {:noreply, socket |> assign(:show_used, !show_used) |> display_ammo_groups()}
 | 
					    {:noreply, socket |> assign(:show_used, !show_used) |> display_packs()}
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def handle_event("search", %{"search" => %{"search_term" => ""}}, socket) do
 | 
					  def handle_event("search", %{"search" => %{"search_term" => ""}}, socket) do
 | 
				
			||||||
    {:noreply, socket |> push_patch(to: Routes.ammo_group_index_path(Endpoint, :index))}
 | 
					    {:noreply, socket |> push_patch(to: Routes.pack_index_path(Endpoint, :index))}
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def handle_event("search", %{"search" => %{"search_term" => search_term}}, socket) do
 | 
					  def handle_event("search", %{"search" => %{"search_term" => search_term}}, socket) do
 | 
				
			||||||
    socket =
 | 
					    socket = socket |> push_patch(to: Routes.pack_index_path(Endpoint, :search, search_term))
 | 
				
			||||||
      socket |> push_patch(to: Routes.ammo_group_index_path(Endpoint, :search, search_term))
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    {:noreply, socket}
 | 
					    {:noreply, socket}
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  defp display_ammo_groups(
 | 
					  def handle_event("change_class", %{"type" => %{"class" => "rifle"}}, socket) do
 | 
				
			||||||
         %{assigns: %{search: search, current_user: current_user, show_used: show_used}} = socket
 | 
					    {:noreply, socket |> assign(:class, :rifle) |> display_packs()}
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def handle_event("change_class", %{"type" => %{"class" => "shotgun"}}, socket) do
 | 
				
			||||||
 | 
					    {:noreply, socket |> assign(:class, :shotgun) |> display_packs()}
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def handle_event("change_class", %{"type" => %{"class" => "pistol"}}, socket) do
 | 
				
			||||||
 | 
					    {:noreply, socket |> assign(:class, :pistol) |> display_packs()}
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def handle_event("change_class", %{"type" => %{"class" => _all}}, socket) do
 | 
				
			||||||
 | 
					    {:noreply, socket |> assign(:class, :all) |> display_packs()}
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  defp display_packs(
 | 
				
			||||||
 | 
					         %{
 | 
				
			||||||
 | 
					           assigns: %{
 | 
				
			||||||
 | 
					             class: class,
 | 
				
			||||||
 | 
					             search: search,
 | 
				
			||||||
 | 
					             current_user: current_user,
 | 
				
			||||||
 | 
					             show_used: show_used
 | 
				
			||||||
 | 
					           }
 | 
				
			||||||
 | 
					         } = socket
 | 
				
			||||||
       ) do
 | 
					       ) do
 | 
				
			||||||
    ammo_groups = Ammo.list_ammo_groups(search, show_used, current_user)
 | 
					    # get total number of packs to determine whether to display onboarding
 | 
				
			||||||
    ammo_types_count = Ammo.get_ammo_types_count!(current_user)
 | 
					    # prompts
 | 
				
			||||||
 | 
					    packs_count = Ammo.get_packs_count!(current_user, true)
 | 
				
			||||||
 | 
					    packs = Ammo.list_packs(search, class, current_user, show_used)
 | 
				
			||||||
 | 
					    types_count = Ammo.get_types_count!(current_user)
 | 
				
			||||||
    containers_count = Containers.get_containers_count!(current_user)
 | 
					    containers_count = Containers.get_containers_count!(current_user)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    socket
 | 
					    socket
 | 
				
			||||||
    |> assign(
 | 
					    |> assign(
 | 
				
			||||||
      ammo_groups: ammo_groups,
 | 
					      packs: packs,
 | 
				
			||||||
      ammo_types_count: ammo_types_count,
 | 
					      types_count: types_count,
 | 
				
			||||||
      containers_count: containers_count
 | 
					      containers_count: containers_count,
 | 
				
			||||||
 | 
					      packs_count: packs_count
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
							
								
								
									
										241
									
								
								lib/cannery_web/live/pack_live/index.html.heex
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										241
									
								
								lib/cannery_web/live/pack_live/index.html.heex
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,241 @@
 | 
				
			|||||||
 | 
					<div class="flex flex-col space-y-8 justify-center items-center">
 | 
				
			||||||
 | 
					  <h1 class="title text-2xl title-primary-500">
 | 
				
			||||||
 | 
					    <%= gettext("Ammo") %>
 | 
				
			||||||
 | 
					  </h1>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  <%= cond do %>
 | 
				
			||||||
 | 
					    <% @containers_count == 0 -> %>
 | 
				
			||||||
 | 
					      <div class="flex justify-center items-center">
 | 
				
			||||||
 | 
					        <h2 class="m-2 title text-md text-primary-600">
 | 
				
			||||||
 | 
					          <%= dgettext("prompts", "You'll need to") %>
 | 
				
			||||||
 | 
					        </h2>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <.link navigate={Routes.container_index_path(Endpoint, :new)} class="btn btn-primary">
 | 
				
			||||||
 | 
					          <%= dgettext("actions", "add a container first") %>
 | 
				
			||||||
 | 
					        </.link>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					    <% @types_count == 0 -> %>
 | 
				
			||||||
 | 
					      <div class="flex justify-center items-center">
 | 
				
			||||||
 | 
					        <h2 class="m-2 title text-md text-primary-600">
 | 
				
			||||||
 | 
					          <%= dgettext("prompts", "You'll need to") %>
 | 
				
			||||||
 | 
					        </h2>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <.link navigate={Routes.type_index_path(Endpoint, :new)} class="btn btn-primary">
 | 
				
			||||||
 | 
					          <%= dgettext("actions", "add a type first") %>
 | 
				
			||||||
 | 
					        </.link>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					    <% @packs_count == 0 -> %>
 | 
				
			||||||
 | 
					      <h2 class="title text-xl text-primary-600">
 | 
				
			||||||
 | 
					        <%= gettext("No ammo") %>
 | 
				
			||||||
 | 
					        <%= display_emoji("😔") %>
 | 
				
			||||||
 | 
					      </h2>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      <.link patch={Routes.pack_index_path(Endpoint, :new)} class="btn btn-primary">
 | 
				
			||||||
 | 
					        <%= dgettext("actions", "Add your first box!") %>
 | 
				
			||||||
 | 
					      </.link>
 | 
				
			||||||
 | 
					    <% true -> %>
 | 
				
			||||||
 | 
					      <.link patch={Routes.pack_index_path(Endpoint, :new)} class="btn btn-primary">
 | 
				
			||||||
 | 
					        <%= dgettext("actions", "Add Ammo") %>
 | 
				
			||||||
 | 
					      </.link>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      <div class="w-full flex flex-col sm:flex-row justify-center items-center space-y-4 sm:space-y-0 sm:space-x-4 max-w-2xl">
 | 
				
			||||||
 | 
					        <.form
 | 
				
			||||||
 | 
					          :let={f}
 | 
				
			||||||
 | 
					          for={%{}}
 | 
				
			||||||
 | 
					          as={:type}
 | 
				
			||||||
 | 
					          phx-change="change_class"
 | 
				
			||||||
 | 
					          phx-submit="change_class"
 | 
				
			||||||
 | 
					          class="flex items-center"
 | 
				
			||||||
 | 
					        >
 | 
				
			||||||
 | 
					          <%= label(f, :class, gettext("Class"),
 | 
				
			||||||
 | 
					            class: "title text-primary-600 text-lg text-center"
 | 
				
			||||||
 | 
					          ) %>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          <%= select(
 | 
				
			||||||
 | 
					            f,
 | 
				
			||||||
 | 
					            :class,
 | 
				
			||||||
 | 
					            [
 | 
				
			||||||
 | 
					              {gettext("All"), :all},
 | 
				
			||||||
 | 
					              {gettext("Rifle"), :rifle},
 | 
				
			||||||
 | 
					              {gettext("Shotgun"), :shotgun},
 | 
				
			||||||
 | 
					              {gettext("Pistol"), :pistol}
 | 
				
			||||||
 | 
					            ],
 | 
				
			||||||
 | 
					            class: "mx-2 my-1 min-w-md input input-primary",
 | 
				
			||||||
 | 
					            value: @class
 | 
				
			||||||
 | 
					          ) %>
 | 
				
			||||||
 | 
					        </.form>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <.form
 | 
				
			||||||
 | 
					          :let={f}
 | 
				
			||||||
 | 
					          for={%{}}
 | 
				
			||||||
 | 
					          as={:search}
 | 
				
			||||||
 | 
					          phx-change="search"
 | 
				
			||||||
 | 
					          phx-submit="search"
 | 
				
			||||||
 | 
					          class="grow flex items-center"
 | 
				
			||||||
 | 
					        >
 | 
				
			||||||
 | 
					          <%= text_input(f, :search_term,
 | 
				
			||||||
 | 
					            class: "grow input input-primary",
 | 
				
			||||||
 | 
					            value: @search,
 | 
				
			||||||
 | 
					            role: "search",
 | 
				
			||||||
 | 
					            phx_debounce: 300,
 | 
				
			||||||
 | 
					            placeholder: gettext("Search ammo")
 | 
				
			||||||
 | 
					          ) %>
 | 
				
			||||||
 | 
					        </.form>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <.toggle_button action="toggle_show_used" value={@show_used}>
 | 
				
			||||||
 | 
					          <span class="title text-lg text-primary-600">
 | 
				
			||||||
 | 
					            <%= gettext("Show used") %>
 | 
				
			||||||
 | 
					          </span>
 | 
				
			||||||
 | 
					        </.toggle_button>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      <%= if @packs |> Enum.empty?() do %>
 | 
				
			||||||
 | 
					        <h2 class="title text-xl text-primary-600">
 | 
				
			||||||
 | 
					          <%= gettext("No Ammo") %>
 | 
				
			||||||
 | 
					          <%= display_emoji("😔") %>
 | 
				
			||||||
 | 
					        </h2>
 | 
				
			||||||
 | 
					      <% else %>
 | 
				
			||||||
 | 
					        <.live_component
 | 
				
			||||||
 | 
					          module={CanneryWeb.Components.PackTableComponent}
 | 
				
			||||||
 | 
					          id="pack-index-table"
 | 
				
			||||||
 | 
					          packs={@packs}
 | 
				
			||||||
 | 
					          current_user={@current_user}
 | 
				
			||||||
 | 
					          show_used={@show_used}
 | 
				
			||||||
 | 
					        >
 | 
				
			||||||
 | 
					          <:type :let={%{name: type_name} = type}>
 | 
				
			||||||
 | 
					            <.link navigate={Routes.type_show_path(Endpoint, :show, type)} class="link">
 | 
				
			||||||
 | 
					              <%= type_name %>
 | 
				
			||||||
 | 
					            </.link>
 | 
				
			||||||
 | 
					          </:type>
 | 
				
			||||||
 | 
					          <:range :let={pack}>
 | 
				
			||||||
 | 
					            <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-pack_id={pack.id}
 | 
				
			||||||
 | 
					              >
 | 
				
			||||||
 | 
					                <%= if pack.staged,
 | 
				
			||||||
 | 
					                  do: dgettext("actions", "Unstage"),
 | 
				
			||||||
 | 
					                  else: dgettext("actions", "Stage") %>
 | 
				
			||||||
 | 
					              </button>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					              <.link
 | 
				
			||||||
 | 
					                patch={Routes.pack_index_path(Endpoint, :add_shot_record, pack)}
 | 
				
			||||||
 | 
					                class="mx-2 my-1 text-sm btn btn-primary"
 | 
				
			||||||
 | 
					              >
 | 
				
			||||||
 | 
					                <%= dgettext("actions", "Record shots") %>
 | 
				
			||||||
 | 
					              </.link>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					          </:range>
 | 
				
			||||||
 | 
					          <:container :let={{pack, %{name: container_name} = container}}>
 | 
				
			||||||
 | 
					            <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.pack_index_path(Endpoint, :move, pack)}
 | 
				
			||||||
 | 
					                class="mx-2 my-1 text-sm btn btn-primary"
 | 
				
			||||||
 | 
					              >
 | 
				
			||||||
 | 
					                <%= dgettext("actions", "Move ammo") %>
 | 
				
			||||||
 | 
					              </.link>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					          </:container>
 | 
				
			||||||
 | 
					          <:actions :let={%{count: pack_count} = pack}>
 | 
				
			||||||
 | 
					            <div class="py-2 px-4 h-full space-x-4 flex justify-center items-center">
 | 
				
			||||||
 | 
					              <.link
 | 
				
			||||||
 | 
					                navigate={Routes.pack_show_path(Endpoint, :show, pack)}
 | 
				
			||||||
 | 
					                class="text-primary-600 link"
 | 
				
			||||||
 | 
					                aria-label={
 | 
				
			||||||
 | 
					                  dgettext("actions", "View pack of %{pack_count} bullets", pack_count: pack_count)
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					              >
 | 
				
			||||||
 | 
					                <i class="fa-fw fa-lg fas fa-eye"></i>
 | 
				
			||||||
 | 
					              </.link>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					              <.link
 | 
				
			||||||
 | 
					                patch={Routes.pack_index_path(Endpoint, :edit, pack)}
 | 
				
			||||||
 | 
					                class="text-primary-600 link"
 | 
				
			||||||
 | 
					                aria-label={
 | 
				
			||||||
 | 
					                  dgettext("actions", "Edit pack of %{pack_count} bullets", pack_count: pack_count)
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					              >
 | 
				
			||||||
 | 
					                <i class="fa-fw fa-lg fas fa-edit"></i>
 | 
				
			||||||
 | 
					              </.link>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					              <.link
 | 
				
			||||||
 | 
					                patch={Routes.pack_index_path(Endpoint, :clone, pack)}
 | 
				
			||||||
 | 
					                class="text-primary-600 link"
 | 
				
			||||||
 | 
					                aria-label={
 | 
				
			||||||
 | 
					                  dgettext("actions", "Clone pack of %{pack_count} bullets",
 | 
				
			||||||
 | 
					                    pack_count: pack_count
 | 
				
			||||||
 | 
					                  )
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					              >
 | 
				
			||||||
 | 
					                <i class="fa-fw fa-lg fas fa-copy"></i>
 | 
				
			||||||
 | 
					              </.link>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					              <.link
 | 
				
			||||||
 | 
					                href="#"
 | 
				
			||||||
 | 
					                class="text-primary-600 link"
 | 
				
			||||||
 | 
					                phx-click="delete"
 | 
				
			||||||
 | 
					                phx-value-id={pack.id}
 | 
				
			||||||
 | 
					                data-confirm={dgettext("prompts", "Are you sure you want to delete this ammo?")}
 | 
				
			||||||
 | 
					                aria-label={
 | 
				
			||||||
 | 
					                  dgettext("actions", "Delete pack of %{pack_count} bullets",
 | 
				
			||||||
 | 
					                    pack_count: pack_count
 | 
				
			||||||
 | 
					                  )
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					              >
 | 
				
			||||||
 | 
					                <i class="fa-fw fa-lg fas fa-trash"></i>
 | 
				
			||||||
 | 
					              </.link>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					          </:actions>
 | 
				
			||||||
 | 
					        </.live_component>
 | 
				
			||||||
 | 
					      <% end %>
 | 
				
			||||||
 | 
					  <% end %>
 | 
				
			||||||
 | 
					</div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<%= case @live_action do %>
 | 
				
			||||||
 | 
					  <% create when create in [:new, :edit, :clone] -> %>
 | 
				
			||||||
 | 
					    <.modal return_to={Routes.pack_index_path(Endpoint, :index)}>
 | 
				
			||||||
 | 
					      <.live_component
 | 
				
			||||||
 | 
					        module={CanneryWeb.PackLive.FormComponent}
 | 
				
			||||||
 | 
					        id={@pack.id || :new}
 | 
				
			||||||
 | 
					        title={@page_title}
 | 
				
			||||||
 | 
					        action={@live_action}
 | 
				
			||||||
 | 
					        pack={@pack}
 | 
				
			||||||
 | 
					        return_to={Routes.pack_index_path(Endpoint, :index)}
 | 
				
			||||||
 | 
					        current_user={@current_user}
 | 
				
			||||||
 | 
					      />
 | 
				
			||||||
 | 
					    </.modal>
 | 
				
			||||||
 | 
					  <% :add_shot_record -> %>
 | 
				
			||||||
 | 
					    <.modal return_to={Routes.pack_index_path(Endpoint, :index)}>
 | 
				
			||||||
 | 
					      <.live_component
 | 
				
			||||||
 | 
					        module={CanneryWeb.Components.AddShotRecordComponent}
 | 
				
			||||||
 | 
					        id={:new}
 | 
				
			||||||
 | 
					        title={@page_title}
 | 
				
			||||||
 | 
					        action={@live_action}
 | 
				
			||||||
 | 
					        pack={@pack}
 | 
				
			||||||
 | 
					        return_to={Routes.pack_index_path(Endpoint, :index)}
 | 
				
			||||||
 | 
					        current_user={@current_user}
 | 
				
			||||||
 | 
					      />
 | 
				
			||||||
 | 
					    </.modal>
 | 
				
			||||||
 | 
					  <% :move -> %>
 | 
				
			||||||
 | 
					    <.modal return_to={Routes.pack_index_path(Endpoint, :index)}>
 | 
				
			||||||
 | 
					      <.live_component
 | 
				
			||||||
 | 
					        module={CanneryWeb.Components.MovePackComponent}
 | 
				
			||||||
 | 
					        id={@pack.id}
 | 
				
			||||||
 | 
					        title={@page_title}
 | 
				
			||||||
 | 
					        action={@live_action}
 | 
				
			||||||
 | 
					        pack={@pack}
 | 
				
			||||||
 | 
					        return_to={Routes.pack_index_path(Endpoint, :index)}
 | 
				
			||||||
 | 
					        current_user={@current_user}
 | 
				
			||||||
 | 
					      />
 | 
				
			||||||
 | 
					    </.modal>
 | 
				
			||||||
 | 
					  <% _ -> %>
 | 
				
			||||||
 | 
					<% end %>
 | 
				
			||||||
@@ -1,11 +1,11 @@
 | 
				
			|||||||
defmodule CanneryWeb.AmmoGroupLive.Show do
 | 
					defmodule CanneryWeb.PackLive.Show do
 | 
				
			||||||
  @moduledoc """
 | 
					  @moduledoc """
 | 
				
			||||||
  Liveview for showing and editing an Cannery.Ammo.AmmoGroup
 | 
					  Liveview for showing and editing an Cannery.Ammo.Pack
 | 
				
			||||||
  """
 | 
					  """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  use CanneryWeb, :live_view
 | 
					  use CanneryWeb, :live_view
 | 
				
			||||||
  alias Cannery.{ActivityLog, ActivityLog.ShotGroup}
 | 
					  alias Cannery.{ActivityLog, ActivityLog.ShotRecord}
 | 
				
			||||||
  alias Cannery.{Ammo, Ammo.AmmoGroup}
 | 
					  alias Cannery.{Ammo, Ammo.Pack}
 | 
				
			||||||
  alias Cannery.{ComparableDate, Containers}
 | 
					  alias Cannery.{ComparableDate, Containers}
 | 
				
			||||||
  alias CanneryWeb.Endpoint
 | 
					  alias CanneryWeb.Endpoint
 | 
				
			||||||
  alias Phoenix.LiveView.Socket
 | 
					  alias Phoenix.LiveView.Socket
 | 
				
			||||||
@@ -15,16 +15,16 @@ defmodule CanneryWeb.AmmoGroupLive.Show do
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  @impl true
 | 
					  @impl true
 | 
				
			||||||
  def handle_params(
 | 
					  def handle_params(
 | 
				
			||||||
        %{"id" => id, "shot_group_id" => shot_group_id},
 | 
					        %{"id" => id, "shot_record_id" => shot_record_id},
 | 
				
			||||||
        _url,
 | 
					        _url,
 | 
				
			||||||
        %{assigns: %{live_action: live_action, current_user: current_user}} = socket
 | 
					        %{assigns: %{live_action: live_action, current_user: current_user}} = socket
 | 
				
			||||||
      ) do
 | 
					      ) do
 | 
				
			||||||
    shot_group = ActivityLog.get_shot_group!(shot_group_id, current_user)
 | 
					    shot_record = ActivityLog.get_shot_record!(shot_record_id, current_user)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    socket =
 | 
					    socket =
 | 
				
			||||||
      socket
 | 
					      socket
 | 
				
			||||||
      |> assign(page_title: page_title(live_action), shot_group: shot_group)
 | 
					      |> assign(page_title: page_title(live_action), shot_record: shot_record)
 | 
				
			||||||
      |> display_ammo_group(id)
 | 
					      |> display_pack(id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    {:noreply, socket}
 | 
					    {:noreply, socket}
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
@@ -33,13 +33,13 @@ defmodule CanneryWeb.AmmoGroupLive.Show do
 | 
				
			|||||||
    socket =
 | 
					    socket =
 | 
				
			||||||
      socket
 | 
					      socket
 | 
				
			||||||
      |> assign(page_title: page_title(live_action))
 | 
					      |> assign(page_title: page_title(live_action))
 | 
				
			||||||
      |> display_ammo_group(id)
 | 
					      |> display_pack(id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    {:noreply, socket}
 | 
					    {:noreply, socket}
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  defp page_title(:add_shot_group), do: gettext("Record Shots")
 | 
					  defp page_title(:add_shot_record), do: gettext("Record Shots")
 | 
				
			||||||
  defp page_title(:edit_shot_group), do: gettext("Edit Shot Records")
 | 
					  defp page_title(:edit_shot_record), do: gettext("Edit Shot Record")
 | 
				
			||||||
  defp page_title(:move), do: gettext("Move Ammo")
 | 
					  defp page_title(:move), do: gettext("Move Ammo")
 | 
				
			||||||
  defp page_title(:show), do: gettext("Show Ammo")
 | 
					  defp page_title(:show), do: gettext("Show Ammo")
 | 
				
			||||||
  defp page_title(:edit), do: gettext("Edit Ammo")
 | 
					  defp page_title(:edit), do: gettext("Edit Ammo")
 | 
				
			||||||
@@ -48,12 +48,12 @@ defmodule CanneryWeb.AmmoGroupLive.Show do
 | 
				
			|||||||
  def handle_event(
 | 
					  def handle_event(
 | 
				
			||||||
        "delete",
 | 
					        "delete",
 | 
				
			||||||
        _params,
 | 
					        _params,
 | 
				
			||||||
        %{assigns: %{ammo_group: ammo_group, current_user: current_user}} = socket
 | 
					        %{assigns: %{pack: pack, current_user: current_user}} = socket
 | 
				
			||||||
      ) do
 | 
					      ) do
 | 
				
			||||||
    ammo_group |> Ammo.delete_ammo_group!(current_user)
 | 
					    pack |> Ammo.delete_pack!(current_user)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    prompt = dgettext("prompts", "Ammo deleted succesfully")
 | 
					    prompt = dgettext("prompts", "Ammo deleted succesfully")
 | 
				
			||||||
    redirect_to = Routes.ammo_group_index_path(socket, :index)
 | 
					    redirect_to = Routes.pack_index_path(socket, :index)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    {:noreply, socket |> put_flash(:info, prompt) |> push_navigate(to: redirect_to)}
 | 
					    {:noreply, socket |> put_flash(:info, prompt) |> push_navigate(to: redirect_to)}
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
@@ -61,31 +61,30 @@ defmodule CanneryWeb.AmmoGroupLive.Show do
 | 
				
			|||||||
  def handle_event(
 | 
					  def handle_event(
 | 
				
			||||||
        "toggle_staged",
 | 
					        "toggle_staged",
 | 
				
			||||||
        _params,
 | 
					        _params,
 | 
				
			||||||
        %{assigns: %{ammo_group: ammo_group, current_user: current_user}} = socket
 | 
					        %{assigns: %{pack: pack, current_user: current_user}} = socket
 | 
				
			||||||
      ) do
 | 
					      ) do
 | 
				
			||||||
    {:ok, ammo_group} =
 | 
					    {:ok, pack} = pack |> Ammo.update_pack(%{"staged" => !pack.staged}, current_user)
 | 
				
			||||||
      ammo_group |> Ammo.update_ammo_group(%{"staged" => !ammo_group.staged}, current_user)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    {:noreply, socket |> display_ammo_group(ammo_group)}
 | 
					    {:noreply, socket |> display_pack(pack)}
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def handle_event(
 | 
					  def handle_event(
 | 
				
			||||||
        "delete_shot_group",
 | 
					        "delete_shot_record",
 | 
				
			||||||
        %{"id" => id},
 | 
					        %{"id" => id},
 | 
				
			||||||
        %{assigns: %{ammo_group: %{id: ammo_group_id}, current_user: current_user}} = socket
 | 
					        %{assigns: %{pack: %{id: pack_id}, current_user: current_user}} = socket
 | 
				
			||||||
      ) do
 | 
					      ) do
 | 
				
			||||||
    {:ok, _} =
 | 
					    {:ok, _} =
 | 
				
			||||||
      ActivityLog.get_shot_group!(id, current_user)
 | 
					      ActivityLog.get_shot_record!(id, current_user)
 | 
				
			||||||
      |> ActivityLog.delete_shot_group(current_user)
 | 
					      |> ActivityLog.delete_shot_record(current_user)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    prompt = dgettext("prompts", "Shot records deleted succesfully")
 | 
					    prompt = dgettext("prompts", "Shot records deleted succesfully")
 | 
				
			||||||
    {:noreply, socket |> put_flash(:info, prompt) |> display_ammo_group(ammo_group_id)}
 | 
					    {:noreply, socket |> put_flash(:info, prompt) |> display_pack(pack_id)}
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @spec display_ammo_group(Socket.t(), AmmoGroup.t() | AmmoGroup.id()) :: Socket.t()
 | 
					  @spec display_pack(Socket.t(), Pack.t() | Pack.id()) :: Socket.t()
 | 
				
			||||||
  defp display_ammo_group(
 | 
					  defp display_pack(
 | 
				
			||||||
         %{assigns: %{current_user: current_user}} = socket,
 | 
					         %{assigns: %{current_user: current_user}} = socket,
 | 
				
			||||||
         %AmmoGroup{container_id: container_id} = ammo_group
 | 
					         %Pack{container_id: container_id} = pack
 | 
				
			||||||
       ) do
 | 
					       ) do
 | 
				
			||||||
    columns = [
 | 
					    columns = [
 | 
				
			||||||
      %{label: gettext("Rounds shot"), key: :count},
 | 
					      %{label: gettext("Rounds shot"), key: :count},
 | 
				
			||||||
@@ -94,35 +93,35 @@ defmodule CanneryWeb.AmmoGroupLive.Show do
 | 
				
			|||||||
      %{label: gettext("Actions"), key: :actions, sortable: false}
 | 
					      %{label: gettext("Actions"), key: :actions, sortable: false}
 | 
				
			||||||
    ]
 | 
					    ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    shot_groups = ActivityLog.list_shot_groups_for_ammo_group(ammo_group, current_user)
 | 
					    shot_records = ActivityLog.list_shot_records_for_pack(pack, current_user)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    rows =
 | 
					    rows =
 | 
				
			||||||
      shot_groups
 | 
					      shot_records
 | 
				
			||||||
      |> Enum.map(fn shot_group ->
 | 
					      |> Enum.map(fn shot_record ->
 | 
				
			||||||
        ammo_group |> get_table_row_for_shot_group(shot_group, columns)
 | 
					        pack |> get_table_row_for_shot_record(shot_record, columns)
 | 
				
			||||||
      end)
 | 
					      end)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    socket
 | 
					    socket
 | 
				
			||||||
    |> assign(
 | 
					    |> assign(
 | 
				
			||||||
      ammo_group: ammo_group,
 | 
					      pack: pack,
 | 
				
			||||||
      original_count: Ammo.get_original_count(ammo_group, current_user),
 | 
					      original_count: Ammo.get_original_count(pack, current_user),
 | 
				
			||||||
      percentage_remaining: Ammo.get_percentage_remaining(ammo_group, current_user),
 | 
					      percentage_remaining: Ammo.get_percentage_remaining(pack, current_user),
 | 
				
			||||||
      container: container_id && Containers.get_container!(container_id, current_user),
 | 
					      container: container_id && Containers.get_container!(container_id, current_user),
 | 
				
			||||||
      shot_groups: shot_groups,
 | 
					      shot_records: shot_records,
 | 
				
			||||||
      columns: columns,
 | 
					      columns: columns,
 | 
				
			||||||
      rows: rows
 | 
					      rows: rows
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  defp display_ammo_group(%{assigns: %{current_user: current_user}} = socket, id),
 | 
					  defp display_pack(%{assigns: %{current_user: current_user}} = socket, id),
 | 
				
			||||||
    do: display_ammo_group(socket, Ammo.get_ammo_group!(id, current_user))
 | 
					    do: display_pack(socket, Ammo.get_pack!(id, current_user))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @spec display_currency(float()) :: String.t()
 | 
					  @spec display_currency(float()) :: String.t()
 | 
				
			||||||
  defp display_currency(float), do: :erlang.float_to_binary(float, decimals: 2)
 | 
					  defp display_currency(float), do: :erlang.float_to_binary(float, decimals: 2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @spec get_table_row_for_shot_group(AmmoGroup.t(), ShotGroup.t(), [map()]) :: map()
 | 
					  @spec get_table_row_for_shot_record(Pack.t(), ShotRecord.t(), [map()]) :: map()
 | 
				
			||||||
  defp get_table_row_for_shot_group(ammo_group, %{id: id, date: date} = shot_group, columns) do
 | 
					  defp get_table_row_for_shot_record(pack, %{id: id, date: date} = shot_record, columns) do
 | 
				
			||||||
    assigns = %{ammo_group: ammo_group, shot_group: shot_group}
 | 
					    assigns = %{pack: pack, shot_record: shot_record}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    columns
 | 
					    columns
 | 
				
			||||||
    |> Map.new(fn %{key: key} ->
 | 
					    |> Map.new(fn %{key: key} ->
 | 
				
			||||||
@@ -140,11 +139,11 @@ defmodule CanneryWeb.AmmoGroupLive.Show do
 | 
				
			|||||||
            ~H"""
 | 
					            ~H"""
 | 
				
			||||||
            <div class="px-4 py-2 space-x-4 flex justify-center items-center">
 | 
					            <div class="px-4 py-2 space-x-4 flex justify-center items-center">
 | 
				
			||||||
              <.link
 | 
					              <.link
 | 
				
			||||||
                patch={Routes.ammo_group_show_path(Endpoint, :edit_shot_group, @ammo_group, @shot_group)}
 | 
					                patch={Routes.pack_show_path(Endpoint, :edit_shot_record, @pack, @shot_record)}
 | 
				
			||||||
                class="text-primary-600 link"
 | 
					                class="text-primary-600 link"
 | 
				
			||||||
                aria-label={
 | 
					                aria-label={
 | 
				
			||||||
                  dgettext("actions", "Edit shot group of %{shot_group_count} shots",
 | 
					                  dgettext("actions", "Edit shot record of %{shot_record_count} shots",
 | 
				
			||||||
                    shot_group_count: @shot_group.count
 | 
					                    shot_record_count: @shot_record.count
 | 
				
			||||||
                  )
 | 
					                  )
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
              >
 | 
					              >
 | 
				
			||||||
@@ -154,12 +153,12 @@ defmodule CanneryWeb.AmmoGroupLive.Show do
 | 
				
			|||||||
              <.link
 | 
					              <.link
 | 
				
			||||||
                href="#"
 | 
					                href="#"
 | 
				
			||||||
                class="text-primary-600 link"
 | 
					                class="text-primary-600 link"
 | 
				
			||||||
                phx-click="delete_shot_group"
 | 
					                phx-click="delete_shot_record"
 | 
				
			||||||
                phx-value-id={@shot_group.id}
 | 
					                phx-value-id={@shot_record.id}
 | 
				
			||||||
                data-confirm={dgettext("prompts", "Are you sure you want to delete this shot record?")}
 | 
					                data-confirm={dgettext("prompts", "Are you sure you want to delete this shot record?")}
 | 
				
			||||||
                aria-label={
 | 
					                aria-label={
 | 
				
			||||||
                  dgettext("actions", "Delete shot record of %{shot_group_count} shots",
 | 
					                  dgettext("actions", "Delete shot record of %{shot_record_count} shots",
 | 
				
			||||||
                    shot_group_count: @shot_group.count
 | 
					                    shot_record_count: @shot_record.count
 | 
				
			||||||
                  )
 | 
					                  )
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
              >
 | 
					              >
 | 
				
			||||||
@@ -169,7 +168,7 @@ defmodule CanneryWeb.AmmoGroupLive.Show do
 | 
				
			|||||||
            """
 | 
					            """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          key ->
 | 
					          key ->
 | 
				
			||||||
            shot_group |> Map.get(key)
 | 
					            shot_record |> Map.get(key)
 | 
				
			||||||
        end
 | 
					        end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      {key, value}
 | 
					      {key, value}
 | 
				
			||||||
@@ -1,12 +1,12 @@
 | 
				
			|||||||
<div class="mx-auto space-y-4 max-w-3xl flex flex-col justify-center items-center">
 | 
					<div class="mx-auto space-y-4 max-w-3xl flex flex-col justify-center items-center">
 | 
				
			||||||
  <h1 class="title text-2xl title-primary-500">
 | 
					  <h1 class="title text-2xl title-primary-500">
 | 
				
			||||||
    <%= @ammo_group.ammo_type.name %>
 | 
					    <%= @pack.type.name %>
 | 
				
			||||||
  </h1>
 | 
					  </h1>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  <div class="space-y-2 flex flex-col justify-center items-center">
 | 
					  <div class="space-y-2 flex flex-col justify-center items-center">
 | 
				
			||||||
    <span class="rounded-lg title text-lg">
 | 
					    <span class="rounded-lg title text-lg">
 | 
				
			||||||
      <%= gettext("Count:") %>
 | 
					      <%= gettext("Count:") %>
 | 
				
			||||||
      <%= @ammo_group.count %>
 | 
					      <%= @pack.count %>
 | 
				
			||||||
    </span>
 | 
					    </span>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <span class="rounded-lg title text-lg">
 | 
					    <span class="rounded-lg title text-lg">
 | 
				
			||||||
@@ -19,28 +19,28 @@
 | 
				
			|||||||
      <%= gettext("%{percentage}%", percentage: @percentage_remaining) %>
 | 
					      <%= gettext("%{percentage}%", percentage: @percentage_remaining) %>
 | 
				
			||||||
    </span>
 | 
					    </span>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <%= if @ammo_group.notes do %>
 | 
					    <%= if @pack.notes do %>
 | 
				
			||||||
      <span class="rounded-lg title text-lg">
 | 
					      <span class="rounded-lg title text-lg">
 | 
				
			||||||
        <%= gettext("Notes:") %>
 | 
					        <%= gettext("Notes:") %>
 | 
				
			||||||
        <%= @ammo_group.notes %>
 | 
					        <%= @pack.notes %>
 | 
				
			||||||
      </span>
 | 
					      </span>
 | 
				
			||||||
    <% end %>
 | 
					    <% end %>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <span class="rounded-lg title text-lg">
 | 
					    <span class="rounded-lg title text-lg">
 | 
				
			||||||
      <%= gettext("Purchased on:") %>
 | 
					      <%= gettext("Purchased on:") %>
 | 
				
			||||||
      <.date id={"#{@ammo_group.id}-purchased-on"} date={@ammo_group.purchased_on} />
 | 
					      <.date id={"#{@pack.id}-purchased-on"} date={@pack.purchased_on} />
 | 
				
			||||||
    </span>
 | 
					    </span>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <%= if @ammo_group.price_paid do %>
 | 
					    <%= if @pack.price_paid do %>
 | 
				
			||||||
      <span class="rounded-lg title text-lg">
 | 
					      <span class="rounded-lg title text-lg">
 | 
				
			||||||
        <%= gettext("Original cost:") %>
 | 
					        <%= gettext("Original cost:") %>
 | 
				
			||||||
        <%= gettext("$%{amount}", amount: display_currency(@ammo_group.price_paid)) %>
 | 
					        <%= gettext("$%{amount}", amount: display_currency(@pack.price_paid)) %>
 | 
				
			||||||
      </span>
 | 
					      </span>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      <span class="rounded-lg title text-lg">
 | 
					      <span class="rounded-lg title text-lg">
 | 
				
			||||||
        <%= gettext("Current value:") %>
 | 
					        <%= gettext("Current value:") %>
 | 
				
			||||||
        <%= gettext("$%{amount}",
 | 
					        <%= gettext("$%{amount}",
 | 
				
			||||||
          amount: display_currency(@ammo_group.price_paid * @percentage_remaining / 100)
 | 
					          amount: display_currency(@pack.price_paid * @percentage_remaining / 100)
 | 
				
			||||||
        ) %>
 | 
					        ) %>
 | 
				
			||||||
      </span>
 | 
					      </span>
 | 
				
			||||||
    <% end %>
 | 
					    <% end %>
 | 
				
			||||||
@@ -49,19 +49,17 @@
 | 
				
			|||||||
  <div class="flex flex-col justify-center items-center">
 | 
					  <div class="flex flex-col justify-center items-center">
 | 
				
			||||||
    <div class="flex flex-wrap justify-center items-center text-primary-600">
 | 
					    <div class="flex flex-wrap justify-center items-center text-primary-600">
 | 
				
			||||||
      <.link
 | 
					      <.link
 | 
				
			||||||
        navigate={Routes.ammo_type_show_path(Endpoint, :show, @ammo_group.ammo_type)}
 | 
					        navigate={Routes.type_show_path(Endpoint, :show, @pack.type)}
 | 
				
			||||||
        class="mx-4 my-2 btn btn-primary"
 | 
					        class="mx-4 my-2 btn btn-primary"
 | 
				
			||||||
      >
 | 
					      >
 | 
				
			||||||
        <%= dgettext("actions", "View in Catalog") %>
 | 
					        <%= dgettext("actions", "View in Catalog") %>
 | 
				
			||||||
      </.link>
 | 
					      </.link>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      <.link
 | 
					      <.link
 | 
				
			||||||
        patch={Routes.ammo_group_show_path(Endpoint, :edit, @ammo_group)}
 | 
					        patch={Routes.pack_show_path(Endpoint, :edit, @pack)}
 | 
				
			||||||
        class="mx-4 my-2 text-primary-600 link"
 | 
					        class="mx-4 my-2 text-primary-600 link"
 | 
				
			||||||
        aria-label={
 | 
					        aria-label={
 | 
				
			||||||
          dgettext("actions", "Edit ammo group of %{ammo_group_count} bullets",
 | 
					          dgettext("actions", "Edit pack of %{pack_count} bullets", pack_count: @pack.count)
 | 
				
			||||||
            ammo_group_count: @ammo_group.count
 | 
					 | 
				
			||||||
          )
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      >
 | 
					      >
 | 
				
			||||||
        <i class="fa-fw fa-lg fas fa-edit"></i>
 | 
					        <i class="fa-fw fa-lg fas fa-edit"></i>
 | 
				
			||||||
@@ -73,9 +71,7 @@
 | 
				
			|||||||
        phx-click="delete"
 | 
					        phx-click="delete"
 | 
				
			||||||
        data-confirm={dgettext("prompts", "Are you sure you want to delete this ammo?")}
 | 
					        data-confirm={dgettext("prompts", "Are you sure you want to delete this ammo?")}
 | 
				
			||||||
        aria-label={
 | 
					        aria-label={
 | 
				
			||||||
          dgettext("actions", "Delete ammo group of %{ammo_group_count} bullets",
 | 
					          dgettext("actions", "Delete pack of %{pack_count} bullets", pack_count: @pack.count)
 | 
				
			||||||
            ammo_group_count: @ammo_group.count
 | 
					 | 
				
			||||||
          )
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      >
 | 
					      >
 | 
				
			||||||
        <i class="fa-fw fa-lg fas fa-trash"></i>
 | 
					        <i class="fa-fw fa-lg fas fa-trash"></i>
 | 
				
			||||||
@@ -84,20 +80,17 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    <div class="flex flex-wrap justify-center items-center text-primary-600">
 | 
					    <div class="flex flex-wrap justify-center items-center text-primary-600">
 | 
				
			||||||
      <button type="button" class="mx-4 my-2 btn btn-primary" phx-click="toggle_staged">
 | 
					      <button type="button" class="mx-4 my-2 btn btn-primary" phx-click="toggle_staged">
 | 
				
			||||||
        <%= if @ammo_group.staged,
 | 
					        <%= if @pack.staged,
 | 
				
			||||||
          do: dgettext("actions", "Unstage from range"),
 | 
					          do: dgettext("actions", "Unstage from range"),
 | 
				
			||||||
          else: dgettext("actions", "Stage for range") %>
 | 
					          else: dgettext("actions", "Stage for range") %>
 | 
				
			||||||
      </button>
 | 
					      </button>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      <.link
 | 
					      <.link patch={Routes.pack_show_path(Endpoint, :move, @pack)} class="btn btn-primary">
 | 
				
			||||||
        patch={Routes.ammo_group_show_path(Endpoint, :move, @ammo_group)}
 | 
					 | 
				
			||||||
        class="btn btn-primary"
 | 
					 | 
				
			||||||
      >
 | 
					 | 
				
			||||||
        <%= dgettext("actions", "Move ammo") %>
 | 
					        <%= dgettext("actions", "Move ammo") %>
 | 
				
			||||||
      </.link>
 | 
					      </.link>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      <.link
 | 
					      <.link
 | 
				
			||||||
        patch={Routes.ammo_group_show_path(Endpoint, :add_shot_group, @ammo_group)}
 | 
					        patch={Routes.pack_show_path(Endpoint, :add_shot_record, @pack)}
 | 
				
			||||||
        class="mx-4 my-2 btn btn-primary"
 | 
					        class="mx-4 my-2 btn btn-primary"
 | 
				
			||||||
      >
 | 
					      >
 | 
				
			||||||
        <%= dgettext("actions", "Record shots") %>
 | 
					        <%= dgettext("actions", "Record shots") %>
 | 
				
			||||||
@@ -119,7 +112,7 @@
 | 
				
			|||||||
    <% end %>
 | 
					    <% end %>
 | 
				
			||||||
  </div>
 | 
					  </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  <%= unless @shot_groups |> Enum.empty?() do %>
 | 
					  <%= unless @shot_records |> Enum.empty?() do %>
 | 
				
			||||||
    <hr class="mb-4 w-full" />
 | 
					    <hr class="mb-4 w-full" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <h1 class="mb-4 px-4 py-2 text-center rounded-lg title text-xl">
 | 
					    <h1 class="mb-4 px-4 py-2 text-center rounded-lg title text-xl">
 | 
				
			||||||
@@ -128,7 +121,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    <.live_component
 | 
					    <.live_component
 | 
				
			||||||
      module={CanneryWeb.Components.TableComponent}
 | 
					      module={CanneryWeb.Components.TableComponent}
 | 
				
			||||||
      id="ammo_group_shot_groups_table"
 | 
					      id="pack_shot_records_table"
 | 
				
			||||||
      columns={@columns}
 | 
					      columns={@columns}
 | 
				
			||||||
      rows={@rows}
 | 
					      rows={@rows}
 | 
				
			||||||
    />
 | 
					    />
 | 
				
			||||||
@@ -137,50 +130,50 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
<%= case @live_action do %>
 | 
					<%= case @live_action do %>
 | 
				
			||||||
  <% :edit -> %>
 | 
					  <% :edit -> %>
 | 
				
			||||||
    <.modal return_to={Routes.ammo_group_show_path(Endpoint, :show, @ammo_group)}>
 | 
					    <.modal return_to={Routes.pack_show_path(Endpoint, :show, @pack)}>
 | 
				
			||||||
      <.live_component
 | 
					      <.live_component
 | 
				
			||||||
        module={CanneryWeb.AmmoGroupLive.FormComponent}
 | 
					        module={CanneryWeb.PackLive.FormComponent}
 | 
				
			||||||
        id={@ammo_group.id}
 | 
					        id={@pack.id}
 | 
				
			||||||
        title={@page_title}
 | 
					        title={@page_title}
 | 
				
			||||||
        action={@live_action}
 | 
					        action={@live_action}
 | 
				
			||||||
        ammo_group={@ammo_group}
 | 
					        pack={@pack}
 | 
				
			||||||
        return_to={Routes.ammo_group_show_path(Endpoint, :show, @ammo_group)}
 | 
					        return_to={Routes.pack_show_path(Endpoint, :show, @pack)}
 | 
				
			||||||
        current_user={@current_user}
 | 
					        current_user={@current_user}
 | 
				
			||||||
      />
 | 
					      />
 | 
				
			||||||
    </.modal>
 | 
					    </.modal>
 | 
				
			||||||
  <% :edit_shot_group -> %>
 | 
					  <% :edit_shot_record -> %>
 | 
				
			||||||
    <.modal return_to={Routes.ammo_group_show_path(Endpoint, :show, @ammo_group)}>
 | 
					    <.modal return_to={Routes.pack_show_path(Endpoint, :show, @pack)}>
 | 
				
			||||||
      <.live_component
 | 
					      <.live_component
 | 
				
			||||||
        module={CanneryWeb.RangeLive.FormComponent}
 | 
					        module={CanneryWeb.RangeLive.FormComponent}
 | 
				
			||||||
        id={@shot_group.id}
 | 
					        id={@shot_record.id}
 | 
				
			||||||
        title={@page_title}
 | 
					        title={@page_title}
 | 
				
			||||||
        action={@live_action}
 | 
					        action={@live_action}
 | 
				
			||||||
        shot_group={@shot_group}
 | 
					        shot_record={@shot_record}
 | 
				
			||||||
        return_to={Routes.ammo_group_show_path(Endpoint, :show, @ammo_group)}
 | 
					        return_to={Routes.pack_show_path(Endpoint, :show, @pack)}
 | 
				
			||||||
        current_user={@current_user}
 | 
					        current_user={@current_user}
 | 
				
			||||||
      />
 | 
					      />
 | 
				
			||||||
    </.modal>
 | 
					    </.modal>
 | 
				
			||||||
  <% :add_shot_group -> %>
 | 
					  <% :add_shot_record -> %>
 | 
				
			||||||
    <.modal return_to={Routes.ammo_group_show_path(Endpoint, :show, @ammo_group)}>
 | 
					    <.modal return_to={Routes.pack_show_path(Endpoint, :show, @pack)}>
 | 
				
			||||||
      <.live_component
 | 
					      <.live_component
 | 
				
			||||||
        module={CanneryWeb.Components.AddShotGroupComponent}
 | 
					        module={CanneryWeb.Components.AddShotRecordComponent}
 | 
				
			||||||
        id={:new}
 | 
					        id={:new}
 | 
				
			||||||
        title={@page_title}
 | 
					        title={@page_title}
 | 
				
			||||||
        action={@live_action}
 | 
					        action={@live_action}
 | 
				
			||||||
        ammo_group={@ammo_group}
 | 
					        pack={@pack}
 | 
				
			||||||
        return_to={Routes.ammo_group_show_path(Endpoint, :show, @ammo_group)}
 | 
					        return_to={Routes.pack_show_path(Endpoint, :show, @pack)}
 | 
				
			||||||
        current_user={@current_user}
 | 
					        current_user={@current_user}
 | 
				
			||||||
      />
 | 
					      />
 | 
				
			||||||
    </.modal>
 | 
					    </.modal>
 | 
				
			||||||
  <% :move -> %>
 | 
					  <% :move -> %>
 | 
				
			||||||
    <.modal return_to={Routes.ammo_group_show_path(Endpoint, :show, @ammo_group)}>
 | 
					    <.modal return_to={Routes.pack_show_path(Endpoint, :show, @pack)}>
 | 
				
			||||||
      <.live_component
 | 
					      <.live_component
 | 
				
			||||||
        module={CanneryWeb.Components.MoveAmmoGroupComponent}
 | 
					        module={CanneryWeb.Components.MovePackComponent}
 | 
				
			||||||
        id={@ammo_group.id}
 | 
					        id={@pack.id}
 | 
				
			||||||
        title={@page_title}
 | 
					        title={@page_title}
 | 
				
			||||||
        action={@live_action}
 | 
					        action={@live_action}
 | 
				
			||||||
        ammo_group={@ammo_group}
 | 
					        pack={@pack}
 | 
				
			||||||
        return_to={Routes.ammo_group_show_path(Endpoint, :show, @ammo_group)}
 | 
					        return_to={Routes.pack_show_path(Endpoint, :show, @pack)}
 | 
				
			||||||
        current_user={@current_user}
 | 
					        current_user={@current_user}
 | 
				
			||||||
      />
 | 
					      />
 | 
				
			||||||
    </.modal>
 | 
					    </.modal>
 | 
				
			||||||
@@ -1,56 +1,56 @@
 | 
				
			|||||||
defmodule CanneryWeb.RangeLive.FormComponent do
 | 
					defmodule CanneryWeb.RangeLive.FormComponent do
 | 
				
			||||||
  @moduledoc """
 | 
					  @moduledoc """
 | 
				
			||||||
  Livecomponent that can update a ShotGroup
 | 
					  Livecomponent that can update a ShotRecord
 | 
				
			||||||
  """
 | 
					  """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  use CanneryWeb, :live_component
 | 
					  use CanneryWeb, :live_component
 | 
				
			||||||
  alias Cannery.{Accounts.User, ActivityLog, ActivityLog.ShotGroup, Ammo, Ammo.AmmoGroup}
 | 
					  alias Cannery.{Accounts.User, ActivityLog, ActivityLog.ShotRecord, Ammo, Ammo.Pack}
 | 
				
			||||||
  alias Ecto.Changeset
 | 
					  alias Ecto.Changeset
 | 
				
			||||||
  alias Phoenix.LiveView.Socket
 | 
					  alias Phoenix.LiveView.Socket
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @impl true
 | 
					  @impl true
 | 
				
			||||||
  def mount(socket), do: {:ok, socket |> assign(:ammo_group, nil)}
 | 
					  def mount(socket), do: {:ok, socket |> assign(:pack, nil)}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @impl true
 | 
					  @impl true
 | 
				
			||||||
  @spec update(
 | 
					  @spec update(
 | 
				
			||||||
          %{
 | 
					          %{
 | 
				
			||||||
            required(:shot_group) => ShotGroup.t(),
 | 
					            required(:shot_record) => ShotRecord.t(),
 | 
				
			||||||
            required(:current_user) => User.t(),
 | 
					            required(:current_user) => User.t(),
 | 
				
			||||||
            optional(:ammo_group) => AmmoGroup.t(),
 | 
					            optional(:pack) => Pack.t(),
 | 
				
			||||||
            optional(any()) => any()
 | 
					            optional(any()) => any()
 | 
				
			||||||
          },
 | 
					          },
 | 
				
			||||||
          Socket.t()
 | 
					          Socket.t()
 | 
				
			||||||
        ) :: {:ok, Socket.t()}
 | 
					        ) :: {:ok, Socket.t()}
 | 
				
			||||||
  def update(
 | 
					  def update(
 | 
				
			||||||
        %{
 | 
					        %{
 | 
				
			||||||
          shot_group: %ShotGroup{ammo_group_id: ammo_group_id},
 | 
					          shot_record: %ShotRecord{pack_id: pack_id},
 | 
				
			||||||
          current_user: current_user
 | 
					          current_user: current_user
 | 
				
			||||||
        } = assigns,
 | 
					        } = assigns,
 | 
				
			||||||
        socket
 | 
					        socket
 | 
				
			||||||
      )
 | 
					      )
 | 
				
			||||||
      when is_binary(ammo_group_id) do
 | 
					      when is_binary(pack_id) do
 | 
				
			||||||
    ammo_group = Ammo.get_ammo_group!(ammo_group_id, current_user)
 | 
					    pack = Ammo.get_pack!(pack_id, current_user)
 | 
				
			||||||
    {:ok, socket |> assign(assigns) |> assign(:ammo_group, ammo_group) |> assign_changeset(%{})}
 | 
					    {:ok, socket |> assign(assigns) |> assign(:pack, pack) |> assign_changeset(%{})}
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def update(%{shot_group: %ShotGroup{}} = assigns, socket) do
 | 
					  def update(%{shot_record: %ShotRecord{}} = assigns, socket) do
 | 
				
			||||||
    {:ok, socket |> assign(assigns) |> assign_changeset(%{})}
 | 
					    {:ok, socket |> assign(assigns) |> assign_changeset(%{})}
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @impl true
 | 
					  @impl true
 | 
				
			||||||
  def handle_event("validate", %{"shot_group" => shot_group_params}, socket) do
 | 
					  def handle_event("validate", %{"shot_record" => shot_record_params}, socket) do
 | 
				
			||||||
    {:noreply, socket |> assign_changeset(shot_group_params, :validate)}
 | 
					    {:noreply, socket |> assign_changeset(shot_record_params, :validate)}
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def handle_event(
 | 
					  def handle_event(
 | 
				
			||||||
        "save",
 | 
					        "save",
 | 
				
			||||||
        %{"shot_group" => shot_group_params},
 | 
					        %{"shot_record" => shot_record_params},
 | 
				
			||||||
        %{assigns: %{shot_group: shot_group, current_user: current_user, return_to: return_to}} =
 | 
					        %{assigns: %{shot_record: shot_record, current_user: current_user, return_to: return_to}} =
 | 
				
			||||||
          socket
 | 
					          socket
 | 
				
			||||||
      ) do
 | 
					      ) do
 | 
				
			||||||
    socket =
 | 
					    socket =
 | 
				
			||||||
      case ActivityLog.update_shot_group(shot_group, shot_group_params, current_user) do
 | 
					      case ActivityLog.update_shot_record(shot_record, shot_record_params, current_user) do
 | 
				
			||||||
        {:ok, _shot_group} ->
 | 
					        {:ok, _shot_record} ->
 | 
				
			||||||
          prompt = dgettext("prompts", "Shot records updated successfully")
 | 
					          prompt = dgettext("prompts", "Shot records updated successfully")
 | 
				
			||||||
          socket |> put_flash(:info, prompt) |> push_navigate(to: return_to)
 | 
					          socket |> put_flash(:info, prompt) |> push_navigate(to: return_to)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -66,23 +66,23 @@ defmodule CanneryWeb.RangeLive.FormComponent do
 | 
				
			|||||||
           assigns: %{
 | 
					           assigns: %{
 | 
				
			||||||
             action: live_action,
 | 
					             action: live_action,
 | 
				
			||||||
             current_user: user,
 | 
					             current_user: user,
 | 
				
			||||||
             ammo_group: ammo_group,
 | 
					             pack: pack,
 | 
				
			||||||
             shot_group: shot_group
 | 
					             shot_record: shot_record
 | 
				
			||||||
           }
 | 
					           }
 | 
				
			||||||
         } = socket,
 | 
					         } = socket,
 | 
				
			||||||
         shot_group_params,
 | 
					         shot_record_params,
 | 
				
			||||||
         action \\ nil
 | 
					         action \\ nil
 | 
				
			||||||
       ) do
 | 
					       ) do
 | 
				
			||||||
    default_action =
 | 
					    default_action =
 | 
				
			||||||
      case live_action do
 | 
					      case live_action do
 | 
				
			||||||
        :add_shot_group -> :insert
 | 
					        :add_shot_record -> :insert
 | 
				
			||||||
        editing when editing in [:edit, :edit_shot_group] -> :update
 | 
					        editing when editing in [:edit, :edit_shot_record] -> :update
 | 
				
			||||||
      end
 | 
					      end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    changeset =
 | 
					    changeset =
 | 
				
			||||||
      case default_action do
 | 
					      case default_action do
 | 
				
			||||||
        :insert -> shot_group |> ShotGroup.create_changeset(user, ammo_group, shot_group_params)
 | 
					        :insert -> shot_record |> ShotRecord.create_changeset(user, pack, shot_record_params)
 | 
				
			||||||
        :update -> shot_group |> ShotGroup.update_changeset(user, shot_group_params)
 | 
					        :update -> shot_record |> ShotRecord.update_changeset(user, shot_record_params)
 | 
				
			||||||
      end
 | 
					      end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    changeset =
 | 
					    changeset =
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,7 +6,7 @@
 | 
				
			|||||||
  <.form
 | 
					  <.form
 | 
				
			||||||
    :let={f}
 | 
					    :let={f}
 | 
				
			||||||
    for={@changeset}
 | 
					    for={@changeset}
 | 
				
			||||||
    id="shot-group-form"
 | 
					    id="shot-record-form"
 | 
				
			||||||
    class="flex flex-col space-y-4 sm:space-y-0 sm:grid sm:grid-cols-3 sm:gap-4 justify-center items-center"
 | 
					    class="flex flex-col space-y-4 sm:space-y-0 sm:grid sm:grid-cols-3 sm:gap-4 justify-center items-center"
 | 
				
			||||||
    phx-target={@myself}
 | 
					    phx-target={@myself}
 | 
				
			||||||
    phx-change="validate"
 | 
					    phx-change="validate"
 | 
				
			||||||
@@ -22,15 +22,16 @@
 | 
				
			|||||||
    <%= label(f, :count, gettext("Shots fired"), class: "title text-lg text-primary-600") %>
 | 
					    <%= label(f, :count, gettext("Shots fired"), class: "title text-lg text-primary-600") %>
 | 
				
			||||||
    <%= number_input(f, :count,
 | 
					    <%= number_input(f, :count,
 | 
				
			||||||
      min: 1,
 | 
					      min: 1,
 | 
				
			||||||
      max: @shot_group.count + @ammo_group.count,
 | 
					      max: @shot_record.count + @pack.count,
 | 
				
			||||||
      class: "input input-primary col-span-2"
 | 
					      class: "input input-primary col-span-2"
 | 
				
			||||||
    ) %>
 | 
					    ) %>
 | 
				
			||||||
    <%= error_tag(f, :count, "col-span-3") %>
 | 
					    <%= error_tag(f, :count, "col-span-3") %>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <%= label(f, :notes, gettext("Notes"), class: "title text-lg text-primary-600") %>
 | 
					    <%= label(f, :notes, gettext("Notes"), class: "title text-lg text-primary-600") %>
 | 
				
			||||||
    <%= textarea(f, :notes,
 | 
					    <%= textarea(f, :notes,
 | 
				
			||||||
      id: "shot-group-form-notes",
 | 
					      id: "shot-record-form-notes",
 | 
				
			||||||
      class: "input input-primary col-span-2",
 | 
					      class: "input input-primary col-span-2",
 | 
				
			||||||
 | 
					      maxlength: 255,
 | 
				
			||||||
      placeholder: gettext("Really great weather"),
 | 
					      placeholder: gettext("Really great weather"),
 | 
				
			||||||
      phx_hook: "MaintainAttrs",
 | 
					      phx_hook: "MaintainAttrs",
 | 
				
			||||||
      phx_update: "ignore"
 | 
					      phx_update: "ignore"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,20 +1,20 @@
 | 
				
			|||||||
defmodule CanneryWeb.RangeLive.Index do
 | 
					defmodule CanneryWeb.RangeLive.Index do
 | 
				
			||||||
  @moduledoc """
 | 
					  @moduledoc """
 | 
				
			||||||
  Main page for range day mode, where `AmmoGroup`s can be used up.
 | 
					  Main page for range day mode, where `Pack`s can be used up.
 | 
				
			||||||
  """
 | 
					  """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  use CanneryWeb, :live_view
 | 
					  use CanneryWeb, :live_view
 | 
				
			||||||
  alias Cannery.{ActivityLog, ActivityLog.ShotGroup, Ammo}
 | 
					  alias Cannery.{ActivityLog, ActivityLog.ShotRecord, Ammo}
 | 
				
			||||||
  alias CanneryWeb.Endpoint
 | 
					  alias CanneryWeb.Endpoint
 | 
				
			||||||
  alias Phoenix.LiveView.Socket
 | 
					  alias Phoenix.LiveView.Socket
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @impl true
 | 
					  @impl true
 | 
				
			||||||
  def mount(%{"search" => search}, _session, socket) do
 | 
					  def mount(%{"search" => search}, _session, socket) do
 | 
				
			||||||
    {:ok, socket |> assign(search: search) |> display_shot_groups()}
 | 
					    {:ok, socket |> assign(class: :all, search: search) |> display_shot_records()}
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def mount(_params, _session, socket) do
 | 
					  def mount(_params, _session, socket) do
 | 
				
			||||||
    {:ok, socket |> assign(search: nil) |> display_shot_groups()}
 | 
					    {:ok, socket |> assign(class: :all, search: nil) |> display_shot_records()}
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @impl true
 | 
					  @impl true
 | 
				
			||||||
@@ -24,21 +24,21 @@ defmodule CanneryWeb.RangeLive.Index do
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  defp apply_action(
 | 
					  defp apply_action(
 | 
				
			||||||
         %{assigns: %{current_user: current_user}} = socket,
 | 
					         %{assigns: %{current_user: current_user}} = socket,
 | 
				
			||||||
         :add_shot_group,
 | 
					         :add_shot_record,
 | 
				
			||||||
         %{"id" => id}
 | 
					         %{"id" => id}
 | 
				
			||||||
       ) do
 | 
					       ) do
 | 
				
			||||||
    socket
 | 
					    socket
 | 
				
			||||||
    |> assign(
 | 
					    |> assign(
 | 
				
			||||||
      page_title: gettext("Record Shots"),
 | 
					      page_title: gettext("Record Shots"),
 | 
				
			||||||
      ammo_group: Ammo.get_ammo_group!(id, current_user)
 | 
					      pack: Ammo.get_pack!(id, current_user)
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  defp apply_action(%{assigns: %{current_user: current_user}} = socket, :edit, %{"id" => id}) do
 | 
					  defp apply_action(%{assigns: %{current_user: current_user}} = socket, :edit, %{"id" => id}) do
 | 
				
			||||||
    socket
 | 
					    socket
 | 
				
			||||||
    |> assign(
 | 
					    |> assign(
 | 
				
			||||||
      page_title: gettext("Edit Shot Records"),
 | 
					      page_title: gettext("Edit Shot Record"),
 | 
				
			||||||
      shot_group: ActivityLog.get_shot_group!(id, current_user)
 | 
					      shot_record: ActivityLog.get_shot_record!(id, current_user)
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -46,7 +46,7 @@ defmodule CanneryWeb.RangeLive.Index do
 | 
				
			|||||||
    socket
 | 
					    socket
 | 
				
			||||||
    |> assign(
 | 
					    |> assign(
 | 
				
			||||||
      page_title: gettext("New Shot Records"),
 | 
					      page_title: gettext("New Shot Records"),
 | 
				
			||||||
      shot_group: %ShotGroup{}
 | 
					      shot_record: %ShotRecord{}
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -55,9 +55,9 @@ defmodule CanneryWeb.RangeLive.Index do
 | 
				
			|||||||
    |> assign(
 | 
					    |> assign(
 | 
				
			||||||
      page_title: gettext("Shot Records"),
 | 
					      page_title: gettext("Shot Records"),
 | 
				
			||||||
      search: nil,
 | 
					      search: nil,
 | 
				
			||||||
      shot_group: nil
 | 
					      shot_record: nil
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
    |> display_shot_groups()
 | 
					    |> display_shot_records()
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  defp apply_action(socket, :search, %{"search" => search}) do
 | 
					  defp apply_action(socket, :search, %{"search" => search}) do
 | 
				
			||||||
@@ -65,33 +65,32 @@ defmodule CanneryWeb.RangeLive.Index do
 | 
				
			|||||||
    |> assign(
 | 
					    |> assign(
 | 
				
			||||||
      page_title: gettext("Shot Records"),
 | 
					      page_title: gettext("Shot Records"),
 | 
				
			||||||
      search: search,
 | 
					      search: search,
 | 
				
			||||||
      shot_group: nil
 | 
					      shot_record: nil
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
    |> display_shot_groups()
 | 
					    |> display_shot_records()
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @impl true
 | 
					  @impl true
 | 
				
			||||||
  def handle_event("delete", %{"id" => id}, %{assigns: %{current_user: current_user}} = socket) do
 | 
					  def handle_event("delete", %{"id" => id}, %{assigns: %{current_user: current_user}} = socket) do
 | 
				
			||||||
    {:ok, _} =
 | 
					    {:ok, _} =
 | 
				
			||||||
      ActivityLog.get_shot_group!(id, current_user)
 | 
					      ActivityLog.get_shot_record!(id, current_user)
 | 
				
			||||||
      |> ActivityLog.delete_shot_group(current_user)
 | 
					      |> ActivityLog.delete_shot_record(current_user)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    prompt = dgettext("prompts", "Shot records deleted succesfully")
 | 
					    prompt = dgettext("prompts", "Shot records deleted succesfully")
 | 
				
			||||||
    {:noreply, socket |> put_flash(:info, prompt) |> display_shot_groups()}
 | 
					    {:noreply, socket |> put_flash(:info, prompt) |> display_shot_records()}
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def handle_event(
 | 
					  def handle_event(
 | 
				
			||||||
        "toggle_staged",
 | 
					        "toggle_staged",
 | 
				
			||||||
        %{"ammo_group_id" => ammo_group_id},
 | 
					        %{"pack_id" => pack_id},
 | 
				
			||||||
        %{assigns: %{current_user: current_user}} = socket
 | 
					        %{assigns: %{current_user: current_user}} = socket
 | 
				
			||||||
      ) do
 | 
					      ) do
 | 
				
			||||||
    ammo_group = Ammo.get_ammo_group!(ammo_group_id, current_user)
 | 
					    pack = Ammo.get_pack!(pack_id, current_user)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    {:ok, _ammo_group} =
 | 
					    {:ok, _pack} = pack |> Ammo.update_pack(%{"staged" => !pack.staged}, current_user)
 | 
				
			||||||
      ammo_group |> Ammo.update_ammo_group(%{"staged" => !ammo_group.staged}, current_user)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    prompt = dgettext("prompts", "Ammo unstaged succesfully")
 | 
					    prompt = dgettext("prompts", "Ammo unstaged succesfully")
 | 
				
			||||||
    {:noreply, socket |> put_flash(:info, prompt) |> display_shot_groups()}
 | 
					    {:noreply, socket |> put_flash(:info, prompt) |> display_shot_records()}
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def handle_event("search", %{"search" => %{"search_term" => ""}}, socket) do
 | 
					  def handle_event("search", %{"search" => %{"search_term" => ""}}, socket) do
 | 
				
			||||||
@@ -102,29 +101,49 @@ defmodule CanneryWeb.RangeLive.Index do
 | 
				
			|||||||
    {:noreply, socket |> push_patch(to: Routes.range_index_path(Endpoint, :search, search_term))}
 | 
					    {:noreply, socket |> push_patch(to: Routes.range_index_path(Endpoint, :search, search_term))}
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @spec display_shot_groups(Socket.t()) :: Socket.t()
 | 
					  def handle_event("change_class", %{"type" => %{"class" => "rifle"}}, socket) do
 | 
				
			||||||
  defp display_shot_groups(%{assigns: %{search: search, current_user: current_user}} = socket) do
 | 
					    {:noreply, socket |> assign(:class, :rifle) |> display_shot_records()}
 | 
				
			||||||
    shot_groups = ActivityLog.list_shot_groups(search, current_user)
 | 
					  end
 | 
				
			||||||
    ammo_groups = Ammo.list_staged_ammo_groups(current_user)
 | 
					
 | 
				
			||||||
    chart_data = shot_groups |> get_chart_data_for_shot_group()
 | 
					  def handle_event("change_class", %{"type" => %{"class" => "shotgun"}}, socket) do
 | 
				
			||||||
    original_counts = ammo_groups |> Ammo.get_original_counts(current_user)
 | 
					    {:noreply, socket |> assign(:class, :shotgun) |> display_shot_records()}
 | 
				
			||||||
    cprs = ammo_groups |> Ammo.get_cprs(current_user)
 | 
					  end
 | 
				
			||||||
    last_used_dates = ammo_groups |> ActivityLog.get_last_used_dates(current_user)
 | 
					
 | 
				
			||||||
 | 
					  def handle_event("change_class", %{"type" => %{"class" => "pistol"}}, socket) do
 | 
				
			||||||
 | 
					    {:noreply, socket |> assign(:class, :pistol) |> display_shot_records()}
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def handle_event("change_class", %{"type" => %{"class" => _all}}, socket) do
 | 
				
			||||||
 | 
					    {:noreply, socket |> assign(:class, :all) |> display_shot_records()}
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @spec display_shot_records(Socket.t()) :: Socket.t()
 | 
				
			||||||
 | 
					  defp display_shot_records(
 | 
				
			||||||
 | 
					         %{assigns: %{class: class, search: search, current_user: current_user}} = socket
 | 
				
			||||||
 | 
					       ) do
 | 
				
			||||||
 | 
					    shot_records = ActivityLog.list_shot_records(search, class, current_user)
 | 
				
			||||||
 | 
					    packs = Ammo.list_staged_packs(current_user)
 | 
				
			||||||
 | 
					    chart_data = shot_records |> get_chart_data_for_shot_record()
 | 
				
			||||||
 | 
					    original_counts = packs |> Ammo.get_original_counts(current_user)
 | 
				
			||||||
 | 
					    cprs = packs |> Ammo.get_cprs(current_user)
 | 
				
			||||||
 | 
					    last_used_dates = packs |> ActivityLog.get_last_used_dates(current_user)
 | 
				
			||||||
 | 
					    shot_record_count = ActivityLog.get_shot_record_count!(current_user)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    socket
 | 
					    socket
 | 
				
			||||||
    |> assign(
 | 
					    |> assign(
 | 
				
			||||||
      ammo_groups: ammo_groups,
 | 
					      packs: packs,
 | 
				
			||||||
      original_counts: original_counts,
 | 
					      original_counts: original_counts,
 | 
				
			||||||
      cprs: cprs,
 | 
					      cprs: cprs,
 | 
				
			||||||
      last_used_dates: last_used_dates,
 | 
					      last_used_dates: last_used_dates,
 | 
				
			||||||
      chart_data: chart_data,
 | 
					      chart_data: chart_data,
 | 
				
			||||||
      shot_groups: shot_groups
 | 
					      shot_records: shot_records,
 | 
				
			||||||
 | 
					      shot_record_count: shot_record_count
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @spec get_chart_data_for_shot_group([ShotGroup.t()]) :: [map()]
 | 
					  @spec get_chart_data_for_shot_record([ShotRecord.t()]) :: [map()]
 | 
				
			||||||
  defp get_chart_data_for_shot_group(shot_groups) do
 | 
					  defp get_chart_data_for_shot_record(shot_records) do
 | 
				
			||||||
    shot_groups
 | 
					    shot_records
 | 
				
			||||||
    |> Enum.group_by(fn %{date: date} -> date end, fn %{count: count} -> count end)
 | 
					    |> Enum.group_by(fn %{date: date} -> date end, fn %{count: count} -> count end)
 | 
				
			||||||
    |> Enum.map(fn {date, rounds} ->
 | 
					    |> Enum.map(fn {date, rounds} ->
 | 
				
			||||||
      sum = Enum.sum(rounds)
 | 
					      sum = Enum.sum(rounds)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,54 +3,54 @@
 | 
				
			|||||||
    <%= gettext("Range day") %>
 | 
					    <%= gettext("Range day") %>
 | 
				
			||||||
  </h1>
 | 
					  </h1>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  <%= if @ammo_groups |> Enum.empty?() do %>
 | 
					  <%= if @packs |> Enum.empty?() do %>
 | 
				
			||||||
    <h1 class="title text-xl text-primary-600">
 | 
					    <h1 class="title text-xl text-primary-600">
 | 
				
			||||||
      <%= gettext("No ammo staged") %>
 | 
					      <%= gettext("No ammo staged") %>
 | 
				
			||||||
      <%= display_emoji("😔") %>
 | 
					      <%= display_emoji("😔") %>
 | 
				
			||||||
    </h1>
 | 
					    </h1>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <.link navigate={Routes.ammo_group_index_path(Endpoint, :index)} class="btn btn-primary">
 | 
					    <.link navigate={Routes.pack_index_path(Endpoint, :index)} class="btn btn-primary">
 | 
				
			||||||
      <%= dgettext("actions", "Why not get some ready to shoot?") %>
 | 
					      <%= dgettext("actions", "Why not get some ready to shoot?") %>
 | 
				
			||||||
    </.link>
 | 
					    </.link>
 | 
				
			||||||
  <% else %>
 | 
					  <% else %>
 | 
				
			||||||
    <.link navigate={Routes.ammo_group_index_path(Endpoint, :index)} class="btn btn-primary">
 | 
					    <.link navigate={Routes.pack_index_path(Endpoint, :index)} class="btn btn-primary">
 | 
				
			||||||
      <%= dgettext("actions", "Stage ammo") %>
 | 
					      <%= dgettext("actions", "Stage ammo") %>
 | 
				
			||||||
    </.link>
 | 
					    </.link>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <div class="w-full flex flex-row flex-wrap justify-center items-stretch">
 | 
					    <div class="w-full flex flex-row flex-wrap justify-center items-stretch">
 | 
				
			||||||
      <.ammo_group_card
 | 
					      <.pack_card
 | 
				
			||||||
        :for={%{id: ammo_group_id} = ammo_group <- @ammo_groups}
 | 
					        :for={%{id: pack_id} = pack <- @packs}
 | 
				
			||||||
        ammo_group={ammo_group}
 | 
					        pack={pack}
 | 
				
			||||||
        original_count={Map.fetch!(@original_counts, ammo_group_id)}
 | 
					        original_count={Map.fetch!(@original_counts, pack_id)}
 | 
				
			||||||
        cpr={Map.get(@cprs, ammo_group_id)}
 | 
					        cpr={Map.get(@cprs, pack_id)}
 | 
				
			||||||
        last_used_date={Map.get(@last_used_dates, ammo_group_id)}
 | 
					        last_used_date={Map.get(@last_used_dates, pack_id)}
 | 
				
			||||||
        current_user={@current_user}
 | 
					        current_user={@current_user}
 | 
				
			||||||
      >
 | 
					      >
 | 
				
			||||||
        <button
 | 
					        <button
 | 
				
			||||||
          type="button"
 | 
					          type="button"
 | 
				
			||||||
          class="btn btn-primary"
 | 
					          class="btn btn-primary"
 | 
				
			||||||
          phx-click="toggle_staged"
 | 
					          phx-click="toggle_staged"
 | 
				
			||||||
          phx-value-ammo_group_id={ammo_group.id}
 | 
					          phx-value-pack_id={pack.id}
 | 
				
			||||||
          data-confirm={"#{dgettext("prompts", "Are you sure you want to unstage this ammo?")}"}
 | 
					          data-confirm={"#{dgettext("prompts", "Are you sure you want to unstage this ammo?")}"}
 | 
				
			||||||
        >
 | 
					        >
 | 
				
			||||||
          <%= if ammo_group.staged,
 | 
					          <%= if pack.staged,
 | 
				
			||||||
            do: dgettext("actions", "Unstage from range"),
 | 
					            do: dgettext("actions", "Unstage from range"),
 | 
				
			||||||
            else: dgettext("actions", "Stage for range") %>
 | 
					            else: dgettext("actions", "Stage for range") %>
 | 
				
			||||||
        </button>
 | 
					        </button>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <.link
 | 
					        <.link
 | 
				
			||||||
          patch={Routes.range_index_path(Endpoint, :add_shot_group, ammo_group)}
 | 
					          patch={Routes.range_index_path(Endpoint, :add_shot_record, pack)}
 | 
				
			||||||
          class="btn btn-primary"
 | 
					          class="btn btn-primary"
 | 
				
			||||||
        >
 | 
					        >
 | 
				
			||||||
          <%= dgettext("actions", "Record shots") %>
 | 
					          <%= dgettext("actions", "Record shots") %>
 | 
				
			||||||
        </.link>
 | 
					        </.link>
 | 
				
			||||||
      </.ammo_group_card>
 | 
					      </.pack_card>
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
  <% end %>
 | 
					  <% end %>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  <hr class="hr" />
 | 
					  <hr class="hr" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  <%= if @shot_groups |> Enum.empty?() and @search |> is_nil() do %>
 | 
					  <%= if @shot_record_count == 0 do %>
 | 
				
			||||||
    <h1 class="title text-xl text-primary-600">
 | 
					    <h1 class="title text-xl text-primary-600">
 | 
				
			||||||
      <%= gettext("No shots recorded") %>
 | 
					      <%= gettext("No shots recorded") %>
 | 
				
			||||||
      <%= display_emoji("😔") %>
 | 
					      <%= display_emoji("😔") %>
 | 
				
			||||||
@@ -74,17 +74,41 @@
 | 
				
			|||||||
      <%= dgettext("errors", "Your browser does not support the canvas element.") %>
 | 
					      <%= dgettext("errors", "Your browser does not support the canvas element.") %>
 | 
				
			||||||
    </canvas>
 | 
					    </canvas>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <div class="w-full flex flex-col sm:flex-row justify-center items-center space-y-4 sm:space-y-0 sm:space-x-4 max-w-xl">
 | 
					    <div class="w-full flex flex-col sm:flex-row justify-center items-center space-y-4 sm:space-y-0 sm:space-x-4 max-w-2xl">
 | 
				
			||||||
 | 
					      <.form
 | 
				
			||||||
 | 
					        :let={f}
 | 
				
			||||||
 | 
					        for={%{}}
 | 
				
			||||||
 | 
					        as={:type}
 | 
				
			||||||
 | 
					        phx-change="change_class"
 | 
				
			||||||
 | 
					        phx-submit="change_class"
 | 
				
			||||||
 | 
					        class="flex items-center"
 | 
				
			||||||
 | 
					      >
 | 
				
			||||||
 | 
					        <%= label(f, :class, gettext("Class"), class: "title text-primary-600 text-lg text-center") %>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <%= select(
 | 
				
			||||||
 | 
					          f,
 | 
				
			||||||
 | 
					          :class,
 | 
				
			||||||
 | 
					          [
 | 
				
			||||||
 | 
					            {gettext("All"), :all},
 | 
				
			||||||
 | 
					            {gettext("Rifle"), :rifle},
 | 
				
			||||||
 | 
					            {gettext("Shotgun"), :shotgun},
 | 
				
			||||||
 | 
					            {gettext("Pistol"), :pistol}
 | 
				
			||||||
 | 
					          ],
 | 
				
			||||||
 | 
					          class: "mx-2 my-1 min-w-md input input-primary",
 | 
				
			||||||
 | 
					          value: @class
 | 
				
			||||||
 | 
					        ) %>
 | 
				
			||||||
 | 
					      </.form>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      <.form
 | 
					      <.form
 | 
				
			||||||
        :let={f}
 | 
					        :let={f}
 | 
				
			||||||
        for={%{}}
 | 
					        for={%{}}
 | 
				
			||||||
        as={:search}
 | 
					        as={:search}
 | 
				
			||||||
        phx-change="search"
 | 
					        phx-change="search"
 | 
				
			||||||
        phx-submit="search"
 | 
					        phx-submit="search"
 | 
				
			||||||
        class="grow self-stretch flex flex-col items-stretch"
 | 
					        class="grow flex items-center"
 | 
				
			||||||
      >
 | 
					      >
 | 
				
			||||||
        <%= text_input(f, :search_term,
 | 
					        <%= text_input(f, :search_term,
 | 
				
			||||||
          class: "input input-primary",
 | 
					          class: "grow input input-primary",
 | 
				
			||||||
          value: @search,
 | 
					          value: @search,
 | 
				
			||||||
          role: "search",
 | 
					          role: "search",
 | 
				
			||||||
          phx_debounce: 300,
 | 
					          phx_debounce: 300,
 | 
				
			||||||
@@ -93,26 +117,26 @@
 | 
				
			|||||||
      </.form>
 | 
					      </.form>
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <%= if @shot_groups |> Enum.empty?() do %>
 | 
					    <%= if @shot_records |> Enum.empty?() do %>
 | 
				
			||||||
      <h1 class="title text-xl text-primary-600">
 | 
					      <h1 class="title text-xl text-primary-600">
 | 
				
			||||||
        <%= gettext("No shots recorded") %>
 | 
					        <%= gettext("No shots recorded") %>
 | 
				
			||||||
        <%= display_emoji("😔") %>
 | 
					        <%= display_emoji("😔") %>
 | 
				
			||||||
      </h1>
 | 
					      </h1>
 | 
				
			||||||
    <% else %>
 | 
					    <% else %>
 | 
				
			||||||
      <.live_component
 | 
					      <.live_component
 | 
				
			||||||
        module={CanneryWeb.Components.ShotGroupTableComponent}
 | 
					        module={CanneryWeb.Components.ShotRecordTableComponent}
 | 
				
			||||||
        id="shot_groups_index_table"
 | 
					        id="shot_records_index_table"
 | 
				
			||||||
        shot_groups={@shot_groups}
 | 
					        shot_records={@shot_records}
 | 
				
			||||||
        current_user={@current_user}
 | 
					        current_user={@current_user}
 | 
				
			||||||
      >
 | 
					      >
 | 
				
			||||||
        <:actions :let={shot_group}>
 | 
					        <:actions :let={shot_record}>
 | 
				
			||||||
          <div class="px-4 py-2 space-x-4 flex justify-center items-center">
 | 
					          <div class="px-4 py-2 space-x-4 flex justify-center items-center">
 | 
				
			||||||
            <.link
 | 
					            <.link
 | 
				
			||||||
              patch={Routes.range_index_path(Endpoint, :edit, shot_group)}
 | 
					              patch={Routes.range_index_path(Endpoint, :edit, shot_record)}
 | 
				
			||||||
              class="text-primary-600 link"
 | 
					              class="text-primary-600 link"
 | 
				
			||||||
              aria-label={
 | 
					              aria-label={
 | 
				
			||||||
                dgettext("actions", "Edit shot record of %{shot_group_count} shots",
 | 
					                dgettext("actions", "Edit shot record of %{shot_record_count} shots",
 | 
				
			||||||
                  shot_group_count: shot_group.count
 | 
					                  shot_record_count: shot_record.count
 | 
				
			||||||
                )
 | 
					                )
 | 
				
			||||||
              }
 | 
					              }
 | 
				
			||||||
            >
 | 
					            >
 | 
				
			||||||
@@ -123,13 +147,13 @@
 | 
				
			|||||||
              href="#"
 | 
					              href="#"
 | 
				
			||||||
              class="text-primary-600 link"
 | 
					              class="text-primary-600 link"
 | 
				
			||||||
              phx-click="delete"
 | 
					              phx-click="delete"
 | 
				
			||||||
              phx-value-id={shot_group.id}
 | 
					              phx-value-id={shot_record.id}
 | 
				
			||||||
              data-confirm={
 | 
					              data-confirm={
 | 
				
			||||||
                dgettext("prompts", "Are you sure you want to delete this shot record?")
 | 
					                dgettext("prompts", "Are you sure you want to delete this shot record?")
 | 
				
			||||||
              }
 | 
					              }
 | 
				
			||||||
              aria-label={
 | 
					              aria-label={
 | 
				
			||||||
                dgettext("actions", "Delete shot record of %{shot_group_count} shots",
 | 
					                dgettext("actions", "Delete shot record of %{shot_record_count} shots",
 | 
				
			||||||
                  shot_group_count: shot_group.count
 | 
					                  shot_record_count: shot_record.count
 | 
				
			||||||
                )
 | 
					                )
 | 
				
			||||||
              }
 | 
					              }
 | 
				
			||||||
            >
 | 
					            >
 | 
				
			||||||
@@ -147,22 +171,22 @@
 | 
				
			|||||||
    <.modal return_to={Routes.range_index_path(Endpoint, :index)}>
 | 
					    <.modal return_to={Routes.range_index_path(Endpoint, :index)}>
 | 
				
			||||||
      <.live_component
 | 
					      <.live_component
 | 
				
			||||||
        module={CanneryWeb.RangeLive.FormComponent}
 | 
					        module={CanneryWeb.RangeLive.FormComponent}
 | 
				
			||||||
        id={@shot_group.id}
 | 
					        id={@shot_record.id}
 | 
				
			||||||
        title={@page_title}
 | 
					        title={@page_title}
 | 
				
			||||||
        action={@live_action}
 | 
					        action={@live_action}
 | 
				
			||||||
        shot_group={@shot_group}
 | 
					        shot_record={@shot_record}
 | 
				
			||||||
        return_to={Routes.range_index_path(Endpoint, :index)}
 | 
					        return_to={Routes.range_index_path(Endpoint, :index)}
 | 
				
			||||||
        current_user={@current_user}
 | 
					        current_user={@current_user}
 | 
				
			||||||
      />
 | 
					      />
 | 
				
			||||||
    </.modal>
 | 
					    </.modal>
 | 
				
			||||||
  <% :add_shot_group -> %>
 | 
					  <% :add_shot_record -> %>
 | 
				
			||||||
    <.modal return_to={Routes.range_index_path(Endpoint, :index)}>
 | 
					    <.modal return_to={Routes.range_index_path(Endpoint, :index)}>
 | 
				
			||||||
      <.live_component
 | 
					      <.live_component
 | 
				
			||||||
        module={CanneryWeb.Components.AddShotGroupComponent}
 | 
					        module={CanneryWeb.Components.AddShotRecordComponent}
 | 
				
			||||||
        id={:new}
 | 
					        id={:new}
 | 
				
			||||||
        title={@page_title}
 | 
					        title={@page_title}
 | 
				
			||||||
        action={@live_action}
 | 
					        action={@live_action}
 | 
				
			||||||
        ammo_group={@ammo_group}
 | 
					        pack={@pack}
 | 
				
			||||||
        return_to={Routes.range_index_path(Endpoint, :index)}
 | 
					        return_to={Routes.range_index_path(Endpoint, :index)}
 | 
				
			||||||
        current_user={@current_user}
 | 
					        current_user={@current_user}
 | 
				
			||||||
      />
 | 
					      />
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -19,7 +19,7 @@
 | 
				
			|||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <%= label(f, :name, gettext("Name"), class: "title text-lg text-primary-600") %>
 | 
					    <%= label(f, :name, gettext("Name"), class: "title text-lg text-primary-600") %>
 | 
				
			||||||
    <%= text_input(f, :name, class: "input input-primary col-span-2") %>
 | 
					    <%= text_input(f, :name, class: "input input-primary col-span-2", maxlength: 255) %>
 | 
				
			||||||
    <%= error_tag(f, :name, "col-span-3") %>
 | 
					    <%= error_tag(f, :name, "col-span-3") %>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <%= label(f, :bg_color, gettext("Background color"), class: "title text-lg text-primary-600") %>
 | 
					    <%= label(f, :bg_color, gettext("Background color"), class: "title text-lg text-primary-600") %>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,57 +18,57 @@
 | 
				
			|||||||
    <.link patch={Routes.tag_index_path(Endpoint, :new)} class="btn btn-primary">
 | 
					    <.link patch={Routes.tag_index_path(Endpoint, :new)} class="btn btn-primary">
 | 
				
			||||||
      <%= dgettext("actions", "New Tag") %>
 | 
					      <%= dgettext("actions", "New Tag") %>
 | 
				
			||||||
    </.link>
 | 
					    </.link>
 | 
				
			||||||
  <% end %>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  <div class="w-full flex flex-col sm:flex-row justify-center items-center space-y-4 sm:space-y-0 sm:space-x-4 max-w-xl">
 | 
					    <div class="w-full flex flex-col sm:flex-row justify-center items-center space-y-4 sm:space-y-0 sm:space-x-4 max-w-2xl">
 | 
				
			||||||
    <.form
 | 
					      <.form
 | 
				
			||||||
      :let={f}
 | 
					        :let={f}
 | 
				
			||||||
      for={%{}}
 | 
					        for={%{}}
 | 
				
			||||||
      as={:search}
 | 
					        as={:search}
 | 
				
			||||||
      phx-change="search"
 | 
					        phx-change="search"
 | 
				
			||||||
      phx-submit="search"
 | 
					        phx-submit="search"
 | 
				
			||||||
      class="grow self-stretch flex flex-col items-stretch"
 | 
					        class="grow flex items-center"
 | 
				
			||||||
    >
 | 
					      >
 | 
				
			||||||
      <%= text_input(f, :search_term,
 | 
					        <%= text_input(f, :search_term,
 | 
				
			||||||
        class: "input input-primary",
 | 
					          class: "grow input input-primary",
 | 
				
			||||||
        value: @search,
 | 
					          value: @search,
 | 
				
			||||||
        role: "search",
 | 
					          role: "search",
 | 
				
			||||||
        phx_debounce: 300,
 | 
					          phx_debounce: 300,
 | 
				
			||||||
        placeholder: gettext("Search tags")
 | 
					          placeholder: gettext("Search tags")
 | 
				
			||||||
      ) %>
 | 
					        ) %>
 | 
				
			||||||
    </.form>
 | 
					      </.form>
 | 
				
			||||||
  </div>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  <%= if @tags |> Enum.empty?() do %>
 | 
					 | 
				
			||||||
    <h2 class="title text-xl text-primary-600">
 | 
					 | 
				
			||||||
      <%= gettext("No tags") %>
 | 
					 | 
				
			||||||
      <%= display_emoji("😔") %>
 | 
					 | 
				
			||||||
    </h2>
 | 
					 | 
				
			||||||
  <% else %>
 | 
					 | 
				
			||||||
    <div class="flex flex-row flex-wrap justify-center items-stretch">
 | 
					 | 
				
			||||||
      <.tag_card :for={tag <- @tags} tag={tag}>
 | 
					 | 
				
			||||||
        <.link
 | 
					 | 
				
			||||||
          patch={Routes.tag_index_path(Endpoint, :edit, tag)}
 | 
					 | 
				
			||||||
          class="text-primary-600 link"
 | 
					 | 
				
			||||||
          aria-label={dgettext("actions", "Edit %{tag_name}", tag_name: tag.name)}
 | 
					 | 
				
			||||||
        >
 | 
					 | 
				
			||||||
          <i class="fa-fw fa-lg fas fa-edit"></i>
 | 
					 | 
				
			||||||
        </.link>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        <.link
 | 
					 | 
				
			||||||
          href="#"
 | 
					 | 
				
			||||||
          class="text-primary-600 link"
 | 
					 | 
				
			||||||
          phx-click="delete"
 | 
					 | 
				
			||||||
          phx-value-id={tag.id}
 | 
					 | 
				
			||||||
          data-confirm={
 | 
					 | 
				
			||||||
            dgettext("prompts", "Are you sure you want to delete %{name}?", name: tag.name)
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
          aria-label={dgettext("actions", "Delete %{tag_name}", tag_name: tag.name)}
 | 
					 | 
				
			||||||
        >
 | 
					 | 
				
			||||||
          <i class="fa-fw fa-lg fas fa-trash"></i>
 | 
					 | 
				
			||||||
        </.link>
 | 
					 | 
				
			||||||
      </.tag_card>
 | 
					 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <%= if @tags |> Enum.empty?() do %>
 | 
				
			||||||
 | 
					      <h2 class="title text-xl text-primary-600">
 | 
				
			||||||
 | 
					        <%= gettext("No tags") %>
 | 
				
			||||||
 | 
					        <%= display_emoji("😔") %>
 | 
				
			||||||
 | 
					      </h2>
 | 
				
			||||||
 | 
					    <% else %>
 | 
				
			||||||
 | 
					      <div class="flex flex-row flex-wrap justify-center items-stretch">
 | 
				
			||||||
 | 
					        <.tag_card :for={tag <- @tags} tag={tag}>
 | 
				
			||||||
 | 
					          <.link
 | 
				
			||||||
 | 
					            patch={Routes.tag_index_path(Endpoint, :edit, tag)}
 | 
				
			||||||
 | 
					            class="text-primary-600 link"
 | 
				
			||||||
 | 
					            aria-label={dgettext("actions", "Edit %{tag_name}", tag_name: tag.name)}
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            <i class="fa-fw fa-lg fas fa-edit"></i>
 | 
				
			||||||
 | 
					          </.link>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          <.link
 | 
				
			||||||
 | 
					            href="#"
 | 
				
			||||||
 | 
					            class="text-primary-600 link"
 | 
				
			||||||
 | 
					            phx-click="delete"
 | 
				
			||||||
 | 
					            phx-value-id={tag.id}
 | 
				
			||||||
 | 
					            data-confirm={
 | 
				
			||||||
 | 
					              dgettext("prompts", "Are you sure you want to delete %{name}?", name: tag.name)
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            aria-label={dgettext("actions", "Delete %{tag_name}", tag_name: tag.name)}
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            <i class="fa-fw fa-lg fas fa-trash"></i>
 | 
				
			||||||
 | 
					          </.link>
 | 
				
			||||||
 | 
					        </.tag_card>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					    <% end %>
 | 
				
			||||||
  <% end %>
 | 
					  <% end %>
 | 
				
			||||||
</div>
 | 
					</div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,16 +1,16 @@
 | 
				
			|||||||
defmodule CanneryWeb.AmmoTypeLive.FormComponent do
 | 
					defmodule CanneryWeb.TypeLive.FormComponent do
 | 
				
			||||||
  @moduledoc """
 | 
					  @moduledoc """
 | 
				
			||||||
  Livecomponent that can update or create an Cannery.Ammo.AmmoType
 | 
					  Livecomponent that can update or create an Cannery.Ammo.Type
 | 
				
			||||||
  """
 | 
					  """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  use CanneryWeb, :live_component
 | 
					  use CanneryWeb, :live_component
 | 
				
			||||||
  alias Cannery.{Accounts.User, Ammo, Ammo.AmmoType}
 | 
					  alias Cannery.{Accounts.User, Ammo, Ammo.Type}
 | 
				
			||||||
  alias Ecto.Changeset
 | 
					  alias Ecto.Changeset
 | 
				
			||||||
  alias Phoenix.LiveView.Socket
 | 
					  alias Phoenix.LiveView.Socket
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @impl true
 | 
					  @impl true
 | 
				
			||||||
  @spec update(
 | 
					  @spec update(
 | 
				
			||||||
          %{:ammo_type => AmmoType.t(), :current_user => User.t(), optional(any) => any},
 | 
					          %{:type => Type.t(), :current_user => User.t(), optional(any) => any},
 | 
				
			||||||
          Socket.t()
 | 
					          Socket.t()
 | 
				
			||||||
        ) :: {:ok, Socket.t()}
 | 
					        ) :: {:ok, Socket.t()}
 | 
				
			||||||
  def update(%{current_user: _current_user} = assigns, socket) do
 | 
					  def update(%{current_user: _current_user} = assigns, socket) do
 | 
				
			||||||
@@ -18,21 +18,21 @@ defmodule CanneryWeb.AmmoTypeLive.FormComponent do
 | 
				
			|||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @impl true
 | 
					  @impl true
 | 
				
			||||||
  def handle_event("validate", %{"ammo_type" => ammo_type_params}, socket) do
 | 
					  def handle_event("validate", %{"type" => type_params}, socket) do
 | 
				
			||||||
    {:noreply, socket |> assign_changeset(ammo_type_params)}
 | 
					    {:noreply, socket |> assign_changeset(type_params)}
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def handle_event(
 | 
					  def handle_event(
 | 
				
			||||||
        "save",
 | 
					        "save",
 | 
				
			||||||
        %{"ammo_type" => ammo_type_params},
 | 
					        %{"type" => type_params},
 | 
				
			||||||
        %{assigns: %{action: action}} = socket
 | 
					        %{assigns: %{action: action}} = socket
 | 
				
			||||||
      ) do
 | 
					      ) do
 | 
				
			||||||
    save_ammo_type(socket, action, ammo_type_params)
 | 
					    save_type(socket, action, type_params)
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  defp assign_changeset(
 | 
					  defp assign_changeset(
 | 
				
			||||||
         %{assigns: %{action: action, ammo_type: ammo_type, current_user: user}} = socket,
 | 
					         %{assigns: %{action: action, type: type, current_user: user}} = socket,
 | 
				
			||||||
         ammo_type_params
 | 
					         type_params
 | 
				
			||||||
       ) do
 | 
					       ) do
 | 
				
			||||||
    changeset_action =
 | 
					    changeset_action =
 | 
				
			||||||
      case action do
 | 
					      case action do
 | 
				
			||||||
@@ -43,10 +43,10 @@ defmodule CanneryWeb.AmmoTypeLive.FormComponent do
 | 
				
			|||||||
    changeset =
 | 
					    changeset =
 | 
				
			||||||
      case action do
 | 
					      case action do
 | 
				
			||||||
        create when create in [:new, :clone] ->
 | 
					        create when create in [:new, :clone] ->
 | 
				
			||||||
          ammo_type |> AmmoType.create_changeset(user, ammo_type_params)
 | 
					          type |> Type.create_changeset(user, type_params)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        :edit ->
 | 
					        :edit ->
 | 
				
			||||||
          ammo_type |> AmmoType.update_changeset(ammo_type_params)
 | 
					          type |> Type.update_changeset(type_params)
 | 
				
			||||||
      end
 | 
					      end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    changeset =
 | 
					    changeset =
 | 
				
			||||||
@@ -58,16 +58,15 @@ defmodule CanneryWeb.AmmoTypeLive.FormComponent do
 | 
				
			|||||||
    socket |> assign(changeset: changeset)
 | 
					    socket |> assign(changeset: changeset)
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  defp save_ammo_type(
 | 
					  defp save_type(
 | 
				
			||||||
         %{assigns: %{ammo_type: ammo_type, current_user: current_user, return_to: return_to}} =
 | 
					         %{assigns: %{type: type, current_user: current_user, return_to: return_to}} = socket,
 | 
				
			||||||
           socket,
 | 
					 | 
				
			||||||
         :edit,
 | 
					         :edit,
 | 
				
			||||||
         ammo_type_params
 | 
					         type_params
 | 
				
			||||||
       ) do
 | 
					       ) do
 | 
				
			||||||
    socket =
 | 
					    socket =
 | 
				
			||||||
      case Ammo.update_ammo_type(ammo_type, ammo_type_params, current_user) do
 | 
					      case Ammo.update_type(type, type_params, current_user) do
 | 
				
			||||||
        {:ok, %{name: ammo_type_name}} ->
 | 
					        {:ok, %{name: type_name}} ->
 | 
				
			||||||
          prompt = dgettext("prompts", "%{name} updated successfully", name: ammo_type_name)
 | 
					          prompt = dgettext("prompts", "%{name} updated successfully", name: type_name)
 | 
				
			||||||
          socket |> put_flash(:info, prompt) |> push_navigate(to: return_to)
 | 
					          socket |> put_flash(:info, prompt) |> push_navigate(to: return_to)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        {:error, %Changeset{} = changeset} ->
 | 
					        {:error, %Changeset{} = changeset} ->
 | 
				
			||||||
@@ -77,16 +76,16 @@ defmodule CanneryWeb.AmmoTypeLive.FormComponent do
 | 
				
			|||||||
    {:noreply, socket}
 | 
					    {:noreply, socket}
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  defp save_ammo_type(
 | 
					  defp save_type(
 | 
				
			||||||
         %{assigns: %{current_user: current_user, return_to: return_to}} = socket,
 | 
					         %{assigns: %{current_user: current_user, return_to: return_to}} = socket,
 | 
				
			||||||
         action,
 | 
					         action,
 | 
				
			||||||
         ammo_type_params
 | 
					         type_params
 | 
				
			||||||
       )
 | 
					       )
 | 
				
			||||||
       when action in [:new, :clone] do
 | 
					       when action in [:new, :clone] do
 | 
				
			||||||
    socket =
 | 
					    socket =
 | 
				
			||||||
      case Ammo.create_ammo_type(ammo_type_params, current_user) do
 | 
					      case Ammo.create_type(type_params, current_user) do
 | 
				
			||||||
        {:ok, %{name: ammo_type_name}} ->
 | 
					        {:ok, %{name: type_name}} ->
 | 
				
			||||||
          prompt = dgettext("prompts", "%{name} created successfully", name: ammo_type_name)
 | 
					          prompt = dgettext("prompts", "%{name} created successfully", name: type_name)
 | 
				
			||||||
          socket |> put_flash(:info, prompt) |> push_navigate(to: return_to)
 | 
					          socket |> put_flash(:info, prompt) |> push_navigate(to: return_to)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        {:error, %Changeset{} = changeset} ->
 | 
					        {:error, %Changeset{} = changeset} ->
 | 
				
			||||||
							
								
								
									
										355
									
								
								lib/cannery_web/live/type_live/form_component.html.heex
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										355
									
								
								lib/cannery_web/live/type_live/form_component.html.heex
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,355 @@
 | 
				
			|||||||
 | 
					<div>
 | 
				
			||||||
 | 
					  <h2 class="mb-8 text-center title text-xl text-primary-600">
 | 
				
			||||||
 | 
					    <%= @title %>
 | 
				
			||||||
 | 
					  </h2>
 | 
				
			||||||
 | 
					  <.form
 | 
				
			||||||
 | 
					    :let={f}
 | 
				
			||||||
 | 
					    for={@changeset}
 | 
				
			||||||
 | 
					    id="type-form"
 | 
				
			||||||
 | 
					    phx-target={@myself}
 | 
				
			||||||
 | 
					    phx-change="validate"
 | 
				
			||||||
 | 
					    phx-submit="save"
 | 
				
			||||||
 | 
					    class="flex flex-col space-y-4 sm:space-y-0 sm:grid sm:grid-cols-3 sm:gap-4 justify-center items-center"
 | 
				
			||||||
 | 
					  >
 | 
				
			||||||
 | 
					    <div
 | 
				
			||||||
 | 
					      :if={@changeset.action && not @changeset.valid?()}
 | 
				
			||||||
 | 
					      class="invalid-feedback col-span-3 text-center"
 | 
				
			||||||
 | 
					    >
 | 
				
			||||||
 | 
					      <%= dgettext("errors", "Oops, something went wrong! Please check the errors below.") %>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <%= label(f, :class, gettext("Class"), class: "title text-lg text-primary-600") %>
 | 
				
			||||||
 | 
					    <%= select(
 | 
				
			||||||
 | 
					      f,
 | 
				
			||||||
 | 
					      :class,
 | 
				
			||||||
 | 
					      [{gettext("Rifle"), :rifle}, {gettext("Shotgun"), :shotgun}, {gettext("Pistol"), :pistol}],
 | 
				
			||||||
 | 
					      class: "text-center col-span-2 input input-primary",
 | 
				
			||||||
 | 
					      maxlength: 255
 | 
				
			||||||
 | 
					    ) %>
 | 
				
			||||||
 | 
					    <%= error_tag(f, :class, "col-span-3 text-center") %>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <%= label(f, :name, gettext("Name"), class: "title text-lg text-primary-600") %>
 | 
				
			||||||
 | 
					    <%= text_input(f, :name,
 | 
				
			||||||
 | 
					      class: "text-center col-span-2 input input-primary",
 | 
				
			||||||
 | 
					      maxlength: 255
 | 
				
			||||||
 | 
					    ) %>
 | 
				
			||||||
 | 
					    <%= error_tag(f, :name, "col-span-3 text-center") %>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <%= label(f, :desc, gettext("Description"), class: "title text-lg text-primary-600") %>
 | 
				
			||||||
 | 
					    <%= textarea(f, :desc,
 | 
				
			||||||
 | 
					      id: "type-form-desc",
 | 
				
			||||||
 | 
					      class: "text-center col-span-2 input input-primary",
 | 
				
			||||||
 | 
					      phx_hook: "MaintainAttrs",
 | 
				
			||||||
 | 
					      phx_update: "ignore"
 | 
				
			||||||
 | 
					    ) %>
 | 
				
			||||||
 | 
					    <%= error_tag(f, :desc, "col-span-3 text-center") %>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <h2 class="text-center title text-lg text-primary-600 col-span-3">
 | 
				
			||||||
 | 
					      <%= gettext("Dimensions") %>
 | 
				
			||||||
 | 
					    </h2>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <%= if Changeset.get_field(@changeset, :class) in [:rifle, :pistol] do %>
 | 
				
			||||||
 | 
					      <%= label(f, :cartridge, gettext("Cartridge"), class: "title text-lg text-primary-600") %>
 | 
				
			||||||
 | 
					      <%= text_input(f, :cartridge,
 | 
				
			||||||
 | 
					        class: "text-center col-span-2 input input-primary",
 | 
				
			||||||
 | 
					        maxlength: 255,
 | 
				
			||||||
 | 
					        placeholder: gettext("5.56x46mm NATO")
 | 
				
			||||||
 | 
					      ) %>
 | 
				
			||||||
 | 
					      <%= error_tag(f, :cartridge, "col-span-3 text-center") %>
 | 
				
			||||||
 | 
					    <% else %>
 | 
				
			||||||
 | 
					      <%= hidden_input(f, :cartridge, value: nil) %>
 | 
				
			||||||
 | 
					    <% end %>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <%= label(
 | 
				
			||||||
 | 
					      f,
 | 
				
			||||||
 | 
					      :caliber,
 | 
				
			||||||
 | 
					      if(Changeset.get_field(@changeset, :class) == :shotgun,
 | 
				
			||||||
 | 
					        do: gettext("Gauge"),
 | 
				
			||||||
 | 
					        else: gettext("Caliber")
 | 
				
			||||||
 | 
					      ),
 | 
				
			||||||
 | 
					      class: "title text-lg text-primary-600"
 | 
				
			||||||
 | 
					    ) %>
 | 
				
			||||||
 | 
					    <%= text_input(f, :caliber,
 | 
				
			||||||
 | 
					      class: "text-center col-span-2 input input-primary",
 | 
				
			||||||
 | 
					      maxlength: 255,
 | 
				
			||||||
 | 
					      placeholder: gettext(".223")
 | 
				
			||||||
 | 
					    ) %>
 | 
				
			||||||
 | 
					    <%= error_tag(f, :caliber, "col-span-3 text-center") %>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <%= if Changeset.get_field(@changeset, :class) == :shotgun do %>
 | 
				
			||||||
 | 
					      <%= label(f, :unfired_length, gettext("Unfired shell length"),
 | 
				
			||||||
 | 
					        class: "title text-lg text-primary-600"
 | 
				
			||||||
 | 
					      ) %>
 | 
				
			||||||
 | 
					      <%= text_input(f, :unfired_length,
 | 
				
			||||||
 | 
					        class: "text-center col-span-2 input input-primary",
 | 
				
			||||||
 | 
					        maxlength: 255
 | 
				
			||||||
 | 
					      ) %>
 | 
				
			||||||
 | 
					      <%= error_tag(f, :unfired_length, "col-span-3 text-center") %>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      <%= label(f, :brass_height, gettext("Brass height"), class: "title text-lg text-primary-600") %>
 | 
				
			||||||
 | 
					      <%= text_input(f, :brass_height,
 | 
				
			||||||
 | 
					        class: "text-center col-span-2 input input-primary",
 | 
				
			||||||
 | 
					        maxlength: 255
 | 
				
			||||||
 | 
					      ) %>
 | 
				
			||||||
 | 
					      <%= error_tag(f, :brass_height, "col-span-3 text-center") %>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      <%= label(f, :chamber_size, gettext("Chamber size"), class: "title text-lg text-primary-600") %>
 | 
				
			||||||
 | 
					      <%= text_input(f, :chamber_size,
 | 
				
			||||||
 | 
					        class: "text-center col-span-2 input input-primary",
 | 
				
			||||||
 | 
					        maxlength: 255
 | 
				
			||||||
 | 
					      ) %>
 | 
				
			||||||
 | 
					      <%= error_tag(f, :chamber_size, "col-span-3 text-center") %>
 | 
				
			||||||
 | 
					    <% else %>
 | 
				
			||||||
 | 
					      <%= hidden_input(f, :unfired_length, value: nil) %>
 | 
				
			||||||
 | 
					      <%= hidden_input(f, :brass_height, value: nil) %>
 | 
				
			||||||
 | 
					      <%= hidden_input(f, :chamber_size, value: nil) %>
 | 
				
			||||||
 | 
					    <% end %>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <h2 class="text-center title text-lg text-primary-600 col-span-3">
 | 
				
			||||||
 | 
					      <%= gettext("Projectile") %>
 | 
				
			||||||
 | 
					    </h2>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <%= label(f, :grains, gettext("Grains"), class: "title text-lg text-primary-600") %>
 | 
				
			||||||
 | 
					    <%= number_input(f, :grains,
 | 
				
			||||||
 | 
					      step: "1",
 | 
				
			||||||
 | 
					      class: "text-center col-span-2 input input-primary",
 | 
				
			||||||
 | 
					      min: 1
 | 
				
			||||||
 | 
					    ) %>
 | 
				
			||||||
 | 
					    <%= error_tag(f, :grains, "col-span-3 text-center") %>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <%= label f, :bullet_type, class: "flex title text-lg text-primary-600 space-x-2" do %>
 | 
				
			||||||
 | 
					      <p><%= gettext("Bullet type") %></p>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      <.link
 | 
				
			||||||
 | 
					        href="https://shootersreference.com/reloadingdata/bullet_abbreviations/"
 | 
				
			||||||
 | 
					        class="link"
 | 
				
			||||||
 | 
					        target="_blank"
 | 
				
			||||||
 | 
					        rel="noopener noreferrer"
 | 
				
			||||||
 | 
					      >
 | 
				
			||||||
 | 
					        <i class="fas fa-md fa-external-link-alt"></i>
 | 
				
			||||||
 | 
					      </.link>
 | 
				
			||||||
 | 
					    <% end %>
 | 
				
			||||||
 | 
					    <%= text_input(f, :bullet_type,
 | 
				
			||||||
 | 
					      class: "text-center col-span-2 input input-primary",
 | 
				
			||||||
 | 
					      maxlength: 255,
 | 
				
			||||||
 | 
					      placeholder: gettext("FMJ")
 | 
				
			||||||
 | 
					    ) %>
 | 
				
			||||||
 | 
					    <%= error_tag(f, :bullet_type, "col-span-3 text-center") %>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <%= label(
 | 
				
			||||||
 | 
					      f,
 | 
				
			||||||
 | 
					      :bullet_core,
 | 
				
			||||||
 | 
					      if(Changeset.get_field(@changeset, :class) == :shotgun,
 | 
				
			||||||
 | 
					        do: gettext("Slug core"),
 | 
				
			||||||
 | 
					        else: gettext("Bullet core")
 | 
				
			||||||
 | 
					      ),
 | 
				
			||||||
 | 
					      class: "title text-lg text-primary-600"
 | 
				
			||||||
 | 
					    ) %>
 | 
				
			||||||
 | 
					    <%= text_input(f, :bullet_core,
 | 
				
			||||||
 | 
					      class: "text-center col-span-2 input input-primary",
 | 
				
			||||||
 | 
					      maxlength: 255,
 | 
				
			||||||
 | 
					      placeholder: gettext("Steel")
 | 
				
			||||||
 | 
					    ) %>
 | 
				
			||||||
 | 
					    <%= error_tag(f, :bullet_core, "col-span-3 text-center") %>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <%= if Changeset.get_field(@changeset, :class) in [:rifle, :pistol] do %>
 | 
				
			||||||
 | 
					      <%= label(f, :jacket_type, gettext("Jacket type"), class: "title text-lg text-primary-600") %>
 | 
				
			||||||
 | 
					      <%= text_input(f, :jacket_type,
 | 
				
			||||||
 | 
					        class: "text-center col-span-2 input input-primary",
 | 
				
			||||||
 | 
					        maxlength: 255,
 | 
				
			||||||
 | 
					        placeholder: gettext("Bimetal")
 | 
				
			||||||
 | 
					      ) %>
 | 
				
			||||||
 | 
					      <%= error_tag(f, :jacket_type, "col-span-3 text-center") %>
 | 
				
			||||||
 | 
					    <% else %>
 | 
				
			||||||
 | 
					      <%= hidden_input(f, :jacket_type, value: nil) %>
 | 
				
			||||||
 | 
					    <% end %>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <%= label(f, :case_material, gettext("Case material"), class: "title text-lg text-primary-600") %>
 | 
				
			||||||
 | 
					    <%= text_input(f, :case_material,
 | 
				
			||||||
 | 
					      class: "text-center col-span-2 input input-primary",
 | 
				
			||||||
 | 
					      maxlength: 255,
 | 
				
			||||||
 | 
					      placeholder: gettext("Brass")
 | 
				
			||||||
 | 
					    ) %>
 | 
				
			||||||
 | 
					    <%= error_tag(f, :case_material, "col-span-3 text-center") %>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <%= if Changeset.get_field(@changeset, :class) == :shotgun do %>
 | 
				
			||||||
 | 
					      <%= label(f, :wadding, gettext("Wadding"), class: "title text-lg text-primary-600") %>
 | 
				
			||||||
 | 
					      <%= text_input(f, :wadding,
 | 
				
			||||||
 | 
					        class: "text-center col-span-2 input input-primary",
 | 
				
			||||||
 | 
					        maxlength: 255
 | 
				
			||||||
 | 
					      ) %>
 | 
				
			||||||
 | 
					      <%= error_tag(f, :wadding, "col-span-3 text-center") %>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      <%= label(f, :shot_type, gettext("Shot type"), class: "title text-lg text-primary-600") %>
 | 
				
			||||||
 | 
					      <%= text_input(f, :shot_type,
 | 
				
			||||||
 | 
					        class: "text-center col-span-2 input input-primary",
 | 
				
			||||||
 | 
					        maxlength: 255,
 | 
				
			||||||
 | 
					        placeholder: gettext("Target, bird, buck, etc")
 | 
				
			||||||
 | 
					      ) %>
 | 
				
			||||||
 | 
					      <%= error_tag(f, :shot_type, "col-span-3 text-center") %>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      <%= label(f, :shot_material, gettext("Shot material"),
 | 
				
			||||||
 | 
					        class: "title text-lg text-primary-600"
 | 
				
			||||||
 | 
					      ) %>
 | 
				
			||||||
 | 
					      <%= text_input(f, :shot_material,
 | 
				
			||||||
 | 
					        class: "text-center col-span-2 input input-primary",
 | 
				
			||||||
 | 
					        maxlength: 255
 | 
				
			||||||
 | 
					      ) %>
 | 
				
			||||||
 | 
					      <%= error_tag(f, :shot_material, "col-span-3 text-center") %>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      <%= label(f, :shot_size, gettext("Shot size"), class: "title text-lg text-primary-600") %>
 | 
				
			||||||
 | 
					      <%= text_input(f, :shot_size,
 | 
				
			||||||
 | 
					        class: "text-center col-span-2 input input-primary",
 | 
				
			||||||
 | 
					        maxlength: 255
 | 
				
			||||||
 | 
					      ) %>
 | 
				
			||||||
 | 
					      <%= error_tag(f, :shot_size, "col-span-3 text-center") %>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      <%= label(f, :load_grains, gettext("Load grains"), class: "title text-lg text-primary-600") %>
 | 
				
			||||||
 | 
					      <%= number_input(f, :load_grains,
 | 
				
			||||||
 | 
					        step: "1",
 | 
				
			||||||
 | 
					        class: "text-center col-span-2 input input-primary",
 | 
				
			||||||
 | 
					        min: 1
 | 
				
			||||||
 | 
					      ) %>
 | 
				
			||||||
 | 
					      <%= error_tag(f, :load_grains, "col-span-3 text-center") %>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      <%= label(f, :shot_charge_weight, gettext("Shot charge weight"),
 | 
				
			||||||
 | 
					        class: "title text-lg text-primary-600"
 | 
				
			||||||
 | 
					      ) %>
 | 
				
			||||||
 | 
					      <%= text_input(f, :shot_charge_weight,
 | 
				
			||||||
 | 
					        class: "text-center col-span-2 input input-primary",
 | 
				
			||||||
 | 
					        maxlength: 255
 | 
				
			||||||
 | 
					      ) %>
 | 
				
			||||||
 | 
					      <%= error_tag(f, :shot_charge_weight, "col-span-3 text-center") %>
 | 
				
			||||||
 | 
					    <% else %>
 | 
				
			||||||
 | 
					      <%= hidden_input(f, :wadding, value: nil) %>
 | 
				
			||||||
 | 
					      <%= hidden_input(f, :shot_type, value: nil) %>
 | 
				
			||||||
 | 
					      <%= hidden_input(f, :shot_material, value: nil) %>
 | 
				
			||||||
 | 
					      <%= hidden_input(f, :shot_size, value: nil) %>
 | 
				
			||||||
 | 
					      <%= hidden_input(f, :load_grains, value: nil) %>
 | 
				
			||||||
 | 
					      <%= hidden_input(f, :shot_charge_weight, value: nil) %>
 | 
				
			||||||
 | 
					    <% end %>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <h2 class="text-center title text-lg text-primary-600 col-span-3">
 | 
				
			||||||
 | 
					      <%= gettext("Powder") %>
 | 
				
			||||||
 | 
					    </h2>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <%= label(f, :powder_type, gettext("Powder type"), class: "title text-lg text-primary-600") %>
 | 
				
			||||||
 | 
					    <%= text_input(f, :powder_type,
 | 
				
			||||||
 | 
					      class: "text-center col-span-2 input input-primary",
 | 
				
			||||||
 | 
					      maxlength: 255
 | 
				
			||||||
 | 
					    ) %>
 | 
				
			||||||
 | 
					    <%= error_tag(f, :powder_type, "col-span-3 text-center") %>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <%= if Changeset.get_field(@changeset, :class) in [:rifle, :pistol] do %>
 | 
				
			||||||
 | 
					      <%= label(f, :powder_grains_per_charge, gettext("Powder grains per charge"),
 | 
				
			||||||
 | 
					        class: "title text-lg text-primary-600"
 | 
				
			||||||
 | 
					      ) %>
 | 
				
			||||||
 | 
					      <%= number_input(f, :powder_grains_per_charge,
 | 
				
			||||||
 | 
					        step: "1",
 | 
				
			||||||
 | 
					        class: "text-center col-span-2 input input-primary",
 | 
				
			||||||
 | 
					        min: 1
 | 
				
			||||||
 | 
					      ) %>
 | 
				
			||||||
 | 
					      <%= error_tag(f, :powder_grains_per_charge, "col-span-3 text-center") %>
 | 
				
			||||||
 | 
					    <% else %>
 | 
				
			||||||
 | 
					      <%= hidden_input(f, :powder_grains_per_charge, value: nil) %>
 | 
				
			||||||
 | 
					    <% end %>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <%= label(f, :pressure, gettext("Pressure"), class: "title text-lg text-primary-600") %>
 | 
				
			||||||
 | 
					    <%= text_input(f, :pressure,
 | 
				
			||||||
 | 
					      class: "text-center col-span-2 input input-primary",
 | 
				
			||||||
 | 
					      maxlength: 255,
 | 
				
			||||||
 | 
					      placeholder: gettext("+P")
 | 
				
			||||||
 | 
					    ) %>
 | 
				
			||||||
 | 
					    <%= error_tag(f, :pressure, "col-span-3 text-center") %>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <%= if Changeset.get_field(@changeset, :class) == :shotgun do %>
 | 
				
			||||||
 | 
					      <%= label(f, :dram_equivalent, gettext("Dram equivalent"),
 | 
				
			||||||
 | 
					        class: "title text-lg text-primary-600"
 | 
				
			||||||
 | 
					      ) %>
 | 
				
			||||||
 | 
					      <%= text_input(f, :dram_equivalent,
 | 
				
			||||||
 | 
					        class: "text-center col-span-2 input input-primary",
 | 
				
			||||||
 | 
					        maxlength: 255
 | 
				
			||||||
 | 
					      ) %>
 | 
				
			||||||
 | 
					      <%= error_tag(f, :dram_equivalent, "col-span-3 text-center") %>
 | 
				
			||||||
 | 
					    <% else %>
 | 
				
			||||||
 | 
					      <%= hidden_input(f, :dram_equivalent, value: nil) %>
 | 
				
			||||||
 | 
					    <% end %>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <%= if Changeset.get_field(@changeset, :class) in [:rifle, :pistol] do %>
 | 
				
			||||||
 | 
					      <%= label(f, :muzzle_velocity, gettext("Muzzle velocity"),
 | 
				
			||||||
 | 
					        class: "title text-lg text-primary-600"
 | 
				
			||||||
 | 
					      ) %>
 | 
				
			||||||
 | 
					      <%= number_input(f, :muzzle_velocity,
 | 
				
			||||||
 | 
					        step: "1",
 | 
				
			||||||
 | 
					        class: "text-center col-span-2 input input-primary",
 | 
				
			||||||
 | 
					        min: 1
 | 
				
			||||||
 | 
					      ) %>
 | 
				
			||||||
 | 
					      <%= error_tag(f, :muzzle_velocity, "col-span-3 text-center") %>
 | 
				
			||||||
 | 
					    <% else %>
 | 
				
			||||||
 | 
					      <%= hidden_input(f, :muzzle_velocity, value: nil) %>
 | 
				
			||||||
 | 
					    <% end %>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <h2 class="text-center title text-lg text-primary-600 col-span-3">
 | 
				
			||||||
 | 
					      <%= gettext("Primer") %>
 | 
				
			||||||
 | 
					    </h2>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <%= label(f, :primer_type, gettext("Primer type"), class: "title text-lg text-primary-600") %>
 | 
				
			||||||
 | 
					    <%= text_input(f, :primer_type,
 | 
				
			||||||
 | 
					      class: "text-center col-span-2 input input-primary",
 | 
				
			||||||
 | 
					      maxlength: 255,
 | 
				
			||||||
 | 
					      placeholder: gettext("Boxer")
 | 
				
			||||||
 | 
					    ) %>
 | 
				
			||||||
 | 
					    <%= error_tag(f, :primer_type, "col-span-3 text-center") %>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <%= label(f, :firing_type, gettext("Firing type"), class: "title text-lg text-primary-600") %>
 | 
				
			||||||
 | 
					    <%= text_input(f, :firing_type,
 | 
				
			||||||
 | 
					      class: "text-center col-span-2 input input-primary",
 | 
				
			||||||
 | 
					      maxlength: 255,
 | 
				
			||||||
 | 
					      placeholder: gettext("Centerfire")
 | 
				
			||||||
 | 
					    ) %>
 | 
				
			||||||
 | 
					    <%= error_tag(f, :firing_type, "col-span-3 text-center") %>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <h2 class="text-center title text-lg text-primary-600 col-span-3">
 | 
				
			||||||
 | 
					      <%= gettext("Attributes") %>
 | 
				
			||||||
 | 
					    </h2>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <%= label(f, :tracer, gettext("Tracer"), class: "title text-lg text-primary-600") %>
 | 
				
			||||||
 | 
					    <%= checkbox(f, :tracer, class: "text-center col-span-2 checkbox") %>
 | 
				
			||||||
 | 
					    <%= error_tag(f, :tracer, "col-span-3 text-center") %>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <%= label(f, :incendiary, gettext("Incendiary"), class: "title text-lg text-primary-600") %>
 | 
				
			||||||
 | 
					    <%= checkbox(f, :incendiary, class: "text-center col-span-2 checkbox") %>
 | 
				
			||||||
 | 
					    <%= error_tag(f, :incendiary, "col-span-3 text-center") %>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <%= label(f, :blank, gettext("Blank"), class: "title text-lg text-primary-600") %>
 | 
				
			||||||
 | 
					    <%= checkbox(f, :blank, class: "text-center col-span-2 checkbox") %>
 | 
				
			||||||
 | 
					    <%= error_tag(f, :blank, "col-span-3 text-center") %>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <%= label(f, :corrosive, gettext("Corrosive"), class: "title text-lg text-primary-600") %>
 | 
				
			||||||
 | 
					    <%= checkbox(f, :corrosive, class: "text-center col-span-2 checkbox") %>
 | 
				
			||||||
 | 
					    <%= error_tag(f, :corrosive, "col-span-3 text-center") %>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <h2 class="text-center title text-lg text-primary-600 col-span-3">
 | 
				
			||||||
 | 
					      <%= gettext("Manufacturer") %>
 | 
				
			||||||
 | 
					    </h2>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <%= label(f, :manufacturer, gettext("Manufacturer"), class: "title text-lg text-primary-600") %>
 | 
				
			||||||
 | 
					    <%= text_input(f, :manufacturer,
 | 
				
			||||||
 | 
					      class: "text-center col-span-2 input input-primary",
 | 
				
			||||||
 | 
					      maxlength: 255
 | 
				
			||||||
 | 
					    ) %>
 | 
				
			||||||
 | 
					    <%= error_tag(f, :manufacturer, "col-span-3 text-center") %>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <%= label(f, :upc, gettext("UPC"), class: "title text-lg text-primary-600") %>
 | 
				
			||||||
 | 
					    <%= text_input(f, :upc,
 | 
				
			||||||
 | 
					      class: "text-center col-span-2 input input-primary",
 | 
				
			||||||
 | 
					      maxlength: 255
 | 
				
			||||||
 | 
					    ) %>
 | 
				
			||||||
 | 
					    <%= error_tag(f, :upc, "col-span-3 text-center") %>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <%= submit(dgettext("actions", "Save"),
 | 
				
			||||||
 | 
					      phx_disable_with: dgettext("prompts", "Saving..."),
 | 
				
			||||||
 | 
					      class: "mx-auto col-span-3 btn btn-primary"
 | 
				
			||||||
 | 
					    ) %>
 | 
				
			||||||
 | 
					  </.form>
 | 
				
			||||||
 | 
					</div>
 | 
				
			||||||
							
								
								
									
										114
									
								
								lib/cannery_web/live/type_live/index.ex
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										114
									
								
								lib/cannery_web/live/type_live/index.ex
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,114 @@
 | 
				
			|||||||
 | 
					defmodule CanneryWeb.TypeLive.Index do
 | 
				
			||||||
 | 
					  @moduledoc """
 | 
				
			||||||
 | 
					  Liveview for showing a Cannery.Ammo.Type index
 | 
				
			||||||
 | 
					  """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  use CanneryWeb, :live_view
 | 
				
			||||||
 | 
					  alias Cannery.{Ammo, Ammo.Type}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @impl true
 | 
				
			||||||
 | 
					  def mount(%{"search" => search}, _session, socket) do
 | 
				
			||||||
 | 
					    {:ok, socket |> assign(class: :all, show_used: false, search: search) |> list_types()}
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def mount(_params, _session, socket) do
 | 
				
			||||||
 | 
					    {:ok, socket |> assign(class: :all, show_used: false, search: nil) |> list_types()}
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @impl true
 | 
				
			||||||
 | 
					  def handle_params(params, _url, %{assigns: %{live_action: live_action}} = socket) do
 | 
				
			||||||
 | 
					    {:noreply, apply_action(socket, live_action, params)}
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  defp apply_action(%{assigns: %{current_user: current_user}} = socket, :edit, %{"id" => id}) do
 | 
				
			||||||
 | 
					    %{name: type_name} = type = Ammo.get_type!(id, current_user)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    socket
 | 
				
			||||||
 | 
					    |> assign(
 | 
				
			||||||
 | 
					      page_title: gettext("Edit %{type_name}", type_name: type_name),
 | 
				
			||||||
 | 
					      type: type
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  defp apply_action(%{assigns: %{current_user: current_user}} = socket, :clone, %{"id" => id}) do
 | 
				
			||||||
 | 
					    socket
 | 
				
			||||||
 | 
					    |> assign(
 | 
				
			||||||
 | 
					      page_title: gettext("New Type"),
 | 
				
			||||||
 | 
					      type: %{Ammo.get_type!(id, current_user) | id: nil}
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  defp apply_action(socket, :new, _params) do
 | 
				
			||||||
 | 
					    socket
 | 
				
			||||||
 | 
					    |> assign(
 | 
				
			||||||
 | 
					      page_title: gettext("New Type"),
 | 
				
			||||||
 | 
					      type: %Type{}
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  defp apply_action(socket, :index, _params) do
 | 
				
			||||||
 | 
					    socket
 | 
				
			||||||
 | 
					    |> assign(
 | 
				
			||||||
 | 
					      page_title: gettext("Catalog"),
 | 
				
			||||||
 | 
					      search: nil,
 | 
				
			||||||
 | 
					      type: nil
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    |> list_types()
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  defp apply_action(socket, :search, %{"search" => search}) do
 | 
				
			||||||
 | 
					    socket
 | 
				
			||||||
 | 
					    |> assign(
 | 
				
			||||||
 | 
					      page_title: gettext("Catalog"),
 | 
				
			||||||
 | 
					      search: search,
 | 
				
			||||||
 | 
					      type: nil
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    |> list_types()
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @impl true
 | 
				
			||||||
 | 
					  def handle_event("delete", %{"id" => id}, %{assigns: %{current_user: current_user}} = socket) do
 | 
				
			||||||
 | 
					    %{name: name} = Ammo.get_type!(id, current_user) |> Ammo.delete_type!(current_user)
 | 
				
			||||||
 | 
					    prompt = dgettext("prompts", "%{name} deleted succesfully", name: name)
 | 
				
			||||||
 | 
					    {:noreply, socket |> put_flash(:info, prompt) |> list_types()}
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def handle_event("toggle_show_used", _params, %{assigns: %{show_used: show_used}} = socket) do
 | 
				
			||||||
 | 
					    {:noreply, socket |> assign(:show_used, !show_used) |> list_types()}
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def handle_event("search", %{"search" => %{"search_term" => ""}}, socket) do
 | 
				
			||||||
 | 
					    {:noreply, socket |> push_patch(to: Routes.type_index_path(Endpoint, :index))}
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def handle_event("search", %{"search" => %{"search_term" => search_term}}, socket) do
 | 
				
			||||||
 | 
					    search_path = Routes.type_index_path(Endpoint, :search, search_term)
 | 
				
			||||||
 | 
					    {:noreply, socket |> push_patch(to: search_path)}
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def handle_event("change_class", %{"type" => %{"class" => "rifle"}}, socket) do
 | 
				
			||||||
 | 
					    {:noreply, socket |> assign(:class, :rifle) |> list_types()}
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def handle_event("change_class", %{"type" => %{"class" => "shotgun"}}, socket) do
 | 
				
			||||||
 | 
					    {:noreply, socket |> assign(:class, :shotgun) |> list_types()}
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def handle_event("change_class", %{"type" => %{"class" => "pistol"}}, socket) do
 | 
				
			||||||
 | 
					    {:noreply, socket |> assign(:class, :pistol) |> list_types()}
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def handle_event("change_class", %{"type" => %{"class" => _all}}, socket) do
 | 
				
			||||||
 | 
					    {:noreply, socket |> assign(:class, :all) |> list_types()}
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  defp list_types(
 | 
				
			||||||
 | 
					         %{assigns: %{class: class, search: search, current_user: current_user}} = socket
 | 
				
			||||||
 | 
					       ) do
 | 
				
			||||||
 | 
					    socket
 | 
				
			||||||
 | 
					    |> assign(
 | 
				
			||||||
 | 
					      types: Ammo.list_types(search, current_user, class),
 | 
				
			||||||
 | 
					      types_count: Ammo.get_types_count!(current_user)
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
@@ -3,31 +3,55 @@
 | 
				
			|||||||
    <%= gettext("Catalog") %>
 | 
					    <%= gettext("Catalog") %>
 | 
				
			||||||
  </h1>
 | 
					  </h1>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  <%= if @ammo_types |> Enum.empty?() and @search |> is_nil() do %>
 | 
					  <%= if @types_count == 0 do %>
 | 
				
			||||||
    <h2 class="title text-xl text-primary-600">
 | 
					    <h2 class="title text-xl text-primary-600">
 | 
				
			||||||
      <%= gettext("No Ammo types") %>
 | 
					      <%= gettext("No Types") %>
 | 
				
			||||||
      <%= display_emoji("😔") %>
 | 
					      <%= display_emoji("😔") %>
 | 
				
			||||||
    </h2>
 | 
					    </h2>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <.link patch={Routes.ammo_type_index_path(Endpoint, :new)} class="btn btn-primary">
 | 
					    <.link patch={Routes.type_index_path(Endpoint, :new)} class="btn btn-primary">
 | 
				
			||||||
      <%= dgettext("actions", "Add your first type!") %>
 | 
					      <%= dgettext("actions", "Add your first type!") %>
 | 
				
			||||||
    </.link>
 | 
					    </.link>
 | 
				
			||||||
  <% else %>
 | 
					  <% else %>
 | 
				
			||||||
    <.link patch={Routes.ammo_type_index_path(Endpoint, :new)} class="btn btn-primary">
 | 
					    <.link patch={Routes.type_index_path(Endpoint, :new)} class="btn btn-primary">
 | 
				
			||||||
      <%= dgettext("actions", "New Ammo type") %>
 | 
					      <%= dgettext("actions", "New Type") %>
 | 
				
			||||||
    </.link>
 | 
					    </.link>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <div class="w-full flex flex-col sm:flex-row justify-center items-center space-y-4 sm:space-y-0 sm:space-x-4 max-w-xl">
 | 
					    <div class="w-full flex flex-col sm:flex-row justify-center items-center space-y-4 sm:space-y-0 sm:space-x-4 max-w-2xl">
 | 
				
			||||||
 | 
					      <.form
 | 
				
			||||||
 | 
					        :let={f}
 | 
				
			||||||
 | 
					        for={%{}}
 | 
				
			||||||
 | 
					        as={:type}
 | 
				
			||||||
 | 
					        phx-change="change_class"
 | 
				
			||||||
 | 
					        phx-submit="change_class"
 | 
				
			||||||
 | 
					        class="flex items-center"
 | 
				
			||||||
 | 
					      >
 | 
				
			||||||
 | 
					        <%= label(f, :class, gettext("Class"), class: "title text-primary-600 text-lg text-center") %>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <%= select(
 | 
				
			||||||
 | 
					          f,
 | 
				
			||||||
 | 
					          :class,
 | 
				
			||||||
 | 
					          [
 | 
				
			||||||
 | 
					            {gettext("All"), :all},
 | 
				
			||||||
 | 
					            {gettext("Rifle"), :rifle},
 | 
				
			||||||
 | 
					            {gettext("Shotgun"), :shotgun},
 | 
				
			||||||
 | 
					            {gettext("Pistol"), :pistol}
 | 
				
			||||||
 | 
					          ],
 | 
				
			||||||
 | 
					          class: "mx-2 my-1 min-w-md input input-primary",
 | 
				
			||||||
 | 
					          value: @class
 | 
				
			||||||
 | 
					        ) %>
 | 
				
			||||||
 | 
					      </.form>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      <.form
 | 
					      <.form
 | 
				
			||||||
        :let={f}
 | 
					        :let={f}
 | 
				
			||||||
        for={%{}}
 | 
					        for={%{}}
 | 
				
			||||||
        as={:search}
 | 
					        as={:search}
 | 
				
			||||||
        phx-change="search"
 | 
					        phx-change="search"
 | 
				
			||||||
        phx-submit="search"
 | 
					        phx-submit="search"
 | 
				
			||||||
        class="grow self-stretch flex flex-col items-stretch"
 | 
					        class="grow flex items-center"
 | 
				
			||||||
      >
 | 
					      >
 | 
				
			||||||
        <%= text_input(f, :search_term,
 | 
					        <%= text_input(f, :search_term,
 | 
				
			||||||
          class: "input input-primary",
 | 
					          class: "grow input input-primary",
 | 
				
			||||||
          value: @search,
 | 
					          value: @search,
 | 
				
			||||||
          role: "search",
 | 
					          role: "search",
 | 
				
			||||||
          phx_debounce: 300,
 | 
					          phx_debounce: 300,
 | 
				
			||||||
@@ -42,48 +66,43 @@
 | 
				
			|||||||
      </.toggle_button>
 | 
					      </.toggle_button>
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <%= if @ammo_types |> Enum.empty?() do %>
 | 
					    <%= if @types |> Enum.empty?() do %>
 | 
				
			||||||
      <h2 class="title text-xl text-primary-600">
 | 
					      <h2 class="title text-xl text-primary-600">
 | 
				
			||||||
        <%= gettext("No Ammo types") %>
 | 
					        <%= gettext("No Types") %>
 | 
				
			||||||
        <%= display_emoji("😔") %>
 | 
					        <%= display_emoji("😔") %>
 | 
				
			||||||
      </h2>
 | 
					      </h2>
 | 
				
			||||||
    <% else %>
 | 
					    <% else %>
 | 
				
			||||||
      <.live_component
 | 
					      <.live_component
 | 
				
			||||||
        module={CanneryWeb.Components.AmmoTypeTableComponent}
 | 
					        module={CanneryWeb.Components.TypeTableComponent}
 | 
				
			||||||
        id="ammo_types_index_table"
 | 
					        id="types_index_table"
 | 
				
			||||||
        action={@live_action}
 | 
					        action={@live_action}
 | 
				
			||||||
        ammo_types={@ammo_types}
 | 
					        types={@types}
 | 
				
			||||||
        current_user={@current_user}
 | 
					        current_user={@current_user}
 | 
				
			||||||
        show_used={@show_used}
 | 
					        show_used={@show_used}
 | 
				
			||||||
 | 
					        class={@class}
 | 
				
			||||||
      >
 | 
					      >
 | 
				
			||||||
        <:actions :let={ammo_type}>
 | 
					        <:actions :let={type}>
 | 
				
			||||||
          <div class="px-4 py-2 space-x-4 flex justify-center items-center">
 | 
					          <div class="px-4 py-2 space-x-4 flex justify-center items-center">
 | 
				
			||||||
            <.link
 | 
					            <.link
 | 
				
			||||||
              navigate={Routes.ammo_type_show_path(Endpoint, :show, ammo_type)}
 | 
					              navigate={Routes.type_show_path(Endpoint, :show, type)}
 | 
				
			||||||
              class="text-primary-600 link"
 | 
					              class="text-primary-600 link"
 | 
				
			||||||
              aria-label={
 | 
					              aria-label={dgettext("actions", "View %{type_name}", type_name: type.name)}
 | 
				
			||||||
                dgettext("actions", "View %{ammo_type_name}", ammo_type_name: ammo_type.name)
 | 
					 | 
				
			||||||
              }
 | 
					 | 
				
			||||||
            >
 | 
					            >
 | 
				
			||||||
              <i class="fa-fw fa-lg fas fa-eye"></i>
 | 
					              <i class="fa-fw fa-lg fas fa-eye"></i>
 | 
				
			||||||
            </.link>
 | 
					            </.link>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            <.link
 | 
					            <.link
 | 
				
			||||||
              patch={Routes.ammo_type_index_path(Endpoint, :edit, ammo_type)}
 | 
					              patch={Routes.type_index_path(Endpoint, :edit, type)}
 | 
				
			||||||
              class="text-primary-600 link"
 | 
					              class="text-primary-600 link"
 | 
				
			||||||
              aria-label={
 | 
					              aria-label={dgettext("actions", "Edit %{type_name}", type_name: type.name)}
 | 
				
			||||||
                dgettext("actions", "Edit %{ammo_type_name}", ammo_type_name: ammo_type.name)
 | 
					 | 
				
			||||||
              }
 | 
					 | 
				
			||||||
            >
 | 
					            >
 | 
				
			||||||
              <i class="fa-fw fa-lg fas fa-edit"></i>
 | 
					              <i class="fa-fw fa-lg fas fa-edit"></i>
 | 
				
			||||||
            </.link>
 | 
					            </.link>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            <.link
 | 
					            <.link
 | 
				
			||||||
              patch={Routes.ammo_type_index_path(Endpoint, :clone, ammo_type)}
 | 
					              patch={Routes.type_index_path(Endpoint, :clone, type)}
 | 
				
			||||||
              class="text-primary-600 link"
 | 
					              class="text-primary-600 link"
 | 
				
			||||||
              aria-label={
 | 
					              aria-label={dgettext("actions", "Clone %{type_name}", type_name: type.name)}
 | 
				
			||||||
                dgettext("actions", "Clone %{ammo_type_name}", ammo_type_name: ammo_type.name)
 | 
					 | 
				
			||||||
              }
 | 
					 | 
				
			||||||
            >
 | 
					            >
 | 
				
			||||||
              <i class="fa-fw fa-lg fas fa-copy"></i>
 | 
					              <i class="fa-fw fa-lg fas fa-copy"></i>
 | 
				
			||||||
            </.link>
 | 
					            </.link>
 | 
				
			||||||
@@ -92,17 +111,15 @@
 | 
				
			|||||||
              href="#"
 | 
					              href="#"
 | 
				
			||||||
              class="text-primary-600 link"
 | 
					              class="text-primary-600 link"
 | 
				
			||||||
              phx-click="delete"
 | 
					              phx-click="delete"
 | 
				
			||||||
              phx-value-id={ammo_type.id}
 | 
					              phx-value-id={type.id}
 | 
				
			||||||
              data-confirm={
 | 
					              data-confirm={
 | 
				
			||||||
                dgettext(
 | 
					                dgettext(
 | 
				
			||||||
                  "prompts",
 | 
					                  "prompts",
 | 
				
			||||||
                  "Are you sure you want to delete %{name}? This will delete all %{name} type ammo as well!",
 | 
					                  "Are you sure you want to delete %{name}? This will delete all %{name} type ammo as well!",
 | 
				
			||||||
                  name: ammo_type.name
 | 
					                  name: type.name
 | 
				
			||||||
                )
 | 
					                )
 | 
				
			||||||
              }
 | 
					              }
 | 
				
			||||||
              aria-label={
 | 
					              aria-label={dgettext("actions", "Delete %{type_name}", type_name: type.name)}
 | 
				
			||||||
                dgettext("actions", "Delete %{ammo_type_name}", ammo_type_name: ammo_type.name)
 | 
					 | 
				
			||||||
              }
 | 
					 | 
				
			||||||
            >
 | 
					            >
 | 
				
			||||||
              <i class="fa-lg fas fa-trash"></i>
 | 
					              <i class="fa-lg fas fa-trash"></i>
 | 
				
			||||||
            </.link>
 | 
					            </.link>
 | 
				
			||||||
@@ -115,15 +132,15 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
<.modal
 | 
					<.modal
 | 
				
			||||||
  :if={@live_action in [:new, :edit, :clone]}
 | 
					  :if={@live_action in [:new, :edit, :clone]}
 | 
				
			||||||
  return_to={Routes.ammo_type_index_path(Endpoint, :index)}
 | 
					  return_to={Routes.type_index_path(Endpoint, :index)}
 | 
				
			||||||
>
 | 
					>
 | 
				
			||||||
  <.live_component
 | 
					  <.live_component
 | 
				
			||||||
    module={CanneryWeb.AmmoTypeLive.FormComponent}
 | 
					    module={CanneryWeb.TypeLive.FormComponent}
 | 
				
			||||||
    id={@ammo_type.id || :new}
 | 
					    id={@type.id || :new}
 | 
				
			||||||
    title={@page_title}
 | 
					    title={@page_title}
 | 
				
			||||||
    action={@live_action}
 | 
					    action={@live_action}
 | 
				
			||||||
    ammo_type={@ammo_type}
 | 
					    type={@type}
 | 
				
			||||||
    return_to={Routes.ammo_type_index_path(Endpoint, :index)}
 | 
					    return_to={Routes.type_index_path(Endpoint, :index)}
 | 
				
			||||||
    current_user={@current_user}
 | 
					    current_user={@current_user}
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  />
 | 
					  />
 | 
				
			||||||
							
								
								
									
										163
									
								
								lib/cannery_web/live/type_live/show.ex
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										163
									
								
								lib/cannery_web/live/type_live/show.ex
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,163 @@
 | 
				
			|||||||
 | 
					defmodule CanneryWeb.TypeLive.Show do
 | 
				
			||||||
 | 
					  @moduledoc """
 | 
				
			||||||
 | 
					  Liveview for showing and editing an Cannery.Ammo.Type
 | 
				
			||||||
 | 
					  """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  use CanneryWeb, :live_view
 | 
				
			||||||
 | 
					  alias Cannery.{ActivityLog, Ammo, Ammo.Type, Containers}
 | 
				
			||||||
 | 
					  alias CanneryWeb.Endpoint
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @impl true
 | 
				
			||||||
 | 
					  def mount(_params, _session, socket),
 | 
				
			||||||
 | 
					    do: {:ok, socket |> assign(show_used: false, view_table: true)}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @impl true
 | 
				
			||||||
 | 
					  def handle_params(%{"id" => id}, _params, socket) do
 | 
				
			||||||
 | 
					    {:noreply, socket |> display_type(id)}
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @impl true
 | 
				
			||||||
 | 
					  def handle_event(
 | 
				
			||||||
 | 
					        "delete",
 | 
				
			||||||
 | 
					        _params,
 | 
				
			||||||
 | 
					        %{assigns: %{type: type, current_user: current_user}} = socket
 | 
				
			||||||
 | 
					      ) do
 | 
				
			||||||
 | 
					    %{name: type_name} = type |> Ammo.delete_type!(current_user)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    prompt = dgettext("prompts", "%{name} deleted succesfully", name: type_name)
 | 
				
			||||||
 | 
					    redirect_to = Routes.type_index_path(socket, :index)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    {:noreply, socket |> put_flash(:info, prompt) |> push_navigate(to: redirect_to)}
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def handle_event("toggle_show_used", _params, %{assigns: %{show_used: show_used}} = socket) do
 | 
				
			||||||
 | 
					    {:noreply, socket |> assign(:show_used, !show_used) |> display_type()}
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def handle_event("toggle_table", _params, %{assigns: %{view_table: view_table}} = socket) do
 | 
				
			||||||
 | 
					    {:noreply, socket |> assign(:view_table, !view_table)}
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  defp display_type(
 | 
				
			||||||
 | 
					         %{assigns: %{live_action: live_action, current_user: current_user, show_used: show_used}} =
 | 
				
			||||||
 | 
					           socket,
 | 
				
			||||||
 | 
					         %Type{name: type_name} = type
 | 
				
			||||||
 | 
					       ) do
 | 
				
			||||||
 | 
					    custom_fields? =
 | 
				
			||||||
 | 
					      fields_to_display(type)
 | 
				
			||||||
 | 
					      |> Enum.any?(fn %{key: field, type: column_type} ->
 | 
				
			||||||
 | 
					        default_value =
 | 
				
			||||||
 | 
					          case column_type do
 | 
				
			||||||
 | 
					            :boolean -> false
 | 
				
			||||||
 | 
					            _other_type -> nil
 | 
				
			||||||
 | 
					          end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        type |> Map.get(field) != default_value
 | 
				
			||||||
 | 
					      end)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    packs = type |> Ammo.list_packs_for_type(current_user, show_used)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    [
 | 
				
			||||||
 | 
					      original_counts,
 | 
				
			||||||
 | 
					      used_packs_count,
 | 
				
			||||||
 | 
					      historical_packs_count,
 | 
				
			||||||
 | 
					      used_rounds,
 | 
				
			||||||
 | 
					      historical_round_count
 | 
				
			||||||
 | 
					    ] =
 | 
				
			||||||
 | 
					      if show_used do
 | 
				
			||||||
 | 
					        [
 | 
				
			||||||
 | 
					          packs |> Ammo.get_original_counts(current_user),
 | 
				
			||||||
 | 
					          type |> Ammo.get_used_packs_count_for_type(current_user),
 | 
				
			||||||
 | 
					          type |> Ammo.get_packs_count_for_type(current_user, true),
 | 
				
			||||||
 | 
					          type |> ActivityLog.get_used_count_for_type(current_user),
 | 
				
			||||||
 | 
					          type |> Ammo.get_historical_count_for_type(current_user)
 | 
				
			||||||
 | 
					        ]
 | 
				
			||||||
 | 
					      else
 | 
				
			||||||
 | 
					        [nil, nil, nil, nil, nil]
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    page_title =
 | 
				
			||||||
 | 
					      case live_action do
 | 
				
			||||||
 | 
					        :show -> type_name
 | 
				
			||||||
 | 
					        :edit -> gettext("Edit %{type_name}", type_name: type_name)
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    containers =
 | 
				
			||||||
 | 
					      packs
 | 
				
			||||||
 | 
					      |> Enum.map(fn %{container_id: container_id} -> container_id end)
 | 
				
			||||||
 | 
					      |> Containers.get_containers(current_user)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    socket
 | 
				
			||||||
 | 
					    |> assign(
 | 
				
			||||||
 | 
					      page_title: page_title,
 | 
				
			||||||
 | 
					      type: type,
 | 
				
			||||||
 | 
					      packs: packs,
 | 
				
			||||||
 | 
					      containers: containers,
 | 
				
			||||||
 | 
					      cprs: packs |> Ammo.get_cprs(current_user),
 | 
				
			||||||
 | 
					      last_used_dates: packs |> ActivityLog.get_last_used_dates(current_user),
 | 
				
			||||||
 | 
					      avg_cost_per_round: type |> Ammo.get_average_cost_for_type(current_user),
 | 
				
			||||||
 | 
					      rounds: type |> Ammo.get_round_count_for_type(current_user),
 | 
				
			||||||
 | 
					      original_counts: original_counts,
 | 
				
			||||||
 | 
					      used_rounds: used_rounds,
 | 
				
			||||||
 | 
					      historical_round_count: historical_round_count,
 | 
				
			||||||
 | 
					      packs_count: type |> Ammo.get_packs_count_for_type(current_user),
 | 
				
			||||||
 | 
					      used_packs_count: used_packs_count,
 | 
				
			||||||
 | 
					      historical_packs_count: historical_packs_count,
 | 
				
			||||||
 | 
					      fields_to_display: fields_to_display(type),
 | 
				
			||||||
 | 
					      custom_fields?: custom_fields?
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  defp display_type(%{assigns: %{current_user: current_user}} = socket, type_id) do
 | 
				
			||||||
 | 
					    socket |> display_type(Ammo.get_type!(type_id, current_user))
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  defp display_type(%{assigns: %{type: type}} = socket) do
 | 
				
			||||||
 | 
					    socket |> display_type(type)
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  defp fields_to_display(%Type{class: class}) do
 | 
				
			||||||
 | 
					    [
 | 
				
			||||||
 | 
					      %{label: gettext("Cartridge:"), key: :cartridge, type: :string},
 | 
				
			||||||
 | 
					      %{
 | 
				
			||||||
 | 
					        label: if(class == :shotgun, do: gettext("Gauge:"), else: gettext("Caliber:")),
 | 
				
			||||||
 | 
					        key: :caliber,
 | 
				
			||||||
 | 
					        type: :string
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      %{label: gettext("Unfired length:"), key: :unfired_length, type: :string},
 | 
				
			||||||
 | 
					      %{label: gettext("Brass height:"), key: :brass_height, type: :string},
 | 
				
			||||||
 | 
					      %{label: gettext("Chamber size:"), key: :chamber_size, type: :string},
 | 
				
			||||||
 | 
					      %{label: gettext("Grains:"), key: :grains, type: :string},
 | 
				
			||||||
 | 
					      %{label: gettext("Bullet type:"), key: :bullet_type, type: :string},
 | 
				
			||||||
 | 
					      %{label: gettext("Bullet core:"), key: :bullet_core, type: :string},
 | 
				
			||||||
 | 
					      %{label: gettext("Jacket type:"), key: :jacket_type, type: :string},
 | 
				
			||||||
 | 
					      %{label: gettext("Case material:"), key: :case_material, type: :string},
 | 
				
			||||||
 | 
					      %{label: gettext("Wadding:"), key: :wadding, type: :string},
 | 
				
			||||||
 | 
					      %{label: gettext("Shot type:"), key: :shot_type, type: :string},
 | 
				
			||||||
 | 
					      %{label: gettext("Shot material:"), key: :shot_material, type: :string},
 | 
				
			||||||
 | 
					      %{label: gettext("Shot size:"), key: :shot_size, type: :string},
 | 
				
			||||||
 | 
					      %{label: gettext("Load grains:"), key: :load_grains, type: :string},
 | 
				
			||||||
 | 
					      %{label: gettext("Shot charge weight:"), key: :shot_charge_weight, 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("Pressure:"), key: :pressure, type: :string},
 | 
				
			||||||
 | 
					      %{label: gettext("Dram equivalent:"), key: :dram_equivalent, type: :string},
 | 
				
			||||||
 | 
					      %{label: gettext("Muzzle velocity:"), key: :muzzle_velocity, 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}
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @spec display_currency(float()) :: String.t()
 | 
				
			||||||
 | 
					  defp display_currency(float), do: :erlang.float_to_binary(float, decimals: 2)
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
@@ -1,22 +1,22 @@
 | 
				
			|||||||
<div class="space-y-4 flex flex-col justify-center items-center">
 | 
					<div class="space-y-4 flex flex-col justify-center items-center">
 | 
				
			||||||
  <h1 class="title text-2xl title-primary-500">
 | 
					  <h1 class="title text-2xl title-primary-500">
 | 
				
			||||||
    <%= @ammo_type.name %>
 | 
					    <%= @type.name %>
 | 
				
			||||||
  </h1>
 | 
					  </h1>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  <span
 | 
					  <span
 | 
				
			||||||
    :if={@ammo_type.desc}
 | 
					    :if={@type.desc}
 | 
				
			||||||
    class="max-w-2xl w-full px-8 py-4 rounded-lg
 | 
					    class="max-w-2xl w-full px-8 py-4 rounded-lg
 | 
				
			||||||
      text-center title text-lg
 | 
					      text-center title text-lg
 | 
				
			||||||
      border border-primary-600"
 | 
					      border border-primary-600"
 | 
				
			||||||
  >
 | 
					  >
 | 
				
			||||||
    <%= @ammo_type.desc %>
 | 
					    <%= @type.desc %>
 | 
				
			||||||
  </span>
 | 
					  </span>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  <div class="flex space-x-4 justify-center items-center text-primary-600">
 | 
					  <div class="flex space-x-4 justify-center items-center text-primary-600">
 | 
				
			||||||
    <.link
 | 
					    <.link
 | 
				
			||||||
      patch={Routes.ammo_type_show_path(Endpoint, :edit, @ammo_type)}
 | 
					      patch={Routes.type_show_path(Endpoint, :edit, @type)}
 | 
				
			||||||
      class="text-primary-600 link"
 | 
					      class="text-primary-600 link"
 | 
				
			||||||
      aria-label={dgettext("actions", "Edit %{ammo_type_name}", ammo_type_name: @ammo_type.name)}
 | 
					      aria-label={dgettext("actions", "Edit %{type_name}", type_name: @type.name)}
 | 
				
			||||||
    >
 | 
					    >
 | 
				
			||||||
      <i class="fa-fw fa-lg fas fa-edit"></i>
 | 
					      <i class="fa-fw fa-lg fas fa-edit"></i>
 | 
				
			||||||
    </.link>
 | 
					    </.link>
 | 
				
			||||||
@@ -29,12 +29,10 @@
 | 
				
			|||||||
        dgettext(
 | 
					        dgettext(
 | 
				
			||||||
          "prompts",
 | 
					          "prompts",
 | 
				
			||||||
          "Are you sure you want to delete %{name}? This will delete all %{name} type ammo as well!",
 | 
					          "Are you sure you want to delete %{name}? This will delete all %{name} type ammo as well!",
 | 
				
			||||||
          name: @ammo_type.name
 | 
					          name: @type.name
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      aria-label={
 | 
					      aria-label={dgettext("actions", "Delete %{type_name}", type_name: @type.name)}
 | 
				
			||||||
        dgettext("actions", "Delete %{ammo_type_name}", ammo_type_name: @ammo_type.name)
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    >
 | 
					    >
 | 
				
			||||||
      <i class="fa-fw fa-lg fas fa-trash"></i>
 | 
					      <i class="fa-fw fa-lg fas fa-trash"></i>
 | 
				
			||||||
    </.link>
 | 
					    </.link>
 | 
				
			||||||
@@ -42,10 +40,27 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  <hr class="hr" />
 | 
					  <hr class="hr" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  <%= if @fields_to_display do %>
 | 
					  <%= if @type.class || @custom_fields? do %>
 | 
				
			||||||
    <div class="grid sm:grid-cols-2 gap-4 text-center justify-center items-center">
 | 
					    <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 %>
 | 
					      <h3 class="title text-lg">
 | 
				
			||||||
        <%= if @ammo_type |> Map.get(key) do %>
 | 
					        <%= gettext("Class") %>
 | 
				
			||||||
 | 
					      </h3>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      <span class="text-primary-600">
 | 
				
			||||||
 | 
					        <%= case @type.class do %>
 | 
				
			||||||
 | 
					          <% :shotgun -> %>
 | 
				
			||||||
 | 
					            <%= gettext("Shotgun") %>
 | 
				
			||||||
 | 
					          <% :rifle -> %>
 | 
				
			||||||
 | 
					            <%= gettext("Rifle") %>
 | 
				
			||||||
 | 
					          <% :pistol -> %>
 | 
				
			||||||
 | 
					            <%= gettext("Pistol") %>
 | 
				
			||||||
 | 
					          <% _ -> %>
 | 
				
			||||||
 | 
					            <%= gettext("None specified") %>
 | 
				
			||||||
 | 
					        <% end %>
 | 
				
			||||||
 | 
					      </span>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      <%= for %{label: label, key: key, type: type} <- @fields_to_display do %>
 | 
				
			||||||
 | 
					        <%= if @type |> Map.get(key) do %>
 | 
				
			||||||
          <h3 class="title text-lg">
 | 
					          <h3 class="title text-lg">
 | 
				
			||||||
            <%= label %>
 | 
					            <%= label %>
 | 
				
			||||||
          </h3>
 | 
					          </h3>
 | 
				
			||||||
@@ -53,9 +68,9 @@
 | 
				
			|||||||
          <span class="text-primary-600">
 | 
					          <span class="text-primary-600">
 | 
				
			||||||
            <%= case type do %>
 | 
					            <%= case type do %>
 | 
				
			||||||
              <% :boolean -> %>
 | 
					              <% :boolean -> %>
 | 
				
			||||||
                <%= @ammo_type |> Map.get(key) |> humanize() %>
 | 
					                <%= @type |> Map.get(key) |> humanize() %>
 | 
				
			||||||
              <% _ -> %>
 | 
					              <% _ -> %>
 | 
				
			||||||
                <%= @ammo_type |> Map.get(key) %>
 | 
					                <%= @type |> Map.get(key) %>
 | 
				
			||||||
            <% end %>
 | 
					            <% end %>
 | 
				
			||||||
          </span>
 | 
					          </span>
 | 
				
			||||||
        <% end %>
 | 
					        <% end %>
 | 
				
			||||||
@@ -123,7 +138,7 @@
 | 
				
			|||||||
    </h3>
 | 
					    </h3>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <span class="text-primary-600">
 | 
					    <span class="text-primary-600">
 | 
				
			||||||
      <.datetime id={"#{@ammo_type.id}-inserted-at"} datetime={@ammo_type.inserted_at} />
 | 
					      <.datetime id={"#{@type.id}-inserted-at"} datetime={@type.inserted_at} />
 | 
				
			||||||
    </span>
 | 
					    </span>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <%= if @avg_cost_per_round do %>
 | 
					    <%= if @avg_cost_per_round do %>
 | 
				
			||||||
@@ -158,7 +173,7 @@
 | 
				
			|||||||
  </div>
 | 
					  </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  <div class="w-full p-4">
 | 
					  <div class="w-full p-4">
 | 
				
			||||||
    <%= if @ammo_groups |> Enum.empty?() do %>
 | 
					    <%= if @packs |> Enum.empty?() do %>
 | 
				
			||||||
      <h2 class="px-4 title text-lg text-primary-600">
 | 
					      <h2 class="px-4 title text-lg text-primary-600">
 | 
				
			||||||
        <%= gettext("No ammo for this type") %>
 | 
					        <%= gettext("No ammo for this type") %>
 | 
				
			||||||
        <%= display_emoji("😔") %>
 | 
					        <%= display_emoji("😔") %>
 | 
				
			||||||
@@ -166,13 +181,13 @@
 | 
				
			|||||||
    <% else %>
 | 
					    <% else %>
 | 
				
			||||||
      <%= if @view_table do %>
 | 
					      <%= if @view_table do %>
 | 
				
			||||||
        <.live_component
 | 
					        <.live_component
 | 
				
			||||||
          module={CanneryWeb.Components.AmmoGroupTableComponent}
 | 
					          module={CanneryWeb.Components.PackTableComponent}
 | 
				
			||||||
          id="ammo-type-show-table"
 | 
					          id="type-show-table"
 | 
				
			||||||
          ammo_groups={@ammo_groups}
 | 
					          packs={@packs}
 | 
				
			||||||
          current_user={@current_user}
 | 
					          current_user={@current_user}
 | 
				
			||||||
          show_used={@show_used}
 | 
					          show_used={@show_used}
 | 
				
			||||||
        >
 | 
					        >
 | 
				
			||||||
          <:container :let={{_ammo_group, %{name: container_name} = container}}>
 | 
					          <:container :let={{_pack, %{name: container_name} = container}}>
 | 
				
			||||||
            <.link
 | 
					            <.link
 | 
				
			||||||
              navigate={Routes.container_show_path(Endpoint, :show, container)}
 | 
					              navigate={Routes.container_show_path(Endpoint, :show, container)}
 | 
				
			||||||
              class="mx-2 my-1 link"
 | 
					              class="mx-2 my-1 link"
 | 
				
			||||||
@@ -180,15 +195,13 @@
 | 
				
			|||||||
              <%= container_name %>
 | 
					              <%= container_name %>
 | 
				
			||||||
            </.link>
 | 
					            </.link>
 | 
				
			||||||
          </:container>
 | 
					          </:container>
 | 
				
			||||||
          <:actions :let={%{count: ammo_group_count} = ammo_group}>
 | 
					          <:actions :let={%{count: pack_count} = pack}>
 | 
				
			||||||
            <div class="py-2 px-4 h-full space-x-4 flex justify-center items-center">
 | 
					            <div class="py-2 px-4 h-full space-x-4 flex justify-center items-center">
 | 
				
			||||||
              <.link
 | 
					              <.link
 | 
				
			||||||
                navigate={Routes.ammo_group_show_path(Endpoint, :show, ammo_group)}
 | 
					                navigate={Routes.pack_show_path(Endpoint, :show, pack)}
 | 
				
			||||||
                class="text-primary-600 link"
 | 
					                class="text-primary-600 link"
 | 
				
			||||||
                aria-label={
 | 
					                aria-label={
 | 
				
			||||||
                  dgettext("actions", "View ammo group of %{ammo_group_count} bullets",
 | 
					                  dgettext("actions", "View pack of %{pack_count} bullets", pack_count: pack_count)
 | 
				
			||||||
                    ammo_group_count: ammo_group_count
 | 
					 | 
				
			||||||
                  )
 | 
					 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
              >
 | 
					              >
 | 
				
			||||||
                <i class="fa-fw fa-lg fas fa-eye"></i>
 | 
					                <i class="fa-fw fa-lg fas fa-eye"></i>
 | 
				
			||||||
@@ -198,12 +211,12 @@
 | 
				
			|||||||
        </.live_component>
 | 
					        </.live_component>
 | 
				
			||||||
      <% else %>
 | 
					      <% else %>
 | 
				
			||||||
        <div class="flex flex-wrap justify-center items-stretch">
 | 
					        <div class="flex flex-wrap justify-center items-stretch">
 | 
				
			||||||
          <.ammo_group_card
 | 
					          <.pack_card
 | 
				
			||||||
            :for={%{id: ammo_group_id, container_id: container_id} = ammo_group <- @ammo_groups}
 | 
					            :for={%{id: pack_id, container_id: container_id} = pack <- @packs}
 | 
				
			||||||
            ammo_group={ammo_group}
 | 
					            pack={pack}
 | 
				
			||||||
            original_count={@original_counts && Map.fetch!(@original_counts, ammo_group_id)}
 | 
					            original_count={@original_counts && Map.fetch!(@original_counts, pack_id)}
 | 
				
			||||||
            cpr={Map.get(@cprs, ammo_group_id)}
 | 
					            cpr={Map.get(@cprs, pack_id)}
 | 
				
			||||||
            last_used_date={Map.get(@last_used_dates, ammo_group_id)}
 | 
					            last_used_date={Map.get(@last_used_dates, pack_id)}
 | 
				
			||||||
            current_user={@current_user}
 | 
					            current_user={@current_user}
 | 
				
			||||||
            container={Map.fetch!(@containers, container_id)}
 | 
					            container={Map.fetch!(@containers, container_id)}
 | 
				
			||||||
          />
 | 
					          />
 | 
				
			||||||
@@ -213,17 +226,14 @@
 | 
				
			|||||||
  </div>
 | 
					  </div>
 | 
				
			||||||
</div>
 | 
					</div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<.modal
 | 
					<.modal :if={@live_action == :edit} return_to={Routes.type_show_path(Endpoint, :show, @type)}>
 | 
				
			||||||
  :if={@live_action == :edit}
 | 
					 | 
				
			||||||
  return_to={Routes.ammo_type_show_path(Endpoint, :show, @ammo_type)}
 | 
					 | 
				
			||||||
>
 | 
					 | 
				
			||||||
  <.live_component
 | 
					  <.live_component
 | 
				
			||||||
    module={CanneryWeb.AmmoTypeLive.FormComponent}
 | 
					    module={CanneryWeb.TypeLive.FormComponent}
 | 
				
			||||||
    id={@ammo_type.id}
 | 
					    id={@type.id}
 | 
				
			||||||
    title={@page_title}
 | 
					    title={@page_title}
 | 
				
			||||||
    action={@live_action}
 | 
					    action={@live_action}
 | 
				
			||||||
    ammo_type={@ammo_type}
 | 
					    type={@type}
 | 
				
			||||||
    return_to={Routes.ammo_type_show_path(Endpoint, :show, @ammo_type)}
 | 
					    return_to={Routes.type_show_path(Endpoint, :show, @type)}
 | 
				
			||||||
    current_user={@current_user}
 | 
					    current_user={@current_user}
 | 
				
			||||||
  />
 | 
					  />
 | 
				
			||||||
</.modal>
 | 
					</.modal>
 | 
				
			||||||
@@ -69,14 +69,14 @@ defmodule CanneryWeb.Router do
 | 
				
			|||||||
    live "/tags/edit/:id", TagLive.Index, :edit
 | 
					    live "/tags/edit/:id", TagLive.Index, :edit
 | 
				
			||||||
    live "/tags/search/:search", TagLive.Index, :search
 | 
					    live "/tags/search/:search", TagLive.Index, :search
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    live "/catalog", AmmoTypeLive.Index, :index
 | 
					    live "/catalog", TypeLive.Index, :index
 | 
				
			||||||
    live "/catalog/new", AmmoTypeLive.Index, :new
 | 
					    live "/catalog/new", TypeLive.Index, :new
 | 
				
			||||||
    live "/catalog/clone/:id", AmmoTypeLive.Index, :clone
 | 
					    live "/catalog/clone/:id", TypeLive.Index, :clone
 | 
				
			||||||
    live "/catalog/edit/:id", AmmoTypeLive.Index, :edit
 | 
					    live "/catalog/edit/:id", TypeLive.Index, :edit
 | 
				
			||||||
    live "/catalog/search/:search", AmmoTypeLive.Index, :search
 | 
					    live "/catalog/search/:search", TypeLive.Index, :search
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    live "/type/:id", AmmoTypeLive.Show, :show
 | 
					    live "/type/:id", TypeLive.Show, :show
 | 
				
			||||||
    live "/type/:id/edit", AmmoTypeLive.Show, :edit
 | 
					    live "/type/:id/edit", TypeLive.Show, :edit
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    live "/containers", ContainerLive.Index, :index
 | 
					    live "/containers", ContainerLive.Index, :index
 | 
				
			||||||
    live "/containers/new", ContainerLive.Index, :new
 | 
					    live "/containers/new", ContainerLive.Index, :new
 | 
				
			||||||
@@ -89,23 +89,23 @@ defmodule CanneryWeb.Router do
 | 
				
			|||||||
    live "/container/edit/:id", ContainerLive.Show, :edit
 | 
					    live "/container/edit/:id", ContainerLive.Show, :edit
 | 
				
			||||||
    live "/container/edit_tags/:id", ContainerLive.Show, :edit_tags
 | 
					    live "/container/edit_tags/:id", ContainerLive.Show, :edit_tags
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    live "/ammo", AmmoGroupLive.Index, :index
 | 
					    live "/ammo", PackLive.Index, :index
 | 
				
			||||||
    live "/ammo/new", AmmoGroupLive.Index, :new
 | 
					    live "/ammo/new", PackLive.Index, :new
 | 
				
			||||||
    live "/ammo/edit/:id", AmmoGroupLive.Index, :edit
 | 
					    live "/ammo/edit/:id", PackLive.Index, :edit
 | 
				
			||||||
    live "/ammo/clone/:id", AmmoGroupLive.Index, :clone
 | 
					    live "/ammo/clone/:id", PackLive.Index, :clone
 | 
				
			||||||
    live "/ammo/add_shot_group/:id", AmmoGroupLive.Index, :add_shot_group
 | 
					    live "/ammo/add_shot_record/:id", PackLive.Index, :add_shot_record
 | 
				
			||||||
    live "/ammo/move/:id", AmmoGroupLive.Index, :move
 | 
					    live "/ammo/move/:id", PackLive.Index, :move
 | 
				
			||||||
    live "/ammo/search/:search", AmmoGroupLive.Index, :search
 | 
					    live "/ammo/search/:search", PackLive.Index, :search
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    live "/ammo/show/:id", AmmoGroupLive.Show, :show
 | 
					    live "/ammo/show/:id", PackLive.Show, :show
 | 
				
			||||||
    live "/ammo/show/edit/:id", AmmoGroupLive.Show, :edit
 | 
					    live "/ammo/show/edit/:id", PackLive.Show, :edit
 | 
				
			||||||
    live "/ammo/show/add_shot_group/:id", AmmoGroupLive.Show, :add_shot_group
 | 
					    live "/ammo/show/add_shot_record/:id", PackLive.Show, :add_shot_record
 | 
				
			||||||
    live "/ammo/show/move/:id", AmmoGroupLive.Show, :move
 | 
					    live "/ammo/show/move/:id", PackLive.Show, :move
 | 
				
			||||||
    live "/ammo/show/:id/edit/:shot_group_id", AmmoGroupLive.Show, :edit_shot_group
 | 
					    live "/ammo/show/:id/edit/:shot_record_id", PackLive.Show, :edit_shot_record
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    live "/range", RangeLive.Index, :index
 | 
					    live "/range", RangeLive.Index, :index
 | 
				
			||||||
    live "/range/edit/:id", RangeLive.Index, :edit
 | 
					    live "/range/edit/:id", RangeLive.Index, :edit
 | 
				
			||||||
    live "/range/add_shot_group/:id", RangeLive.Index, :add_shot_group
 | 
					    live "/range/add_shot_record/:id", RangeLive.Index, :add_shot_record
 | 
				
			||||||
    live "/range/search/:search", RangeLive.Index, :search
 | 
					    live "/range/search/:search", RangeLive.Index, :search
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										2
									
								
								mix.exs
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								mix.exs
									
									
									
									
									
								
							@@ -4,7 +4,7 @@ defmodule Cannery.MixProject do
 | 
				
			|||||||
  def project do
 | 
					  def project do
 | 
				
			||||||
    [
 | 
					    [
 | 
				
			||||||
      app: :cannery,
 | 
					      app: :cannery,
 | 
				
			||||||
      version: "0.8.6",
 | 
					      version: "0.9.2",
 | 
				
			||||||
      elixir: "1.14.1",
 | 
					      elixir: "1.14.1",
 | 
				
			||||||
      elixirc_paths: elixirc_paths(Mix.env()),
 | 
					      elixirc_paths: elixirc_paths(Mix.env()),
 | 
				
			||||||
      compilers: Mix.compilers(),
 | 
					      compilers: Mix.compilers(),
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,14 +10,14 @@
 | 
				
			|||||||
msgid ""
 | 
					msgid ""
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/index.ex:54
 | 
					#: lib/cannery_web/live/pack_live/index.ex:59
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/index.ex:62
 | 
					#: lib/cannery_web/live/pack_live/index.ex:67
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/index.html.heex:41
 | 
					#: lib/cannery_web/live/pack_live/index.html.heex:38
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Add Ammo"
 | 
					msgid "Add Ammo"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/index.html.heex:37
 | 
					#: lib/cannery_web/live/pack_live/index.html.heex:34
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Add your first box!"
 | 
					msgid "Add your first box!"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
@@ -27,7 +27,7 @@ msgstr ""
 | 
				
			|||||||
msgid "Add your first container!"
 | 
					msgid "Add your first container!"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_type_live/index.html.heex:13
 | 
					#: lib/cannery_web/live/type_live/index.html.heex:13
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Add your first type!"
 | 
					msgid "Add your first type!"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
@@ -82,11 +82,6 @@ msgstr ""
 | 
				
			|||||||
msgid "Make your first tag!"
 | 
					msgid "Make your first tag!"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_type_live/index.html.heex:17
 | 
					 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					 | 
				
			||||||
msgid "New Ammo type"
 | 
					 | 
				
			||||||
msgstr ""
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/container_live/index.html.heex:17
 | 
					#: lib/cannery_web/live/container_live/index.html.heex:17
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "New Container"
 | 
					msgid "New Container"
 | 
				
			||||||
@@ -120,13 +115,13 @@ msgstr ""
 | 
				
			|||||||
msgid "Reset password"
 | 
					msgid "Reset password"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/components/add_shot_group_component.html.heex:56
 | 
					#: lib/cannery_web/components/add_shot_record_component.html.heex:57
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/form_component.html.heex:84
 | 
					#: lib/cannery_web/live/container_live/form_component.html.heex:57
 | 
				
			||||||
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:159
 | 
					#: lib/cannery_web/live/invite_live/form_component.html.heex:35
 | 
				
			||||||
#: lib/cannery_web/live/container_live/form_component.html.heex:55
 | 
					#: lib/cannery_web/live/pack_live/form_component.html.heex:91
 | 
				
			||||||
#: lib/cannery_web/live/invite_live/form_component.html.heex:32
 | 
					#: lib/cannery_web/live/range_live/form_component.html.heex:45
 | 
				
			||||||
#: lib/cannery_web/live/range_live/form_component.html.heex:44
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/tag_live/form_component.html.heex:37
 | 
					#: lib/cannery_web/live/tag_live/form_component.html.heex:37
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/type_live/form_component.html.heex:350
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Save"
 | 
					msgid "Save"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
@@ -136,7 +131,7 @@ msgstr ""
 | 
				
			|||||||
msgid "Send instructions to reset password"
 | 
					msgid "Send instructions to reset password"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/container_live/show.html.heex:75
 | 
					#: lib/cannery_web/live/container_live/show.html.heex:68
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Why not add one?"
 | 
					msgid "Why not add one?"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
@@ -156,19 +151,19 @@ msgstr ""
 | 
				
			|||||||
msgid "Why not get some ready to shoot?"
 | 
					msgid "Why not get some ready to shoot?"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/index.html.heex:105
 | 
					#: lib/cannery_web/live/pack_live/index.html.heex:127
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/show.html.heex:103
 | 
					#: lib/cannery_web/live/pack_live/show.html.heex:96
 | 
				
			||||||
#: lib/cannery_web/live/range_live/index.html.heex:45
 | 
					#: lib/cannery_web/live/range_live/index.html.heex:45
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Record shots"
 | 
					msgid "Record shots"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/components/move_ammo_group_component.ex:90
 | 
					#: lib/cannery_web/components/move_pack_component.ex:88
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Add another container!"
 | 
					msgid "Add another container!"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/components/move_ammo_group_component.ex:126
 | 
					#: lib/cannery_web/components/move_pack_component.ex:124
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Select"
 | 
					msgid "Select"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
@@ -178,12 +173,12 @@ msgstr ""
 | 
				
			|||||||
msgid "Copy to clipboard"
 | 
					msgid "Copy to clipboard"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/index.html.heex:22
 | 
					#: lib/cannery_web/live/pack_live/index.html.heex:14
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "add a container first"
 | 
					msgid "add a container first"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/form_component.html.heex:77
 | 
					#: lib/cannery_web/live/pack_live/form_component.html.heex:84
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Create"
 | 
					msgid "Create"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
@@ -198,19 +193,14 @@ msgstr ""
 | 
				
			|||||||
msgid "Change language"
 | 
					msgid "Change language"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/show.html.heex:55
 | 
					#: lib/cannery_web/live/pack_live/show.html.heex:55
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "View in Catalog"
 | 
					msgid "View in Catalog"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/index.html.heex:32
 | 
					#: lib/cannery_web/components/move_pack_component.ex:78
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#: lib/cannery_web/live/pack_live/index.html.heex:144
 | 
				
			||||||
msgid "add an ammo type first"
 | 
					#: lib/cannery_web/live/pack_live/show.html.heex:89
 | 
				
			||||||
msgstr ""
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#: lib/cannery_web/components/move_ammo_group_component.ex:80
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/index.html.heex:122
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/show.html.heex:96
 | 
					 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Move ammo"
 | 
					msgid "Move ammo"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
@@ -220,13 +210,13 @@ msgstr ""
 | 
				
			|||||||
msgid "Set Unlimited"
 | 
					msgid "Set Unlimited"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/show.html.heex:89
 | 
					#: lib/cannery_web/live/pack_live/show.html.heex:85
 | 
				
			||||||
#: lib/cannery_web/live/range_live/index.html.heex:38
 | 
					#: lib/cannery_web/live/range_live/index.html.heex:38
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Stage for range"
 | 
					msgid "Stage for range"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/show.html.heex:88
 | 
					#: lib/cannery_web/live/pack_live/show.html.heex:84
 | 
				
			||||||
#: lib/cannery_web/live/range_live/index.html.heex:37
 | 
					#: lib/cannery_web/live/range_live/index.html.heex:37
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Unstage from range"
 | 
					msgid "Unstage from range"
 | 
				
			||||||
@@ -237,13 +227,8 @@ msgstr ""
 | 
				
			|||||||
msgid "Export Data as JSON"
 | 
					msgid "Export Data as JSON"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_type_live/index.html.heex:85
 | 
					#: lib/cannery_web/live/container_live/index.html.heex:87
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#: lib/cannery_web/live/container_live/index.html.heex:145
 | 
				
			||||||
msgid "Clone %{ammo_type_name}"
 | 
					 | 
				
			||||||
msgstr ""
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/container_live/index.html.heex:88
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/container_live/index.html.heex:144
 | 
					 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Clone %{container_name}"
 | 
					msgid "Clone %{container_name}"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
@@ -253,20 +238,14 @@ msgstr ""
 | 
				
			|||||||
msgid "Copy invite link for %{invite_name}"
 | 
					msgid "Copy invite link for %{invite_name}"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_type_live/index.html.heex:104
 | 
					#: lib/cannery_web/live/container_live/index.html.heex:104
 | 
				
			||||||
#: lib/cannery_web/live/ammo_type_live/show.html.heex:36
 | 
					#: lib/cannery_web/live/container_live/index.html.heex:162
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#: lib/cannery_web/live/container_live/show.html.heex:48
 | 
				
			||||||
msgid "Delete %{ammo_type_name}"
 | 
					 | 
				
			||||||
msgstr ""
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/container_live/index.html.heex:103
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/container_live/index.html.heex:159
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/container_live/show.html.heex:55
 | 
					 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Delete %{container_name}"
 | 
					msgid "Delete %{container_name}"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/tag_live/index.html.heex:66
 | 
					#: lib/cannery_web/live/tag_live/index.html.heex:65
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Delete %{tag_name}"
 | 
					msgid "Delete %{tag_name}"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
@@ -276,85 +255,102 @@ msgstr ""
 | 
				
			|||||||
msgid "Delete invite for %{invite_name}"
 | 
					msgid "Delete invite for %{invite_name}"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/show.ex:161
 | 
					#: lib/cannery_web/live/container_live/index.html.heex:77
 | 
				
			||||||
#: lib/cannery_web/live/range_live/index.html.heex:131
 | 
					#: lib/cannery_web/live/container_live/index.html.heex:135
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#: lib/cannery_web/live/container_live/show.html.heex:35
 | 
				
			||||||
msgid "Delete shot record of %{shot_group_count} shots"
 | 
					 | 
				
			||||||
msgstr ""
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/ammo_type_live/index.html.heex:75
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/ammo_type_live/show.html.heex:19
 | 
					 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					 | 
				
			||||||
msgid "Edit %{ammo_type_name}"
 | 
					 | 
				
			||||||
msgstr ""
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/container_live/index.html.heex:78
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/container_live/index.html.heex:134
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/container_live/show.html.heex:42
 | 
					 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Edit %{container_name}"
 | 
					msgid "Edit %{container_name}"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/tag_live/index.html.heex:53
 | 
					#: lib/cannery_web/live/tag_live/index.html.heex:52
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Edit %{tag_name}"
 | 
					msgid "Edit %{tag_name}"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/index.html.heex:144
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/show.html.heex:62
 | 
					 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					 | 
				
			||||||
msgid "Edit ammo group of %{ammo_group_count} bullets"
 | 
					 | 
				
			||||||
msgstr ""
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/invite_live/index.html.heex:46
 | 
					#: lib/cannery_web/live/invite_live/index.html.heex:46
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Edit invite for %{invite_name}"
 | 
					msgid "Edit invite for %{invite_name}"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/show.ex:146
 | 
					#: lib/cannery_web/live/pack_live/index.html.heex:120
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					 | 
				
			||||||
msgid "Edit shot group of %{shot_group_count} shots"
 | 
					 | 
				
			||||||
msgstr ""
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/range_live/index.html.heex:114
 | 
					 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					 | 
				
			||||||
msgid "Edit shot record of %{shot_group_count} shots"
 | 
					 | 
				
			||||||
msgstr ""
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/index.html.heex:98
 | 
					 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Stage"
 | 
					msgid "Stage"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/container_live/index.html.heex:66
 | 
					#: lib/cannery_web/live/container_live/index.html.heex:65
 | 
				
			||||||
#: lib/cannery_web/live/container_live/index.html.heex:123
 | 
					#: lib/cannery_web/live/container_live/index.html.heex:124
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Tag %{container_name}"
 | 
					msgid "Tag %{container_name}"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/index.html.heex:97
 | 
					#: lib/cannery_web/live/pack_live/index.html.heex:119
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Unstage"
 | 
					msgid "Unstage"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_type_live/index.html.heex:65
 | 
					#: lib/cannery_web/live/pack_live/index.html.heex:174
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "View %{ammo_type_name}"
 | 
					msgid "Clone pack of %{pack_count} bullets"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/index.html.heex:156
 | 
					#: lib/cannery_web/live/pack_live/index.html.heex:189
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/pack_live/show.html.heex:74
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Clone ammo group of %{ammo_group_count} bullets"
 | 
					msgid "Delete pack of %{pack_count} bullets"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/index.html.heex:171
 | 
					#: lib/cannery_web/live/pack_live/index.html.heex:164
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/show.html.heex:76
 | 
					#: lib/cannery_web/live/pack_live/show.html.heex:62
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Delete ammo group of %{ammo_group_count} bullets"
 | 
					msgid "Edit pack of %{pack_count} bullets"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/index.html.heex:132
 | 
					#: lib/cannery_web/live/pack_live/index.html.heex:154
 | 
				
			||||||
#: lib/cannery_web/live/ammo_type_live/show.html.heex:189
 | 
					#: lib/cannery_web/live/type_live/show.html.heex:204
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "View ammo group of %{ammo_group_count} bullets"
 | 
					msgid "View pack of %{pack_count} bullets"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/pack_live/show.ex:160
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/range_live/index.html.heex:155
 | 
				
			||||||
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
 | 
					msgid "Delete shot record of %{shot_record_count} shots"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/pack_live/show.ex:145
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/range_live/index.html.heex:138
 | 
				
			||||||
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
 | 
					msgid "Edit shot record of %{shot_record_count} shots"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/type_live/index.html.heex:105
 | 
				
			||||||
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
 | 
					msgid "Clone %{type_name}"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/type_live/index.html.heex:122
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/type_live/show.html.heex:35
 | 
				
			||||||
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
 | 
					msgid "Delete %{type_name}"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/type_live/index.html.heex:97
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/type_live/show.html.heex:19
 | 
				
			||||||
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
 | 
					msgid "Edit %{type_name}"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/type_live/index.html.heex:17
 | 
				
			||||||
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
 | 
					msgid "New Type"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/type_live/index.html.heex:89
 | 
				
			||||||
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
 | 
					msgid "View %{type_name}"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/pack_live/index.html.heex:24
 | 
				
			||||||
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
 | 
					msgid "add a type first"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -23,14 +23,14 @@ msgstr ""
 | 
				
			|||||||
## Run "mix gettext.extract" to bring this file up to
 | 
					## Run "mix gettext.extract" to bring this file up to
 | 
				
			||||||
## date. Leave "msgstr"s empty as changing them here has no
 | 
					## date. Leave "msgstr"s empty as changing them here has no
 | 
				
			||||||
## effect: edit them in PO (.po) files instead.
 | 
					## effect: edit them in PO (.po) files instead.
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/index.ex:54
 | 
					#: lib/cannery_web/live/pack_live/index.ex:59
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/index.ex:62
 | 
					#: lib/cannery_web/live/pack_live/index.ex:67
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/index.html.heex:41
 | 
					#: lib/cannery_web/live/pack_live/index.html.heex:38
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Add Ammo"
 | 
					msgid "Add Ammo"
 | 
				
			||||||
msgstr "Munition hinzufügen"
 | 
					msgstr "Munition hinzufügen"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/index.html.heex:37
 | 
					#: lib/cannery_web/live/pack_live/index.html.heex:34
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Add your first box!"
 | 
					msgid "Add your first box!"
 | 
				
			||||||
msgstr "Fügen Sie ihre erste Box hinzu!"
 | 
					msgstr "Fügen Sie ihre erste Box hinzu!"
 | 
				
			||||||
@@ -40,7 +40,7 @@ msgstr "Fügen Sie ihre erste Box hinzu!"
 | 
				
			|||||||
msgid "Add your first container!"
 | 
					msgid "Add your first container!"
 | 
				
			||||||
msgstr "Fügen Sie ihren ersten Behälter hinzu!"
 | 
					msgstr "Fügen Sie ihren ersten Behälter hinzu!"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_type_live/index.html.heex:13
 | 
					#: lib/cannery_web/live/type_live/index.html.heex:13
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Add your first type!"
 | 
					msgid "Add your first type!"
 | 
				
			||||||
msgstr "Fügen Sie ihre erste Munitionsart hinzu!"
 | 
					msgstr "Fügen Sie ihre erste Munitionsart hinzu!"
 | 
				
			||||||
@@ -95,11 +95,6 @@ msgstr "Einloggen"
 | 
				
			|||||||
msgid "Make your first tag!"
 | 
					msgid "Make your first tag!"
 | 
				
			||||||
msgstr "Erstellen Sie ihren ersten Tag!"
 | 
					msgstr "Erstellen Sie ihren ersten Tag!"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_type_live/index.html.heex:17
 | 
					 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					 | 
				
			||||||
msgid "New Ammo type"
 | 
					 | 
				
			||||||
msgstr "Neue Munitionsart"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/container_live/index.html.heex:17
 | 
					#: lib/cannery_web/live/container_live/index.html.heex:17
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "New Container"
 | 
					msgid "New Container"
 | 
				
			||||||
@@ -133,13 +128,13 @@ msgstr "Bestätigungsmail erneut senden"
 | 
				
			|||||||
msgid "Reset password"
 | 
					msgid "Reset password"
 | 
				
			||||||
msgstr "Passwort zurücksetzen"
 | 
					msgstr "Passwort zurücksetzen"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/components/add_shot_group_component.html.heex:56
 | 
					#: lib/cannery_web/components/add_shot_record_component.html.heex:57
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/form_component.html.heex:84
 | 
					#: lib/cannery_web/live/container_live/form_component.html.heex:57
 | 
				
			||||||
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:159
 | 
					#: lib/cannery_web/live/invite_live/form_component.html.heex:35
 | 
				
			||||||
#: lib/cannery_web/live/container_live/form_component.html.heex:55
 | 
					#: lib/cannery_web/live/pack_live/form_component.html.heex:91
 | 
				
			||||||
#: lib/cannery_web/live/invite_live/form_component.html.heex:32
 | 
					#: lib/cannery_web/live/range_live/form_component.html.heex:45
 | 
				
			||||||
#: lib/cannery_web/live/range_live/form_component.html.heex:44
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/tag_live/form_component.html.heex:37
 | 
					#: lib/cannery_web/live/tag_live/form_component.html.heex:37
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/type_live/form_component.html.heex:350
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Save"
 | 
					msgid "Save"
 | 
				
			||||||
msgstr "Speichern"
 | 
					msgstr "Speichern"
 | 
				
			||||||
@@ -149,7 +144,7 @@ msgstr "Speichern"
 | 
				
			|||||||
msgid "Send instructions to reset password"
 | 
					msgid "Send instructions to reset password"
 | 
				
			||||||
msgstr "Anleitung zum Passwort zurücksetzen zusenden"
 | 
					msgstr "Anleitung zum Passwort zurücksetzen zusenden"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/container_live/show.html.heex:75
 | 
					#: lib/cannery_web/live/container_live/show.html.heex:68
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Why not add one?"
 | 
					msgid "Why not add one?"
 | 
				
			||||||
msgstr "Warum fügen Sie keine hinzu?"
 | 
					msgstr "Warum fügen Sie keine hinzu?"
 | 
				
			||||||
@@ -169,19 +164,19 @@ msgstr "Munition markieren"
 | 
				
			|||||||
msgid "Why not get some ready to shoot?"
 | 
					msgid "Why not get some ready to shoot?"
 | 
				
			||||||
msgstr "Warum nicht einige für den Schießstand auswählen?"
 | 
					msgstr "Warum nicht einige für den Schießstand auswählen?"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/index.html.heex:105
 | 
					#: lib/cannery_web/live/pack_live/index.html.heex:127
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/show.html.heex:103
 | 
					#: lib/cannery_web/live/pack_live/show.html.heex:96
 | 
				
			||||||
#: lib/cannery_web/live/range_live/index.html.heex:45
 | 
					#: lib/cannery_web/live/range_live/index.html.heex:45
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Record shots"
 | 
					msgid "Record shots"
 | 
				
			||||||
msgstr "Schüsse dokumentieren"
 | 
					msgstr "Schüsse dokumentieren"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/components/move_ammo_group_component.ex:90
 | 
					#: lib/cannery_web/components/move_pack_component.ex:88
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Add another container!"
 | 
					msgid "Add another container!"
 | 
				
			||||||
msgstr "Einen weiteren Behälter hinzufügen!"
 | 
					msgstr "Einen weiteren Behälter hinzufügen!"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/components/move_ammo_group_component.ex:126
 | 
					#: lib/cannery_web/components/move_pack_component.ex:124
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Select"
 | 
					msgid "Select"
 | 
				
			||||||
msgstr "Markieren"
 | 
					msgstr "Markieren"
 | 
				
			||||||
@@ -191,12 +186,12 @@ msgstr "Markieren"
 | 
				
			|||||||
msgid "Copy to clipboard"
 | 
					msgid "Copy to clipboard"
 | 
				
			||||||
msgstr "In die Zwischenablage kopieren"
 | 
					msgstr "In die Zwischenablage kopieren"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/index.html.heex:22
 | 
					#: lib/cannery_web/live/pack_live/index.html.heex:14
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "add a container first"
 | 
					msgid "add a container first"
 | 
				
			||||||
msgstr "Zuerst einen Behälter hinzufügen"
 | 
					msgstr "Zuerst einen Behälter hinzufügen"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/form_component.html.heex:77
 | 
					#: lib/cannery_web/live/pack_live/form_component.html.heex:84
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Create"
 | 
					msgid "Create"
 | 
				
			||||||
msgstr "Erstellen"
 | 
					msgstr "Erstellen"
 | 
				
			||||||
@@ -211,19 +206,14 @@ msgstr "Sprache wechseln"
 | 
				
			|||||||
msgid "Change language"
 | 
					msgid "Change language"
 | 
				
			||||||
msgstr "Sprache wechseln"
 | 
					msgstr "Sprache wechseln"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/show.html.heex:55
 | 
					#: lib/cannery_web/live/pack_live/show.html.heex:55
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "View in Catalog"
 | 
					msgid "View in Catalog"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/index.html.heex:32
 | 
					#: lib/cannery_web/components/move_pack_component.ex:78
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#: lib/cannery_web/live/pack_live/index.html.heex:144
 | 
				
			||||||
msgid "add an ammo type first"
 | 
					#: lib/cannery_web/live/pack_live/show.html.heex:89
 | 
				
			||||||
msgstr ""
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#: lib/cannery_web/components/move_ammo_group_component.ex:80
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/index.html.heex:122
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/show.html.heex:96
 | 
					 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Move ammo"
 | 
					msgid "Move ammo"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
@@ -233,13 +223,13 @@ msgstr ""
 | 
				
			|||||||
msgid "Set Unlimited"
 | 
					msgid "Set Unlimited"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/show.html.heex:89
 | 
					#: lib/cannery_web/live/pack_live/show.html.heex:85
 | 
				
			||||||
#: lib/cannery_web/live/range_live/index.html.heex:38
 | 
					#: lib/cannery_web/live/range_live/index.html.heex:38
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Stage for range"
 | 
					msgid "Stage for range"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/show.html.heex:88
 | 
					#: lib/cannery_web/live/pack_live/show.html.heex:84
 | 
				
			||||||
#: lib/cannery_web/live/range_live/index.html.heex:37
 | 
					#: lib/cannery_web/live/range_live/index.html.heex:37
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Unstage from range"
 | 
					msgid "Unstage from range"
 | 
				
			||||||
@@ -250,13 +240,8 @@ msgstr ""
 | 
				
			|||||||
msgid "Export Data as JSON"
 | 
					msgid "Export Data as JSON"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_type_live/index.html.heex:85
 | 
					#: lib/cannery_web/live/container_live/index.html.heex:87
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#: lib/cannery_web/live/container_live/index.html.heex:145
 | 
				
			||||||
msgid "Clone %{ammo_type_name}"
 | 
					 | 
				
			||||||
msgstr ""
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/container_live/index.html.heex:88
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/container_live/index.html.heex:144
 | 
					 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Clone %{container_name}"
 | 
					msgid "Clone %{container_name}"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
@@ -266,20 +251,14 @@ msgstr ""
 | 
				
			|||||||
msgid "Copy invite link for %{invite_name}"
 | 
					msgid "Copy invite link for %{invite_name}"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_type_live/index.html.heex:104
 | 
					#: lib/cannery_web/live/container_live/index.html.heex:104
 | 
				
			||||||
#: lib/cannery_web/live/ammo_type_live/show.html.heex:36
 | 
					#: lib/cannery_web/live/container_live/index.html.heex:162
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#: lib/cannery_web/live/container_live/show.html.heex:48
 | 
				
			||||||
msgid "Delete %{ammo_type_name}"
 | 
					 | 
				
			||||||
msgstr ""
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/container_live/index.html.heex:103
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/container_live/index.html.heex:159
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/container_live/show.html.heex:55
 | 
					 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Delete %{container_name}"
 | 
					msgid "Delete %{container_name}"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/tag_live/index.html.heex:66
 | 
					#: lib/cannery_web/live/tag_live/index.html.heex:65
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Delete %{tag_name}"
 | 
					msgid "Delete %{tag_name}"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
@@ -289,85 +268,102 @@ msgstr ""
 | 
				
			|||||||
msgid "Delete invite for %{invite_name}"
 | 
					msgid "Delete invite for %{invite_name}"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/show.ex:161
 | 
					#: lib/cannery_web/live/container_live/index.html.heex:77
 | 
				
			||||||
#: lib/cannery_web/live/range_live/index.html.heex:131
 | 
					#: lib/cannery_web/live/container_live/index.html.heex:135
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#: lib/cannery_web/live/container_live/show.html.heex:35
 | 
				
			||||||
msgid "Delete shot record of %{shot_group_count} shots"
 | 
					 | 
				
			||||||
msgstr ""
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/ammo_type_live/index.html.heex:75
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/ammo_type_live/show.html.heex:19
 | 
					 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					 | 
				
			||||||
msgid "Edit %{ammo_type_name}"
 | 
					 | 
				
			||||||
msgstr ""
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/container_live/index.html.heex:78
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/container_live/index.html.heex:134
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/container_live/show.html.heex:42
 | 
					 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Edit %{container_name}"
 | 
					msgid "Edit %{container_name}"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/tag_live/index.html.heex:53
 | 
					#: lib/cannery_web/live/tag_live/index.html.heex:52
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Edit %{tag_name}"
 | 
					msgid "Edit %{tag_name}"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/index.html.heex:144
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/show.html.heex:62
 | 
					 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					 | 
				
			||||||
msgid "Edit ammo group of %{ammo_group_count} bullets"
 | 
					 | 
				
			||||||
msgstr ""
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/invite_live/index.html.heex:46
 | 
					#: lib/cannery_web/live/invite_live/index.html.heex:46
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Edit invite for %{invite_name}"
 | 
					msgid "Edit invite for %{invite_name}"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/show.ex:146
 | 
					#: lib/cannery_web/live/pack_live/index.html.heex:120
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					 | 
				
			||||||
msgid "Edit shot group of %{shot_group_count} shots"
 | 
					 | 
				
			||||||
msgstr ""
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/range_live/index.html.heex:114
 | 
					 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					 | 
				
			||||||
msgid "Edit shot record of %{shot_group_count} shots"
 | 
					 | 
				
			||||||
msgstr ""
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/index.html.heex:98
 | 
					 | 
				
			||||||
#, elixir-autogen, elixir-format, fuzzy
 | 
					#, elixir-autogen, elixir-format, fuzzy
 | 
				
			||||||
msgid "Stage"
 | 
					msgid "Stage"
 | 
				
			||||||
msgstr "Munition markieren"
 | 
					msgstr "Munition markieren"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/container_live/index.html.heex:66
 | 
					#: lib/cannery_web/live/container_live/index.html.heex:65
 | 
				
			||||||
#: lib/cannery_web/live/container_live/index.html.heex:123
 | 
					#: lib/cannery_web/live/container_live/index.html.heex:124
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Tag %{container_name}"
 | 
					msgid "Tag %{container_name}"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/index.html.heex:97
 | 
					#: lib/cannery_web/live/pack_live/index.html.heex:119
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Unstage"
 | 
					msgid "Unstage"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_type_live/index.html.heex:65
 | 
					#: lib/cannery_web/live/pack_live/index.html.heex:174
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format, fuzzy
 | 
				
			||||||
msgid "View %{ammo_type_name}"
 | 
					msgid "Clone pack of %{pack_count} bullets"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/index.html.heex:156
 | 
					#: lib/cannery_web/live/pack_live/index.html.heex:189
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/pack_live/show.html.heex:74
 | 
				
			||||||
#, elixir-autogen, elixir-format, fuzzy
 | 
					#, elixir-autogen, elixir-format, fuzzy
 | 
				
			||||||
msgid "Clone ammo group of %{ammo_group_count} bullets"
 | 
					msgid "Delete pack of %{pack_count} bullets"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/index.html.heex:171
 | 
					#: lib/cannery_web/live/pack_live/index.html.heex:164
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/show.html.heex:76
 | 
					#: lib/cannery_web/live/pack_live/show.html.heex:62
 | 
				
			||||||
#, elixir-autogen, elixir-format, fuzzy
 | 
					#, elixir-autogen, elixir-format, fuzzy
 | 
				
			||||||
msgid "Delete ammo group of %{ammo_group_count} bullets"
 | 
					msgid "Edit pack of %{pack_count} bullets"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/index.html.heex:132
 | 
					#: lib/cannery_web/live/pack_live/index.html.heex:154
 | 
				
			||||||
#: lib/cannery_web/live/ammo_type_live/show.html.heex:189
 | 
					#: lib/cannery_web/live/type_live/show.html.heex:204
 | 
				
			||||||
#, elixir-autogen, elixir-format, fuzzy
 | 
					#, elixir-autogen, elixir-format, fuzzy
 | 
				
			||||||
msgid "View ammo group of %{ammo_group_count} bullets"
 | 
					msgid "View pack of %{pack_count} bullets"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/pack_live/show.ex:160
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/range_live/index.html.heex:155
 | 
				
			||||||
 | 
					#, elixir-autogen, elixir-format, fuzzy
 | 
				
			||||||
 | 
					msgid "Delete shot record of %{shot_record_count} shots"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/pack_live/show.ex:145
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/range_live/index.html.heex:138
 | 
				
			||||||
 | 
					#, elixir-autogen, elixir-format, fuzzy
 | 
				
			||||||
 | 
					msgid "Edit shot record of %{shot_record_count} shots"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/type_live/index.html.heex:105
 | 
				
			||||||
 | 
					#, elixir-autogen, elixir-format, fuzzy
 | 
				
			||||||
 | 
					msgid "Clone %{type_name}"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/type_live/index.html.heex:122
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/type_live/show.html.heex:35
 | 
				
			||||||
 | 
					#, elixir-autogen, elixir-format, fuzzy
 | 
				
			||||||
 | 
					msgid "Delete %{type_name}"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/type_live/index.html.heex:97
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/type_live/show.html.heex:19
 | 
				
			||||||
 | 
					#, elixir-autogen, elixir-format, fuzzy
 | 
				
			||||||
 | 
					msgid "Edit %{type_name}"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/type_live/index.html.heex:17
 | 
				
			||||||
 | 
					#, elixir-autogen, elixir-format, fuzzy
 | 
				
			||||||
 | 
					msgid "New Type"
 | 
				
			||||||
 | 
					msgstr "Neue Munitionsart"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/type_live/index.html.heex:89
 | 
				
			||||||
 | 
					#, elixir-autogen, elixir-format, fuzzy
 | 
				
			||||||
 | 
					msgid "View %{type_name}"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/pack_live/index.html.heex:24
 | 
				
			||||||
 | 
					#, elixir-autogen, elixir-format, fuzzy
 | 
				
			||||||
 | 
					msgid "add a type first"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 
 | 
				
			|||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -69,6 +69,7 @@ msgstr "Ungültige Mailadresse oder Passwort"
 | 
				
			|||||||
msgid "Not found"
 | 
					msgid "Not found"
 | 
				
			||||||
msgstr "Nicht gefunden"
 | 
					msgstr "Nicht gefunden"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/type_live/form_component.html.heex:18
 | 
				
			||||||
#: lib/cannery_web/templates/user_registration/new.html.heex:13
 | 
					#: lib/cannery_web/templates/user_registration/new.html.heex:13
 | 
				
			||||||
#: lib/cannery_web/templates/user_reset_password/edit.html.heex:13
 | 
					#: lib/cannery_web/templates/user_reset_password/edit.html.heex:13
 | 
				
			||||||
#: lib/cannery_web/templates/user_settings/edit.html.heex:22
 | 
					#: lib/cannery_web/templates/user_settings/edit.html.heex:22
 | 
				
			||||||
@@ -117,22 +118,22 @@ msgstr "Nutzerkonto Bestätigungslink ist ungültig oder abgelaufen."
 | 
				
			|||||||
msgid "You are not authorized to view this page."
 | 
					msgid "You are not authorized to view this page."
 | 
				
			||||||
msgstr "Sie sind nicht berechtigt, diese Seite aufzurufen."
 | 
					msgstr "Sie sind nicht berechtigt, diese Seite aufzurufen."
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery/accounts/user.ex:144
 | 
					#: lib/cannery/accounts/user.ex:145
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "did not change"
 | 
					msgid "did not change"
 | 
				
			||||||
msgstr "hat sich nicht geändert"
 | 
					msgstr "hat sich nicht geändert"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery/accounts/user.ex:165
 | 
					#: lib/cannery/accounts/user.ex:166
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "does not match password"
 | 
					msgid "does not match password"
 | 
				
			||||||
msgstr "Passwort stimmt nicht überein"
 | 
					msgstr "Passwort stimmt nicht überein"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery/accounts/user.ex:202
 | 
					#: lib/cannery/accounts/user.ex:203
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "is not valid"
 | 
					msgid "is not valid"
 | 
				
			||||||
msgstr "ist nicht gültig"
 | 
					msgstr "ist nicht gültig"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery/accounts/user.ex:99
 | 
					#: lib/cannery/accounts/user.ex:100
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "must have the @ sign and no spaces"
 | 
					msgid "must have the @ sign and no spaces"
 | 
				
			||||||
msgstr "Muss ein @ Zeichen und keine Leerzeichen haben"
 | 
					msgstr "Muss ein @ Zeichen und keine Leerzeichen haben"
 | 
				
			||||||
@@ -160,54 +161,54 @@ msgstr ""
 | 
				
			|||||||
msgid "Tag could not be removed"
 | 
					msgid "Tag could not be removed"
 | 
				
			||||||
msgstr "Tag konnte nicht gelöscht werden"
 | 
					msgstr "Tag konnte nicht gelöscht werden"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/form_component.ex:160
 | 
					#: lib/cannery_web/live/pack_live/form_component.ex:159
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Could not parse number of copies"
 | 
					msgid "Could not parse number of copies"
 | 
				
			||||||
msgstr "Konnte die Anzahl der Kopien nicht verstehen"
 | 
					msgstr "Konnte die Anzahl der Kopien nicht verstehen"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/form_component.ex:150
 | 
					#: lib/cannery_web/live/pack_live/form_component.ex:149
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Invalid number of copies, must be between 1 and %{max}. Was %{multiplier}"
 | 
					msgid "Invalid number of copies, must be between 1 and %{max}. Was %{multiplier}"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
"Ungültige Nummer an Kopien. Muss zwischen 1 and %{max} liegen. War "
 | 
					"Ungültige Nummer an Kopien. Muss zwischen 1 and %{max} liegen. War "
 | 
				
			||||||
"%{multiplier}"
 | 
					"%{multiplier}"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery/ammo.ex:1043
 | 
					#: lib/cannery/ammo.ex:1121
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Invalid multiplier"
 | 
					msgid "Invalid multiplier"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery/ammo/ammo_group.ex:92
 | 
					 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					 | 
				
			||||||
msgid "Please select an ammo type and container"
 | 
					 | 
				
			||||||
msgstr ""
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/range_live/index.html.heex:74
 | 
					#: lib/cannery_web/live/range_live/index.html.heex:74
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Your browser does not support the canvas element."
 | 
					msgid "Your browser does not support the canvas element."
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery/activity_log/shot_group.ex:72
 | 
					#: lib/cannery/activity_log/shot_record.ex:74
 | 
				
			||||||
#, elixir-autogen, elixir-format, fuzzy
 | 
					#, elixir-autogen, elixir-format, fuzzy
 | 
				
			||||||
msgid "Please select a valid user and ammo pack"
 | 
					msgid "Please select a valid user and ammo pack"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery/activity_log/shot_group.ex:86
 | 
					#: lib/cannery/activity_log/shot_record.ex:88
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Ammo left can be at most %{count} rounds"
 | 
					msgid "Ammo left can be at most %{count} rounds"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery/activity_log/shot_group.ex:82
 | 
					#: lib/cannery/activity_log/shot_record.ex:84
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Ammo left must be at least 0"
 | 
					msgid "Ammo left must be at least 0"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery/activity_log/shot_group.ex:119
 | 
					#: lib/cannery/activity_log/shot_record.ex:119
 | 
				
			||||||
#, elixir-autogen, elixir-format, fuzzy
 | 
					#, elixir-autogen, elixir-format, fuzzy
 | 
				
			||||||
msgid "Count can be at most %{count} shots"
 | 
					msgid "Count can be at most %{count} shots"
 | 
				
			||||||
msgstr "Anzahl muss weniger als %{count} betragen"
 | 
					msgstr "Anzahl muss weniger als %{count} betragen"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery/activity_log/shot_group.ex:78
 | 
					#: lib/cannery/activity_log/shot_record.ex:80
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "can't be blank"
 | 
					msgid "can't be blank"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: lib/cannery/ammo/pack.ex:100
 | 
				
			||||||
 | 
					#, elixir-autogen, elixir-format, fuzzy
 | 
				
			||||||
 | 
					msgid "Please select a type and container"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -23,17 +23,17 @@ msgstr ""
 | 
				
			|||||||
## Run "mix gettext.extract" to bring this file up to
 | 
					## Run "mix gettext.extract" to bring this file up to
 | 
				
			||||||
## date. Leave "msgstr"s empty as changing them here has no
 | 
					## date. Leave "msgstr"s empty as changing them here has no
 | 
				
			||||||
## effect: edit them in PO (.po) files instead.
 | 
					## effect: edit them in PO (.po) files instead.
 | 
				
			||||||
#: lib/cannery_web/live/ammo_type_live/form_component.ex:89
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/container_live/form_component.ex:89
 | 
					#: lib/cannery_web/live/container_live/form_component.ex:89
 | 
				
			||||||
#: lib/cannery_web/live/invite_live/form_component.ex:80
 | 
					#: lib/cannery_web/live/invite_live/form_component.ex:80
 | 
				
			||||||
#: lib/cannery_web/live/tag_live/form_component.ex:78
 | 
					#: lib/cannery_web/live/tag_live/form_component.ex:78
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/type_live/form_component.ex:88
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "%{name} created successfully"
 | 
					msgid "%{name} created successfully"
 | 
				
			||||||
msgstr "%{name} erfolgreich erstellt"
 | 
					msgstr "%{name} erfolgreich erstellt"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_type_live/index.ex:72
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/ammo_type_live/show.ex:49
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/tag_live/index.ex:65
 | 
					#: lib/cannery_web/live/tag_live/index.ex:65
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/type_live/index.ex:72
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/type_live/show.ex:27
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "%{name} deleted succesfully"
 | 
					msgid "%{name} deleted succesfully"
 | 
				
			||||||
msgstr "%{name} erfolgreich gelöscht"
 | 
					msgstr "%{name} erfolgreich gelöscht"
 | 
				
			||||||
@@ -44,10 +44,10 @@ msgstr "%{name} erfolgreich gelöscht"
 | 
				
			|||||||
msgid "%{name} has been deleted"
 | 
					msgid "%{name} has been deleted"
 | 
				
			||||||
msgstr "%{name} wurde gelöscht"
 | 
					msgstr "%{name} wurde gelöscht"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_type_live/form_component.ex:70
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/container_live/form_component.ex:70
 | 
					#: lib/cannery_web/live/container_live/form_component.ex:70
 | 
				
			||||||
#: lib/cannery_web/live/invite_live/form_component.ex:62
 | 
					#: lib/cannery_web/live/invite_live/form_component.ex:62
 | 
				
			||||||
#: lib/cannery_web/live/tag_live/form_component.ex:60
 | 
					#: lib/cannery_web/live/tag_live/form_component.ex:60
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/type_live/form_component.ex:69
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "%{name} updated successfully"
 | 
					msgid "%{name} updated successfully"
 | 
				
			||||||
msgstr "%{name} erfolgreich aktualisiert"
 | 
					msgstr "%{name} erfolgreich aktualisiert"
 | 
				
			||||||
@@ -65,16 +65,16 @@ msgstr ""
 | 
				
			|||||||
"Sind Sie sicher, dass sie %{email} löschen möchten? Dies kann nicht "
 | 
					"Sind Sie sicher, dass sie %{email} löschen möchten? Dies kann nicht "
 | 
				
			||||||
"zurückgenommen werden!"
 | 
					"zurückgenommen werden!"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/container_live/index.html.heex:100
 | 
					#: lib/cannery_web/live/container_live/index.html.heex:99
 | 
				
			||||||
#: lib/cannery_web/live/container_live/index.html.heex:156
 | 
					#: lib/cannery_web/live/container_live/index.html.heex:157
 | 
				
			||||||
#: lib/cannery_web/live/container_live/show.html.heex:52
 | 
					#: lib/cannery_web/live/container_live/show.html.heex:45
 | 
				
			||||||
#: lib/cannery_web/live/tag_live/index.html.heex:64
 | 
					#: lib/cannery_web/live/tag_live/index.html.heex:63
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Are you sure you want to delete %{name}?"
 | 
					msgid "Are you sure you want to delete %{name}?"
 | 
				
			||||||
msgstr "Sind Sie sicher, dass sie %{name} löschen möchten?"
 | 
					msgstr "Sind Sie sicher, dass sie %{name} löschen möchten?"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/index.html.heex:169
 | 
					#: lib/cannery_web/live/pack_live/index.html.heex:187
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/show.html.heex:74
 | 
					#: lib/cannery_web/live/pack_live/show.html.heex:72
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Are you sure you want to delete this ammo?"
 | 
					msgid "Are you sure you want to delete this ammo?"
 | 
				
			||||||
msgstr "Sind Sie sicher, dass sie diese Munition löschen möchten?"
 | 
					msgstr "Sind Sie sicher, dass sie diese Munition löschen möchten?"
 | 
				
			||||||
@@ -128,13 +128,13 @@ msgstr "Passwort erfolgreich geändert."
 | 
				
			|||||||
msgid "Please check your email to verify your account"
 | 
					msgid "Please check your email to verify your account"
 | 
				
			||||||
msgstr "Bitte überprüfen Sie ihre Mailbox und bestätigen Sie das Nutzerkonto"
 | 
					msgstr "Bitte überprüfen Sie ihre Mailbox und bestätigen Sie das Nutzerkonto"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/components/add_shot_group_component.html.heex:58
 | 
					#: lib/cannery_web/components/add_shot_record_component.html.heex:59
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/form_component.html.heex:85
 | 
					#: lib/cannery_web/live/container_live/form_component.html.heex:59
 | 
				
			||||||
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:160
 | 
					#: lib/cannery_web/live/invite_live/form_component.html.heex:37
 | 
				
			||||||
#: lib/cannery_web/live/container_live/form_component.html.heex:57
 | 
					#: lib/cannery_web/live/pack_live/form_component.html.heex:92
 | 
				
			||||||
#: lib/cannery_web/live/invite_live/form_component.html.heex:34
 | 
					#: lib/cannery_web/live/range_live/form_component.html.heex:47
 | 
				
			||||||
#: lib/cannery_web/live/range_live/form_component.html.heex:46
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/tag_live/form_component.html.heex:39
 | 
					#: lib/cannery_web/live/tag_live/form_component.html.heex:39
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/type_live/form_component.html.heex:351
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Saving..."
 | 
					msgid "Saving..."
 | 
				
			||||||
msgstr "Speichere..."
 | 
					msgstr "Speichere..."
 | 
				
			||||||
@@ -166,7 +166,7 @@ msgstr "%{tag_name} wurde von %{container_name} entfernt"
 | 
				
			|||||||
msgid "Adding..."
 | 
					msgid "Adding..."
 | 
				
			||||||
msgstr "Füge hinzu..."
 | 
					msgstr "Füge hinzu..."
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/components/add_shot_group_component.ex:60
 | 
					#: lib/cannery_web/components/add_shot_record_component.ex:60
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Shots recorded successfully"
 | 
					msgid "Shots recorded successfully"
 | 
				
			||||||
msgstr "Schüsse erfolgreich dokumentiert"
 | 
					msgstr "Schüsse erfolgreich dokumentiert"
 | 
				
			||||||
@@ -176,13 +176,13 @@ msgstr "Schüsse erfolgreich dokumentiert"
 | 
				
			|||||||
msgid "Are you sure you want to unstage this ammo?"
 | 
					msgid "Are you sure you want to unstage this ammo?"
 | 
				
			||||||
msgstr "Sind sie sicher, dass Sie diese Munition demarkieren möchten?"
 | 
					msgstr "Sind sie sicher, dass Sie diese Munition demarkieren möchten?"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/show.ex:159
 | 
					#: lib/cannery_web/live/pack_live/show.ex:158
 | 
				
			||||||
#: lib/cannery_web/live/range_live/index.html.heex:128
 | 
					#: lib/cannery_web/live/range_live/index.html.heex:152
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Are you sure you want to delete this shot record?"
 | 
					msgid "Are you sure you want to delete this shot record?"
 | 
				
			||||||
msgstr "Sind sie sicher, dass sie die Schießkladde löschen möchten?"
 | 
					msgstr "Sind sie sicher, dass sie die Schießkladde löschen möchten?"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/show.ex:81
 | 
					#: lib/cannery_web/live/pack_live/show.ex:80
 | 
				
			||||||
#: lib/cannery_web/live/range_live/index.ex:79
 | 
					#: lib/cannery_web/live/range_live/index.ex:79
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Shot records deleted succesfully"
 | 
					msgid "Shot records deleted succesfully"
 | 
				
			||||||
@@ -198,7 +198,7 @@ msgstr "Schießkladde erfolgreich aktualisiert"
 | 
				
			|||||||
msgid "%{email} confirmed successfully."
 | 
					msgid "%{email} confirmed successfully."
 | 
				
			||||||
msgstr "%{email} erfolgreich bestätigt."
 | 
					msgstr "%{email} erfolgreich bestätigt."
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/components/move_ammo_group_component.ex:54
 | 
					#: lib/cannery_web/components/move_pack_component.ex:52
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Ammo moved to %{name} successfully"
 | 
					msgid "Ammo moved to %{name} successfully"
 | 
				
			||||||
msgstr "Munition erfolgreich zu %{name} verschoben"
 | 
					msgstr "Munition erfolgreich zu %{name} verschoben"
 | 
				
			||||||
@@ -213,13 +213,13 @@ msgstr "Der Zwischenablage hinzugefügt"
 | 
				
			|||||||
msgid "%{name} removed successfully"
 | 
					msgid "%{name} removed successfully"
 | 
				
			||||||
msgstr "%{name} erfolgreich entfernt"
 | 
					msgstr "%{name} erfolgreich entfernt"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/index.html.heex:18
 | 
					#: lib/cannery_web/live/pack_live/index.html.heex:10
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/index.html.heex:28
 | 
					#: lib/cannery_web/live/pack_live/index.html.heex:20
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "You'll need to"
 | 
					msgid "You'll need to"
 | 
				
			||||||
msgstr "Sie müssen"
 | 
					msgstr "Sie müssen"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/form_component.html.heex:78
 | 
					#: lib/cannery_web/live/pack_live/form_component.html.heex:85
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Creating..."
 | 
					msgid "Creating..."
 | 
				
			||||||
msgstr "Erstellen..."
 | 
					msgstr "Erstellen..."
 | 
				
			||||||
@@ -234,31 +234,31 @@ msgstr "Möchten Sie die Sprache wechseln?"
 | 
				
			|||||||
msgid "Language updated successfully."
 | 
					msgid "Language updated successfully."
 | 
				
			||||||
msgstr "Spracheinstellung gespeichert."
 | 
					msgstr "Spracheinstellung gespeichert."
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/index.ex:89
 | 
					#: lib/cannery_web/live/pack_live/index.ex:94
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/show.ex:55
 | 
					#: lib/cannery_web/live/pack_live/show.ex:55
 | 
				
			||||||
#, elixir-autogen, elixir-format, fuzzy
 | 
					#, elixir-autogen, elixir-format, fuzzy
 | 
				
			||||||
msgid "Ammo deleted succesfully"
 | 
					msgid "Ammo deleted succesfully"
 | 
				
			||||||
msgstr "Munitionsgruppe erfolgreich gelöscht"
 | 
					msgstr "Munitionsgruppe erfolgreich gelöscht"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/range_live/index.ex:93
 | 
					#: lib/cannery_web/live/range_live/index.ex:92
 | 
				
			||||||
#, elixir-autogen, elixir-format, fuzzy
 | 
					#, elixir-autogen, elixir-format, fuzzy
 | 
				
			||||||
msgid "Ammo unstaged succesfully"
 | 
					msgid "Ammo unstaged succesfully"
 | 
				
			||||||
msgstr "Munition erfolgreich demarkiert"
 | 
					msgstr "Munition erfolgreich demarkiert"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/form_component.ex:126
 | 
					#: lib/cannery_web/live/pack_live/form_component.ex:125
 | 
				
			||||||
#, elixir-autogen, elixir-format, fuzzy
 | 
					#, elixir-autogen, elixir-format, fuzzy
 | 
				
			||||||
msgid "Ammo updated successfully"
 | 
					msgid "Ammo updated successfully"
 | 
				
			||||||
msgstr "Munitionsgruppe erfolgreich aktualisiert"
 | 
					msgstr "Munitionsgruppe erfolgreich aktualisiert"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/form_component.ex:185
 | 
					#: lib/cannery_web/live/pack_live/form_component.ex:184
 | 
				
			||||||
#, elixir-autogen, elixir-format, fuzzy
 | 
					#, elixir-autogen, elixir-format, fuzzy
 | 
				
			||||||
msgid "Ammo added successfully"
 | 
					msgid "Ammo added successfully"
 | 
				
			||||||
msgid_plural "Ammo added successfully"
 | 
					msgid_plural "Ammo added successfully"
 | 
				
			||||||
msgstr[0] "Munitionsgruppe erfolgreich aktualisiert"
 | 
					msgstr[0] "Munitionsgruppe erfolgreich aktualisiert"
 | 
				
			||||||
msgstr[1] "Munitionsgruppe erfolgreich aktualisiert"
 | 
					msgstr[1] "Munitionsgruppe erfolgreich aktualisiert"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_type_live/index.html.heex:97
 | 
					#: lib/cannery_web/live/type_live/index.html.heex:116
 | 
				
			||||||
#: lib/cannery_web/live/ammo_type_live/show.html.heex:29
 | 
					#: lib/cannery_web/live/type_live/show.html.heex:29
 | 
				
			||||||
#, elixir-autogen, elixir-format, fuzzy
 | 
					#, elixir-autogen, elixir-format, fuzzy
 | 
				
			||||||
msgid "Are you sure you want to delete %{name}? This will delete all %{name} type ammo as well!"
 | 
					msgid "Are you sure you want to delete %{name}? This will delete all %{name} type ammo as well!"
 | 
				
			||||||
msgstr "Sind Sie sicher, dass sie %{name} löschen möchten?"
 | 
					msgstr "Sind Sie sicher, dass sie %{name} löschen möchten?"
 | 
				
			||||||
 
 | 
				
			|||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -10,14 +10,14 @@ msgid ""
 | 
				
			|||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
"Language: en\n"
 | 
					"Language: en\n"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/index.ex:54
 | 
					#: lib/cannery_web/live/pack_live/index.ex:59
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/index.ex:62
 | 
					#: lib/cannery_web/live/pack_live/index.ex:67
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/index.html.heex:41
 | 
					#: lib/cannery_web/live/pack_live/index.html.heex:38
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Add Ammo"
 | 
					msgid "Add Ammo"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/index.html.heex:37
 | 
					#: lib/cannery_web/live/pack_live/index.html.heex:34
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Add your first box!"
 | 
					msgid "Add your first box!"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
@@ -27,7 +27,7 @@ msgstr ""
 | 
				
			|||||||
msgid "Add your first container!"
 | 
					msgid "Add your first container!"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_type_live/index.html.heex:13
 | 
					#: lib/cannery_web/live/type_live/index.html.heex:13
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Add your first type!"
 | 
					msgid "Add your first type!"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
@@ -82,11 +82,6 @@ msgstr ""
 | 
				
			|||||||
msgid "Make your first tag!"
 | 
					msgid "Make your first tag!"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_type_live/index.html.heex:17
 | 
					 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					 | 
				
			||||||
msgid "New Ammo type"
 | 
					 | 
				
			||||||
msgstr ""
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/container_live/index.html.heex:17
 | 
					#: lib/cannery_web/live/container_live/index.html.heex:17
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "New Container"
 | 
					msgid "New Container"
 | 
				
			||||||
@@ -120,13 +115,13 @@ msgstr ""
 | 
				
			|||||||
msgid "Reset password"
 | 
					msgid "Reset password"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/components/add_shot_group_component.html.heex:56
 | 
					#: lib/cannery_web/components/add_shot_record_component.html.heex:57
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/form_component.html.heex:84
 | 
					#: lib/cannery_web/live/container_live/form_component.html.heex:57
 | 
				
			||||||
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:159
 | 
					#: lib/cannery_web/live/invite_live/form_component.html.heex:35
 | 
				
			||||||
#: lib/cannery_web/live/container_live/form_component.html.heex:55
 | 
					#: lib/cannery_web/live/pack_live/form_component.html.heex:91
 | 
				
			||||||
#: lib/cannery_web/live/invite_live/form_component.html.heex:32
 | 
					#: lib/cannery_web/live/range_live/form_component.html.heex:45
 | 
				
			||||||
#: lib/cannery_web/live/range_live/form_component.html.heex:44
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/tag_live/form_component.html.heex:37
 | 
					#: lib/cannery_web/live/tag_live/form_component.html.heex:37
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/type_live/form_component.html.heex:350
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Save"
 | 
					msgid "Save"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
@@ -136,7 +131,7 @@ msgstr ""
 | 
				
			|||||||
msgid "Send instructions to reset password"
 | 
					msgid "Send instructions to reset password"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/container_live/show.html.heex:75
 | 
					#: lib/cannery_web/live/container_live/show.html.heex:68
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Why not add one?"
 | 
					msgid "Why not add one?"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
@@ -156,19 +151,19 @@ msgstr ""
 | 
				
			|||||||
msgid "Why not get some ready to shoot?"
 | 
					msgid "Why not get some ready to shoot?"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/index.html.heex:105
 | 
					#: lib/cannery_web/live/pack_live/index.html.heex:127
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/show.html.heex:103
 | 
					#: lib/cannery_web/live/pack_live/show.html.heex:96
 | 
				
			||||||
#: lib/cannery_web/live/range_live/index.html.heex:45
 | 
					#: lib/cannery_web/live/range_live/index.html.heex:45
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Record shots"
 | 
					msgid "Record shots"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/components/move_ammo_group_component.ex:90
 | 
					#: lib/cannery_web/components/move_pack_component.ex:88
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Add another container!"
 | 
					msgid "Add another container!"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/components/move_ammo_group_component.ex:126
 | 
					#: lib/cannery_web/components/move_pack_component.ex:124
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Select"
 | 
					msgid "Select"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
@@ -178,12 +173,12 @@ msgstr ""
 | 
				
			|||||||
msgid "Copy to clipboard"
 | 
					msgid "Copy to clipboard"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/index.html.heex:22
 | 
					#: lib/cannery_web/live/pack_live/index.html.heex:14
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "add a container first"
 | 
					msgid "add a container first"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/form_component.html.heex:77
 | 
					#: lib/cannery_web/live/pack_live/form_component.html.heex:84
 | 
				
			||||||
#, elixir-autogen, elixir-format, fuzzy
 | 
					#, elixir-autogen, elixir-format, fuzzy
 | 
				
			||||||
msgid "Create"
 | 
					msgid "Create"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
@@ -198,19 +193,14 @@ msgstr ""
 | 
				
			|||||||
msgid "Change language"
 | 
					msgid "Change language"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/show.html.heex:55
 | 
					#: lib/cannery_web/live/pack_live/show.html.heex:55
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "View in Catalog"
 | 
					msgid "View in Catalog"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/index.html.heex:32
 | 
					#: lib/cannery_web/components/move_pack_component.ex:78
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#: lib/cannery_web/live/pack_live/index.html.heex:144
 | 
				
			||||||
msgid "add an ammo type first"
 | 
					#: lib/cannery_web/live/pack_live/show.html.heex:89
 | 
				
			||||||
msgstr ""
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#: lib/cannery_web/components/move_ammo_group_component.ex:80
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/index.html.heex:122
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/show.html.heex:96
 | 
					 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Move ammo"
 | 
					msgid "Move ammo"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
@@ -220,13 +210,13 @@ msgstr ""
 | 
				
			|||||||
msgid "Set Unlimited"
 | 
					msgid "Set Unlimited"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/show.html.heex:89
 | 
					#: lib/cannery_web/live/pack_live/show.html.heex:85
 | 
				
			||||||
#: lib/cannery_web/live/range_live/index.html.heex:38
 | 
					#: lib/cannery_web/live/range_live/index.html.heex:38
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Stage for range"
 | 
					msgid "Stage for range"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/show.html.heex:88
 | 
					#: lib/cannery_web/live/pack_live/show.html.heex:84
 | 
				
			||||||
#: lib/cannery_web/live/range_live/index.html.heex:37
 | 
					#: lib/cannery_web/live/range_live/index.html.heex:37
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Unstage from range"
 | 
					msgid "Unstage from range"
 | 
				
			||||||
@@ -237,13 +227,8 @@ msgstr ""
 | 
				
			|||||||
msgid "Export Data as JSON"
 | 
					msgid "Export Data as JSON"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_type_live/index.html.heex:85
 | 
					#: lib/cannery_web/live/container_live/index.html.heex:87
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#: lib/cannery_web/live/container_live/index.html.heex:145
 | 
				
			||||||
msgid "Clone %{ammo_type_name}"
 | 
					 | 
				
			||||||
msgstr ""
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/container_live/index.html.heex:88
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/container_live/index.html.heex:144
 | 
					 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Clone %{container_name}"
 | 
					msgid "Clone %{container_name}"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
@@ -253,20 +238,14 @@ msgstr ""
 | 
				
			|||||||
msgid "Copy invite link for %{invite_name}"
 | 
					msgid "Copy invite link for %{invite_name}"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_type_live/index.html.heex:104
 | 
					#: lib/cannery_web/live/container_live/index.html.heex:104
 | 
				
			||||||
#: lib/cannery_web/live/ammo_type_live/show.html.heex:36
 | 
					#: lib/cannery_web/live/container_live/index.html.heex:162
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#: lib/cannery_web/live/container_live/show.html.heex:48
 | 
				
			||||||
msgid "Delete %{ammo_type_name}"
 | 
					 | 
				
			||||||
msgstr ""
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/container_live/index.html.heex:103
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/container_live/index.html.heex:159
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/container_live/show.html.heex:55
 | 
					 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Delete %{container_name}"
 | 
					msgid "Delete %{container_name}"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/tag_live/index.html.heex:66
 | 
					#: lib/cannery_web/live/tag_live/index.html.heex:65
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Delete %{tag_name}"
 | 
					msgid "Delete %{tag_name}"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
@@ -276,85 +255,102 @@ msgstr ""
 | 
				
			|||||||
msgid "Delete invite for %{invite_name}"
 | 
					msgid "Delete invite for %{invite_name}"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/show.ex:161
 | 
					#: lib/cannery_web/live/container_live/index.html.heex:77
 | 
				
			||||||
#: lib/cannery_web/live/range_live/index.html.heex:131
 | 
					#: lib/cannery_web/live/container_live/index.html.heex:135
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#: lib/cannery_web/live/container_live/show.html.heex:35
 | 
				
			||||||
msgid "Delete shot record of %{shot_group_count} shots"
 | 
					 | 
				
			||||||
msgstr ""
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/ammo_type_live/index.html.heex:75
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/ammo_type_live/show.html.heex:19
 | 
					 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					 | 
				
			||||||
msgid "Edit %{ammo_type_name}"
 | 
					 | 
				
			||||||
msgstr ""
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/container_live/index.html.heex:78
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/container_live/index.html.heex:134
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/container_live/show.html.heex:42
 | 
					 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Edit %{container_name}"
 | 
					msgid "Edit %{container_name}"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/tag_live/index.html.heex:53
 | 
					#: lib/cannery_web/live/tag_live/index.html.heex:52
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Edit %{tag_name}"
 | 
					msgid "Edit %{tag_name}"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/index.html.heex:144
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/show.html.heex:62
 | 
					 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					 | 
				
			||||||
msgid "Edit ammo group of %{ammo_group_count} bullets"
 | 
					 | 
				
			||||||
msgstr ""
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/invite_live/index.html.heex:46
 | 
					#: lib/cannery_web/live/invite_live/index.html.heex:46
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Edit invite for %{invite_name}"
 | 
					msgid "Edit invite for %{invite_name}"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/show.ex:146
 | 
					#: lib/cannery_web/live/pack_live/index.html.heex:120
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					 | 
				
			||||||
msgid "Edit shot group of %{shot_group_count} shots"
 | 
					 | 
				
			||||||
msgstr ""
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/range_live/index.html.heex:114
 | 
					 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					 | 
				
			||||||
msgid "Edit shot record of %{shot_group_count} shots"
 | 
					 | 
				
			||||||
msgstr ""
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/index.html.heex:98
 | 
					 | 
				
			||||||
#, elixir-autogen, elixir-format, fuzzy
 | 
					#, elixir-autogen, elixir-format, fuzzy
 | 
				
			||||||
msgid "Stage"
 | 
					msgid "Stage"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/container_live/index.html.heex:66
 | 
					#: lib/cannery_web/live/container_live/index.html.heex:65
 | 
				
			||||||
#: lib/cannery_web/live/container_live/index.html.heex:123
 | 
					#: lib/cannery_web/live/container_live/index.html.heex:124
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Tag %{container_name}"
 | 
					msgid "Tag %{container_name}"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/index.html.heex:97
 | 
					#: lib/cannery_web/live/pack_live/index.html.heex:119
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Unstage"
 | 
					msgid "Unstage"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_type_live/index.html.heex:65
 | 
					#: lib/cannery_web/live/pack_live/index.html.heex:174
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format, fuzzy
 | 
				
			||||||
msgid "View %{ammo_type_name}"
 | 
					msgid "Clone pack of %{pack_count} bullets"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/index.html.heex:156
 | 
					#: lib/cannery_web/live/pack_live/index.html.heex:189
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/pack_live/show.html.heex:74
 | 
				
			||||||
#, elixir-autogen, elixir-format, fuzzy
 | 
					#, elixir-autogen, elixir-format, fuzzy
 | 
				
			||||||
msgid "Clone ammo group of %{ammo_group_count} bullets"
 | 
					msgid "Delete pack of %{pack_count} bullets"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/index.html.heex:171
 | 
					#: lib/cannery_web/live/pack_live/index.html.heex:164
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/show.html.heex:76
 | 
					#: lib/cannery_web/live/pack_live/show.html.heex:62
 | 
				
			||||||
#, elixir-autogen, elixir-format, fuzzy
 | 
					#, elixir-autogen, elixir-format, fuzzy
 | 
				
			||||||
msgid "Delete ammo group of %{ammo_group_count} bullets"
 | 
					msgid "Edit pack of %{pack_count} bullets"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/index.html.heex:132
 | 
					#: lib/cannery_web/live/pack_live/index.html.heex:154
 | 
				
			||||||
#: lib/cannery_web/live/ammo_type_live/show.html.heex:189
 | 
					#: lib/cannery_web/live/type_live/show.html.heex:204
 | 
				
			||||||
#, elixir-autogen, elixir-format, fuzzy
 | 
					#, elixir-autogen, elixir-format, fuzzy
 | 
				
			||||||
msgid "View ammo group of %{ammo_group_count} bullets"
 | 
					msgid "View pack of %{pack_count} bullets"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/pack_live/show.ex:160
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/range_live/index.html.heex:155
 | 
				
			||||||
 | 
					#, elixir-autogen, elixir-format, fuzzy
 | 
				
			||||||
 | 
					msgid "Delete shot record of %{shot_record_count} shots"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/pack_live/show.ex:145
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/range_live/index.html.heex:138
 | 
				
			||||||
 | 
					#, elixir-autogen, elixir-format, fuzzy
 | 
				
			||||||
 | 
					msgid "Edit shot record of %{shot_record_count} shots"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/type_live/index.html.heex:105
 | 
				
			||||||
 | 
					#, elixir-autogen, elixir-format, fuzzy
 | 
				
			||||||
 | 
					msgid "Clone %{type_name}"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/type_live/index.html.heex:122
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/type_live/show.html.heex:35
 | 
				
			||||||
 | 
					#, elixir-autogen, elixir-format, fuzzy
 | 
				
			||||||
 | 
					msgid "Delete %{type_name}"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/type_live/index.html.heex:97
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/type_live/show.html.heex:19
 | 
				
			||||||
 | 
					#, elixir-autogen, elixir-format, fuzzy
 | 
				
			||||||
 | 
					msgid "Edit %{type_name}"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/type_live/index.html.heex:17
 | 
				
			||||||
 | 
					#, elixir-autogen, elixir-format, fuzzy
 | 
				
			||||||
 | 
					msgid "New Type"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/type_live/index.html.heex:89
 | 
				
			||||||
 | 
					#, elixir-autogen, elixir-format, fuzzy
 | 
				
			||||||
 | 
					msgid "View %{type_name}"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/pack_live/index.html.heex:24
 | 
				
			||||||
 | 
					#, elixir-autogen, elixir-format, fuzzy
 | 
				
			||||||
 | 
					msgid "add a type first"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 
 | 
				
			|||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -56,6 +56,7 @@ msgstr ""
 | 
				
			|||||||
msgid "Not found"
 | 
					msgid "Not found"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/type_live/form_component.html.heex:18
 | 
				
			||||||
#: lib/cannery_web/templates/user_registration/new.html.heex:13
 | 
					#: lib/cannery_web/templates/user_registration/new.html.heex:13
 | 
				
			||||||
#: lib/cannery_web/templates/user_reset_password/edit.html.heex:13
 | 
					#: lib/cannery_web/templates/user_reset_password/edit.html.heex:13
 | 
				
			||||||
#: lib/cannery_web/templates/user_settings/edit.html.heex:22
 | 
					#: lib/cannery_web/templates/user_settings/edit.html.heex:22
 | 
				
			||||||
@@ -103,23 +104,23 @@ msgstr ""
 | 
				
			|||||||
msgid "You are not authorized to view this page."
 | 
					msgid "You are not authorized to view this page."
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery/accounts/user.ex:144
 | 
					#: lib/cannery/accounts/user.ex:145
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "did not change"
 | 
					msgid "did not change"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery/accounts/user.ex:165
 | 
					#: lib/cannery/accounts/user.ex:166
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "does not match password"
 | 
					msgid "does not match password"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## From Ecto.Changeset.put_change/3
 | 
					## From Ecto.Changeset.put_change/3
 | 
				
			||||||
#: lib/cannery/accounts/user.ex:202
 | 
					#: lib/cannery/accounts/user.ex:203
 | 
				
			||||||
#, elixir-autogen, elixir-format, fuzzy
 | 
					#, elixir-autogen, elixir-format, fuzzy
 | 
				
			||||||
msgid "is not valid"
 | 
					msgid "is not valid"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery/accounts/user.ex:99
 | 
					#: lib/cannery/accounts/user.ex:100
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "must have the @ sign and no spaces"
 | 
					msgid "must have the @ sign and no spaces"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
@@ -145,52 +146,52 @@ msgstr ""
 | 
				
			|||||||
msgid "Tag could not be removed"
 | 
					msgid "Tag could not be removed"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/form_component.ex:160
 | 
					#: lib/cannery_web/live/pack_live/form_component.ex:159
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Could not parse number of copies"
 | 
					msgid "Could not parse number of copies"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/form_component.ex:150
 | 
					#: lib/cannery_web/live/pack_live/form_component.ex:149
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Invalid number of copies, must be between 1 and %{max}. Was %{multiplier}"
 | 
					msgid "Invalid number of copies, must be between 1 and %{max}. Was %{multiplier}"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery/ammo.ex:1043
 | 
					#: lib/cannery/ammo.ex:1121
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Invalid multiplier"
 | 
					msgid "Invalid multiplier"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery/ammo/ammo_group.ex:92
 | 
					 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					 | 
				
			||||||
msgid "Please select an ammo type and container"
 | 
					 | 
				
			||||||
msgstr ""
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/range_live/index.html.heex:74
 | 
					#: lib/cannery_web/live/range_live/index.html.heex:74
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Your browser does not support the canvas element."
 | 
					msgid "Your browser does not support the canvas element."
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery/activity_log/shot_group.ex:72
 | 
					#: lib/cannery/activity_log/shot_record.ex:74
 | 
				
			||||||
#, elixir-autogen, elixir-format, fuzzy
 | 
					#, elixir-autogen, elixir-format, fuzzy
 | 
				
			||||||
msgid "Please select a valid user and ammo pack"
 | 
					msgid "Please select a valid user and ammo pack"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery/activity_log/shot_group.ex:86
 | 
					#: lib/cannery/activity_log/shot_record.ex:88
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Ammo left can be at most %{count} rounds"
 | 
					msgid "Ammo left can be at most %{count} rounds"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery/activity_log/shot_group.ex:82
 | 
					#: lib/cannery/activity_log/shot_record.ex:84
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Ammo left must be at least 0"
 | 
					msgid "Ammo left must be at least 0"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery/activity_log/shot_group.ex:119
 | 
					#: lib/cannery/activity_log/shot_record.ex:119
 | 
				
			||||||
#, elixir-autogen, elixir-format, fuzzy
 | 
					#, elixir-autogen, elixir-format, fuzzy
 | 
				
			||||||
msgid "Count can be at most %{count} shots"
 | 
					msgid "Count can be at most %{count} shots"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery/activity_log/shot_group.ex:78
 | 
					#: lib/cannery/activity_log/shot_record.ex:80
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "can't be blank"
 | 
					msgid "can't be blank"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: lib/cannery/ammo/pack.ex:100
 | 
				
			||||||
 | 
					#, elixir-autogen, elixir-format, fuzzy
 | 
				
			||||||
 | 
					msgid "Please select a type and container"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,17 +10,17 @@ msgid ""
 | 
				
			|||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
"Language: en\n"
 | 
					"Language: en\n"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_type_live/form_component.ex:89
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/container_live/form_component.ex:89
 | 
					#: lib/cannery_web/live/container_live/form_component.ex:89
 | 
				
			||||||
#: lib/cannery_web/live/invite_live/form_component.ex:80
 | 
					#: lib/cannery_web/live/invite_live/form_component.ex:80
 | 
				
			||||||
#: lib/cannery_web/live/tag_live/form_component.ex:78
 | 
					#: lib/cannery_web/live/tag_live/form_component.ex:78
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/type_live/form_component.ex:88
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "%{name} created successfully"
 | 
					msgid "%{name} created successfully"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_type_live/index.ex:72
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/ammo_type_live/show.ex:49
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/tag_live/index.ex:65
 | 
					#: lib/cannery_web/live/tag_live/index.ex:65
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/type_live/index.ex:72
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/type_live/show.ex:27
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "%{name} deleted succesfully"
 | 
					msgid "%{name} deleted succesfully"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
@@ -31,10 +31,10 @@ msgstr ""
 | 
				
			|||||||
msgid "%{name} has been deleted"
 | 
					msgid "%{name} has been deleted"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_type_live/form_component.ex:70
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/container_live/form_component.ex:70
 | 
					#: lib/cannery_web/live/container_live/form_component.ex:70
 | 
				
			||||||
#: lib/cannery_web/live/invite_live/form_component.ex:62
 | 
					#: lib/cannery_web/live/invite_live/form_component.ex:62
 | 
				
			||||||
#: lib/cannery_web/live/tag_live/form_component.ex:60
 | 
					#: lib/cannery_web/live/tag_live/form_component.ex:60
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/type_live/form_component.ex:69
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "%{name} updated successfully"
 | 
					msgid "%{name} updated successfully"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
@@ -50,16 +50,16 @@ msgstr ""
 | 
				
			|||||||
msgid "Are you sure you want to delete %{email}? This action is permanent!"
 | 
					msgid "Are you sure you want to delete %{email}? This action is permanent!"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/container_live/index.html.heex:100
 | 
					#: lib/cannery_web/live/container_live/index.html.heex:99
 | 
				
			||||||
#: lib/cannery_web/live/container_live/index.html.heex:156
 | 
					#: lib/cannery_web/live/container_live/index.html.heex:157
 | 
				
			||||||
#: lib/cannery_web/live/container_live/show.html.heex:52
 | 
					#: lib/cannery_web/live/container_live/show.html.heex:45
 | 
				
			||||||
#: lib/cannery_web/live/tag_live/index.html.heex:64
 | 
					#: lib/cannery_web/live/tag_live/index.html.heex:63
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Are you sure you want to delete %{name}?"
 | 
					msgid "Are you sure you want to delete %{name}?"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/index.html.heex:169
 | 
					#: lib/cannery_web/live/pack_live/index.html.heex:187
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/show.html.heex:74
 | 
					#: lib/cannery_web/live/pack_live/show.html.heex:72
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Are you sure you want to delete this ammo?"
 | 
					msgid "Are you sure you want to delete this ammo?"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
@@ -109,13 +109,13 @@ msgstr ""
 | 
				
			|||||||
msgid "Please check your email to verify your account"
 | 
					msgid "Please check your email to verify your account"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/components/add_shot_group_component.html.heex:58
 | 
					#: lib/cannery_web/components/add_shot_record_component.html.heex:59
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/form_component.html.heex:85
 | 
					#: lib/cannery_web/live/container_live/form_component.html.heex:59
 | 
				
			||||||
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:160
 | 
					#: lib/cannery_web/live/invite_live/form_component.html.heex:37
 | 
				
			||||||
#: lib/cannery_web/live/container_live/form_component.html.heex:57
 | 
					#: lib/cannery_web/live/pack_live/form_component.html.heex:92
 | 
				
			||||||
#: lib/cannery_web/live/invite_live/form_component.html.heex:34
 | 
					#: lib/cannery_web/live/range_live/form_component.html.heex:47
 | 
				
			||||||
#: lib/cannery_web/live/range_live/form_component.html.heex:46
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/tag_live/form_component.html.heex:39
 | 
					#: lib/cannery_web/live/tag_live/form_component.html.heex:39
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/type_live/form_component.html.heex:351
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Saving..."
 | 
					msgid "Saving..."
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
@@ -145,7 +145,7 @@ msgstr ""
 | 
				
			|||||||
msgid "Adding..."
 | 
					msgid "Adding..."
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/components/add_shot_group_component.ex:60
 | 
					#: lib/cannery_web/components/add_shot_record_component.ex:60
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Shots recorded successfully"
 | 
					msgid "Shots recorded successfully"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
@@ -155,13 +155,13 @@ msgstr ""
 | 
				
			|||||||
msgid "Are you sure you want to unstage this ammo?"
 | 
					msgid "Are you sure you want to unstage this ammo?"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/show.ex:159
 | 
					#: lib/cannery_web/live/pack_live/show.ex:158
 | 
				
			||||||
#: lib/cannery_web/live/range_live/index.html.heex:128
 | 
					#: lib/cannery_web/live/range_live/index.html.heex:152
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Are you sure you want to delete this shot record?"
 | 
					msgid "Are you sure you want to delete this shot record?"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/show.ex:81
 | 
					#: lib/cannery_web/live/pack_live/show.ex:80
 | 
				
			||||||
#: lib/cannery_web/live/range_live/index.ex:79
 | 
					#: lib/cannery_web/live/range_live/index.ex:79
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Shot records deleted succesfully"
 | 
					msgid "Shot records deleted succesfully"
 | 
				
			||||||
@@ -177,7 +177,7 @@ msgstr ""
 | 
				
			|||||||
msgid "%{email} confirmed successfully."
 | 
					msgid "%{email} confirmed successfully."
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/components/move_ammo_group_component.ex:54
 | 
					#: lib/cannery_web/components/move_pack_component.ex:52
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Ammo moved to %{name} successfully"
 | 
					msgid "Ammo moved to %{name} successfully"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
@@ -192,13 +192,13 @@ msgstr ""
 | 
				
			|||||||
msgid "%{name} removed successfully"
 | 
					msgid "%{name} removed successfully"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/index.html.heex:18
 | 
					#: lib/cannery_web/live/pack_live/index.html.heex:10
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/index.html.heex:28
 | 
					#: lib/cannery_web/live/pack_live/index.html.heex:20
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "You'll need to"
 | 
					msgid "You'll need to"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/form_component.html.heex:78
 | 
					#: lib/cannery_web/live/pack_live/form_component.html.heex:85
 | 
				
			||||||
#, elixir-autogen, elixir-format, fuzzy
 | 
					#, elixir-autogen, elixir-format, fuzzy
 | 
				
			||||||
msgid "Creating..."
 | 
					msgid "Creating..."
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
@@ -213,31 +213,31 @@ msgstr ""
 | 
				
			|||||||
msgid "Language updated successfully."
 | 
					msgid "Language updated successfully."
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/index.ex:89
 | 
					#: lib/cannery_web/live/pack_live/index.ex:94
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/show.ex:55
 | 
					#: lib/cannery_web/live/pack_live/show.ex:55
 | 
				
			||||||
#, elixir-autogen, elixir-format, fuzzy
 | 
					#, elixir-autogen, elixir-format, fuzzy
 | 
				
			||||||
msgid "Ammo deleted succesfully"
 | 
					msgid "Ammo deleted succesfully"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/range_live/index.ex:93
 | 
					#: lib/cannery_web/live/range_live/index.ex:92
 | 
				
			||||||
#, elixir-autogen, elixir-format, fuzzy
 | 
					#, elixir-autogen, elixir-format, fuzzy
 | 
				
			||||||
msgid "Ammo unstaged succesfully"
 | 
					msgid "Ammo unstaged succesfully"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/form_component.ex:126
 | 
					#: lib/cannery_web/live/pack_live/form_component.ex:125
 | 
				
			||||||
#, elixir-autogen, elixir-format, fuzzy
 | 
					#, elixir-autogen, elixir-format, fuzzy
 | 
				
			||||||
msgid "Ammo updated successfully"
 | 
					msgid "Ammo updated successfully"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/form_component.ex:185
 | 
					#: lib/cannery_web/live/pack_live/form_component.ex:184
 | 
				
			||||||
#, elixir-autogen, elixir-format, fuzzy
 | 
					#, elixir-autogen, elixir-format, fuzzy
 | 
				
			||||||
msgid "Ammo added successfully"
 | 
					msgid "Ammo added successfully"
 | 
				
			||||||
msgid_plural "Ammo added successfully"
 | 
					msgid_plural "Ammo added successfully"
 | 
				
			||||||
msgstr[0] ""
 | 
					msgstr[0] ""
 | 
				
			||||||
msgstr[1] ""
 | 
					msgstr[1] ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_type_live/index.html.heex:97
 | 
					#: lib/cannery_web/live/type_live/index.html.heex:116
 | 
				
			||||||
#: lib/cannery_web/live/ammo_type_live/show.html.heex:29
 | 
					#: lib/cannery_web/live/type_live/show.html.heex:29
 | 
				
			||||||
#, elixir-autogen, elixir-format, fuzzy
 | 
					#, elixir-autogen, elixir-format, fuzzy
 | 
				
			||||||
msgid "Are you sure you want to delete %{name}? This will delete all %{name} type ammo as well!"
 | 
					msgid "Are you sure you want to delete %{name}? This will delete all %{name} type ammo as well!"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -56,6 +56,7 @@ msgstr ""
 | 
				
			|||||||
msgid "Not found"
 | 
					msgid "Not found"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/type_live/form_component.html.heex:18
 | 
				
			||||||
#: lib/cannery_web/templates/user_registration/new.html.heex:13
 | 
					#: lib/cannery_web/templates/user_registration/new.html.heex:13
 | 
				
			||||||
#: lib/cannery_web/templates/user_reset_password/edit.html.heex:13
 | 
					#: lib/cannery_web/templates/user_reset_password/edit.html.heex:13
 | 
				
			||||||
#: lib/cannery_web/templates/user_settings/edit.html.heex:22
 | 
					#: lib/cannery_web/templates/user_settings/edit.html.heex:22
 | 
				
			||||||
@@ -103,22 +104,22 @@ msgstr ""
 | 
				
			|||||||
msgid "You are not authorized to view this page."
 | 
					msgid "You are not authorized to view this page."
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery/accounts/user.ex:144
 | 
					#: lib/cannery/accounts/user.ex:145
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "did not change"
 | 
					msgid "did not change"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery/accounts/user.ex:165
 | 
					#: lib/cannery/accounts/user.ex:166
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "does not match password"
 | 
					msgid "does not match password"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery/accounts/user.ex:202
 | 
					#: lib/cannery/accounts/user.ex:203
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "is not valid"
 | 
					msgid "is not valid"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery/accounts/user.ex:99
 | 
					#: lib/cannery/accounts/user.ex:100
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "must have the @ sign and no spaces"
 | 
					msgid "must have the @ sign and no spaces"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
@@ -144,52 +145,52 @@ msgstr ""
 | 
				
			|||||||
msgid "Tag could not be removed"
 | 
					msgid "Tag could not be removed"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/form_component.ex:160
 | 
					#: lib/cannery_web/live/pack_live/form_component.ex:159
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Could not parse number of copies"
 | 
					msgid "Could not parse number of copies"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/form_component.ex:150
 | 
					#: lib/cannery_web/live/pack_live/form_component.ex:149
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Invalid number of copies, must be between 1 and %{max}. Was %{multiplier}"
 | 
					msgid "Invalid number of copies, must be between 1 and %{max}. Was %{multiplier}"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery/ammo.ex:1043
 | 
					#: lib/cannery/ammo.ex:1121
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Invalid multiplier"
 | 
					msgid "Invalid multiplier"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery/ammo/ammo_group.ex:92
 | 
					 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					 | 
				
			||||||
msgid "Please select an ammo type and container"
 | 
					 | 
				
			||||||
msgstr ""
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/range_live/index.html.heex:74
 | 
					#: lib/cannery_web/live/range_live/index.html.heex:74
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Your browser does not support the canvas element."
 | 
					msgid "Your browser does not support the canvas element."
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery/activity_log/shot_group.ex:72
 | 
					#: lib/cannery/activity_log/shot_record.ex:74
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Please select a valid user and ammo pack"
 | 
					msgid "Please select a valid user and ammo pack"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery/activity_log/shot_group.ex:86
 | 
					#: lib/cannery/activity_log/shot_record.ex:88
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Ammo left can be at most %{count} rounds"
 | 
					msgid "Ammo left can be at most %{count} rounds"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery/activity_log/shot_group.ex:82
 | 
					#: lib/cannery/activity_log/shot_record.ex:84
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Ammo left must be at least 0"
 | 
					msgid "Ammo left must be at least 0"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery/activity_log/shot_group.ex:119
 | 
					#: lib/cannery/activity_log/shot_record.ex:119
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Count can be at most %{count} shots"
 | 
					msgid "Count can be at most %{count} shots"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery/activity_log/shot_group.ex:78
 | 
					#: lib/cannery/activity_log/shot_record.ex:80
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "can't be blank"
 | 
					msgid "can't be blank"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: lib/cannery/ammo/pack.ex:100
 | 
				
			||||||
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
 | 
					msgid "Please select a type and container"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -23,14 +23,14 @@ msgstr ""
 | 
				
			|||||||
## Run "mix gettext.extract" to bring this file up to
 | 
					## Run "mix gettext.extract" to bring this file up to
 | 
				
			||||||
## date. Leave "msgstr"s empty as changing them here has no
 | 
					## date. Leave "msgstr"s empty as changing them here has no
 | 
				
			||||||
## effect: edit them in PO (.po) files instead.
 | 
					## effect: edit them in PO (.po) files instead.
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/index.ex:54
 | 
					#: lib/cannery_web/live/pack_live/index.ex:59
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/index.ex:62
 | 
					#: lib/cannery_web/live/pack_live/index.ex:67
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/index.html.heex:41
 | 
					#: lib/cannery_web/live/pack_live/index.html.heex:38
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Add Ammo"
 | 
					msgid "Add Ammo"
 | 
				
			||||||
msgstr "Añadir Munición"
 | 
					msgstr "Añadir Munición"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/index.html.heex:37
 | 
					#: lib/cannery_web/live/pack_live/index.html.heex:34
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Add your first box!"
 | 
					msgid "Add your first box!"
 | 
				
			||||||
msgstr "¡Añade tu primera caja!"
 | 
					msgstr "¡Añade tu primera caja!"
 | 
				
			||||||
@@ -40,7 +40,7 @@ msgstr "¡Añade tu primera caja!"
 | 
				
			|||||||
msgid "Add your first container!"
 | 
					msgid "Add your first container!"
 | 
				
			||||||
msgstr "¡Añade tu primer contenedor!"
 | 
					msgstr "¡Añade tu primer contenedor!"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_type_live/index.html.heex:13
 | 
					#: lib/cannery_web/live/type_live/index.html.heex:13
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Add your first type!"
 | 
					msgid "Add your first type!"
 | 
				
			||||||
msgstr "¡Añade tu primer tipo!"
 | 
					msgstr "¡Añade tu primer tipo!"
 | 
				
			||||||
@@ -95,11 +95,6 @@ msgstr "Entrar"
 | 
				
			|||||||
msgid "Make your first tag!"
 | 
					msgid "Make your first tag!"
 | 
				
			||||||
msgstr "¡Aplica tu primera etiqueta!"
 | 
					msgstr "¡Aplica tu primera etiqueta!"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_type_live/index.html.heex:17
 | 
					 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					 | 
				
			||||||
msgid "New Ammo type"
 | 
					 | 
				
			||||||
msgstr "Nuevo tipo de Munición"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/container_live/index.html.heex:17
 | 
					#: lib/cannery_web/live/container_live/index.html.heex:17
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "New Container"
 | 
					msgid "New Container"
 | 
				
			||||||
@@ -133,13 +128,13 @@ msgstr "Reenviar instrucciones de confirmación"
 | 
				
			|||||||
msgid "Reset password"
 | 
					msgid "Reset password"
 | 
				
			||||||
msgstr "Resetear contraseña"
 | 
					msgstr "Resetear contraseña"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/components/add_shot_group_component.html.heex:56
 | 
					#: lib/cannery_web/components/add_shot_record_component.html.heex:57
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/form_component.html.heex:84
 | 
					#: lib/cannery_web/live/container_live/form_component.html.heex:57
 | 
				
			||||||
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:159
 | 
					#: lib/cannery_web/live/invite_live/form_component.html.heex:35
 | 
				
			||||||
#: lib/cannery_web/live/container_live/form_component.html.heex:55
 | 
					#: lib/cannery_web/live/pack_live/form_component.html.heex:91
 | 
				
			||||||
#: lib/cannery_web/live/invite_live/form_component.html.heex:32
 | 
					#: lib/cannery_web/live/range_live/form_component.html.heex:45
 | 
				
			||||||
#: lib/cannery_web/live/range_live/form_component.html.heex:44
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/tag_live/form_component.html.heex:37
 | 
					#: lib/cannery_web/live/tag_live/form_component.html.heex:37
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/type_live/form_component.html.heex:350
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Save"
 | 
					msgid "Save"
 | 
				
			||||||
msgstr "Guardar"
 | 
					msgstr "Guardar"
 | 
				
			||||||
@@ -149,7 +144,7 @@ msgstr "Guardar"
 | 
				
			|||||||
msgid "Send instructions to reset password"
 | 
					msgid "Send instructions to reset password"
 | 
				
			||||||
msgstr "Enviar instrucciones para reestablecer contraseña"
 | 
					msgstr "Enviar instrucciones para reestablecer contraseña"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/container_live/show.html.heex:75
 | 
					#: lib/cannery_web/live/container_live/show.html.heex:68
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Why not add one?"
 | 
					msgid "Why not add one?"
 | 
				
			||||||
msgstr "¿Por qué no añadir una?"
 | 
					msgstr "¿Por qué no añadir una?"
 | 
				
			||||||
@@ -169,19 +164,19 @@ msgstr "Preparar munición"
 | 
				
			|||||||
msgid "Why not get some ready to shoot?"
 | 
					msgid "Why not get some ready to shoot?"
 | 
				
			||||||
msgstr "¿Por qué no preparar parte para disparar?"
 | 
					msgstr "¿Por qué no preparar parte para disparar?"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/index.html.heex:105
 | 
					#: lib/cannery_web/live/pack_live/index.html.heex:127
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/show.html.heex:103
 | 
					#: lib/cannery_web/live/pack_live/show.html.heex:96
 | 
				
			||||||
#: lib/cannery_web/live/range_live/index.html.heex:45
 | 
					#: lib/cannery_web/live/range_live/index.html.heex:45
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Record shots"
 | 
					msgid "Record shots"
 | 
				
			||||||
msgstr "Tiros récord"
 | 
					msgstr "Tiros récord"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/components/move_ammo_group_component.ex:90
 | 
					#: lib/cannery_web/components/move_pack_component.ex:88
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Add another container!"
 | 
					msgid "Add another container!"
 | 
				
			||||||
msgstr "¡Añade otro contenedor!"
 | 
					msgstr "¡Añade otro contenedor!"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/components/move_ammo_group_component.ex:126
 | 
					#: lib/cannery_web/components/move_pack_component.ex:124
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Select"
 | 
					msgid "Select"
 | 
				
			||||||
msgstr "Seleccionar"
 | 
					msgstr "Seleccionar"
 | 
				
			||||||
@@ -191,12 +186,12 @@ msgstr "Seleccionar"
 | 
				
			|||||||
msgid "Copy to clipboard"
 | 
					msgid "Copy to clipboard"
 | 
				
			||||||
msgstr "Copiar al portapapeles"
 | 
					msgstr "Copiar al portapapeles"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/index.html.heex:22
 | 
					#: lib/cannery_web/live/pack_live/index.html.heex:14
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "add a container first"
 | 
					msgid "add a container first"
 | 
				
			||||||
msgstr "añade primero un contenedor"
 | 
					msgstr "añade primero un contenedor"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/form_component.html.heex:77
 | 
					#: lib/cannery_web/live/pack_live/form_component.html.heex:84
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Create"
 | 
					msgid "Create"
 | 
				
			||||||
msgstr "Crear"
 | 
					msgstr "Crear"
 | 
				
			||||||
@@ -211,19 +206,14 @@ msgstr "Cambiar Lenguaje"
 | 
				
			|||||||
msgid "Change language"
 | 
					msgid "Change language"
 | 
				
			||||||
msgstr "Cambiar lenguaje"
 | 
					msgstr "Cambiar lenguaje"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/show.html.heex:55
 | 
					#: lib/cannery_web/live/pack_live/show.html.heex:55
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "View in Catalog"
 | 
					msgid "View in Catalog"
 | 
				
			||||||
msgstr "Ver en Catalogo"
 | 
					msgstr "Ver en Catalogo"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/index.html.heex:32
 | 
					#: lib/cannery_web/components/move_pack_component.ex:78
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#: lib/cannery_web/live/pack_live/index.html.heex:144
 | 
				
			||||||
msgid "add an ammo type first"
 | 
					#: lib/cannery_web/live/pack_live/show.html.heex:89
 | 
				
			||||||
msgstr "añade primero un tipo de munición"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#: lib/cannery_web/components/move_ammo_group_component.ex:80
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/index.html.heex:122
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/show.html.heex:96
 | 
					 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Move ammo"
 | 
					msgid "Move ammo"
 | 
				
			||||||
msgstr "Mover munición"
 | 
					msgstr "Mover munición"
 | 
				
			||||||
@@ -233,13 +223,13 @@ msgstr "Mover munición"
 | 
				
			|||||||
msgid "Set Unlimited"
 | 
					msgid "Set Unlimited"
 | 
				
			||||||
msgstr "Activar ilimitados"
 | 
					msgstr "Activar ilimitados"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/show.html.heex:89
 | 
					#: lib/cannery_web/live/pack_live/show.html.heex:85
 | 
				
			||||||
#: lib/cannery_web/live/range_live/index.html.heex:38
 | 
					#: lib/cannery_web/live/range_live/index.html.heex:38
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Stage for range"
 | 
					msgid "Stage for range"
 | 
				
			||||||
msgstr "Preparar para el campo de tiro"
 | 
					msgstr "Preparar para el campo de tiro"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/show.html.heex:88
 | 
					#: lib/cannery_web/live/pack_live/show.html.heex:84
 | 
				
			||||||
#: lib/cannery_web/live/range_live/index.html.heex:37
 | 
					#: lib/cannery_web/live/range_live/index.html.heex:37
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Unstage from range"
 | 
					msgid "Unstage from range"
 | 
				
			||||||
@@ -250,13 +240,8 @@ msgstr "Desmontar del campo de tiro"
 | 
				
			|||||||
msgid "Export Data as JSON"
 | 
					msgid "Export Data as JSON"
 | 
				
			||||||
msgstr "Exportar datos como JSON"
 | 
					msgstr "Exportar datos como JSON"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_type_live/index.html.heex:85
 | 
					#: lib/cannery_web/live/container_live/index.html.heex:87
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#: lib/cannery_web/live/container_live/index.html.heex:145
 | 
				
			||||||
msgid "Clone %{ammo_type_name}"
 | 
					 | 
				
			||||||
msgstr ""
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/container_live/index.html.heex:88
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/container_live/index.html.heex:144
 | 
					 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Clone %{container_name}"
 | 
					msgid "Clone %{container_name}"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
@@ -266,20 +251,14 @@ msgstr ""
 | 
				
			|||||||
msgid "Copy invite link for %{invite_name}"
 | 
					msgid "Copy invite link for %{invite_name}"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_type_live/index.html.heex:104
 | 
					#: lib/cannery_web/live/container_live/index.html.heex:104
 | 
				
			||||||
#: lib/cannery_web/live/ammo_type_live/show.html.heex:36
 | 
					#: lib/cannery_web/live/container_live/index.html.heex:162
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#: lib/cannery_web/live/container_live/show.html.heex:48
 | 
				
			||||||
msgid "Delete %{ammo_type_name}"
 | 
					 | 
				
			||||||
msgstr ""
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/container_live/index.html.heex:103
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/container_live/index.html.heex:159
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/container_live/show.html.heex:55
 | 
					 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Delete %{container_name}"
 | 
					msgid "Delete %{container_name}"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/tag_live/index.html.heex:66
 | 
					#: lib/cannery_web/live/tag_live/index.html.heex:65
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Delete %{tag_name}"
 | 
					msgid "Delete %{tag_name}"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
@@ -289,85 +268,102 @@ msgstr ""
 | 
				
			|||||||
msgid "Delete invite for %{invite_name}"
 | 
					msgid "Delete invite for %{invite_name}"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/show.ex:161
 | 
					#: lib/cannery_web/live/container_live/index.html.heex:77
 | 
				
			||||||
#: lib/cannery_web/live/range_live/index.html.heex:131
 | 
					#: lib/cannery_web/live/container_live/index.html.heex:135
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#: lib/cannery_web/live/container_live/show.html.heex:35
 | 
				
			||||||
msgid "Delete shot record of %{shot_group_count} shots"
 | 
					 | 
				
			||||||
msgstr ""
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/ammo_type_live/index.html.heex:75
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/ammo_type_live/show.html.heex:19
 | 
					 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					 | 
				
			||||||
msgid "Edit %{ammo_type_name}"
 | 
					 | 
				
			||||||
msgstr ""
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/container_live/index.html.heex:78
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/container_live/index.html.heex:134
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/container_live/show.html.heex:42
 | 
					 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Edit %{container_name}"
 | 
					msgid "Edit %{container_name}"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/tag_live/index.html.heex:53
 | 
					#: lib/cannery_web/live/tag_live/index.html.heex:52
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Edit %{tag_name}"
 | 
					msgid "Edit %{tag_name}"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/index.html.heex:144
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/show.html.heex:62
 | 
					 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					 | 
				
			||||||
msgid "Edit ammo group of %{ammo_group_count} bullets"
 | 
					 | 
				
			||||||
msgstr ""
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/invite_live/index.html.heex:46
 | 
					#: lib/cannery_web/live/invite_live/index.html.heex:46
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Edit invite for %{invite_name}"
 | 
					msgid "Edit invite for %{invite_name}"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/show.ex:146
 | 
					#: lib/cannery_web/live/pack_live/index.html.heex:120
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					 | 
				
			||||||
msgid "Edit shot group of %{shot_group_count} shots"
 | 
					 | 
				
			||||||
msgstr ""
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/range_live/index.html.heex:114
 | 
					 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					 | 
				
			||||||
msgid "Edit shot record of %{shot_group_count} shots"
 | 
					 | 
				
			||||||
msgstr ""
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/index.html.heex:98
 | 
					 | 
				
			||||||
#, elixir-autogen, elixir-format, fuzzy
 | 
					#, elixir-autogen, elixir-format, fuzzy
 | 
				
			||||||
msgid "Stage"
 | 
					msgid "Stage"
 | 
				
			||||||
msgstr "Preparar munición"
 | 
					msgstr "Preparar munición"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/container_live/index.html.heex:66
 | 
					#: lib/cannery_web/live/container_live/index.html.heex:65
 | 
				
			||||||
#: lib/cannery_web/live/container_live/index.html.heex:123
 | 
					#: lib/cannery_web/live/container_live/index.html.heex:124
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Tag %{container_name}"
 | 
					msgid "Tag %{container_name}"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/index.html.heex:97
 | 
					#: lib/cannery_web/live/pack_live/index.html.heex:119
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Unstage"
 | 
					msgid "Unstage"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_type_live/index.html.heex:65
 | 
					#: lib/cannery_web/live/pack_live/index.html.heex:174
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format, fuzzy
 | 
				
			||||||
msgid "View %{ammo_type_name}"
 | 
					msgid "Clone pack of %{pack_count} bullets"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/index.html.heex:156
 | 
					#: lib/cannery_web/live/pack_live/index.html.heex:189
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/pack_live/show.html.heex:74
 | 
				
			||||||
#, elixir-autogen, elixir-format, fuzzy
 | 
					#, elixir-autogen, elixir-format, fuzzy
 | 
				
			||||||
msgid "Clone ammo group of %{ammo_group_count} bullets"
 | 
					msgid "Delete pack of %{pack_count} bullets"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/index.html.heex:171
 | 
					#: lib/cannery_web/live/pack_live/index.html.heex:164
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/show.html.heex:76
 | 
					#: lib/cannery_web/live/pack_live/show.html.heex:62
 | 
				
			||||||
#, elixir-autogen, elixir-format, fuzzy
 | 
					#, elixir-autogen, elixir-format, fuzzy
 | 
				
			||||||
msgid "Delete ammo group of %{ammo_group_count} bullets"
 | 
					msgid "Edit pack of %{pack_count} bullets"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/index.html.heex:132
 | 
					#: lib/cannery_web/live/pack_live/index.html.heex:154
 | 
				
			||||||
#: lib/cannery_web/live/ammo_type_live/show.html.heex:189
 | 
					#: lib/cannery_web/live/type_live/show.html.heex:204
 | 
				
			||||||
#, elixir-autogen, elixir-format, fuzzy
 | 
					#, elixir-autogen, elixir-format, fuzzy
 | 
				
			||||||
msgid "View ammo group of %{ammo_group_count} bullets"
 | 
					msgid "View pack of %{pack_count} bullets"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/pack_live/show.ex:160
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/range_live/index.html.heex:155
 | 
				
			||||||
 | 
					#, elixir-autogen, elixir-format, fuzzy
 | 
				
			||||||
 | 
					msgid "Delete shot record of %{shot_record_count} shots"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/pack_live/show.ex:145
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/range_live/index.html.heex:138
 | 
				
			||||||
 | 
					#, elixir-autogen, elixir-format, fuzzy
 | 
				
			||||||
 | 
					msgid "Edit shot record of %{shot_record_count} shots"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/type_live/index.html.heex:105
 | 
				
			||||||
 | 
					#, elixir-autogen, elixir-format, fuzzy
 | 
				
			||||||
 | 
					msgid "Clone %{type_name}"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/type_live/index.html.heex:122
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/type_live/show.html.heex:35
 | 
				
			||||||
 | 
					#, elixir-autogen, elixir-format, fuzzy
 | 
				
			||||||
 | 
					msgid "Delete %{type_name}"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/type_live/index.html.heex:97
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/type_live/show.html.heex:19
 | 
				
			||||||
 | 
					#, elixir-autogen, elixir-format, fuzzy
 | 
				
			||||||
 | 
					msgid "Edit %{type_name}"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/type_live/index.html.heex:17
 | 
				
			||||||
 | 
					#, elixir-autogen, elixir-format, fuzzy
 | 
				
			||||||
 | 
					msgid "New Type"
 | 
				
			||||||
 | 
					msgstr "Nuevo tipo de Munición"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/type_live/index.html.heex:89
 | 
				
			||||||
 | 
					#, elixir-autogen, elixir-format, fuzzy
 | 
				
			||||||
 | 
					msgid "View %{type_name}"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/pack_live/index.html.heex:24
 | 
				
			||||||
 | 
					#, elixir-autogen, elixir-format, fuzzy
 | 
				
			||||||
 | 
					msgid "add a type first"
 | 
				
			||||||
 | 
					msgstr "añade primero un tipo de munición"
 | 
				
			||||||
 
 | 
				
			|||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -69,6 +69,7 @@ msgstr "Correo o contraseña incorrecta"
 | 
				
			|||||||
msgid "Not found"
 | 
					msgid "Not found"
 | 
				
			||||||
msgstr "No se encontró"
 | 
					msgstr "No se encontró"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/type_live/form_component.html.heex:18
 | 
				
			||||||
#: lib/cannery_web/templates/user_registration/new.html.heex:13
 | 
					#: lib/cannery_web/templates/user_registration/new.html.heex:13
 | 
				
			||||||
#: lib/cannery_web/templates/user_reset_password/edit.html.heex:13
 | 
					#: lib/cannery_web/templates/user_reset_password/edit.html.heex:13
 | 
				
			||||||
#: lib/cannery_web/templates/user_settings/edit.html.heex:22
 | 
					#: lib/cannery_web/templates/user_settings/edit.html.heex:22
 | 
				
			||||||
@@ -119,22 +120,22 @@ msgstr "El enlace de confirmación de usuario no es válido o ha caducado."
 | 
				
			|||||||
msgid "You are not authorized to view this page."
 | 
					msgid "You are not authorized to view this page."
 | 
				
			||||||
msgstr "No está autorizado a ver esta página."
 | 
					msgstr "No está autorizado a ver esta página."
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery/accounts/user.ex:144
 | 
					#: lib/cannery/accounts/user.ex:145
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "did not change"
 | 
					msgid "did not change"
 | 
				
			||||||
msgstr "no cambió"
 | 
					msgstr "no cambió"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery/accounts/user.ex:165
 | 
					#: lib/cannery/accounts/user.ex:166
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "does not match password"
 | 
					msgid "does not match password"
 | 
				
			||||||
msgstr "no coincide con la contraseña"
 | 
					msgstr "no coincide con la contraseña"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery/accounts/user.ex:202
 | 
					#: lib/cannery/accounts/user.ex:203
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "is not valid"
 | 
					msgid "is not valid"
 | 
				
			||||||
msgstr "no es válido"
 | 
					msgstr "no es válido"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery/accounts/user.ex:99
 | 
					#: lib/cannery/accounts/user.ex:100
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "must have the @ sign and no spaces"
 | 
					msgid "must have the @ sign and no spaces"
 | 
				
			||||||
msgstr "debe tener el signo @ y no contener espacios"
 | 
					msgstr "debe tener el signo @ y no contener espacios"
 | 
				
			||||||
@@ -160,52 +161,52 @@ msgstr "Debe confirmar su cuenta e iniciar sesión para acceder a esta página."
 | 
				
			|||||||
msgid "Tag could not be removed"
 | 
					msgid "Tag could not be removed"
 | 
				
			||||||
msgstr "La etiqueta no pudo ser eliminada"
 | 
					msgstr "La etiqueta no pudo ser eliminada"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/form_component.ex:160
 | 
					#: lib/cannery_web/live/pack_live/form_component.ex:159
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Could not parse number of copies"
 | 
					msgid "Could not parse number of copies"
 | 
				
			||||||
msgstr "No se ha podido procesar el número de copias"
 | 
					msgstr "No se ha podido procesar el número de copias"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/form_component.ex:150
 | 
					#: lib/cannery_web/live/pack_live/form_component.ex:149
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Invalid number of copies, must be between 1 and %{max}. Was %{multiplier}"
 | 
					msgid "Invalid number of copies, must be between 1 and %{max}. Was %{multiplier}"
 | 
				
			||||||
msgstr "Número inválido de copias, debe ser entre 1 y %{max}. Fue %{multiplier"
 | 
					msgstr "Número inválido de copias, debe ser entre 1 y %{max}. Fue %{multiplier"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery/ammo.ex:1043
 | 
					#: lib/cannery/ammo.ex:1121
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Invalid multiplier"
 | 
					msgid "Invalid multiplier"
 | 
				
			||||||
msgstr "Multiplicador inválido"
 | 
					msgstr "Multiplicador inválido"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery/ammo/ammo_group.ex:92
 | 
					 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					 | 
				
			||||||
msgid "Please select an ammo type and container"
 | 
					 | 
				
			||||||
msgstr "Por favor escoja un tipo de munición y un contenedor"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/range_live/index.html.heex:74
 | 
					#: lib/cannery_web/live/range_live/index.html.heex:74
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Your browser does not support the canvas element."
 | 
					msgid "Your browser does not support the canvas element."
 | 
				
			||||||
msgstr "Su navegador no es compatible con el elemento lienzo."
 | 
					msgstr "Su navegador no es compatible con el elemento lienzo."
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery/activity_log/shot_group.ex:72
 | 
					#: lib/cannery/activity_log/shot_record.ex:74
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Please select a valid user and ammo pack"
 | 
					msgid "Please select a valid user and ammo pack"
 | 
				
			||||||
msgstr "Por favor escoja un usuario y tipo de munición valido"
 | 
					msgstr "Por favor escoja un usuario y tipo de munición valido"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery/activity_log/shot_group.ex:86
 | 
					#: lib/cannery/activity_log/shot_record.ex:88
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Ammo left can be at most %{count} rounds"
 | 
					msgid "Ammo left can be at most %{count} rounds"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery/activity_log/shot_group.ex:82
 | 
					#: lib/cannery/activity_log/shot_record.ex:84
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Ammo left must be at least 0"
 | 
					msgid "Ammo left must be at least 0"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery/activity_log/shot_group.ex:119
 | 
					#: lib/cannery/activity_log/shot_record.ex:119
 | 
				
			||||||
#, elixir-autogen, elixir-format, fuzzy
 | 
					#, elixir-autogen, elixir-format, fuzzy
 | 
				
			||||||
msgid "Count can be at most %{count} shots"
 | 
					msgid "Count can be at most %{count} shots"
 | 
				
			||||||
msgstr "El recuento debe ser menos de %{count}"
 | 
					msgstr "El recuento debe ser menos de %{count}"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery/activity_log/shot_group.ex:78
 | 
					#: lib/cannery/activity_log/shot_record.ex:80
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "can't be blank"
 | 
					msgid "can't be blank"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: lib/cannery/ammo/pack.ex:100
 | 
				
			||||||
 | 
					#, elixir-autogen, elixir-format, fuzzy
 | 
				
			||||||
 | 
					msgid "Please select a type and container"
 | 
				
			||||||
 | 
					msgstr "Por favor escoja un tipo de munición y un contenedor"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -23,17 +23,17 @@ msgstr ""
 | 
				
			|||||||
## Run "mix gettext.extract" to bring this file up to
 | 
					## Run "mix gettext.extract" to bring this file up to
 | 
				
			||||||
## date. Leave "msgstr"s empty as changing them here has no
 | 
					## date. Leave "msgstr"s empty as changing them here has no
 | 
				
			||||||
## effect: edit them in PO (.po) files instead.
 | 
					## effect: edit them in PO (.po) files instead.
 | 
				
			||||||
#: lib/cannery_web/live/ammo_type_live/form_component.ex:89
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/container_live/form_component.ex:89
 | 
					#: lib/cannery_web/live/container_live/form_component.ex:89
 | 
				
			||||||
#: lib/cannery_web/live/invite_live/form_component.ex:80
 | 
					#: lib/cannery_web/live/invite_live/form_component.ex:80
 | 
				
			||||||
#: lib/cannery_web/live/tag_live/form_component.ex:78
 | 
					#: lib/cannery_web/live/tag_live/form_component.ex:78
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/type_live/form_component.ex:88
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "%{name} created successfully"
 | 
					msgid "%{name} created successfully"
 | 
				
			||||||
msgstr "%{name} creado exitosamente"
 | 
					msgstr "%{name} creado exitosamente"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_type_live/index.ex:72
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/ammo_type_live/show.ex:49
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/tag_live/index.ex:65
 | 
					#: lib/cannery_web/live/tag_live/index.ex:65
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/type_live/index.ex:72
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/type_live/show.ex:27
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "%{name} deleted succesfully"
 | 
					msgid "%{name} deleted succesfully"
 | 
				
			||||||
msgstr "%{name} borrado exitosamente"
 | 
					msgstr "%{name} borrado exitosamente"
 | 
				
			||||||
@@ -44,10 +44,10 @@ msgstr "%{name} borrado exitosamente"
 | 
				
			|||||||
msgid "%{name} has been deleted"
 | 
					msgid "%{name} has been deleted"
 | 
				
			||||||
msgstr "%{name} ha sido borrado"
 | 
					msgstr "%{name} ha sido borrado"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_type_live/form_component.ex:70
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/container_live/form_component.ex:70
 | 
					#: lib/cannery_web/live/container_live/form_component.ex:70
 | 
				
			||||||
#: lib/cannery_web/live/invite_live/form_component.ex:62
 | 
					#: lib/cannery_web/live/invite_live/form_component.ex:62
 | 
				
			||||||
#: lib/cannery_web/live/tag_live/form_component.ex:60
 | 
					#: lib/cannery_web/live/tag_live/form_component.ex:60
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/type_live/form_component.ex:69
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "%{name} updated successfully"
 | 
					msgid "%{name} updated successfully"
 | 
				
			||||||
msgstr "%{name} actualizado exitosamente"
 | 
					msgstr "%{name} actualizado exitosamente"
 | 
				
			||||||
@@ -65,16 +65,16 @@ msgstr ""
 | 
				
			|||||||
msgid "Are you sure you want to delete %{email}? This action is permanent!"
 | 
					msgid "Are you sure you want to delete %{email}? This action is permanent!"
 | 
				
			||||||
msgstr "Está seguro que desea eliminar %{email}? Esta acción es permanente!"
 | 
					msgstr "Está seguro que desea eliminar %{email}? Esta acción es permanente!"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/container_live/index.html.heex:100
 | 
					#: lib/cannery_web/live/container_live/index.html.heex:99
 | 
				
			||||||
#: lib/cannery_web/live/container_live/index.html.heex:156
 | 
					#: lib/cannery_web/live/container_live/index.html.heex:157
 | 
				
			||||||
#: lib/cannery_web/live/container_live/show.html.heex:52
 | 
					#: lib/cannery_web/live/container_live/show.html.heex:45
 | 
				
			||||||
#: lib/cannery_web/live/tag_live/index.html.heex:64
 | 
					#: lib/cannery_web/live/tag_live/index.html.heex:63
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Are you sure you want to delete %{name}?"
 | 
					msgid "Are you sure you want to delete %{name}?"
 | 
				
			||||||
msgstr "Está seguro que desea eliminar %{name}?"
 | 
					msgstr "Está seguro que desea eliminar %{name}?"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/index.html.heex:169
 | 
					#: lib/cannery_web/live/pack_live/index.html.heex:187
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/show.html.heex:74
 | 
					#: lib/cannery_web/live/pack_live/show.html.heex:72
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Are you sure you want to delete this ammo?"
 | 
					msgid "Are you sure you want to delete this ammo?"
 | 
				
			||||||
msgstr "Está seguro que desea eliminar esta munición?"
 | 
					msgstr "Está seguro que desea eliminar esta munición?"
 | 
				
			||||||
@@ -128,13 +128,13 @@ msgstr "Contraseña cambiada exitosamente."
 | 
				
			|||||||
msgid "Please check your email to verify your account"
 | 
					msgid "Please check your email to verify your account"
 | 
				
			||||||
msgstr "Por favor chequea el correo para verificar tu cuenta"
 | 
					msgstr "Por favor chequea el correo para verificar tu cuenta"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/components/add_shot_group_component.html.heex:58
 | 
					#: lib/cannery_web/components/add_shot_record_component.html.heex:59
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/form_component.html.heex:85
 | 
					#: lib/cannery_web/live/container_live/form_component.html.heex:59
 | 
				
			||||||
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:160
 | 
					#: lib/cannery_web/live/invite_live/form_component.html.heex:37
 | 
				
			||||||
#: lib/cannery_web/live/container_live/form_component.html.heex:57
 | 
					#: lib/cannery_web/live/pack_live/form_component.html.heex:92
 | 
				
			||||||
#: lib/cannery_web/live/invite_live/form_component.html.heex:34
 | 
					#: lib/cannery_web/live/range_live/form_component.html.heex:47
 | 
				
			||||||
#: lib/cannery_web/live/range_live/form_component.html.heex:46
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/tag_live/form_component.html.heex:39
 | 
					#: lib/cannery_web/live/tag_live/form_component.html.heex:39
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/type_live/form_component.html.heex:351
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Saving..."
 | 
					msgid "Saving..."
 | 
				
			||||||
msgstr "Guardando..."
 | 
					msgstr "Guardando..."
 | 
				
			||||||
@@ -165,7 +165,7 @@ msgstr "se ha removido %{tag_name} de %{container_name}"
 | 
				
			|||||||
msgid "Adding..."
 | 
					msgid "Adding..."
 | 
				
			||||||
msgstr "Añadiendo..."
 | 
					msgstr "Añadiendo..."
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/components/add_shot_group_component.ex:60
 | 
					#: lib/cannery_web/components/add_shot_record_component.ex:60
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Shots recorded successfully"
 | 
					msgid "Shots recorded successfully"
 | 
				
			||||||
msgstr "Tiros registrados exitosamente"
 | 
					msgstr "Tiros registrados exitosamente"
 | 
				
			||||||
@@ -175,13 +175,13 @@ msgstr "Tiros registrados exitosamente"
 | 
				
			|||||||
msgid "Are you sure you want to unstage this ammo?"
 | 
					msgid "Are you sure you want to unstage this ammo?"
 | 
				
			||||||
msgstr "Está seguro que desea desmontar esta munición?"
 | 
					msgstr "Está seguro que desea desmontar esta munición?"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/show.ex:159
 | 
					#: lib/cannery_web/live/pack_live/show.ex:158
 | 
				
			||||||
#: lib/cannery_web/live/range_live/index.html.heex:128
 | 
					#: lib/cannery_web/live/range_live/index.html.heex:152
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Are you sure you want to delete this shot record?"
 | 
					msgid "Are you sure you want to delete this shot record?"
 | 
				
			||||||
msgstr "¿Está segure que quiere borrar este récord de disparos?"
 | 
					msgstr "¿Está segure que quiere borrar este récord de disparos?"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/show.ex:81
 | 
					#: lib/cannery_web/live/pack_live/show.ex:80
 | 
				
			||||||
#: lib/cannery_web/live/range_live/index.ex:79
 | 
					#: lib/cannery_web/live/range_live/index.ex:79
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Shot records deleted succesfully"
 | 
					msgid "Shot records deleted succesfully"
 | 
				
			||||||
@@ -197,7 +197,7 @@ msgstr "Récord de disparos actualizado exitosamente"
 | 
				
			|||||||
msgid "%{email} confirmed successfully."
 | 
					msgid "%{email} confirmed successfully."
 | 
				
			||||||
msgstr "%{email} confirmado exitosamente."
 | 
					msgstr "%{email} confirmado exitosamente."
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/components/move_ammo_group_component.ex:54
 | 
					#: lib/cannery_web/components/move_pack_component.ex:52
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Ammo moved to %{name} successfully"
 | 
					msgid "Ammo moved to %{name} successfully"
 | 
				
			||||||
msgstr "Munición movida a %{name} exitosamente"
 | 
					msgstr "Munición movida a %{name} exitosamente"
 | 
				
			||||||
@@ -212,13 +212,13 @@ msgstr "Copiado al portapapeles"
 | 
				
			|||||||
msgid "%{name} removed successfully"
 | 
					msgid "%{name} removed successfully"
 | 
				
			||||||
msgstr "%{name} eliminado exitosamente"
 | 
					msgstr "%{name} eliminado exitosamente"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/index.html.heex:18
 | 
					#: lib/cannery_web/live/pack_live/index.html.heex:10
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/index.html.heex:28
 | 
					#: lib/cannery_web/live/pack_live/index.html.heex:20
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "You'll need to"
 | 
					msgid "You'll need to"
 | 
				
			||||||
msgstr "Necesitará hacerlo"
 | 
					msgstr "Necesitará hacerlo"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/form_component.html.heex:78
 | 
					#: lib/cannery_web/live/pack_live/form_component.html.heex:85
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Creating..."
 | 
					msgid "Creating..."
 | 
				
			||||||
msgstr "Creando..."
 | 
					msgstr "Creando..."
 | 
				
			||||||
@@ -233,31 +233,31 @@ msgstr "¿Está segure de que quiere cambiar el idioma?"
 | 
				
			|||||||
msgid "Language updated successfully."
 | 
					msgid "Language updated successfully."
 | 
				
			||||||
msgstr "Idioma cambiado exitosamente."
 | 
					msgstr "Idioma cambiado exitosamente."
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/index.ex:89
 | 
					#: lib/cannery_web/live/pack_live/index.ex:94
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/show.ex:55
 | 
					#: lib/cannery_web/live/pack_live/show.ex:55
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Ammo deleted succesfully"
 | 
					msgid "Ammo deleted succesfully"
 | 
				
			||||||
msgstr "Munición borrada exitosamente"
 | 
					msgstr "Munición borrada exitosamente"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/range_live/index.ex:93
 | 
					#: lib/cannery_web/live/range_live/index.ex:92
 | 
				
			||||||
#, elixir-autogen, elixir-format, fuzzy
 | 
					#, elixir-autogen, elixir-format, fuzzy
 | 
				
			||||||
msgid "Ammo unstaged succesfully"
 | 
					msgid "Ammo unstaged succesfully"
 | 
				
			||||||
msgstr "Munición descargada exitosamente"
 | 
					msgstr "Munición descargada exitosamente"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/form_component.ex:126
 | 
					#: lib/cannery_web/live/pack_live/form_component.ex:125
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Ammo updated successfully"
 | 
					msgid "Ammo updated successfully"
 | 
				
			||||||
msgstr "Munición actualizada exitosamente"
 | 
					msgstr "Munición actualizada exitosamente"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/form_component.ex:185
 | 
					#: lib/cannery_web/live/pack_live/form_component.ex:184
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Ammo added successfully"
 | 
					msgid "Ammo added successfully"
 | 
				
			||||||
msgid_plural "Ammo added successfully"
 | 
					msgid_plural "Ammo added successfully"
 | 
				
			||||||
msgstr[0] "Munición añadida exitosamente"
 | 
					msgstr[0] "Munición añadida exitosamente"
 | 
				
			||||||
msgstr[1] "Municiones añadidas exitosamente"
 | 
					msgstr[1] "Municiones añadidas exitosamente"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_type_live/index.html.heex:97
 | 
					#: lib/cannery_web/live/type_live/index.html.heex:116
 | 
				
			||||||
#: lib/cannery_web/live/ammo_type_live/show.html.heex:29
 | 
					#: lib/cannery_web/live/type_live/show.html.heex:29
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Are you sure you want to delete %{name}? This will delete all %{name} type ammo as well!"
 | 
					msgid "Are you sure you want to delete %{name}? This will delete all %{name} type ammo as well!"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -23,14 +23,14 @@ msgstr ""
 | 
				
			|||||||
# # Run "mix gettext.extract" to bring this file up to
 | 
					# # Run "mix gettext.extract" to bring this file up to
 | 
				
			||||||
# # date. Leave "msgstr"s empty as changing them here has no
 | 
					# # date. Leave "msgstr"s empty as changing them here has no
 | 
				
			||||||
# # effect: edit them in PO (.po) files instead.
 | 
					# # effect: edit them in PO (.po) files instead.
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/index.ex:54
 | 
					#: lib/cannery_web/live/pack_live/index.ex:59
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/index.ex:62
 | 
					#: lib/cannery_web/live/pack_live/index.ex:67
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/index.html.heex:41
 | 
					#: lib/cannery_web/live/pack_live/index.html.heex:38
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Add Ammo"
 | 
					msgid "Add Ammo"
 | 
				
			||||||
msgstr "ajouter munition"
 | 
					msgstr "ajouter munition"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/index.html.heex:37
 | 
					#: lib/cannery_web/live/pack_live/index.html.heex:34
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Add your first box!"
 | 
					msgid "Add your first box!"
 | 
				
			||||||
msgstr "Ajoutez votre première caisse !"
 | 
					msgstr "Ajoutez votre première caisse !"
 | 
				
			||||||
@@ -40,7 +40,7 @@ msgstr "Ajoutez votre première caisse !"
 | 
				
			|||||||
msgid "Add your first container!"
 | 
					msgid "Add your first container!"
 | 
				
			||||||
msgstr "Ajoutez votre premier conteneur !"
 | 
					msgstr "Ajoutez votre premier conteneur !"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_type_live/index.html.heex:13
 | 
					#: lib/cannery_web/live/type_live/index.html.heex:13
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Add your first type!"
 | 
					msgid "Add your first type!"
 | 
				
			||||||
msgstr "Ajoutez votre premier type !"
 | 
					msgstr "Ajoutez votre premier type !"
 | 
				
			||||||
@@ -95,11 +95,6 @@ msgstr "Se connecter"
 | 
				
			|||||||
msgid "Make your first tag!"
 | 
					msgid "Make your first tag!"
 | 
				
			||||||
msgstr "Faîtes votre premier tag !"
 | 
					msgstr "Faîtes votre premier tag !"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_type_live/index.html.heex:17
 | 
					 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					 | 
				
			||||||
msgid "New Ammo type"
 | 
					 | 
				
			||||||
msgstr "Nouveau type de munition"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/container_live/index.html.heex:17
 | 
					#: lib/cannery_web/live/container_live/index.html.heex:17
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "New Container"
 | 
					msgid "New Container"
 | 
				
			||||||
@@ -133,13 +128,13 @@ msgstr "Renvoyer les instructions de confirmation"
 | 
				
			|||||||
msgid "Reset password"
 | 
					msgid "Reset password"
 | 
				
			||||||
msgstr "Réinitialisé le mot de passe"
 | 
					msgstr "Réinitialisé le mot de passe"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/components/add_shot_group_component.html.heex:56
 | 
					#: lib/cannery_web/components/add_shot_record_component.html.heex:57
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/form_component.html.heex:84
 | 
					#: lib/cannery_web/live/container_live/form_component.html.heex:57
 | 
				
			||||||
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:159
 | 
					#: lib/cannery_web/live/invite_live/form_component.html.heex:35
 | 
				
			||||||
#: lib/cannery_web/live/container_live/form_component.html.heex:55
 | 
					#: lib/cannery_web/live/pack_live/form_component.html.heex:91
 | 
				
			||||||
#: lib/cannery_web/live/invite_live/form_component.html.heex:32
 | 
					#: lib/cannery_web/live/range_live/form_component.html.heex:45
 | 
				
			||||||
#: lib/cannery_web/live/range_live/form_component.html.heex:44
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/tag_live/form_component.html.heex:37
 | 
					#: lib/cannery_web/live/tag_live/form_component.html.heex:37
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/type_live/form_component.html.heex:350
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Save"
 | 
					msgid "Save"
 | 
				
			||||||
msgstr "Sauvegarder"
 | 
					msgstr "Sauvegarder"
 | 
				
			||||||
@@ -149,7 +144,7 @@ msgstr "Sauvegarder"
 | 
				
			|||||||
msgid "Send instructions to reset password"
 | 
					msgid "Send instructions to reset password"
 | 
				
			||||||
msgstr "Envoyer les instructions pour réinitialiser le mot de passe"
 | 
					msgstr "Envoyer les instructions pour réinitialiser le mot de passe"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/container_live/show.html.heex:75
 | 
					#: lib/cannery_web/live/container_live/show.html.heex:68
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Why not add one?"
 | 
					msgid "Why not add one?"
 | 
				
			||||||
msgstr "Pourquoi pas en ajouter un ?"
 | 
					msgstr "Pourquoi pas en ajouter un ?"
 | 
				
			||||||
@@ -169,19 +164,19 @@ msgstr "Munition préparée"
 | 
				
			|||||||
msgid "Why not get some ready to shoot?"
 | 
					msgid "Why not get some ready to shoot?"
 | 
				
			||||||
msgstr "Pourquoi pas en préparer pour tirer ?"
 | 
					msgstr "Pourquoi pas en préparer pour tirer ?"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/index.html.heex:105
 | 
					#: lib/cannery_web/live/pack_live/index.html.heex:127
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/show.html.heex:103
 | 
					#: lib/cannery_web/live/pack_live/show.html.heex:96
 | 
				
			||||||
#: lib/cannery_web/live/range_live/index.html.heex:45
 | 
					#: lib/cannery_web/live/range_live/index.html.heex:45
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Record shots"
 | 
					msgid "Record shots"
 | 
				
			||||||
msgstr "Enregistrer des tirs"
 | 
					msgstr "Enregistrer des tirs"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/components/move_ammo_group_component.ex:90
 | 
					#: lib/cannery_web/components/move_pack_component.ex:88
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Add another container!"
 | 
					msgid "Add another container!"
 | 
				
			||||||
msgstr "Ajoutez un autre conteneur !"
 | 
					msgstr "Ajoutez un autre conteneur !"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/components/move_ammo_group_component.ex:126
 | 
					#: lib/cannery_web/components/move_pack_component.ex:124
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Select"
 | 
					msgid "Select"
 | 
				
			||||||
msgstr "Sélectionner"
 | 
					msgstr "Sélectionner"
 | 
				
			||||||
@@ -191,12 +186,12 @@ msgstr "Sélectionner"
 | 
				
			|||||||
msgid "Copy to clipboard"
 | 
					msgid "Copy to clipboard"
 | 
				
			||||||
msgstr "Copier dans le presse-papier"
 | 
					msgstr "Copier dans le presse-papier"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/index.html.heex:22
 | 
					#: lib/cannery_web/live/pack_live/index.html.heex:14
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "add a container first"
 | 
					msgid "add a container first"
 | 
				
			||||||
msgstr "ajouter un conteneur en premier"
 | 
					msgstr "ajouter un conteneur en premier"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/form_component.html.heex:77
 | 
					#: lib/cannery_web/live/pack_live/form_component.html.heex:84
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Create"
 | 
					msgid "Create"
 | 
				
			||||||
msgstr "Créer"
 | 
					msgstr "Créer"
 | 
				
			||||||
@@ -211,19 +206,14 @@ msgstr "Changer la langue"
 | 
				
			|||||||
msgid "Change language"
 | 
					msgid "Change language"
 | 
				
			||||||
msgstr "Changer la langue"
 | 
					msgstr "Changer la langue"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/show.html.heex:55
 | 
					#: lib/cannery_web/live/pack_live/show.html.heex:55
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "View in Catalog"
 | 
					msgid "View in Catalog"
 | 
				
			||||||
msgstr "Voir en catalogue"
 | 
					msgstr "Voir en catalogue"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/index.html.heex:32
 | 
					#: lib/cannery_web/components/move_pack_component.ex:78
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#: lib/cannery_web/live/pack_live/index.html.heex:144
 | 
				
			||||||
msgid "add an ammo type first"
 | 
					#: lib/cannery_web/live/pack_live/show.html.heex:89
 | 
				
			||||||
msgstr "Ajoutez d'abord un type de munitions"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#: lib/cannery_web/components/move_ammo_group_component.ex:80
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/index.html.heex:122
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/show.html.heex:96
 | 
					 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Move ammo"
 | 
					msgid "Move ammo"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
@@ -233,13 +223,13 @@ msgstr ""
 | 
				
			|||||||
msgid "Set Unlimited"
 | 
					msgid "Set Unlimited"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/show.html.heex:89
 | 
					#: lib/cannery_web/live/pack_live/show.html.heex:85
 | 
				
			||||||
#: lib/cannery_web/live/range_live/index.html.heex:38
 | 
					#: lib/cannery_web/live/range_live/index.html.heex:38
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Stage for range"
 | 
					msgid "Stage for range"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/show.html.heex:88
 | 
					#: lib/cannery_web/live/pack_live/show.html.heex:84
 | 
				
			||||||
#: lib/cannery_web/live/range_live/index.html.heex:37
 | 
					#: lib/cannery_web/live/range_live/index.html.heex:37
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Unstage from range"
 | 
					msgid "Unstage from range"
 | 
				
			||||||
@@ -250,13 +240,8 @@ msgstr ""
 | 
				
			|||||||
msgid "Export Data as JSON"
 | 
					msgid "Export Data as JSON"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_type_live/index.html.heex:85
 | 
					#: lib/cannery_web/live/container_live/index.html.heex:87
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#: lib/cannery_web/live/container_live/index.html.heex:145
 | 
				
			||||||
msgid "Clone %{ammo_type_name}"
 | 
					 | 
				
			||||||
msgstr ""
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/container_live/index.html.heex:88
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/container_live/index.html.heex:144
 | 
					 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Clone %{container_name}"
 | 
					msgid "Clone %{container_name}"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
@@ -266,20 +251,14 @@ msgstr ""
 | 
				
			|||||||
msgid "Copy invite link for %{invite_name}"
 | 
					msgid "Copy invite link for %{invite_name}"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_type_live/index.html.heex:104
 | 
					#: lib/cannery_web/live/container_live/index.html.heex:104
 | 
				
			||||||
#: lib/cannery_web/live/ammo_type_live/show.html.heex:36
 | 
					#: lib/cannery_web/live/container_live/index.html.heex:162
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#: lib/cannery_web/live/container_live/show.html.heex:48
 | 
				
			||||||
msgid "Delete %{ammo_type_name}"
 | 
					 | 
				
			||||||
msgstr ""
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/container_live/index.html.heex:103
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/container_live/index.html.heex:159
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/container_live/show.html.heex:55
 | 
					 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Delete %{container_name}"
 | 
					msgid "Delete %{container_name}"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/tag_live/index.html.heex:66
 | 
					#: lib/cannery_web/live/tag_live/index.html.heex:65
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Delete %{tag_name}"
 | 
					msgid "Delete %{tag_name}"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
@@ -289,85 +268,102 @@ msgstr ""
 | 
				
			|||||||
msgid "Delete invite for %{invite_name}"
 | 
					msgid "Delete invite for %{invite_name}"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/show.ex:161
 | 
					#: lib/cannery_web/live/container_live/index.html.heex:77
 | 
				
			||||||
#: lib/cannery_web/live/range_live/index.html.heex:131
 | 
					#: lib/cannery_web/live/container_live/index.html.heex:135
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#: lib/cannery_web/live/container_live/show.html.heex:35
 | 
				
			||||||
msgid "Delete shot record of %{shot_group_count} shots"
 | 
					 | 
				
			||||||
msgstr ""
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/ammo_type_live/index.html.heex:75
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/ammo_type_live/show.html.heex:19
 | 
					 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					 | 
				
			||||||
msgid "Edit %{ammo_type_name}"
 | 
					 | 
				
			||||||
msgstr ""
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/container_live/index.html.heex:78
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/container_live/index.html.heex:134
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/container_live/show.html.heex:42
 | 
					 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Edit %{container_name}"
 | 
					msgid "Edit %{container_name}"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/tag_live/index.html.heex:53
 | 
					#: lib/cannery_web/live/tag_live/index.html.heex:52
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Edit %{tag_name}"
 | 
					msgid "Edit %{tag_name}"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/index.html.heex:144
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/show.html.heex:62
 | 
					 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					 | 
				
			||||||
msgid "Edit ammo group of %{ammo_group_count} bullets"
 | 
					 | 
				
			||||||
msgstr ""
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/invite_live/index.html.heex:46
 | 
					#: lib/cannery_web/live/invite_live/index.html.heex:46
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Edit invite for %{invite_name}"
 | 
					msgid "Edit invite for %{invite_name}"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/show.ex:146
 | 
					#: lib/cannery_web/live/pack_live/index.html.heex:120
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					 | 
				
			||||||
msgid "Edit shot group of %{shot_group_count} shots"
 | 
					 | 
				
			||||||
msgstr ""
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/range_live/index.html.heex:114
 | 
					 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					 | 
				
			||||||
msgid "Edit shot record of %{shot_group_count} shots"
 | 
					 | 
				
			||||||
msgstr ""
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/index.html.heex:98
 | 
					 | 
				
			||||||
#, elixir-autogen, elixir-format, fuzzy
 | 
					#, elixir-autogen, elixir-format, fuzzy
 | 
				
			||||||
msgid "Stage"
 | 
					msgid "Stage"
 | 
				
			||||||
msgstr "Munition préparée"
 | 
					msgstr "Munition préparée"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/container_live/index.html.heex:66
 | 
					#: lib/cannery_web/live/container_live/index.html.heex:65
 | 
				
			||||||
#: lib/cannery_web/live/container_live/index.html.heex:123
 | 
					#: lib/cannery_web/live/container_live/index.html.heex:124
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Tag %{container_name}"
 | 
					msgid "Tag %{container_name}"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/index.html.heex:97
 | 
					#: lib/cannery_web/live/pack_live/index.html.heex:119
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Unstage"
 | 
					msgid "Unstage"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_type_live/index.html.heex:65
 | 
					#: lib/cannery_web/live/pack_live/index.html.heex:174
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format, fuzzy
 | 
				
			||||||
msgid "View %{ammo_type_name}"
 | 
					msgid "Clone pack of %{pack_count} bullets"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/index.html.heex:156
 | 
					#: lib/cannery_web/live/pack_live/index.html.heex:189
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/pack_live/show.html.heex:74
 | 
				
			||||||
#, elixir-autogen, elixir-format, fuzzy
 | 
					#, elixir-autogen, elixir-format, fuzzy
 | 
				
			||||||
msgid "Clone ammo group of %{ammo_group_count} bullets"
 | 
					msgid "Delete pack of %{pack_count} bullets"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/index.html.heex:171
 | 
					#: lib/cannery_web/live/pack_live/index.html.heex:164
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/show.html.heex:76
 | 
					#: lib/cannery_web/live/pack_live/show.html.heex:62
 | 
				
			||||||
#, elixir-autogen, elixir-format, fuzzy
 | 
					#, elixir-autogen, elixir-format, fuzzy
 | 
				
			||||||
msgid "Delete ammo group of %{ammo_group_count} bullets"
 | 
					msgid "Edit pack of %{pack_count} bullets"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/index.html.heex:132
 | 
					#: lib/cannery_web/live/pack_live/index.html.heex:154
 | 
				
			||||||
#: lib/cannery_web/live/ammo_type_live/show.html.heex:189
 | 
					#: lib/cannery_web/live/type_live/show.html.heex:204
 | 
				
			||||||
#, elixir-autogen, elixir-format, fuzzy
 | 
					#, elixir-autogen, elixir-format, fuzzy
 | 
				
			||||||
msgid "View ammo group of %{ammo_group_count} bullets"
 | 
					msgid "View pack of %{pack_count} bullets"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/pack_live/show.ex:160
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/range_live/index.html.heex:155
 | 
				
			||||||
 | 
					#, elixir-autogen, elixir-format, fuzzy
 | 
				
			||||||
 | 
					msgid "Delete shot record of %{shot_record_count} shots"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/pack_live/show.ex:145
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/range_live/index.html.heex:138
 | 
				
			||||||
 | 
					#, elixir-autogen, elixir-format, fuzzy
 | 
				
			||||||
 | 
					msgid "Edit shot record of %{shot_record_count} shots"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/type_live/index.html.heex:105
 | 
				
			||||||
 | 
					#, elixir-autogen, elixir-format, fuzzy
 | 
				
			||||||
 | 
					msgid "Clone %{type_name}"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/type_live/index.html.heex:122
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/type_live/show.html.heex:35
 | 
				
			||||||
 | 
					#, elixir-autogen, elixir-format, fuzzy
 | 
				
			||||||
 | 
					msgid "Delete %{type_name}"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/type_live/index.html.heex:97
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/type_live/show.html.heex:19
 | 
				
			||||||
 | 
					#, elixir-autogen, elixir-format, fuzzy
 | 
				
			||||||
 | 
					msgid "Edit %{type_name}"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/type_live/index.html.heex:17
 | 
				
			||||||
 | 
					#, elixir-autogen, elixir-format, fuzzy
 | 
				
			||||||
 | 
					msgid "New Type"
 | 
				
			||||||
 | 
					msgstr "Nouveau type de munition"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/type_live/index.html.heex:89
 | 
				
			||||||
 | 
					#, elixir-autogen, elixir-format, fuzzy
 | 
				
			||||||
 | 
					msgid "View %{type_name}"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/pack_live/index.html.heex:24
 | 
				
			||||||
 | 
					#, elixir-autogen, elixir-format, fuzzy
 | 
				
			||||||
 | 
					msgid "add a type first"
 | 
				
			||||||
 | 
					msgstr "Ajoutez d'abord un type de munitions"
 | 
				
			||||||
 
 | 
				
			|||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -69,6 +69,7 @@ msgstr "Mél ou mot de passe invalide"
 | 
				
			|||||||
msgid "Not found"
 | 
					msgid "Not found"
 | 
				
			||||||
msgstr "Pas trouvé"
 | 
					msgstr "Pas trouvé"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/type_live/form_component.html.heex:18
 | 
				
			||||||
#: lib/cannery_web/templates/user_registration/new.html.heex:13
 | 
					#: lib/cannery_web/templates/user_registration/new.html.heex:13
 | 
				
			||||||
#: lib/cannery_web/templates/user_reset_password/edit.html.heex:13
 | 
					#: lib/cannery_web/templates/user_reset_password/edit.html.heex:13
 | 
				
			||||||
#: lib/cannery_web/templates/user_settings/edit.html.heex:22
 | 
					#: lib/cannery_web/templates/user_settings/edit.html.heex:22
 | 
				
			||||||
@@ -118,22 +119,22 @@ msgstr "Le lien de confirmation d’utilisateur·ice est invalide ou a expiré."
 | 
				
			|||||||
msgid "You are not authorized to view this page."
 | 
					msgid "You are not authorized to view this page."
 | 
				
			||||||
msgstr "Vous n’êtes pas autorisé·e à voir cette page."
 | 
					msgstr "Vous n’êtes pas autorisé·e à voir cette page."
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery/accounts/user.ex:144
 | 
					#: lib/cannery/accounts/user.ex:145
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "did not change"
 | 
					msgid "did not change"
 | 
				
			||||||
msgstr "est inchangé"
 | 
					msgstr "est inchangé"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery/accounts/user.ex:165
 | 
					#: lib/cannery/accounts/user.ex:166
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "does not match password"
 | 
					msgid "does not match password"
 | 
				
			||||||
msgstr "le mot de passe ne correspond pas"
 | 
					msgstr "le mot de passe ne correspond pas"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery/accounts/user.ex:202
 | 
					#: lib/cannery/accounts/user.ex:203
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "is not valid"
 | 
					msgid "is not valid"
 | 
				
			||||||
msgstr "n’est pas valide"
 | 
					msgstr "n’est pas valide"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery/accounts/user.ex:99
 | 
					#: lib/cannery/accounts/user.ex:100
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "must have the @ sign and no spaces"
 | 
					msgid "must have the @ sign and no spaces"
 | 
				
			||||||
msgstr "doit contenir le symbole @ et aucune espace"
 | 
					msgstr "doit contenir le symbole @ et aucune espace"
 | 
				
			||||||
@@ -161,52 +162,52 @@ msgstr ""
 | 
				
			|||||||
msgid "Tag could not be removed"
 | 
					msgid "Tag could not be removed"
 | 
				
			||||||
msgstr "Le tag n’a pas pu être retiré"
 | 
					msgstr "Le tag n’a pas pu être retiré"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/form_component.ex:160
 | 
					#: lib/cannery_web/live/pack_live/form_component.ex:159
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Could not parse number of copies"
 | 
					msgid "Could not parse number of copies"
 | 
				
			||||||
msgstr "Impossible d'analyser le nombre de copies"
 | 
					msgstr "Impossible d'analyser le nombre de copies"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/form_component.ex:150
 | 
					#: lib/cannery_web/live/pack_live/form_component.ex:149
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Invalid number of copies, must be between 1 and %{max}. Was %{multiplier}"
 | 
					msgid "Invalid number of copies, must be between 1 and %{max}. Was %{multiplier}"
 | 
				
			||||||
msgstr "Nombre de copies invalide, doit être 1 et %{max}. Été %{multiplier}"
 | 
					msgstr "Nombre de copies invalide, doit être 1 et %{max}. Été %{multiplier}"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery/ammo.ex:1043
 | 
					#: lib/cannery/ammo.ex:1121
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Invalid multiplier"
 | 
					msgid "Invalid multiplier"
 | 
				
			||||||
msgstr "Multiplicateur invalide"
 | 
					msgstr "Multiplicateur invalide"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery/ammo/ammo_group.ex:92
 | 
					 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					 | 
				
			||||||
msgid "Please select an ammo type and container"
 | 
					 | 
				
			||||||
msgstr "Veuillez choisir un type de munitions et un conteneur"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/range_live/index.html.heex:74
 | 
					#: lib/cannery_web/live/range_live/index.html.heex:74
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Your browser does not support the canvas element."
 | 
					msgid "Your browser does not support the canvas element."
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery/activity_log/shot_group.ex:72
 | 
					#: lib/cannery/activity_log/shot_record.ex:74
 | 
				
			||||||
#, elixir-autogen, elixir-format, fuzzy
 | 
					#, elixir-autogen, elixir-format, fuzzy
 | 
				
			||||||
msgid "Please select a valid user and ammo pack"
 | 
					msgid "Please select a valid user and ammo pack"
 | 
				
			||||||
msgstr "Veuillez choisir un utilisateur valide et un groupe de munitions"
 | 
					msgstr "Veuillez choisir un utilisateur valide et un groupe de munitions"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery/activity_log/shot_group.ex:86
 | 
					#: lib/cannery/activity_log/shot_record.ex:88
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Ammo left can be at most %{count} rounds"
 | 
					msgid "Ammo left can be at most %{count} rounds"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery/activity_log/shot_group.ex:82
 | 
					#: lib/cannery/activity_log/shot_record.ex:84
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Ammo left must be at least 0"
 | 
					msgid "Ammo left must be at least 0"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery/activity_log/shot_group.ex:119
 | 
					#: lib/cannery/activity_log/shot_record.ex:119
 | 
				
			||||||
#, elixir-autogen, elixir-format, fuzzy
 | 
					#, elixir-autogen, elixir-format, fuzzy
 | 
				
			||||||
msgid "Count can be at most %{count} shots"
 | 
					msgid "Count can be at most %{count} shots"
 | 
				
			||||||
msgstr "La quantité doit être inférieur à %{count}"
 | 
					msgstr "La quantité doit être inférieur à %{count}"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery/activity_log/shot_group.ex:78
 | 
					#: lib/cannery/activity_log/shot_record.ex:80
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "can't be blank"
 | 
					msgid "can't be blank"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: lib/cannery/ammo/pack.ex:100
 | 
				
			||||||
 | 
					#, elixir-autogen, elixir-format, fuzzy
 | 
				
			||||||
 | 
					msgid "Please select a type and container"
 | 
				
			||||||
 | 
					msgstr "Veuillez choisir un type de munitions et un conteneur"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -23,17 +23,17 @@ msgstr ""
 | 
				
			|||||||
## Run "mix gettext.extract" to bring this file up to
 | 
					## Run "mix gettext.extract" to bring this file up to
 | 
				
			||||||
## date. Leave "msgstr"s empty as changing them here has no
 | 
					## date. Leave "msgstr"s empty as changing them here has no
 | 
				
			||||||
## effect: edit them in PO (.po) files instead.
 | 
					## effect: edit them in PO (.po) files instead.
 | 
				
			||||||
#: lib/cannery_web/live/ammo_type_live/form_component.ex:89
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/container_live/form_component.ex:89
 | 
					#: lib/cannery_web/live/container_live/form_component.ex:89
 | 
				
			||||||
#: lib/cannery_web/live/invite_live/form_component.ex:80
 | 
					#: lib/cannery_web/live/invite_live/form_component.ex:80
 | 
				
			||||||
#: lib/cannery_web/live/tag_live/form_component.ex:78
 | 
					#: lib/cannery_web/live/tag_live/form_component.ex:78
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/type_live/form_component.ex:88
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "%{name} created successfully"
 | 
					msgid "%{name} created successfully"
 | 
				
			||||||
msgstr "%{name} créé· avec succès"
 | 
					msgstr "%{name} créé· avec succès"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_type_live/index.ex:72
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/ammo_type_live/show.ex:49
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/tag_live/index.ex:65
 | 
					#: lib/cannery_web/live/tag_live/index.ex:65
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/type_live/index.ex:72
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/type_live/show.ex:27
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "%{name} deleted succesfully"
 | 
					msgid "%{name} deleted succesfully"
 | 
				
			||||||
msgstr "%{name} supprimé· avec succès"
 | 
					msgstr "%{name} supprimé· avec succès"
 | 
				
			||||||
@@ -44,10 +44,10 @@ msgstr "%{name} supprimé· avec succès"
 | 
				
			|||||||
msgid "%{name} has been deleted"
 | 
					msgid "%{name} has been deleted"
 | 
				
			||||||
msgstr "%{name} a été supprimé·e"
 | 
					msgstr "%{name} a été supprimé·e"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_type_live/form_component.ex:70
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/container_live/form_component.ex:70
 | 
					#: lib/cannery_web/live/container_live/form_component.ex:70
 | 
				
			||||||
#: lib/cannery_web/live/invite_live/form_component.ex:62
 | 
					#: lib/cannery_web/live/invite_live/form_component.ex:62
 | 
				
			||||||
#: lib/cannery_web/live/tag_live/form_component.ex:60
 | 
					#: lib/cannery_web/live/tag_live/form_component.ex:60
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/type_live/form_component.ex:69
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "%{name} updated successfully"
 | 
					msgid "%{name} updated successfully"
 | 
				
			||||||
msgstr "%{name} mis à jour avec succès"
 | 
					msgstr "%{name} mis à jour avec succès"
 | 
				
			||||||
@@ -66,16 +66,16 @@ msgid "Are you sure you want to delete %{email}? This action is permanent!"
 | 
				
			|||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
"Êtes-vous certain·e de supprimer %{email} ? Cette action est définitive !"
 | 
					"Êtes-vous certain·e de supprimer %{email} ? Cette action est définitive !"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/container_live/index.html.heex:100
 | 
					#: lib/cannery_web/live/container_live/index.html.heex:99
 | 
				
			||||||
#: lib/cannery_web/live/container_live/index.html.heex:156
 | 
					#: lib/cannery_web/live/container_live/index.html.heex:157
 | 
				
			||||||
#: lib/cannery_web/live/container_live/show.html.heex:52
 | 
					#: lib/cannery_web/live/container_live/show.html.heex:45
 | 
				
			||||||
#: lib/cannery_web/live/tag_live/index.html.heex:64
 | 
					#: lib/cannery_web/live/tag_live/index.html.heex:63
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Are you sure you want to delete %{name}?"
 | 
					msgid "Are you sure you want to delete %{name}?"
 | 
				
			||||||
msgstr "Êtes-vous certain·e de supprimer %{name} ?"
 | 
					msgstr "Êtes-vous certain·e de supprimer %{name} ?"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/index.html.heex:169
 | 
					#: lib/cannery_web/live/pack_live/index.html.heex:187
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/show.html.heex:74
 | 
					#: lib/cannery_web/live/pack_live/show.html.heex:72
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Are you sure you want to delete this ammo?"
 | 
					msgid "Are you sure you want to delete this ammo?"
 | 
				
			||||||
msgstr "Êtes-vous certain·e de supprimer cette munition ?"
 | 
					msgstr "Êtes-vous certain·e de supprimer cette munition ?"
 | 
				
			||||||
@@ -129,13 +129,13 @@ msgstr "Mot de passe mis à jour avec succès."
 | 
				
			|||||||
msgid "Please check your email to verify your account"
 | 
					msgid "Please check your email to verify your account"
 | 
				
			||||||
msgstr "Veuillez vérifier votre mél pour confirmer votre compte"
 | 
					msgstr "Veuillez vérifier votre mél pour confirmer votre compte"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/components/add_shot_group_component.html.heex:58
 | 
					#: lib/cannery_web/components/add_shot_record_component.html.heex:59
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/form_component.html.heex:85
 | 
					#: lib/cannery_web/live/container_live/form_component.html.heex:59
 | 
				
			||||||
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:160
 | 
					#: lib/cannery_web/live/invite_live/form_component.html.heex:37
 | 
				
			||||||
#: lib/cannery_web/live/container_live/form_component.html.heex:57
 | 
					#: lib/cannery_web/live/pack_live/form_component.html.heex:92
 | 
				
			||||||
#: lib/cannery_web/live/invite_live/form_component.html.heex:34
 | 
					#: lib/cannery_web/live/range_live/form_component.html.heex:47
 | 
				
			||||||
#: lib/cannery_web/live/range_live/form_component.html.heex:46
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/tag_live/form_component.html.heex:39
 | 
					#: lib/cannery_web/live/tag_live/form_component.html.heex:39
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/type_live/form_component.html.heex:351
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Saving..."
 | 
					msgid "Saving..."
 | 
				
			||||||
msgstr "Sauvegarde en cours…"
 | 
					msgstr "Sauvegarde en cours…"
 | 
				
			||||||
@@ -167,7 +167,7 @@ msgstr "%{tag_name} a été retiré de %{container_name}"
 | 
				
			|||||||
msgid "Adding..."
 | 
					msgid "Adding..."
 | 
				
			||||||
msgstr "Ajout en cours…"
 | 
					msgstr "Ajout en cours…"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/components/add_shot_group_component.ex:60
 | 
					#: lib/cannery_web/components/add_shot_record_component.ex:60
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Shots recorded successfully"
 | 
					msgid "Shots recorded successfully"
 | 
				
			||||||
msgstr "Tirs enregistré avec succès"
 | 
					msgstr "Tirs enregistré avec succès"
 | 
				
			||||||
@@ -177,13 +177,13 @@ msgstr "Tirs enregistré avec succès"
 | 
				
			|||||||
msgid "Are you sure you want to unstage this ammo?"
 | 
					msgid "Are you sure you want to unstage this ammo?"
 | 
				
			||||||
msgstr "Êtes-vous certain·e de vouloir désélectionner cette munition ?"
 | 
					msgstr "Êtes-vous certain·e de vouloir désélectionner cette munition ?"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/show.ex:159
 | 
					#: lib/cannery_web/live/pack_live/show.ex:158
 | 
				
			||||||
#: lib/cannery_web/live/range_live/index.html.heex:128
 | 
					#: lib/cannery_web/live/range_live/index.html.heex:152
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Are you sure you want to delete this shot record?"
 | 
					msgid "Are you sure you want to delete this shot record?"
 | 
				
			||||||
msgstr "Êtes-vous certain·e de vouloir supprimer cet enregistrement de tir ?"
 | 
					msgstr "Êtes-vous certain·e de vouloir supprimer cet enregistrement de tir ?"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/show.ex:81
 | 
					#: lib/cannery_web/live/pack_live/show.ex:80
 | 
				
			||||||
#: lib/cannery_web/live/range_live/index.ex:79
 | 
					#: lib/cannery_web/live/range_live/index.ex:79
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Shot records deleted succesfully"
 | 
					msgid "Shot records deleted succesfully"
 | 
				
			||||||
@@ -199,7 +199,7 @@ msgstr "Enregistrements de tir mis à jour avec succès"
 | 
				
			|||||||
msgid "%{email} confirmed successfully."
 | 
					msgid "%{email} confirmed successfully."
 | 
				
			||||||
msgstr "%{email} confirmé avec succès."
 | 
					msgstr "%{email} confirmé avec succès."
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/components/move_ammo_group_component.ex:54
 | 
					#: lib/cannery_web/components/move_pack_component.ex:52
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Ammo moved to %{name} successfully"
 | 
					msgid "Ammo moved to %{name} successfully"
 | 
				
			||||||
msgstr "Munition déplacée à %{name} avec succès"
 | 
					msgstr "Munition déplacée à %{name} avec succès"
 | 
				
			||||||
@@ -214,13 +214,13 @@ msgstr "Copié dans le presse-papier"
 | 
				
			|||||||
msgid "%{name} removed successfully"
 | 
					msgid "%{name} removed successfully"
 | 
				
			||||||
msgstr "%{name} retiré avec succès"
 | 
					msgstr "%{name} retiré avec succès"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/index.html.heex:18
 | 
					#: lib/cannery_web/live/pack_live/index.html.heex:10
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/index.html.heex:28
 | 
					#: lib/cannery_web/live/pack_live/index.html.heex:20
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "You'll need to"
 | 
					msgid "You'll need to"
 | 
				
			||||||
msgstr "Vous aurez besoin de"
 | 
					msgstr "Vous aurez besoin de"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/form_component.html.heex:78
 | 
					#: lib/cannery_web/live/pack_live/form_component.html.heex:85
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Creating..."
 | 
					msgid "Creating..."
 | 
				
			||||||
msgstr "Création en cours…"
 | 
					msgstr "Création en cours…"
 | 
				
			||||||
@@ -235,31 +235,31 @@ msgstr "Êtes-vous certain·e de vouloir changer votre langue ?"
 | 
				
			|||||||
msgid "Language updated successfully."
 | 
					msgid "Language updated successfully."
 | 
				
			||||||
msgstr "Langue mise à jour avec succès."
 | 
					msgstr "Langue mise à jour avec succès."
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/index.ex:89
 | 
					#: lib/cannery_web/live/pack_live/index.ex:94
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/show.ex:55
 | 
					#: lib/cannery_web/live/pack_live/show.ex:55
 | 
				
			||||||
#, elixir-autogen, elixir-format, fuzzy
 | 
					#, elixir-autogen, elixir-format, fuzzy
 | 
				
			||||||
msgid "Ammo deleted succesfully"
 | 
					msgid "Ammo deleted succesfully"
 | 
				
			||||||
msgstr "Groupe de munition supprimé avec succès"
 | 
					msgstr "Groupe de munition supprimé avec succès"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/range_live/index.ex:93
 | 
					#: lib/cannery_web/live/range_live/index.ex:92
 | 
				
			||||||
#, elixir-autogen, elixir-format, fuzzy
 | 
					#, elixir-autogen, elixir-format, fuzzy
 | 
				
			||||||
msgid "Ammo unstaged succesfully"
 | 
					msgid "Ammo unstaged succesfully"
 | 
				
			||||||
msgstr "Groupe de munition désélectionner avec succès"
 | 
					msgstr "Groupe de munition désélectionner avec succès"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/form_component.ex:126
 | 
					#: lib/cannery_web/live/pack_live/form_component.ex:125
 | 
				
			||||||
#, elixir-autogen, elixir-format, fuzzy
 | 
					#, elixir-autogen, elixir-format, fuzzy
 | 
				
			||||||
msgid "Ammo updated successfully"
 | 
					msgid "Ammo updated successfully"
 | 
				
			||||||
msgstr "Groupe de munition mis à jour avec succès"
 | 
					msgstr "Groupe de munition mis à jour avec succès"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/form_component.ex:185
 | 
					#: lib/cannery_web/live/pack_live/form_component.ex:184
 | 
				
			||||||
#, elixir-autogen, elixir-format, fuzzy
 | 
					#, elixir-autogen, elixir-format, fuzzy
 | 
				
			||||||
msgid "Ammo added successfully"
 | 
					msgid "Ammo added successfully"
 | 
				
			||||||
msgid_plural "Ammo added successfully"
 | 
					msgid_plural "Ammo added successfully"
 | 
				
			||||||
msgstr[0] "Groupe de munition mis à jour avec succès"
 | 
					msgstr[0] "Groupe de munition mis à jour avec succès"
 | 
				
			||||||
msgstr[1] "Groupe de munition mis à jour avec succès"
 | 
					msgstr[1] "Groupe de munition mis à jour avec succès"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_type_live/index.html.heex:97
 | 
					#: lib/cannery_web/live/type_live/index.html.heex:116
 | 
				
			||||||
#: lib/cannery_web/live/ammo_type_live/show.html.heex:29
 | 
					#: lib/cannery_web/live/type_live/show.html.heex:29
 | 
				
			||||||
#, elixir-autogen, elixir-format, fuzzy
 | 
					#, elixir-autogen, elixir-format, fuzzy
 | 
				
			||||||
msgid "Are you sure you want to delete %{name}? This will delete all %{name} type ammo as well!"
 | 
					msgid "Are you sure you want to delete %{name}? This will delete all %{name} type ammo as well!"
 | 
				
			||||||
msgstr "Êtes-vous certain·e de supprimer %{name} ?"
 | 
					msgstr "Êtes-vous certain·e de supprimer %{name} ?"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -21,14 +21,14 @@ msgstr ""
 | 
				
			|||||||
## Run "mix gettext.extract" to bring this file up to
 | 
					## Run "mix gettext.extract" to bring this file up to
 | 
				
			||||||
## date. Leave "msgstr"s empty as changing them here has no
 | 
					## date. Leave "msgstr"s empty as changing them here has no
 | 
				
			||||||
## effect: edit them in PO (.po) files instead.
 | 
					## effect: edit them in PO (.po) files instead.
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/index.ex:54
 | 
					#: lib/cannery_web/live/pack_live/index.ex:59
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/index.ex:62
 | 
					#: lib/cannery_web/live/pack_live/index.ex:67
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/index.html.heex:41
 | 
					#: lib/cannery_web/live/pack_live/index.html.heex:38
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Add Ammo"
 | 
					msgid "Add Ammo"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/index.html.heex:37
 | 
					#: lib/cannery_web/live/pack_live/index.html.heex:34
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Add your first box!"
 | 
					msgid "Add your first box!"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
@@ -38,7 +38,7 @@ msgstr ""
 | 
				
			|||||||
msgid "Add your first container!"
 | 
					msgid "Add your first container!"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_type_live/index.html.heex:13
 | 
					#: lib/cannery_web/live/type_live/index.html.heex:13
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Add your first type!"
 | 
					msgid "Add your first type!"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
@@ -93,11 +93,6 @@ msgstr ""
 | 
				
			|||||||
msgid "Make your first tag!"
 | 
					msgid "Make your first tag!"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_type_live/index.html.heex:17
 | 
					 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					 | 
				
			||||||
msgid "New Ammo type"
 | 
					 | 
				
			||||||
msgstr ""
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/container_live/index.html.heex:17
 | 
					#: lib/cannery_web/live/container_live/index.html.heex:17
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "New Container"
 | 
					msgid "New Container"
 | 
				
			||||||
@@ -131,13 +126,13 @@ msgstr ""
 | 
				
			|||||||
msgid "Reset password"
 | 
					msgid "Reset password"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/components/add_shot_group_component.html.heex:56
 | 
					#: lib/cannery_web/components/add_shot_record_component.html.heex:57
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/form_component.html.heex:84
 | 
					#: lib/cannery_web/live/container_live/form_component.html.heex:57
 | 
				
			||||||
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:159
 | 
					#: lib/cannery_web/live/invite_live/form_component.html.heex:35
 | 
				
			||||||
#: lib/cannery_web/live/container_live/form_component.html.heex:55
 | 
					#: lib/cannery_web/live/pack_live/form_component.html.heex:91
 | 
				
			||||||
#: lib/cannery_web/live/invite_live/form_component.html.heex:32
 | 
					#: lib/cannery_web/live/range_live/form_component.html.heex:45
 | 
				
			||||||
#: lib/cannery_web/live/range_live/form_component.html.heex:44
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/tag_live/form_component.html.heex:37
 | 
					#: lib/cannery_web/live/tag_live/form_component.html.heex:37
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/type_live/form_component.html.heex:350
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Save"
 | 
					msgid "Save"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
@@ -147,7 +142,7 @@ msgstr ""
 | 
				
			|||||||
msgid "Send instructions to reset password"
 | 
					msgid "Send instructions to reset password"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/container_live/show.html.heex:75
 | 
					#: lib/cannery_web/live/container_live/show.html.heex:68
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Why not add one?"
 | 
					msgid "Why not add one?"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
@@ -167,19 +162,19 @@ msgstr ""
 | 
				
			|||||||
msgid "Why not get some ready to shoot?"
 | 
					msgid "Why not get some ready to shoot?"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/index.html.heex:105
 | 
					#: lib/cannery_web/live/pack_live/index.html.heex:127
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/show.html.heex:103
 | 
					#: lib/cannery_web/live/pack_live/show.html.heex:96
 | 
				
			||||||
#: lib/cannery_web/live/range_live/index.html.heex:45
 | 
					#: lib/cannery_web/live/range_live/index.html.heex:45
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Record shots"
 | 
					msgid "Record shots"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/components/move_ammo_group_component.ex:90
 | 
					#: lib/cannery_web/components/move_pack_component.ex:88
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Add another container!"
 | 
					msgid "Add another container!"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/components/move_ammo_group_component.ex:126
 | 
					#: lib/cannery_web/components/move_pack_component.ex:124
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Select"
 | 
					msgid "Select"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
@@ -189,12 +184,12 @@ msgstr ""
 | 
				
			|||||||
msgid "Copy to clipboard"
 | 
					msgid "Copy to clipboard"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/index.html.heex:22
 | 
					#: lib/cannery_web/live/pack_live/index.html.heex:14
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "add a container first"
 | 
					msgid "add a container first"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/form_component.html.heex:77
 | 
					#: lib/cannery_web/live/pack_live/form_component.html.heex:84
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Create"
 | 
					msgid "Create"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
@@ -209,19 +204,14 @@ msgstr ""
 | 
				
			|||||||
msgid "Change language"
 | 
					msgid "Change language"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/show.html.heex:55
 | 
					#: lib/cannery_web/live/pack_live/show.html.heex:55
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "View in Catalog"
 | 
					msgid "View in Catalog"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/index.html.heex:32
 | 
					#: lib/cannery_web/components/move_pack_component.ex:78
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#: lib/cannery_web/live/pack_live/index.html.heex:144
 | 
				
			||||||
msgid "add an ammo type first"
 | 
					#: lib/cannery_web/live/pack_live/show.html.heex:89
 | 
				
			||||||
msgstr ""
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#: lib/cannery_web/components/move_ammo_group_component.ex:80
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/index.html.heex:122
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/show.html.heex:96
 | 
					 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Move ammo"
 | 
					msgid "Move ammo"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
@@ -231,13 +221,13 @@ msgstr ""
 | 
				
			|||||||
msgid "Set Unlimited"
 | 
					msgid "Set Unlimited"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/show.html.heex:89
 | 
					#: lib/cannery_web/live/pack_live/show.html.heex:85
 | 
				
			||||||
#: lib/cannery_web/live/range_live/index.html.heex:38
 | 
					#: lib/cannery_web/live/range_live/index.html.heex:38
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Stage for range"
 | 
					msgid "Stage for range"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/show.html.heex:88
 | 
					#: lib/cannery_web/live/pack_live/show.html.heex:84
 | 
				
			||||||
#: lib/cannery_web/live/range_live/index.html.heex:37
 | 
					#: lib/cannery_web/live/range_live/index.html.heex:37
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Unstage from range"
 | 
					msgid "Unstage from range"
 | 
				
			||||||
@@ -248,13 +238,8 @@ msgstr ""
 | 
				
			|||||||
msgid "Export Data as JSON"
 | 
					msgid "Export Data as JSON"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_type_live/index.html.heex:85
 | 
					#: lib/cannery_web/live/container_live/index.html.heex:87
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#: lib/cannery_web/live/container_live/index.html.heex:145
 | 
				
			||||||
msgid "Clone %{ammo_type_name}"
 | 
					 | 
				
			||||||
msgstr ""
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/container_live/index.html.heex:88
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/container_live/index.html.heex:144
 | 
					 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Clone %{container_name}"
 | 
					msgid "Clone %{container_name}"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
@@ -264,20 +249,14 @@ msgstr ""
 | 
				
			|||||||
msgid "Copy invite link for %{invite_name}"
 | 
					msgid "Copy invite link for %{invite_name}"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_type_live/index.html.heex:104
 | 
					#: lib/cannery_web/live/container_live/index.html.heex:104
 | 
				
			||||||
#: lib/cannery_web/live/ammo_type_live/show.html.heex:36
 | 
					#: lib/cannery_web/live/container_live/index.html.heex:162
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#: lib/cannery_web/live/container_live/show.html.heex:48
 | 
				
			||||||
msgid "Delete %{ammo_type_name}"
 | 
					 | 
				
			||||||
msgstr ""
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/container_live/index.html.heex:103
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/container_live/index.html.heex:159
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/container_live/show.html.heex:55
 | 
					 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Delete %{container_name}"
 | 
					msgid "Delete %{container_name}"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/tag_live/index.html.heex:66
 | 
					#: lib/cannery_web/live/tag_live/index.html.heex:65
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Delete %{tag_name}"
 | 
					msgid "Delete %{tag_name}"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
@@ -287,85 +266,102 @@ msgstr ""
 | 
				
			|||||||
msgid "Delete invite for %{invite_name}"
 | 
					msgid "Delete invite for %{invite_name}"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/show.ex:161
 | 
					#: lib/cannery_web/live/container_live/index.html.heex:77
 | 
				
			||||||
#: lib/cannery_web/live/range_live/index.html.heex:131
 | 
					#: lib/cannery_web/live/container_live/index.html.heex:135
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#: lib/cannery_web/live/container_live/show.html.heex:35
 | 
				
			||||||
msgid "Delete shot record of %{shot_group_count} shots"
 | 
					 | 
				
			||||||
msgstr ""
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/ammo_type_live/index.html.heex:75
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/ammo_type_live/show.html.heex:19
 | 
					 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					 | 
				
			||||||
msgid "Edit %{ammo_type_name}"
 | 
					 | 
				
			||||||
msgstr ""
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/container_live/index.html.heex:78
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/container_live/index.html.heex:134
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/container_live/show.html.heex:42
 | 
					 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Edit %{container_name}"
 | 
					msgid "Edit %{container_name}"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/tag_live/index.html.heex:53
 | 
					#: lib/cannery_web/live/tag_live/index.html.heex:52
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Edit %{tag_name}"
 | 
					msgid "Edit %{tag_name}"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/index.html.heex:144
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/show.html.heex:62
 | 
					 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					 | 
				
			||||||
msgid "Edit ammo group of %{ammo_group_count} bullets"
 | 
					 | 
				
			||||||
msgstr ""
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/invite_live/index.html.heex:46
 | 
					#: lib/cannery_web/live/invite_live/index.html.heex:46
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Edit invite for %{invite_name}"
 | 
					msgid "Edit invite for %{invite_name}"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/show.ex:146
 | 
					#: lib/cannery_web/live/pack_live/index.html.heex:120
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					 | 
				
			||||||
msgid "Edit shot group of %{shot_group_count} shots"
 | 
					 | 
				
			||||||
msgstr ""
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/range_live/index.html.heex:114
 | 
					 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					 | 
				
			||||||
msgid "Edit shot record of %{shot_group_count} shots"
 | 
					 | 
				
			||||||
msgstr ""
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/index.html.heex:98
 | 
					 | 
				
			||||||
#, elixir-autogen, elixir-format, fuzzy
 | 
					#, elixir-autogen, elixir-format, fuzzy
 | 
				
			||||||
msgid "Stage"
 | 
					msgid "Stage"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/container_live/index.html.heex:66
 | 
					#: lib/cannery_web/live/container_live/index.html.heex:65
 | 
				
			||||||
#: lib/cannery_web/live/container_live/index.html.heex:123
 | 
					#: lib/cannery_web/live/container_live/index.html.heex:124
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Tag %{container_name}"
 | 
					msgid "Tag %{container_name}"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/index.html.heex:97
 | 
					#: lib/cannery_web/live/pack_live/index.html.heex:119
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Unstage"
 | 
					msgid "Unstage"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_type_live/index.html.heex:65
 | 
					#: lib/cannery_web/live/pack_live/index.html.heex:174
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format, fuzzy
 | 
				
			||||||
msgid "View %{ammo_type_name}"
 | 
					msgid "Clone pack of %{pack_count} bullets"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/index.html.heex:156
 | 
					#: lib/cannery_web/live/pack_live/index.html.heex:189
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/pack_live/show.html.heex:74
 | 
				
			||||||
#, elixir-autogen, elixir-format, fuzzy
 | 
					#, elixir-autogen, elixir-format, fuzzy
 | 
				
			||||||
msgid "Clone ammo group of %{ammo_group_count} bullets"
 | 
					msgid "Delete pack of %{pack_count} bullets"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/index.html.heex:171
 | 
					#: lib/cannery_web/live/pack_live/index.html.heex:164
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/show.html.heex:76
 | 
					#: lib/cannery_web/live/pack_live/show.html.heex:62
 | 
				
			||||||
#, elixir-autogen, elixir-format, fuzzy
 | 
					#, elixir-autogen, elixir-format, fuzzy
 | 
				
			||||||
msgid "Delete ammo group of %{ammo_group_count} bullets"
 | 
					msgid "Edit pack of %{pack_count} bullets"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/index.html.heex:132
 | 
					#: lib/cannery_web/live/pack_live/index.html.heex:154
 | 
				
			||||||
#: lib/cannery_web/live/ammo_type_live/show.html.heex:189
 | 
					#: lib/cannery_web/live/type_live/show.html.heex:204
 | 
				
			||||||
#, elixir-autogen, elixir-format, fuzzy
 | 
					#, elixir-autogen, elixir-format, fuzzy
 | 
				
			||||||
msgid "View ammo group of %{ammo_group_count} bullets"
 | 
					msgid "View pack of %{pack_count} bullets"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/pack_live/show.ex:160
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/range_live/index.html.heex:155
 | 
				
			||||||
 | 
					#, elixir-autogen, elixir-format, fuzzy
 | 
				
			||||||
 | 
					msgid "Delete shot record of %{shot_record_count} shots"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/pack_live/show.ex:145
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/range_live/index.html.heex:138
 | 
				
			||||||
 | 
					#, elixir-autogen, elixir-format, fuzzy
 | 
				
			||||||
 | 
					msgid "Edit shot record of %{shot_record_count} shots"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/type_live/index.html.heex:105
 | 
				
			||||||
 | 
					#, elixir-autogen, elixir-format, fuzzy
 | 
				
			||||||
 | 
					msgid "Clone %{type_name}"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/type_live/index.html.heex:122
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/type_live/show.html.heex:35
 | 
				
			||||||
 | 
					#, elixir-autogen, elixir-format, fuzzy
 | 
				
			||||||
 | 
					msgid "Delete %{type_name}"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/type_live/index.html.heex:97
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/type_live/show.html.heex:19
 | 
				
			||||||
 | 
					#, elixir-autogen, elixir-format, fuzzy
 | 
				
			||||||
 | 
					msgid "Edit %{type_name}"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/type_live/index.html.heex:17
 | 
				
			||||||
 | 
					#, elixir-autogen, elixir-format, fuzzy
 | 
				
			||||||
 | 
					msgid "New Type"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/type_live/index.html.heex:89
 | 
				
			||||||
 | 
					#, elixir-autogen, elixir-format, fuzzy
 | 
				
			||||||
 | 
					msgid "View %{type_name}"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/pack_live/index.html.heex:24
 | 
				
			||||||
 | 
					#, elixir-autogen, elixir-format, fuzzy
 | 
				
			||||||
 | 
					msgid "add a type first"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 
 | 
				
			|||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -70,6 +70,7 @@ msgstr "Seoladh email nó pasfhocal neamhbhailí"
 | 
				
			|||||||
msgid "Not found"
 | 
					msgid "Not found"
 | 
				
			||||||
msgstr "Ní feidir é a fáil"
 | 
					msgstr "Ní feidir é a fáil"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/type_live/form_component.html.heex:18
 | 
				
			||||||
#: lib/cannery_web/templates/user_registration/new.html.heex:13
 | 
					#: lib/cannery_web/templates/user_registration/new.html.heex:13
 | 
				
			||||||
#: lib/cannery_web/templates/user_reset_password/edit.html.heex:13
 | 
					#: lib/cannery_web/templates/user_reset_password/edit.html.heex:13
 | 
				
			||||||
#: lib/cannery_web/templates/user_settings/edit.html.heex:22
 | 
					#: lib/cannery_web/templates/user_settings/edit.html.heex:22
 | 
				
			||||||
@@ -119,22 +120,22 @@ msgstr "Tá nasc an úsáideoir a deimhnigh neamhbailí nó as dáta."
 | 
				
			|||||||
msgid "You are not authorized to view this page."
 | 
					msgid "You are not authorized to view this page."
 | 
				
			||||||
msgstr "Níl cead agaibh féachaint ar an leathanach seo."
 | 
					msgstr "Níl cead agaibh féachaint ar an leathanach seo."
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery/accounts/user.ex:144
 | 
					#: lib/cannery/accounts/user.ex:145
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "did not change"
 | 
					msgid "did not change"
 | 
				
			||||||
msgstr "Níor athraigh sé"
 | 
					msgstr "Níor athraigh sé"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery/accounts/user.ex:165
 | 
					#: lib/cannery/accounts/user.ex:166
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "does not match password"
 | 
					msgid "does not match password"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery/accounts/user.ex:202
 | 
					#: lib/cannery/accounts/user.ex:203
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "is not valid"
 | 
					msgid "is not valid"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery/accounts/user.ex:99
 | 
					#: lib/cannery/accounts/user.ex:100
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "must have the @ sign and no spaces"
 | 
					msgid "must have the @ sign and no spaces"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
@@ -160,52 +161,52 @@ msgstr ""
 | 
				
			|||||||
msgid "Tag could not be removed"
 | 
					msgid "Tag could not be removed"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/form_component.ex:160
 | 
					#: lib/cannery_web/live/pack_live/form_component.ex:159
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Could not parse number of copies"
 | 
					msgid "Could not parse number of copies"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/form_component.ex:150
 | 
					#: lib/cannery_web/live/pack_live/form_component.ex:149
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Invalid number of copies, must be between 1 and %{max}. Was %{multiplier}"
 | 
					msgid "Invalid number of copies, must be between 1 and %{max}. Was %{multiplier}"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery/ammo.ex:1043
 | 
					#: lib/cannery/ammo.ex:1121
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Invalid multiplier"
 | 
					msgid "Invalid multiplier"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery/ammo/ammo_group.ex:92
 | 
					 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					 | 
				
			||||||
msgid "Please select an ammo type and container"
 | 
					 | 
				
			||||||
msgstr ""
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/range_live/index.html.heex:74
 | 
					#: lib/cannery_web/live/range_live/index.html.heex:74
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Your browser does not support the canvas element."
 | 
					msgid "Your browser does not support the canvas element."
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery/activity_log/shot_group.ex:72
 | 
					#: lib/cannery/activity_log/shot_record.ex:74
 | 
				
			||||||
#, elixir-autogen, elixir-format, fuzzy
 | 
					#, elixir-autogen, elixir-format, fuzzy
 | 
				
			||||||
msgid "Please select a valid user and ammo pack"
 | 
					msgid "Please select a valid user and ammo pack"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery/activity_log/shot_group.ex:86
 | 
					#: lib/cannery/activity_log/shot_record.ex:88
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Ammo left can be at most %{count} rounds"
 | 
					msgid "Ammo left can be at most %{count} rounds"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery/activity_log/shot_group.ex:82
 | 
					#: lib/cannery/activity_log/shot_record.ex:84
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Ammo left must be at least 0"
 | 
					msgid "Ammo left must be at least 0"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery/activity_log/shot_group.ex:119
 | 
					#: lib/cannery/activity_log/shot_record.ex:119
 | 
				
			||||||
#, elixir-autogen, elixir-format, fuzzy
 | 
					#, elixir-autogen, elixir-format, fuzzy
 | 
				
			||||||
msgid "Count can be at most %{count} shots"
 | 
					msgid "Count can be at most %{count} shots"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery/activity_log/shot_group.ex:78
 | 
					#: lib/cannery/activity_log/shot_record.ex:80
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "can't be blank"
 | 
					msgid "can't be blank"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: lib/cannery/ammo/pack.ex:100
 | 
				
			||||||
 | 
					#, elixir-autogen, elixir-format, fuzzy
 | 
				
			||||||
 | 
					msgid "Please select a type and container"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -21,17 +21,17 @@ msgstr ""
 | 
				
			|||||||
## Run "mix gettext.extract" to bring this file up to
 | 
					## Run "mix gettext.extract" to bring this file up to
 | 
				
			||||||
## date. Leave "msgstr"s empty as changing them here has no
 | 
					## date. Leave "msgstr"s empty as changing them here has no
 | 
				
			||||||
## effect: edit them in PO (.po) files instead.
 | 
					## effect: edit them in PO (.po) files instead.
 | 
				
			||||||
#: lib/cannery_web/live/ammo_type_live/form_component.ex:89
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/container_live/form_component.ex:89
 | 
					#: lib/cannery_web/live/container_live/form_component.ex:89
 | 
				
			||||||
#: lib/cannery_web/live/invite_live/form_component.ex:80
 | 
					#: lib/cannery_web/live/invite_live/form_component.ex:80
 | 
				
			||||||
#: lib/cannery_web/live/tag_live/form_component.ex:78
 | 
					#: lib/cannery_web/live/tag_live/form_component.ex:78
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/type_live/form_component.ex:88
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "%{name} created successfully"
 | 
					msgid "%{name} created successfully"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_type_live/index.ex:72
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/ammo_type_live/show.ex:49
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/tag_live/index.ex:65
 | 
					#: lib/cannery_web/live/tag_live/index.ex:65
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/type_live/index.ex:72
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/type_live/show.ex:27
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "%{name} deleted succesfully"
 | 
					msgid "%{name} deleted succesfully"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
@@ -42,10 +42,10 @@ msgstr ""
 | 
				
			|||||||
msgid "%{name} has been deleted"
 | 
					msgid "%{name} has been deleted"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_type_live/form_component.ex:70
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/container_live/form_component.ex:70
 | 
					#: lib/cannery_web/live/container_live/form_component.ex:70
 | 
				
			||||||
#: lib/cannery_web/live/invite_live/form_component.ex:62
 | 
					#: lib/cannery_web/live/invite_live/form_component.ex:62
 | 
				
			||||||
#: lib/cannery_web/live/tag_live/form_component.ex:60
 | 
					#: lib/cannery_web/live/tag_live/form_component.ex:60
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/type_live/form_component.ex:69
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "%{name} updated successfully"
 | 
					msgid "%{name} updated successfully"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
@@ -61,16 +61,16 @@ msgstr ""
 | 
				
			|||||||
msgid "Are you sure you want to delete %{email}? This action is permanent!"
 | 
					msgid "Are you sure you want to delete %{email}? This action is permanent!"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/container_live/index.html.heex:100
 | 
					#: lib/cannery_web/live/container_live/index.html.heex:99
 | 
				
			||||||
#: lib/cannery_web/live/container_live/index.html.heex:156
 | 
					#: lib/cannery_web/live/container_live/index.html.heex:157
 | 
				
			||||||
#: lib/cannery_web/live/container_live/show.html.heex:52
 | 
					#: lib/cannery_web/live/container_live/show.html.heex:45
 | 
				
			||||||
#: lib/cannery_web/live/tag_live/index.html.heex:64
 | 
					#: lib/cannery_web/live/tag_live/index.html.heex:63
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Are you sure you want to delete %{name}?"
 | 
					msgid "Are you sure you want to delete %{name}?"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/index.html.heex:169
 | 
					#: lib/cannery_web/live/pack_live/index.html.heex:187
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/show.html.heex:74
 | 
					#: lib/cannery_web/live/pack_live/show.html.heex:72
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Are you sure you want to delete this ammo?"
 | 
					msgid "Are you sure you want to delete this ammo?"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
@@ -120,13 +120,13 @@ msgstr ""
 | 
				
			|||||||
msgid "Please check your email to verify your account"
 | 
					msgid "Please check your email to verify your account"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/components/add_shot_group_component.html.heex:58
 | 
					#: lib/cannery_web/components/add_shot_record_component.html.heex:59
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/form_component.html.heex:85
 | 
					#: lib/cannery_web/live/container_live/form_component.html.heex:59
 | 
				
			||||||
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:160
 | 
					#: lib/cannery_web/live/invite_live/form_component.html.heex:37
 | 
				
			||||||
#: lib/cannery_web/live/container_live/form_component.html.heex:57
 | 
					#: lib/cannery_web/live/pack_live/form_component.html.heex:92
 | 
				
			||||||
#: lib/cannery_web/live/invite_live/form_component.html.heex:34
 | 
					#: lib/cannery_web/live/range_live/form_component.html.heex:47
 | 
				
			||||||
#: lib/cannery_web/live/range_live/form_component.html.heex:46
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/tag_live/form_component.html.heex:39
 | 
					#: lib/cannery_web/live/tag_live/form_component.html.heex:39
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/type_live/form_component.html.heex:351
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Saving..."
 | 
					msgid "Saving..."
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
@@ -156,7 +156,7 @@ msgstr ""
 | 
				
			|||||||
msgid "Adding..."
 | 
					msgid "Adding..."
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/components/add_shot_group_component.ex:60
 | 
					#: lib/cannery_web/components/add_shot_record_component.ex:60
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Shots recorded successfully"
 | 
					msgid "Shots recorded successfully"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
@@ -166,13 +166,13 @@ msgstr ""
 | 
				
			|||||||
msgid "Are you sure you want to unstage this ammo?"
 | 
					msgid "Are you sure you want to unstage this ammo?"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/show.ex:159
 | 
					#: lib/cannery_web/live/pack_live/show.ex:158
 | 
				
			||||||
#: lib/cannery_web/live/range_live/index.html.heex:128
 | 
					#: lib/cannery_web/live/range_live/index.html.heex:152
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Are you sure you want to delete this shot record?"
 | 
					msgid "Are you sure you want to delete this shot record?"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/show.ex:81
 | 
					#: lib/cannery_web/live/pack_live/show.ex:80
 | 
				
			||||||
#: lib/cannery_web/live/range_live/index.ex:79
 | 
					#: lib/cannery_web/live/range_live/index.ex:79
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Shot records deleted succesfully"
 | 
					msgid "Shot records deleted succesfully"
 | 
				
			||||||
@@ -188,7 +188,7 @@ msgstr ""
 | 
				
			|||||||
msgid "%{email} confirmed successfully."
 | 
					msgid "%{email} confirmed successfully."
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/components/move_ammo_group_component.ex:54
 | 
					#: lib/cannery_web/components/move_pack_component.ex:52
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Ammo moved to %{name} successfully"
 | 
					msgid "Ammo moved to %{name} successfully"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
@@ -203,13 +203,13 @@ msgstr ""
 | 
				
			|||||||
msgid "%{name} removed successfully"
 | 
					msgid "%{name} removed successfully"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/index.html.heex:18
 | 
					#: lib/cannery_web/live/pack_live/index.html.heex:10
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/index.html.heex:28
 | 
					#: lib/cannery_web/live/pack_live/index.html.heex:20
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "You'll need to"
 | 
					msgid "You'll need to"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/form_component.html.heex:78
 | 
					#: lib/cannery_web/live/pack_live/form_component.html.heex:85
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Creating..."
 | 
					msgid "Creating..."
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
@@ -224,23 +224,23 @@ msgstr ""
 | 
				
			|||||||
msgid "Language updated successfully."
 | 
					msgid "Language updated successfully."
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/index.ex:89
 | 
					#: lib/cannery_web/live/pack_live/index.ex:94
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/show.ex:55
 | 
					#: lib/cannery_web/live/pack_live/show.ex:55
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Ammo deleted succesfully"
 | 
					msgid "Ammo deleted succesfully"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/range_live/index.ex:93
 | 
					#: lib/cannery_web/live/range_live/index.ex:92
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Ammo unstaged succesfully"
 | 
					msgid "Ammo unstaged succesfully"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/form_component.ex:126
 | 
					#: lib/cannery_web/live/pack_live/form_component.ex:125
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Ammo updated successfully"
 | 
					msgid "Ammo updated successfully"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/form_component.ex:185
 | 
					#: lib/cannery_web/live/pack_live/form_component.ex:184
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Ammo added successfully"
 | 
					msgid "Ammo added successfully"
 | 
				
			||||||
msgid_plural "Ammo added successfully"
 | 
					msgid_plural "Ammo added successfully"
 | 
				
			||||||
@@ -250,8 +250,8 @@ msgstr[2] ""
 | 
				
			|||||||
msgstr[3] ""
 | 
					msgstr[3] ""
 | 
				
			||||||
msgstr[4] ""
 | 
					msgstr[4] ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_type_live/index.html.heex:97
 | 
					#: lib/cannery_web/live/type_live/index.html.heex:116
 | 
				
			||||||
#: lib/cannery_web/live/ammo_type_live/show.html.heex:29
 | 
					#: lib/cannery_web/live/type_live/show.html.heex:29
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Are you sure you want to delete %{name}? This will delete all %{name} type ammo as well!"
 | 
					msgid "Are you sure you want to delete %{name}? This will delete all %{name} type ammo as well!"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,17 +10,17 @@
 | 
				
			|||||||
msgid ""
 | 
					msgid ""
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_type_live/form_component.ex:89
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/container_live/form_component.ex:89
 | 
					#: lib/cannery_web/live/container_live/form_component.ex:89
 | 
				
			||||||
#: lib/cannery_web/live/invite_live/form_component.ex:80
 | 
					#: lib/cannery_web/live/invite_live/form_component.ex:80
 | 
				
			||||||
#: lib/cannery_web/live/tag_live/form_component.ex:78
 | 
					#: lib/cannery_web/live/tag_live/form_component.ex:78
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/type_live/form_component.ex:88
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "%{name} created successfully"
 | 
					msgid "%{name} created successfully"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_type_live/index.ex:72
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/ammo_type_live/show.ex:49
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/tag_live/index.ex:65
 | 
					#: lib/cannery_web/live/tag_live/index.ex:65
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/type_live/index.ex:72
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/type_live/show.ex:27
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "%{name} deleted succesfully"
 | 
					msgid "%{name} deleted succesfully"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
@@ -31,10 +31,10 @@ msgstr ""
 | 
				
			|||||||
msgid "%{name} has been deleted"
 | 
					msgid "%{name} has been deleted"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_type_live/form_component.ex:70
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/container_live/form_component.ex:70
 | 
					#: lib/cannery_web/live/container_live/form_component.ex:70
 | 
				
			||||||
#: lib/cannery_web/live/invite_live/form_component.ex:62
 | 
					#: lib/cannery_web/live/invite_live/form_component.ex:62
 | 
				
			||||||
#: lib/cannery_web/live/tag_live/form_component.ex:60
 | 
					#: lib/cannery_web/live/tag_live/form_component.ex:60
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/type_live/form_component.ex:69
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "%{name} updated successfully"
 | 
					msgid "%{name} updated successfully"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
@@ -50,16 +50,16 @@ msgstr ""
 | 
				
			|||||||
msgid "Are you sure you want to delete %{email}? This action is permanent!"
 | 
					msgid "Are you sure you want to delete %{email}? This action is permanent!"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/container_live/index.html.heex:100
 | 
					#: lib/cannery_web/live/container_live/index.html.heex:99
 | 
				
			||||||
#: lib/cannery_web/live/container_live/index.html.heex:156
 | 
					#: lib/cannery_web/live/container_live/index.html.heex:157
 | 
				
			||||||
#: lib/cannery_web/live/container_live/show.html.heex:52
 | 
					#: lib/cannery_web/live/container_live/show.html.heex:45
 | 
				
			||||||
#: lib/cannery_web/live/tag_live/index.html.heex:64
 | 
					#: lib/cannery_web/live/tag_live/index.html.heex:63
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Are you sure you want to delete %{name}?"
 | 
					msgid "Are you sure you want to delete %{name}?"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/index.html.heex:169
 | 
					#: lib/cannery_web/live/pack_live/index.html.heex:187
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/show.html.heex:74
 | 
					#: lib/cannery_web/live/pack_live/show.html.heex:72
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Are you sure you want to delete this ammo?"
 | 
					msgid "Are you sure you want to delete this ammo?"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
@@ -109,13 +109,13 @@ msgstr ""
 | 
				
			|||||||
msgid "Please check your email to verify your account"
 | 
					msgid "Please check your email to verify your account"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/components/add_shot_group_component.html.heex:58
 | 
					#: lib/cannery_web/components/add_shot_record_component.html.heex:59
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/form_component.html.heex:85
 | 
					#: lib/cannery_web/live/container_live/form_component.html.heex:59
 | 
				
			||||||
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:160
 | 
					#: lib/cannery_web/live/invite_live/form_component.html.heex:37
 | 
				
			||||||
#: lib/cannery_web/live/container_live/form_component.html.heex:57
 | 
					#: lib/cannery_web/live/pack_live/form_component.html.heex:92
 | 
				
			||||||
#: lib/cannery_web/live/invite_live/form_component.html.heex:34
 | 
					#: lib/cannery_web/live/range_live/form_component.html.heex:47
 | 
				
			||||||
#: lib/cannery_web/live/range_live/form_component.html.heex:46
 | 
					 | 
				
			||||||
#: lib/cannery_web/live/tag_live/form_component.html.heex:39
 | 
					#: lib/cannery_web/live/tag_live/form_component.html.heex:39
 | 
				
			||||||
 | 
					#: lib/cannery_web/live/type_live/form_component.html.heex:351
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Saving..."
 | 
					msgid "Saving..."
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
@@ -145,7 +145,7 @@ msgstr ""
 | 
				
			|||||||
msgid "Adding..."
 | 
					msgid "Adding..."
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/components/add_shot_group_component.ex:60
 | 
					#: lib/cannery_web/components/add_shot_record_component.ex:60
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Shots recorded successfully"
 | 
					msgid "Shots recorded successfully"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
@@ -155,13 +155,13 @@ msgstr ""
 | 
				
			|||||||
msgid "Are you sure you want to unstage this ammo?"
 | 
					msgid "Are you sure you want to unstage this ammo?"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/show.ex:159
 | 
					#: lib/cannery_web/live/pack_live/show.ex:158
 | 
				
			||||||
#: lib/cannery_web/live/range_live/index.html.heex:128
 | 
					#: lib/cannery_web/live/range_live/index.html.heex:152
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Are you sure you want to delete this shot record?"
 | 
					msgid "Are you sure you want to delete this shot record?"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/show.ex:81
 | 
					#: lib/cannery_web/live/pack_live/show.ex:80
 | 
				
			||||||
#: lib/cannery_web/live/range_live/index.ex:79
 | 
					#: lib/cannery_web/live/range_live/index.ex:79
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Shot records deleted succesfully"
 | 
					msgid "Shot records deleted succesfully"
 | 
				
			||||||
@@ -177,7 +177,7 @@ msgstr ""
 | 
				
			|||||||
msgid "%{email} confirmed successfully."
 | 
					msgid "%{email} confirmed successfully."
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/components/move_ammo_group_component.ex:54
 | 
					#: lib/cannery_web/components/move_pack_component.ex:52
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Ammo moved to %{name} successfully"
 | 
					msgid "Ammo moved to %{name} successfully"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
@@ -192,13 +192,13 @@ msgstr ""
 | 
				
			|||||||
msgid "%{name} removed successfully"
 | 
					msgid "%{name} removed successfully"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/index.html.heex:18
 | 
					#: lib/cannery_web/live/pack_live/index.html.heex:10
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/index.html.heex:28
 | 
					#: lib/cannery_web/live/pack_live/index.html.heex:20
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "You'll need to"
 | 
					msgid "You'll need to"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/form_component.html.heex:78
 | 
					#: lib/cannery_web/live/pack_live/form_component.html.heex:85
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Creating..."
 | 
					msgid "Creating..."
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
@@ -213,31 +213,31 @@ msgstr ""
 | 
				
			|||||||
msgid "Language updated successfully."
 | 
					msgid "Language updated successfully."
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/index.ex:89
 | 
					#: lib/cannery_web/live/pack_live/index.ex:94
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/show.ex:55
 | 
					#: lib/cannery_web/live/pack_live/show.ex:55
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Ammo deleted succesfully"
 | 
					msgid "Ammo deleted succesfully"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/range_live/index.ex:93
 | 
					#: lib/cannery_web/live/range_live/index.ex:92
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Ammo unstaged succesfully"
 | 
					msgid "Ammo unstaged succesfully"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/form_component.ex:126
 | 
					#: lib/cannery_web/live/pack_live/form_component.ex:125
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Ammo updated successfully"
 | 
					msgid "Ammo updated successfully"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_group_live/form_component.ex:185
 | 
					#: lib/cannery_web/live/pack_live/form_component.ex:184
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Ammo added successfully"
 | 
					msgid "Ammo added successfully"
 | 
				
			||||||
msgid_plural "Ammo added successfully"
 | 
					msgid_plural "Ammo added successfully"
 | 
				
			||||||
msgstr[0] ""
 | 
					msgstr[0] ""
 | 
				
			||||||
msgstr[1] ""
 | 
					msgstr[1] ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: lib/cannery_web/live/ammo_type_live/index.html.heex:97
 | 
					#: lib/cannery_web/live/type_live/index.html.heex:116
 | 
				
			||||||
#: lib/cannery_web/live/ammo_type_live/show.html.heex:29
 | 
					#: lib/cannery_web/live/type_live/show.html.heex:29
 | 
				
			||||||
#, elixir-autogen, elixir-format
 | 
					#, elixir-autogen, elixir-format
 | 
				
			||||||
msgid "Are you sure you want to delete %{name}? This will delete all %{name} type ammo as well!"
 | 
					msgid "Are you sure you want to delete %{name}? This will delete all %{name} type ammo as well!"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,7 +2,7 @@ defmodule Cannery.Repo.Migrations.AddLocaleSetting do
 | 
				
			|||||||
  use Ecto.Migration
 | 
					  use Ecto.Migration
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def change do
 | 
					  def change do
 | 
				
			||||||
    alter table("users") do
 | 
					    alter table(:users) do
 | 
				
			||||||
      add :locale, :string
 | 
					      add :locale, :string
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -0,0 +1,98 @@
 | 
				
			|||||||
 | 
					defmodule Cannery.Repo.Migrations.AddAmmoTypeTypesAndShotgunFields do
 | 
				
			||||||
 | 
					  use Ecto.Migration
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def change do
 | 
				
			||||||
 | 
					    alter table(:ammo_types) do
 | 
				
			||||||
 | 
					      # rifle/shotgun/pistol
 | 
				
			||||||
 | 
					      add :type, :string, default: "rifle"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      add :wadding, :string
 | 
				
			||||||
 | 
					      # target/bird/buck/slug/special
 | 
				
			||||||
 | 
					      add :shot_type, :string
 | 
				
			||||||
 | 
					      add :shot_material, :string
 | 
				
			||||||
 | 
					      add :shot_size, :string
 | 
				
			||||||
 | 
					      add :unfired_length, :string
 | 
				
			||||||
 | 
					      add :brass_height, :string
 | 
				
			||||||
 | 
					      add :chamber_size, :string
 | 
				
			||||||
 | 
					      add :load_grains, :integer
 | 
				
			||||||
 | 
					      add :shot_charge_weight, :string
 | 
				
			||||||
 | 
					      add :dram_equivalent, :string
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    create index(:ammo_types, [:type])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    execute(&add_fields_to_search/0, &remove_fields_from_search/0)
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  defp add_fields_to_search() do
 | 
				
			||||||
 | 
					    execute """
 | 
				
			||||||
 | 
					    ALTER TABLE ammo_types
 | 
				
			||||||
 | 
					      ALTER COLUMN search tsvector
 | 
				
			||||||
 | 
					      GENERATED ALWAYS AS (
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', coalesce("name", '')), 'A') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', coalesce("desc", '')), 'B') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', coalesce("type", '')), 'B') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', coalesce("manufacturer", '')), 'C') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', coalesce("upc", '')), 'C') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', coalesce("bullet_type", '')), 'D') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', coalesce("bullet_core", '')), 'D') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', coalesce("cartridge", '')), 'D') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', coalesce("caliber", '')), 'D') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', coalesce("case_material", '')), 'D') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', coalesce("jacket_type", '')), 'D') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', immutable_to_string("muzzle_velocity", '')), 'D') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', coalesce("powder_type", '')), 'D') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', immutable_to_string("powder_grains_per_charge", '')), 'D') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', immutable_to_string("grains", '')), 'D') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', coalesce("pressure", '')), 'D') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', coalesce("primer_type", '')), 'D') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', coalesce("firing_type", '')), 'D') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', coalesce("wadding", '')), 'D') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', coalesce("shot_type", '')), 'D') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', coalesce("shot_material", '')), 'D') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', coalesce("shot_size", '')), 'D') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', coalesce("unfired_length", '')), 'D') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', coalesce("brass_height", '')), 'D') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', coalesce("chamber_size", '')), 'D') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', coalesce("load_grains", '')), 'D') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', coalesce("shot_charge_weight,", '')), 'D') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', coalesce("dram_equivalent", '')), 'D') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', boolean_to_string("tracer", 'tracer', '')), 'D') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', boolean_to_string("incendiary", 'incendiary', '')), 'D') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', boolean_to_string("blank", 'blank', '')), 'D') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', boolean_to_string("corrosive", 'corrosive', '')), 'D')
 | 
				
			||||||
 | 
					        setwe
 | 
				
			||||||
 | 
					      ) STORED
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  defp remove_fields_from_search() do
 | 
				
			||||||
 | 
					    execute """
 | 
				
			||||||
 | 
					    ALTER TABLE ammo_types
 | 
				
			||||||
 | 
					      ALTER COLUMN search tsvector
 | 
				
			||||||
 | 
					      GENERATED ALWAYS AS (
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', coalesce("name", '')), 'A') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', coalesce("desc", '')), 'B') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', coalesce("bullet_type", '')), 'C') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', coalesce("bullet_core", '')), 'C') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', coalesce("cartridge", '')), 'C') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', coalesce("caliber", '')), 'C') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', coalesce("case_material", '')), 'C') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', coalesce("jacket_type", '')), 'C') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', immutable_to_string("muzzle_velocity", '')), 'C') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', coalesce("powder_type", '')), 'C') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', immutable_to_string("powder_grains_per_charge", '')), 'C') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', immutable_to_string("grains", '')), 'C') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', coalesce("pressure", '')), 'C') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', coalesce("primer_type", '')), 'C') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', coalesce("firing_type", '')), 'C') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', boolean_to_string("tracer", 'tracer', '')), 'C') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', boolean_to_string("incendiary", 'incendiary', '')), 'C') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', boolean_to_string("blank", 'blank', '')), 'C') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', boolean_to_string("corrosive", 'corrosive', '')), 'C') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', coalesce("manufacturer", '')), 'D') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', coalesce("upc", '')), 'D')
 | 
				
			||||||
 | 
					      ) STORED
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
							
								
								
									
										105
									
								
								priv/repo/migrations/20230329025816_rename_type_to_class.exs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										105
									
								
								priv/repo/migrations/20230329025816_rename_type_to_class.exs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,105 @@
 | 
				
			|||||||
 | 
					defmodule Cannery.Repo.Migrations.RenameTypeToClass do
 | 
				
			||||||
 | 
					  use Ecto.Migration
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def up do
 | 
				
			||||||
 | 
					    rename table(:ammo_types), :type, to: :class
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    alter table(:ammo_types) do
 | 
				
			||||||
 | 
					      remove_if_exists :search, :tsvector
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    flush()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    execute """
 | 
				
			||||||
 | 
					    ALTER TABLE ammo_types
 | 
				
			||||||
 | 
					      ADD COLUMN search tsvector
 | 
				
			||||||
 | 
					        GENERATED ALWAYS AS (
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', coalesce("name", '')), 'A') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', coalesce("desc", '')), 'B') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', coalesce("class", '')), 'B') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', coalesce("manufacturer", '')), 'C') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', coalesce("upc", '')), 'C') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', coalesce("bullet_type", '')), 'D') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', coalesce("bullet_core", '')), 'D') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', coalesce("cartridge", '')), 'D') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', coalesce("caliber", '')), 'D') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', coalesce("case_material", '')), 'D') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', coalesce("jacket_type", '')), 'D') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', immutable_to_string("muzzle_velocity", '')), 'D') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', coalesce("powder_type", '')), 'D') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', immutable_to_string("powder_grains_per_charge", '')), 'D') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', immutable_to_string("grains", '')), 'D') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', coalesce("pressure", '')), 'D') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', coalesce("primer_type", '')), 'D') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', coalesce("firing_type", '')), 'D') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', coalesce("wadding", '')), 'D') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', coalesce("shot_type", '')), 'D') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', coalesce("shot_material", '')), 'D') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', coalesce("shot_size", '')), 'D') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', coalesce("unfired_length", '')), 'D') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', coalesce("brass_height", '')), 'D') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', coalesce("chamber_size", '')), 'D') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', immutable_to_string("load_grains", '')), 'D') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', coalesce("shot_charge_weight", '')), 'D') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', coalesce("dram_equivalent", '')), 'D') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', boolean_to_string("tracer", 'tracer', '')), 'D') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', boolean_to_string("incendiary", 'incendiary', '')), 'D') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', boolean_to_string("blank", 'blank', '')), 'D') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', boolean_to_string("corrosive", 'corrosive', '')), 'D') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', coalesce("manufacturer", '')), 'D') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', coalesce("upc", '')), 'D')
 | 
				
			||||||
 | 
					      ) STORED
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def down do
 | 
				
			||||||
 | 
					    rename table(:ammo_types), :class, to: :type
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    alter table(:ammo_types) do
 | 
				
			||||||
 | 
					      remove_if_exists :search, :tsvector
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    flush()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    execute """
 | 
				
			||||||
 | 
					    ALTER TABLE ammo_types
 | 
				
			||||||
 | 
					      ADD COLUMN search TSVECTOR
 | 
				
			||||||
 | 
					        GENERATED ALWAYS AS (
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', coalesce("name", '')), 'A') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', coalesce("desc", '')), 'B') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', coalesce("type", '')), 'B') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', coalesce("manufacturer", '')), 'C') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', coalesce("upc", '')), 'C') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', coalesce("bullet_type", '')), 'D') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', coalesce("bullet_core", '')), 'D') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', coalesce("cartridge", '')), 'D') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', coalesce("caliber", '')), 'D') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', coalesce("case_material", '')), 'D') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', coalesce("jacket_type", '')), 'D') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', immutable_to_string("muzzle_velocity", '')), 'D') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', coalesce("powder_type", '')), 'D') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', immutable_to_string("powder_grains_per_charge", '')), 'D') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', immutable_to_string("grains", '')), 'D') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', coalesce("pressure", '')), 'D') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', coalesce("primer_type", '')), 'D') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', coalesce("firing_type", '')), 'D') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', coalesce("wadding", '')), 'D') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', coalesce("shot_type", '')), 'D') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', coalesce("shot_material", '')), 'D') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', coalesce("shot_size", '')), 'D') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', coalesce("unfired_length", '')), 'D') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', coalesce("brass_height", '')), 'D') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', coalesce("chamber_size", '')), 'D') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', immutable_to_string("load_grains", '')), 'D') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', coalesce("shot_charge_weight", '')), 'D') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', coalesce("dram_equivalent", '')), 'D') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', boolean_to_string("tracer", 'tracer', '')), 'D') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', boolean_to_string("incendiary", 'incendiary', '')), 'D') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', boolean_to_string("blank", 'blank', '')), 'D') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', boolean_to_string("corrosive", 'corrosive', '')), 'D') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', coalesce("manufacturer", '')), 'D') ||
 | 
				
			||||||
 | 
					        setweight(to_tsvector('english', coalesce("upc", '')), 'D')
 | 
				
			||||||
 | 
					      ) STORED
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
@@ -0,0 +1,34 @@
 | 
				
			|||||||
 | 
					defmodule Cannery.Repo.Migrations.RenameAmmoGroupsToPacks do
 | 
				
			||||||
 | 
					  use Ecto.Migration
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def up do
 | 
				
			||||||
 | 
					    drop index(:ammo_groups, [:user_id], where: "count = 0", name: :empty_ammo_groups_index)
 | 
				
			||||||
 | 
					    drop index(:shot_groups, [:user_id, :ammo_group_id])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    flush()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    rename table(:ammo_groups), to: table(:packs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    flush()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    create index(:packs, [:user_id], where: "count = 0", name: :empty_packs_index)
 | 
				
			||||||
 | 
					    rename table(:shot_groups), :ammo_group_id, to: :pack_id
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def down do
 | 
				
			||||||
 | 
					    drop index(:packs, [:user_id], where: "count = 0", name: :empty_packs_index)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    flush()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    rename table(:packs), to: table(:ammo_groups)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    flush()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    create index(:ammo_groups, [:user_id], where: "count = 0", name: :empty_ammo_groups_index)
 | 
				
			||||||
 | 
					    rename table(:shot_groups), :pack_id, to: :ammo_group_id
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    flush()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    create index(:shot_groups, [:user_id, :ammo_group_id])
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
@@ -0,0 +1,7 @@
 | 
				
			|||||||
 | 
					defmodule Cannery.Repo.Migrations.RenameShotGroupsToShotRecords do
 | 
				
			||||||
 | 
					  use Ecto.Migration
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def change do
 | 
				
			||||||
 | 
					    rename table(:shot_groups), to: table(:shot_records)
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
@@ -0,0 +1,8 @@
 | 
				
			|||||||
 | 
					defmodule Cannery.Repo.Migrations.RenameAmmoTypeToType do
 | 
				
			||||||
 | 
					  use Ecto.Migration
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def change do
 | 
				
			||||||
 | 
					    rename table(:ammo_types), to: table(:types)
 | 
				
			||||||
 | 
					    rename table(:packs), :ammo_type_id, to: :type_id
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
@@ -0,0 +1,9 @@
 | 
				
			|||||||
 | 
					defmodule Cannery.Repo.Migrations.AddLotNumberToPacks do
 | 
				
			||||||
 | 
					  use Ecto.Migration
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def change do
 | 
				
			||||||
 | 
					    alter table(:packs) do
 | 
				
			||||||
 | 
					      add :lot_number, :string
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
@@ -11,11 +11,11 @@ defmodule Cannery.InvitesTest do
 | 
				
			|||||||
  @moduletag :invites_test
 | 
					  @moduletag :invites_test
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @valid_attrs %{
 | 
					  @valid_attrs %{
 | 
				
			||||||
    "name" => "some name"
 | 
					    name: "some name"
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  @invalid_attrs %{
 | 
					  @invalid_attrs %{
 | 
				
			||||||
    "name" => nil,
 | 
					    name: nil,
 | 
				
			||||||
    "token" => nil
 | 
					    token: nil
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  describe "invites" do
 | 
					  describe "invites" do
 | 
				
			||||||
@@ -57,7 +57,7 @@ defmodule Cannery.InvitesTest do
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
      assert {:ok, _user} =
 | 
					      assert {:ok, _user} =
 | 
				
			||||||
               Accounts.register_user(
 | 
					               Accounts.register_user(
 | 
				
			||||||
                 %{"email" => unique_user_email(), "password" => valid_user_password()},
 | 
					                 %{email: unique_user_email(), password: valid_user_password()},
 | 
				
			||||||
                 token
 | 
					                 token
 | 
				
			||||||
               )
 | 
					               )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -65,7 +65,7 @@ defmodule Cannery.InvitesTest do
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
      assert {:ok, _user} =
 | 
					      assert {:ok, _user} =
 | 
				
			||||||
               Accounts.register_user(
 | 
					               Accounts.register_user(
 | 
				
			||||||
                 %{"email" => unique_user_email(), "password" => valid_user_password()},
 | 
					                 %{email: unique_user_email(), password: valid_user_password()},
 | 
				
			||||||
                 token
 | 
					                 token
 | 
				
			||||||
               )
 | 
					               )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -81,13 +81,13 @@ defmodule Cannery.InvitesTest do
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
      assert {:ok, _user} =
 | 
					      assert {:ok, _user} =
 | 
				
			||||||
               Accounts.register_user(
 | 
					               Accounts.register_user(
 | 
				
			||||||
                 %{"email" => unique_user_email(), "password" => valid_user_password()},
 | 
					                 %{email: unique_user_email(), password: valid_user_password()},
 | 
				
			||||||
                 token
 | 
					                 token
 | 
				
			||||||
               )
 | 
					               )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      assert {:ok, _user} =
 | 
					      assert {:ok, _user} =
 | 
				
			||||||
               Accounts.register_user(
 | 
					               Accounts.register_user(
 | 
				
			||||||
                 %{"email" => unique_user_email(), "password" => valid_user_password()},
 | 
					                 %{email: unique_user_email(), password: valid_user_password()},
 | 
				
			||||||
                 another_token
 | 
					                 another_token
 | 
				
			||||||
               )
 | 
					               )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -97,7 +97,7 @@ defmodule Cannery.InvitesTest do
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
      assert {:ok, _user} =
 | 
					      assert {:ok, _user} =
 | 
				
			||||||
               Accounts.register_user(
 | 
					               Accounts.register_user(
 | 
				
			||||||
                 %{"email" => unique_user_email(), "password" => valid_user_password()},
 | 
					                 %{email: unique_user_email(), password: valid_user_password()},
 | 
				
			||||||
                 token
 | 
					                 token
 | 
				
			||||||
               )
 | 
					               )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -138,21 +138,14 @@ defmodule Cannery.InvitesTest do
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    test "create_invite/1 with valid data creates an unlimited invite",
 | 
					    test "create_invite/1 with valid data creates an unlimited invite",
 | 
				
			||||||
         %{current_user: current_user} do
 | 
					         %{current_user: current_user} do
 | 
				
			||||||
      assert {:ok, %Invite{} = invite} =
 | 
					      assert {:ok, %Invite{} = invite} = Invites.create_invite(current_user, %{name: "some name"})
 | 
				
			||||||
               Invites.create_invite(current_user, %{
 | 
					 | 
				
			||||||
                 "name" => "some name"
 | 
					 | 
				
			||||||
               })
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      assert invite.name == "some name"
 | 
					      assert invite.name == "some name"
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    test "create_invite/1 with valid data creates a limited invite",
 | 
					    test "create_invite/1 with valid data creates a limited invite",
 | 
				
			||||||
         %{current_user: current_user} do
 | 
					         %{current_user: current_user} do
 | 
				
			||||||
      assert {:ok, %Invite{} = invite} =
 | 
					      assert {:ok, %Invite{} = invite} =
 | 
				
			||||||
               Invites.create_invite(current_user, %{
 | 
					               Invites.create_invite(current_user, %{name: "some name", uses_left: 10})
 | 
				
			||||||
                 "name" => "some name",
 | 
					 | 
				
			||||||
                 "uses_left" => 10
 | 
					 | 
				
			||||||
               })
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
      assert invite.name == "some name"
 | 
					      assert invite.name == "some name"
 | 
				
			||||||
      assert invite.uses_left == 10
 | 
					      assert invite.uses_left == 10
 | 
				
			||||||
@@ -168,7 +161,7 @@ defmodule Cannery.InvitesTest do
 | 
				
			|||||||
      assert {:ok, %Invite{} = new_invite} =
 | 
					      assert {:ok, %Invite{} = new_invite} =
 | 
				
			||||||
               Invites.update_invite(
 | 
					               Invites.update_invite(
 | 
				
			||||||
                 invite,
 | 
					                 invite,
 | 
				
			||||||
                 %{"name" => "some updated name", "uses_left" => 5},
 | 
					                 %{name: "some updated name", uses_left: 5},
 | 
				
			||||||
                 current_user
 | 
					                 current_user
 | 
				
			||||||
               )
 | 
					               )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -178,12 +171,12 @@ defmodule Cannery.InvitesTest do
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    test "update_invite/2 can set an invite to be unlimited",
 | 
					    test "update_invite/2 can set an invite to be unlimited",
 | 
				
			||||||
         %{invite: invite, current_user: current_user} do
 | 
					         %{invite: invite, current_user: current_user} do
 | 
				
			||||||
      {:ok, invite} = Invites.update_invite(invite, %{"uses_left" => 5}, current_user)
 | 
					      {:ok, invite} = Invites.update_invite(invite, %{uses_left: 5}, current_user)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      assert {:ok, %Invite{} = new_invite} =
 | 
					      assert {:ok, %Invite{} = new_invite} =
 | 
				
			||||||
               Invites.update_invite(
 | 
					               Invites.update_invite(
 | 
				
			||||||
                 invite,
 | 
					                 invite,
 | 
				
			||||||
                 %{"name" => "some updated name", "uses_left" => nil},
 | 
					                 %{name: "some updated name", uses_left: nil},
 | 
				
			||||||
                 current_user
 | 
					                 current_user
 | 
				
			||||||
               )
 | 
					               )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -63,8 +63,7 @@ defmodule Cannery.AccountsTest do
 | 
				
			|||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    test "validates email and password when given" do
 | 
					    test "validates email and password when given" do
 | 
				
			||||||
      {:error, changeset} =
 | 
					      {:error, changeset} = Accounts.register_user(%{email: "not valid", password: "not valid"})
 | 
				
			||||||
        Accounts.register_user(%{"email" => "not valid", "password" => "not valid"})
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
      assert %{
 | 
					      assert %{
 | 
				
			||||||
               email: ["must have the @ sign and no spaces"],
 | 
					               email: ["must have the @ sign and no spaces"],
 | 
				
			||||||
@@ -74,26 +73,25 @@ defmodule Cannery.AccountsTest do
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    test "validates maximum values for email and password for security" do
 | 
					    test "validates maximum values for email and password for security" do
 | 
				
			||||||
      too_long = String.duplicate("db", 100)
 | 
					      too_long = String.duplicate("db", 100)
 | 
				
			||||||
      {:error, changeset} = Accounts.register_user(%{"email" => too_long, "password" => too_long})
 | 
					      {:error, changeset} = Accounts.register_user(%{email: too_long, password: too_long})
 | 
				
			||||||
      assert "should be at most 160 character(s)" in errors_on(changeset).email
 | 
					      assert "should be at most 160 character(s)" in errors_on(changeset).email
 | 
				
			||||||
      assert "should be at most 80 character(s)" in errors_on(changeset).password
 | 
					      assert "should be at most 80 character(s)" in errors_on(changeset).password
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    test "validates email uniqueness" do
 | 
					    test "validates email uniqueness" do
 | 
				
			||||||
      %{email: email} = user_fixture()
 | 
					      %{email: email} = user_fixture()
 | 
				
			||||||
      {:error, changeset} = Accounts.register_user(%{"email" => email})
 | 
					      {:error, changeset} = Accounts.register_user(%{email: email})
 | 
				
			||||||
      assert "has already been taken" in errors_on(changeset).email
 | 
					      assert "has already been taken" in errors_on(changeset).email
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      # Now try with the upper cased email too, to check that email case is ignored.
 | 
					      # Now try with the upper cased email too, to check that email case is ignored.
 | 
				
			||||||
      {:error, changeset} = Accounts.register_user(%{"email" => String.upcase(email)})
 | 
					      {:error, changeset} = Accounts.register_user(%{email: String.upcase(email)})
 | 
				
			||||||
      assert "has already been taken" in errors_on(changeset).email
 | 
					      assert "has already been taken" in errors_on(changeset).email
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    test "registers users with a hashed password" do
 | 
					    test "registers users with a hashed password" do
 | 
				
			||||||
      email = unique_user_email()
 | 
					      email = unique_user_email()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      {:ok, user} =
 | 
					      {:ok, user} = Accounts.register_user(%{email: email, password: valid_user_password()})
 | 
				
			||||||
        Accounts.register_user(%{"email" => email, "password" => valid_user_password()})
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
      assert user.email == email
 | 
					      assert user.email == email
 | 
				
			||||||
      assert is_binary(user.hashed_password)
 | 
					      assert is_binary(user.hashed_password)
 | 
				
			||||||
@@ -103,11 +101,11 @@ defmodule Cannery.AccountsTest do
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    test "records used invite during registration" do
 | 
					    test "records used invite during registration" do
 | 
				
			||||||
      {:ok, %{id: invite_id, token: token}} =
 | 
					      {:ok, %{id: invite_id, token: token}} =
 | 
				
			||||||
        admin_fixture() |> Invites.create_invite(%{"name" => "my invite"})
 | 
					        admin_fixture() |> Invites.create_invite(%{name: "my invite"})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      assert {:ok, %{invite_id: ^invite_id}} =
 | 
					      assert {:ok, %{invite_id: ^invite_id}} =
 | 
				
			||||||
               Accounts.register_user(
 | 
					               Accounts.register_user(
 | 
				
			||||||
                 %{"email" => unique_user_email(), "password" => valid_user_password()},
 | 
					                 %{email: unique_user_email(), password: valid_user_password()},
 | 
				
			||||||
                 token
 | 
					                 token
 | 
				
			||||||
               )
 | 
					               )
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
@@ -123,7 +121,7 @@ defmodule Cannery.AccountsTest do
 | 
				
			|||||||
      email = unique_user_email()
 | 
					      email = unique_user_email()
 | 
				
			||||||
      password = valid_user_password()
 | 
					      password = valid_user_password()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      changeset = Accounts.change_user_registration(%{"email" => email, "password" => password})
 | 
					      changeset = Accounts.change_user_registration(%{email: email, password: password})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      assert changeset.valid?
 | 
					      assert changeset.valid?
 | 
				
			||||||
      assert get_change(changeset, :email) == email
 | 
					      assert get_change(changeset, :email) == email
 | 
				
			||||||
@@ -151,7 +149,7 @@ defmodule Cannery.AccountsTest do
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    test "validates email", %{user: user} do
 | 
					    test "validates email", %{user: user} do
 | 
				
			||||||
      {:error, changeset} =
 | 
					      {:error, changeset} =
 | 
				
			||||||
        Accounts.apply_user_email(user, valid_user_password(), %{"email" => "not valid"})
 | 
					        Accounts.apply_user_email(user, valid_user_password(), %{email: "not valid"})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      assert %{email: ["must have the @ sign and no spaces"]} = errors_on(changeset)
 | 
					      assert %{email: ["must have the @ sign and no spaces"]} = errors_on(changeset)
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
@@ -160,7 +158,7 @@ defmodule Cannery.AccountsTest do
 | 
				
			|||||||
      too_long = String.duplicate("db", 100)
 | 
					      too_long = String.duplicate("db", 100)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      {:error, changeset} =
 | 
					      {:error, changeset} =
 | 
				
			||||||
        Accounts.apply_user_email(user, valid_user_password(), %{"email" => too_long})
 | 
					        Accounts.apply_user_email(user, valid_user_password(), %{email: too_long})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      assert "should be at most 160 character(s)" in errors_on(changeset).email
 | 
					      assert "should be at most 160 character(s)" in errors_on(changeset).email
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
@@ -169,21 +167,21 @@ defmodule Cannery.AccountsTest do
 | 
				
			|||||||
      %{email: email} = user_fixture()
 | 
					      %{email: email} = user_fixture()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      {:error, changeset} =
 | 
					      {:error, changeset} =
 | 
				
			||||||
        Accounts.apply_user_email(user, valid_user_password(), %{"email" => email})
 | 
					        Accounts.apply_user_email(user, valid_user_password(), %{email: email})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      assert "has already been taken" in errors_on(changeset).email
 | 
					      assert "has already been taken" in errors_on(changeset).email
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    test "validates current password", %{user: user} do
 | 
					    test "validates current password", %{user: user} do
 | 
				
			||||||
      {:error, changeset} =
 | 
					      {:error, changeset} =
 | 
				
			||||||
        Accounts.apply_user_email(user, "invalid", %{"email" => unique_user_email()})
 | 
					        Accounts.apply_user_email(user, "invalid", %{email: unique_user_email()})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      assert %{current_password: ["is not valid"]} = errors_on(changeset)
 | 
					      assert %{current_password: ["is not valid"]} = errors_on(changeset)
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    test "applies the email without persisting it", %{user: user} do
 | 
					    test "applies the email without persisting it", %{user: user} do
 | 
				
			||||||
      email = unique_user_email()
 | 
					      email = unique_user_email()
 | 
				
			||||||
      {:ok, user} = Accounts.apply_user_email(user, valid_user_password(), %{"email" => email})
 | 
					      {:ok, user} = Accounts.apply_user_email(user, valid_user_password(), %{email: email})
 | 
				
			||||||
      assert user.email == email
 | 
					      assert user.email == email
 | 
				
			||||||
      assert Accounts.get_user!(user.id).email != email
 | 
					      assert Accounts.get_user!(user.id).email != email
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
@@ -258,11 +256,7 @@ defmodule Cannery.AccountsTest do
 | 
				
			|||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    test "allows fields to be set" do
 | 
					    test "allows fields to be set" do
 | 
				
			||||||
      changeset =
 | 
					      changeset = Accounts.change_user_password(%User{}, %{password: "new valid password"})
 | 
				
			||||||
        Accounts.change_user_password(%User{}, %{
 | 
					 | 
				
			||||||
          "password" => "new valid password"
 | 
					 | 
				
			||||||
        })
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      assert changeset.valid?
 | 
					      assert changeset.valid?
 | 
				
			||||||
      assert get_change(changeset, :password) == "new valid password"
 | 
					      assert get_change(changeset, :password) == "new valid password"
 | 
				
			||||||
      assert is_nil(get_change(changeset, :hashed_password))
 | 
					      assert is_nil(get_change(changeset, :hashed_password))
 | 
				
			||||||
@@ -277,8 +271,8 @@ defmodule Cannery.AccountsTest do
 | 
				
			|||||||
    test "validates password", %{user: user} do
 | 
					    test "validates password", %{user: user} do
 | 
				
			||||||
      {:error, changeset} =
 | 
					      {:error, changeset} =
 | 
				
			||||||
        Accounts.update_user_password(user, valid_user_password(), %{
 | 
					        Accounts.update_user_password(user, valid_user_password(), %{
 | 
				
			||||||
          "password" => "not valid",
 | 
					          password: "not valid",
 | 
				
			||||||
          "password_confirmation" => "another"
 | 
					          password_confirmation: "another"
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      assert %{
 | 
					      assert %{
 | 
				
			||||||
@@ -291,14 +285,14 @@ defmodule Cannery.AccountsTest do
 | 
				
			|||||||
      too_long = String.duplicate("db", 100)
 | 
					      too_long = String.duplicate("db", 100)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      {:error, changeset} =
 | 
					      {:error, changeset} =
 | 
				
			||||||
        Accounts.update_user_password(user, valid_user_password(), %{"password" => too_long})
 | 
					        Accounts.update_user_password(user, valid_user_password(), %{password: too_long})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      assert "should be at most 80 character(s)" in errors_on(changeset).password
 | 
					      assert "should be at most 80 character(s)" in errors_on(changeset).password
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    test "validates current password", %{user: user} do
 | 
					    test "validates current password", %{user: user} do
 | 
				
			||||||
      {:error, changeset} =
 | 
					      {:error, changeset} =
 | 
				
			||||||
        Accounts.update_user_password(user, "invalid", %{"password" => valid_user_password()})
 | 
					        Accounts.update_user_password(user, "invalid", %{password: valid_user_password()})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      assert %{current_password: ["is not valid"]} = errors_on(changeset)
 | 
					      assert %{current_password: ["is not valid"]} = errors_on(changeset)
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
@@ -306,7 +300,7 @@ defmodule Cannery.AccountsTest do
 | 
				
			|||||||
    test "updates the password", %{user: user} do
 | 
					    test "updates the password", %{user: user} do
 | 
				
			||||||
      {:ok, user} =
 | 
					      {:ok, user} =
 | 
				
			||||||
        Accounts.update_user_password(user, valid_user_password(), %{
 | 
					        Accounts.update_user_password(user, valid_user_password(), %{
 | 
				
			||||||
          "password" => "new valid password"
 | 
					          password: "new valid password"
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      assert is_nil(user.password)
 | 
					      assert is_nil(user.password)
 | 
				
			||||||
@@ -318,7 +312,7 @@ defmodule Cannery.AccountsTest do
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
      {:ok, _} =
 | 
					      {:ok, _} =
 | 
				
			||||||
        Accounts.update_user_password(user, valid_user_password(), %{
 | 
					        Accounts.update_user_password(user, valid_user_password(), %{
 | 
				
			||||||
          "password" => "new valid password"
 | 
					          password: "new valid password"
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      refute Repo.get_by(UserToken, user_id: user.id)
 | 
					      refute Repo.get_by(UserToken, user_id: user.id)
 | 
				
			||||||
@@ -486,8 +480,8 @@ defmodule Cannery.AccountsTest do
 | 
				
			|||||||
    test "validates password", %{user: user} do
 | 
					    test "validates password", %{user: user} do
 | 
				
			||||||
      {:error, changeset} =
 | 
					      {:error, changeset} =
 | 
				
			||||||
        Accounts.reset_user_password(user, %{
 | 
					        Accounts.reset_user_password(user, %{
 | 
				
			||||||
          "password" => "not valid",
 | 
					          password: "not valid",
 | 
				
			||||||
          "password_confirmation" => "another"
 | 
					          password_confirmation: "another"
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      assert %{
 | 
					      assert %{
 | 
				
			||||||
@@ -498,13 +492,12 @@ defmodule Cannery.AccountsTest do
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    test "validates maximum values for password for security", %{user: user} do
 | 
					    test "validates maximum values for password for security", %{user: user} do
 | 
				
			||||||
      too_long = String.duplicate("db", 100)
 | 
					      too_long = String.duplicate("db", 100)
 | 
				
			||||||
      {:error, changeset} = Accounts.reset_user_password(user, %{"password" => too_long})
 | 
					      {:error, changeset} = Accounts.reset_user_password(user, %{password: too_long})
 | 
				
			||||||
      assert "should be at most 80 character(s)" in errors_on(changeset).password
 | 
					      assert "should be at most 80 character(s)" in errors_on(changeset).password
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    test "updates the password", %{user: user} do
 | 
					    test "updates the password", %{user: user} do
 | 
				
			||||||
      {:ok, updated_user} =
 | 
					      {:ok, updated_user} = Accounts.reset_user_password(user, %{password: "new valid password"})
 | 
				
			||||||
        Accounts.reset_user_password(user, %{"password" => "new valid password"})
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
      assert is_nil(updated_user.password)
 | 
					      assert is_nil(updated_user.password)
 | 
				
			||||||
      assert Accounts.get_user_by_email_and_password(user.email, "new valid password")
 | 
					      assert Accounts.get_user_by_email_and_password(user.email, "new valid password")
 | 
				
			||||||
@@ -512,7 +505,7 @@ defmodule Cannery.AccountsTest do
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    test "deletes all tokens for the given user", %{user: user} do
 | 
					    test "deletes all tokens for the given user", %{user: user} do
 | 
				
			||||||
      _session_token = Accounts.generate_user_session_token(user)
 | 
					      _session_token = Accounts.generate_user_session_token(user)
 | 
				
			||||||
      {:ok, _user} = Accounts.reset_user_password(user, %{"password" => "new valid password"})
 | 
					      {:ok, _user} = Accounts.reset_user_password(user, %{password: "new valid password"})
 | 
				
			||||||
      refute Repo.get_by(UserToken, user_id: user.id)
 | 
					      refute Repo.get_by(UserToken, user_id: user.id)
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,370 +5,428 @@ defmodule Cannery.ActivityLogTest do
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  use Cannery.DataCase
 | 
					  use Cannery.DataCase
 | 
				
			||||||
  import Cannery.Fixtures
 | 
					  import Cannery.Fixtures
 | 
				
			||||||
 | 
					  alias Cannery.{ActivityLog, ActivityLog.ShotRecord, Ammo}
 | 
				
			||||||
  alias Cannery.{
 | 
					 | 
				
			||||||
    ActivityLog,
 | 
					 | 
				
			||||||
    ActivityLog.ShotGroup,
 | 
					 | 
				
			||||||
    Ammo
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @moduletag :activity_log_test
 | 
					  @moduletag :activity_log_test
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  describe "shot_groups" do
 | 
					  describe "shot_records" do
 | 
				
			||||||
    setup do
 | 
					    setup do
 | 
				
			||||||
      current_user = user_fixture()
 | 
					      current_user = user_fixture()
 | 
				
			||||||
      container = container_fixture(current_user)
 | 
					      container = container_fixture(current_user)
 | 
				
			||||||
      ammo_type = ammo_type_fixture(current_user)
 | 
					      type = type_fixture(current_user)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      {1, [%{id: ammo_group_id} = ammo_group]} =
 | 
					      {1, [%{id: pack_id} = pack]} = pack_fixture(%{count: 25}, type, container, current_user)
 | 
				
			||||||
        ammo_group_fixture(%{"count" => 25}, ammo_type, container, current_user)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
      shot_group =
 | 
					      shot_record =
 | 
				
			||||||
        %{"count" => 5, "date" => ~N[2022-02-13 03:17:00], "notes" => "some notes"}
 | 
					        %{count: 5, date: ~N[2022-02-13 03:17:00], notes: "some notes"}
 | 
				
			||||||
        |> shot_group_fixture(current_user, ammo_group)
 | 
					        |> shot_record_fixture(current_user, pack)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      ammo_group = ammo_group_id |> Ammo.get_ammo_group!(current_user)
 | 
					      pack = pack_id |> Ammo.get_pack!(current_user)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      [
 | 
					      [
 | 
				
			||||||
        current_user: current_user,
 | 
					        current_user: current_user,
 | 
				
			||||||
        container: container,
 | 
					        container: container,
 | 
				
			||||||
        ammo_type: ammo_type,
 | 
					        type: type,
 | 
				
			||||||
        ammo_group: ammo_group,
 | 
					        pack: pack,
 | 
				
			||||||
        shot_group: shot_group
 | 
					        shot_record: shot_record
 | 
				
			||||||
      ]
 | 
					      ]
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    test "list_shot_groups/1 returns all shot_groups",
 | 
					    test "get_shot_record_count!/1 returns the correct amount of shot records",
 | 
				
			||||||
         %{shot_group: shot_group, current_user: current_user} do
 | 
					         %{pack: pack, current_user: current_user} do
 | 
				
			||||||
      assert ActivityLog.list_shot_groups(current_user) == [shot_group]
 | 
					      assert ActivityLog.get_shot_record_count!(current_user) == 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      shot_record_fixture(%{count: 1, date: ~N[2022-02-13 03:17:00]}, current_user, pack)
 | 
				
			||||||
 | 
					      assert ActivityLog.get_shot_record_count!(current_user) == 2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      shot_record_fixture(%{count: 1, date: ~N[2022-02-13 03:17:00]}, current_user, pack)
 | 
				
			||||||
 | 
					      assert ActivityLog.get_shot_record_count!(current_user) == 3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      other_user = user_fixture()
 | 
				
			||||||
 | 
					      assert ActivityLog.get_shot_record_count!(other_user) == 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      container = container_fixture(other_user)
 | 
				
			||||||
 | 
					      type = type_fixture(other_user)
 | 
				
			||||||
 | 
					      {1, [pack]} = pack_fixture(%{count: 25}, type, container, other_user)
 | 
				
			||||||
 | 
					      shot_record_fixture(%{count: 1, date: ~N[2022-02-13 03:17:00]}, other_user, pack)
 | 
				
			||||||
 | 
					      assert ActivityLog.get_shot_record_count!(other_user) == 1
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    test "list_shot_groups/2 returns relevant shot_groups for a user", %{
 | 
					    test "get_shot_record!/2 returns the shot_record with given id",
 | 
				
			||||||
      ammo_type: ammo_type,
 | 
					         %{shot_record: shot_record, current_user: current_user} do
 | 
				
			||||||
      ammo_group: ammo_group,
 | 
					      assert ActivityLog.get_shot_record!(shot_record.id, current_user) == shot_record
 | 
				
			||||||
      container: container,
 | 
					 | 
				
			||||||
      current_user: current_user
 | 
					 | 
				
			||||||
    } do
 | 
					 | 
				
			||||||
      shot_group_a = shot_group_fixture(%{"notes" => "amazing"}, current_user, ammo_group)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      {1, [another_ammo_group]} =
 | 
					 | 
				
			||||||
        ammo_group_fixture(%{"notes" => "stupendous"}, ammo_type, container, current_user)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      shot_group_b = shot_group_fixture(current_user, another_ammo_group)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      another_ammo_type = ammo_type_fixture(%{"name" => "fabulous ammo"}, current_user)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      {1, [yet_another_ammo_group]} =
 | 
					 | 
				
			||||||
        ammo_group_fixture(another_ammo_type, container, current_user)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      shot_group_c = shot_group_fixture(current_user, yet_another_ammo_group)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      random_user = user_fixture()
 | 
					 | 
				
			||||||
      random_container = container_fixture(random_user)
 | 
					 | 
				
			||||||
      random_ammo_type = ammo_type_fixture(random_user)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      {1, [random_ammo_group]} =
 | 
					 | 
				
			||||||
        ammo_group_fixture(random_ammo_type, random_container, random_user)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      _shouldnt_return = shot_group_fixture(random_user, random_ammo_group)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      # notes
 | 
					 | 
				
			||||||
      assert ActivityLog.list_shot_groups("amazing", current_user) == [shot_group_a]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      # ammo group attributes
 | 
					 | 
				
			||||||
      assert ActivityLog.list_shot_groups("stupendous", current_user) == [shot_group_b]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      # ammo type attributes
 | 
					 | 
				
			||||||
      assert ActivityLog.list_shot_groups("fabulous", current_user) == [shot_group_c]
 | 
					 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    test "get_shot_group!/2 returns the shot_group with given id",
 | 
					    test "get_shot_record!/2 does not return a shot_record of another user",
 | 
				
			||||||
         %{shot_group: shot_group, current_user: current_user} do
 | 
					         %{shot_record: shot_record} do
 | 
				
			||||||
      assert ActivityLog.get_shot_group!(shot_group.id, current_user) == shot_group
 | 
					 | 
				
			||||||
    end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    test "get_shot_group!/2 does not return a shot_group of another user",
 | 
					 | 
				
			||||||
         %{shot_group: shot_group} do
 | 
					 | 
				
			||||||
      another_user = user_fixture()
 | 
					      another_user = user_fixture()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      assert_raise Ecto.NoResultsError, fn ->
 | 
					      assert_raise Ecto.NoResultsError, fn ->
 | 
				
			||||||
        ActivityLog.get_shot_group!(shot_group.id, another_user)
 | 
					        ActivityLog.get_shot_record!(shot_record.id, another_user)
 | 
				
			||||||
      end
 | 
					      end
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    test "create_shot_group/3 with valid data creates a shot_group",
 | 
					    test "create_shot_record/3 with valid data creates a shot_record",
 | 
				
			||||||
         %{current_user: current_user, ammo_group: ammo_group} do
 | 
					         %{current_user: current_user, pack: pack} do
 | 
				
			||||||
      valid_attrs = %{"count" => 10, "date" => ~D[2022-02-13], "notes" => "some notes"}
 | 
					      valid_attrs = %{count: 10, date: ~D[2022-02-13], notes: "some notes"}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      assert {:ok, %ShotGroup{} = shot_group} =
 | 
					      assert {:ok, %ShotRecord{} = shot_record} =
 | 
				
			||||||
               ActivityLog.create_shot_group(valid_attrs, current_user, ammo_group)
 | 
					               ActivityLog.create_shot_record(valid_attrs, current_user, pack)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      assert shot_group.count == 10
 | 
					      assert shot_record.count == 10
 | 
				
			||||||
      assert shot_group.date == ~D[2022-02-13]
 | 
					      assert shot_record.date == ~D[2022-02-13]
 | 
				
			||||||
      assert shot_group.notes == "some notes"
 | 
					      assert shot_record.notes == "some notes"
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    test "create_shot_group/3 removes corresponding count from ammo group",
 | 
					    test "create_shot_record/3 removes corresponding count from pack",
 | 
				
			||||||
         %{
 | 
					         %{
 | 
				
			||||||
           current_user: current_user,
 | 
					           current_user: current_user,
 | 
				
			||||||
           ammo_group: %{id: ammo_group_id, count: org_count} = ammo_group
 | 
					           pack: %{id: pack_id, count: org_count} = pack
 | 
				
			||||||
         } do
 | 
					         } do
 | 
				
			||||||
      valid_attrs = %{"count" => 10, "date" => ~D[2022-02-13], "notes" => "some notes"}
 | 
					      valid_attrs = %{count: 10, date: ~D[2022-02-13], notes: "some notes"}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      assert {:ok, %ShotGroup{} = shot_group} =
 | 
					      assert {:ok, %ShotRecord{} = shot_record} =
 | 
				
			||||||
               ActivityLog.create_shot_group(valid_attrs, current_user, ammo_group)
 | 
					               ActivityLog.create_shot_record(valid_attrs, current_user, pack)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      %{count: new_count} = ammo_group_id |> Ammo.get_ammo_group!(current_user)
 | 
					      %{count: new_count} = pack_id |> Ammo.get_pack!(current_user)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      assert org_count - shot_group.count == new_count
 | 
					      assert org_count - shot_record.count == new_count
 | 
				
			||||||
      assert new_count == 10
 | 
					      assert new_count == 10
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    test "create_shot_group/3 does not remove more than ammo group amount",
 | 
					    test "create_shot_record/3 does not remove more tha pack amount",
 | 
				
			||||||
         %{current_user: current_user, ammo_group: %{id: ammo_group_id} = ammo_group} do
 | 
					         %{current_user: current_user, pack: %{id: pack_id} = pack} do
 | 
				
			||||||
      valid_attrs = %{"count" => 20, "date" => ~D[2022-02-13], "notes" => "some notes"}
 | 
					      valid_attrs = %{count: 20, date: ~D[2022-02-13], notes: "some notes"}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      assert {:ok, %ShotGroup{}} =
 | 
					      assert {:ok, %ShotRecord{}} =
 | 
				
			||||||
               ActivityLog.create_shot_group(valid_attrs, current_user, ammo_group)
 | 
					               ActivityLog.create_shot_record(valid_attrs, current_user, pack)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      ammo_group = ammo_group_id |> Ammo.get_ammo_group!(current_user)
 | 
					      pack = pack_id |> Ammo.get_pack!(current_user)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      assert ammo_group.count == 0
 | 
					      assert pack.count == 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      assert {:error, %Ecto.Changeset{}} =
 | 
					      assert {:error, %Ecto.Changeset{}} =
 | 
				
			||||||
               ActivityLog.create_shot_group(%{"count" => 1}, current_user, ammo_group)
 | 
					               ActivityLog.create_shot_record(%{count: 1}, current_user, pack)
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    test "create_shot_group/3 with invalid data returns error changeset",
 | 
					    test "create_shot_record/3 with invalid data returns error changeset",
 | 
				
			||||||
         %{current_user: current_user, ammo_group: ammo_group} do
 | 
					         %{current_user: current_user, pack: pack} do
 | 
				
			||||||
      invalid_params = %{"count" => nil, "date" => nil, "notes" => nil}
 | 
					      invalid_params = %{count: nil, date: nil, notes: nil}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      assert {:error, %Ecto.Changeset{}} =
 | 
					      assert {:error, %Ecto.Changeset{}} =
 | 
				
			||||||
               ActivityLog.create_shot_group(invalid_params, current_user, ammo_group)
 | 
					               ActivityLog.create_shot_record(invalid_params, current_user, pack)
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    test "update_shot_group/3 with valid data updates the shot_group and ammo_group",
 | 
					    test "update_shot_record/3 with valid data updates the shot_record and pack",
 | 
				
			||||||
         %{
 | 
					         %{
 | 
				
			||||||
           shot_group: shot_group,
 | 
					           shot_record: shot_record,
 | 
				
			||||||
           ammo_group: %{id: ammo_group_id},
 | 
					           pack: %{id: pack_id},
 | 
				
			||||||
           current_user: current_user
 | 
					           current_user: current_user
 | 
				
			||||||
         } do
 | 
					         } do
 | 
				
			||||||
      assert {:ok, %ShotGroup{} = shot_group} =
 | 
					      assert {:ok, %ShotRecord{} = shot_record} =
 | 
				
			||||||
               ActivityLog.update_shot_group(
 | 
					               ActivityLog.update_shot_record(
 | 
				
			||||||
                 shot_group,
 | 
					                 shot_record,
 | 
				
			||||||
                 %{
 | 
					                 %{
 | 
				
			||||||
                   "count" => 10,
 | 
					                   count: 10,
 | 
				
			||||||
                   "date" => ~D[2022-02-13],
 | 
					                   date: ~D[2022-02-13],
 | 
				
			||||||
                   "notes" => "some updated notes"
 | 
					                   notes: "some updated notes"
 | 
				
			||||||
                 },
 | 
					                 },
 | 
				
			||||||
                 current_user
 | 
					                 current_user
 | 
				
			||||||
               )
 | 
					               )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      ammo_group = ammo_group_id |> Ammo.get_ammo_group!(current_user)
 | 
					      pack = pack_id |> Ammo.get_pack!(current_user)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      assert shot_group.count == 10
 | 
					      assert shot_record.count == 10
 | 
				
			||||||
      assert ammo_group.count == 15
 | 
					      assert pack.count == 15
 | 
				
			||||||
      assert shot_group.date == ~D[2022-02-13]
 | 
					      assert shot_record.date == ~D[2022-02-13]
 | 
				
			||||||
      assert shot_group.notes == "some updated notes"
 | 
					      assert shot_record.notes == "some updated notes"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      assert {:ok, %ShotGroup{} = shot_group} =
 | 
					      assert {:ok, %ShotRecord{} = shot_record} =
 | 
				
			||||||
               ActivityLog.update_shot_group(
 | 
					               ActivityLog.update_shot_record(
 | 
				
			||||||
                 shot_group,
 | 
					                 shot_record,
 | 
				
			||||||
                 %{
 | 
					                 %{
 | 
				
			||||||
                   "count" => 25,
 | 
					                   count: 25,
 | 
				
			||||||
                   "date" => ~D[2022-02-13],
 | 
					                   date: ~D[2022-02-13],
 | 
				
			||||||
                   "notes" => "some updated notes"
 | 
					                   notes: "some updated notes"
 | 
				
			||||||
                 },
 | 
					                 },
 | 
				
			||||||
                 current_user
 | 
					                 current_user
 | 
				
			||||||
               )
 | 
					               )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      ammo_group = ammo_group_id |> Ammo.get_ammo_group!(current_user)
 | 
					      pack = pack_id |> Ammo.get_pack!(current_user)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      assert shot_group.count == 25
 | 
					      assert shot_record.count == 25
 | 
				
			||||||
      assert ammo_group.count == 0
 | 
					      assert pack.count == 0
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    test "update_shot_group/3 with invalid data returns error changeset",
 | 
					    test "update_shot_record/3 with invalid data returns error changeset",
 | 
				
			||||||
         %{shot_group: shot_group, current_user: current_user} do
 | 
					         %{shot_record: shot_record, current_user: current_user} do
 | 
				
			||||||
      assert {:error, %Ecto.Changeset{}} =
 | 
					      assert {:error, %Ecto.Changeset{}} =
 | 
				
			||||||
               ActivityLog.update_shot_group(
 | 
					               ActivityLog.update_shot_record(
 | 
				
			||||||
                 shot_group,
 | 
					                 shot_record,
 | 
				
			||||||
                 %{"count" => 26, "date" => nil, "notes" => nil},
 | 
					                 %{count: 26, date: nil, notes: nil},
 | 
				
			||||||
                 current_user
 | 
					                 current_user
 | 
				
			||||||
               )
 | 
					               )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      assert {:error, %Ecto.Changeset{}} =
 | 
					      assert {:error, %Ecto.Changeset{}} =
 | 
				
			||||||
               ActivityLog.update_shot_group(
 | 
					               ActivityLog.update_shot_record(
 | 
				
			||||||
                 shot_group,
 | 
					                 shot_record,
 | 
				
			||||||
                 %{"count" => -1, "date" => nil, "notes" => nil},
 | 
					                 %{count: -1, date: nil, notes: nil},
 | 
				
			||||||
                 current_user
 | 
					                 current_user
 | 
				
			||||||
               )
 | 
					               )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      assert shot_group == ActivityLog.get_shot_group!(shot_group.id, current_user)
 | 
					      assert shot_record == ActivityLog.get_shot_record!(shot_record.id, current_user)
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    test "delete_shot_group/2 deletes the shot_group and adds value back",
 | 
					    test "delete_shot_record/2 deletes the shot_record and adds value back",
 | 
				
			||||||
         %{shot_group: shot_group, current_user: current_user, ammo_group: %{id: ammo_group_id}} do
 | 
					         %{shot_record: shot_record, current_user: current_user, pack: %{id: pack_id}} do
 | 
				
			||||||
      assert {:ok, %ShotGroup{}} = ActivityLog.delete_shot_group(shot_group, current_user)
 | 
					      assert {:ok, %ShotRecord{}} = ActivityLog.delete_shot_record(shot_record, current_user)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      assert %{count: 25} = ammo_group_id |> Ammo.get_ammo_group!(current_user)
 | 
					      assert %{count: 25} = pack_id |> Ammo.get_pack!(current_user)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      assert_raise Ecto.NoResultsError, fn ->
 | 
					      assert_raise Ecto.NoResultsError, fn ->
 | 
				
			||||||
        ActivityLog.get_shot_group!(shot_group.id, current_user)
 | 
					        ActivityLog.get_shot_record!(shot_record.id, current_user)
 | 
				
			||||||
      end
 | 
					      end
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    test "get_used_count/2 returns accurate used count", %{
 | 
					    test "get_used_count/2 returns accurate used count", %{
 | 
				
			||||||
      ammo_group: ammo_group,
 | 
					      pack: pack,
 | 
				
			||||||
      ammo_type: ammo_type,
 | 
					      type: type,
 | 
				
			||||||
      container: container,
 | 
					      container: container,
 | 
				
			||||||
      current_user: current_user
 | 
					      current_user: current_user
 | 
				
			||||||
    } do
 | 
					    } do
 | 
				
			||||||
      {1, [another_ammo_group]} = ammo_group_fixture(ammo_type, container, current_user)
 | 
					      {1, [another_pack]} = pack_fixture(type, container, current_user)
 | 
				
			||||||
      assert 0 = another_ammo_group |> ActivityLog.get_used_count(current_user)
 | 
					      assert 0 = another_pack |> ActivityLog.get_used_count(current_user)
 | 
				
			||||||
      assert 5 = ammo_group |> ActivityLog.get_used_count(current_user)
 | 
					      assert 5 = pack |> ActivityLog.get_used_count(current_user)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      shot_group_fixture(%{"count" => 15}, current_user, ammo_group)
 | 
					      shot_record_fixture(%{count: 15}, current_user, pack)
 | 
				
			||||||
      assert 20 = ammo_group |> ActivityLog.get_used_count(current_user)
 | 
					      assert 20 = pack |> ActivityLog.get_used_count(current_user)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      shot_group_fixture(%{"count" => 10}, current_user, ammo_group)
 | 
					      shot_record_fixture(%{count: 10}, current_user, pack)
 | 
				
			||||||
      assert 30 = ammo_group |> ActivityLog.get_used_count(current_user)
 | 
					      assert 30 = pack |> ActivityLog.get_used_count(current_user)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      {1, [another_ammo_group]} = ammo_group_fixture(ammo_type, container, current_user)
 | 
					      {1, [another_pack]} = pack_fixture(type, container, current_user)
 | 
				
			||||||
      assert 0 = another_ammo_group |> ActivityLog.get_used_count(current_user)
 | 
					      assert 0 = another_pack |> ActivityLog.get_used_count(current_user)
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    test "get_used_counts/2 returns accurate used counts", %{
 | 
					    test "get_used_counts/2 returns accurate used counts", %{
 | 
				
			||||||
      ammo_group: %{id: ammo_group_id} = ammo_group,
 | 
					      pack: %{id: pack_id} = pack,
 | 
				
			||||||
      ammo_type: ammo_type,
 | 
					      type: type,
 | 
				
			||||||
      container: container,
 | 
					      container: container,
 | 
				
			||||||
      current_user: current_user
 | 
					      current_user: current_user
 | 
				
			||||||
    } do
 | 
					    } do
 | 
				
			||||||
      {1, [%{id: another_ammo_group_id} = another_ammo_group]} =
 | 
					      {1, [%{id: another_pack_id} = another_pack]} = pack_fixture(type, container, current_user)
 | 
				
			||||||
        ammo_group_fixture(ammo_type, container, current_user)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
      assert %{ammo_group_id => 5} ==
 | 
					      assert %{pack_id => 5} ==
 | 
				
			||||||
               [ammo_group, another_ammo_group] |> ActivityLog.get_used_counts(current_user)
 | 
					               [pack, another_pack] |> ActivityLog.get_used_counts(current_user)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      shot_group_fixture(%{"count" => 5}, current_user, another_ammo_group)
 | 
					      shot_record_fixture(%{count: 5}, current_user, another_pack)
 | 
				
			||||||
      used_counts = [ammo_group, another_ammo_group] |> ActivityLog.get_used_counts(current_user)
 | 
					      used_counts = [pack, another_pack] |> ActivityLog.get_used_counts(current_user)
 | 
				
			||||||
      assert %{^ammo_group_id => 5} = used_counts
 | 
					      assert %{^pack_id => 5} = used_counts
 | 
				
			||||||
      assert %{^another_ammo_group_id => 5} = used_counts
 | 
					      assert %{^another_pack_id => 5} = used_counts
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      shot_group_fixture(%{"count" => 15}, current_user, ammo_group)
 | 
					      shot_record_fixture(%{count: 15}, current_user, pack)
 | 
				
			||||||
      used_counts = [ammo_group, another_ammo_group] |> ActivityLog.get_used_counts(current_user)
 | 
					      used_counts = [pack, another_pack] |> ActivityLog.get_used_counts(current_user)
 | 
				
			||||||
      assert %{^ammo_group_id => 20} = used_counts
 | 
					      assert %{^pack_id => 20} = used_counts
 | 
				
			||||||
      assert %{^another_ammo_group_id => 5} = used_counts
 | 
					      assert %{^another_pack_id => 5} = used_counts
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      shot_group_fixture(%{"count" => 10}, current_user, ammo_group)
 | 
					      shot_record_fixture(%{count: 10}, current_user, pack)
 | 
				
			||||||
      used_counts = [ammo_group, another_ammo_group] |> ActivityLog.get_used_counts(current_user)
 | 
					      used_counts = [pack, another_pack] |> ActivityLog.get_used_counts(current_user)
 | 
				
			||||||
      assert %{^ammo_group_id => 30} = used_counts
 | 
					      assert %{^pack_id => 30} = used_counts
 | 
				
			||||||
      assert %{^another_ammo_group_id => 5} = used_counts
 | 
					      assert %{^another_pack_id => 5} = used_counts
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    test "get_last_used_date/2 returns accurate used count", %{
 | 
					    test "get_last_used_date/2 returns accurate used count", %{
 | 
				
			||||||
      ammo_group: ammo_group,
 | 
					      pack: pack,
 | 
				
			||||||
      ammo_type: ammo_type,
 | 
					      type: type,
 | 
				
			||||||
      container: container,
 | 
					      container: container,
 | 
				
			||||||
      shot_group: %{date: date},
 | 
					      shot_record: %{date: date},
 | 
				
			||||||
      current_user: current_user
 | 
					      current_user: current_user
 | 
				
			||||||
    } do
 | 
					    } do
 | 
				
			||||||
      {1, [another_ammo_group]} = ammo_group_fixture(ammo_type, container, current_user)
 | 
					      {1, [another_pack]} = pack_fixture(type, container, current_user)
 | 
				
			||||||
      assert another_ammo_group |> ActivityLog.get_last_used_date(current_user) |> is_nil()
 | 
					      assert another_pack |> ActivityLog.get_last_used_date(current_user) |> is_nil()
 | 
				
			||||||
      assert ^date = ammo_group |> ActivityLog.get_last_used_date(current_user)
 | 
					      assert ^date = pack |> ActivityLog.get_last_used_date(current_user)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      %{date: date} = shot_group_fixture(%{"date" => ~D[2022-11-10]}, current_user, ammo_group)
 | 
					      %{date: date} = shot_record_fixture(%{date: ~D[2022-11-10]}, current_user, pack)
 | 
				
			||||||
      assert ^date = ammo_group |> ActivityLog.get_last_used_date(current_user)
 | 
					      assert ^date = pack |> ActivityLog.get_last_used_date(current_user)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      %{date: date} = shot_group_fixture(%{"date" => ~D[2022-11-11]}, current_user, ammo_group)
 | 
					      %{date: date} = shot_record_fixture(%{date: ~D[2022-11-11]}, current_user, pack)
 | 
				
			||||||
      assert ^date = ammo_group |> ActivityLog.get_last_used_date(current_user)
 | 
					      assert ^date = pack |> ActivityLog.get_last_used_date(current_user)
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    test "get_last_used_dates/2 returns accurate used counts", %{
 | 
					    test "get_last_used_dates/2 returns accurate used counts", %{
 | 
				
			||||||
      ammo_group: %{id: ammo_group_id} = ammo_group,
 | 
					      pack: %{id: pack_id} = pack,
 | 
				
			||||||
      ammo_type: ammo_type,
 | 
					      type: type,
 | 
				
			||||||
      container: container,
 | 
					      container: container,
 | 
				
			||||||
      shot_group: %{date: date},
 | 
					      shot_record: %{date: date},
 | 
				
			||||||
      current_user: current_user
 | 
					      current_user: current_user
 | 
				
			||||||
    } do
 | 
					    } do
 | 
				
			||||||
      {1, [%{id: another_ammo_group_id} = another_ammo_group]} =
 | 
					      {1, [%{id: another_pack_id} = another_pack]} = pack_fixture(type, container, current_user)
 | 
				
			||||||
        ammo_group_fixture(ammo_type, container, current_user)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
      # unset date
 | 
					      # unset date
 | 
				
			||||||
      assert %{ammo_group_id => date} ==
 | 
					      assert %{pack_id => date} ==
 | 
				
			||||||
               [ammo_group, another_ammo_group] |> ActivityLog.get_last_used_dates(current_user)
 | 
					               [pack, another_pack] |> ActivityLog.get_last_used_dates(current_user)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      shot_group_fixture(%{"date" => ~D[2022-11-09]}, current_user, another_ammo_group)
 | 
					      shot_record_fixture(%{date: ~D[2022-11-09]}, current_user, another_pack)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      # setting initial date
 | 
					      # setting initial date
 | 
				
			||||||
      last_used_shot_groups =
 | 
					      last_used_shot_records =
 | 
				
			||||||
        [ammo_group, another_ammo_group] |> ActivityLog.get_last_used_dates(current_user)
 | 
					        [pack, another_pack] |> ActivityLog.get_last_used_dates(current_user)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      assert %{^ammo_group_id => ^date} = last_used_shot_groups
 | 
					      assert %{^pack_id => ^date} = last_used_shot_records
 | 
				
			||||||
      assert %{^another_ammo_group_id => ~D[2022-11-09]} = last_used_shot_groups
 | 
					      assert %{^another_pack_id => ~D[2022-11-09]} = last_used_shot_records
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      # setting another date
 | 
					      # setting another date
 | 
				
			||||||
      shot_group_fixture(%{"date" => ~D[2022-11-10]}, current_user, ammo_group)
 | 
					      shot_record_fixture(%{date: ~D[2022-11-10]}, current_user, pack)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      last_used_shot_groups =
 | 
					      last_used_shot_records =
 | 
				
			||||||
        [ammo_group, another_ammo_group] |> ActivityLog.get_last_used_dates(current_user)
 | 
					        [pack, another_pack] |> ActivityLog.get_last_used_dates(current_user)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      assert %{^ammo_group_id => ~D[2022-11-10]} = last_used_shot_groups
 | 
					      assert %{^pack_id => ~D[2022-11-10]} = last_used_shot_records
 | 
				
			||||||
      assert %{^another_ammo_group_id => ~D[2022-11-09]} = last_used_shot_groups
 | 
					      assert %{^another_pack_id => ~D[2022-11-09]} = last_used_shot_records
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      # setting yet another date
 | 
					      # setting yet another date
 | 
				
			||||||
      shot_group_fixture(%{"date" => ~D[2022-11-11]}, current_user, ammo_group)
 | 
					      shot_record_fixture(%{date: ~D[2022-11-11]}, current_user, pack)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      last_used_shot_groups =
 | 
					      last_used_shot_records =
 | 
				
			||||||
        [ammo_group, another_ammo_group] |> ActivityLog.get_last_used_dates(current_user)
 | 
					        [pack, another_pack] |> ActivityLog.get_last_used_dates(current_user)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      assert %{^ammo_group_id => ~D[2022-11-11]} = last_used_shot_groups
 | 
					      assert %{^pack_id => ~D[2022-11-11]} = last_used_shot_records
 | 
				
			||||||
      assert %{^another_ammo_group_id => ~D[2022-11-09]} = last_used_shot_groups
 | 
					      assert %{^another_pack_id => ~D[2022-11-09]} = last_used_shot_records
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    test "get_used_count_for_ammo_type/2 gets accurate used round count for ammo type",
 | 
					    test "get_used_count_for_type/2 gets accurate used round count for type",
 | 
				
			||||||
         %{ammo_type: ammo_type, ammo_group: ammo_group, current_user: current_user} do
 | 
					         %{type: type, pack: pack, current_user: current_user} do
 | 
				
			||||||
      another_ammo_type = ammo_type_fixture(current_user)
 | 
					      another_type = type_fixture(current_user)
 | 
				
			||||||
      assert 0 = another_ammo_type |> ActivityLog.get_used_count_for_ammo_type(current_user)
 | 
					      assert 0 = another_type |> ActivityLog.get_used_count_for_type(current_user)
 | 
				
			||||||
      assert 5 = ammo_type |> ActivityLog.get_used_count_for_ammo_type(current_user)
 | 
					      assert 5 = type |> ActivityLog.get_used_count_for_type(current_user)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      shot_group_fixture(%{"count" => 5}, current_user, ammo_group)
 | 
					      shot_record_fixture(%{count: 5}, current_user, pack)
 | 
				
			||||||
      assert 10 = ammo_type |> ActivityLog.get_used_count_for_ammo_type(current_user)
 | 
					      assert 10 = type |> ActivityLog.get_used_count_for_type(current_user)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      shot_group_fixture(%{"count" => 1}, current_user, ammo_group)
 | 
					      shot_record_fixture(%{count: 1}, current_user, pack)
 | 
				
			||||||
      assert 11 = ammo_type |> ActivityLog.get_used_count_for_ammo_type(current_user)
 | 
					      assert 11 = type |> ActivityLog.get_used_count_for_type(current_user)
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    test "get_used_count_for_ammo_types/2 gets accurate used round count for ammo types", %{
 | 
					    test "get_used_count_for_types/2 gets accurate used round count for types", %{
 | 
				
			||||||
      ammo_type: %{id: ammo_type_id} = ammo_type,
 | 
					      type: %{id: type_id} = type,
 | 
				
			||||||
      container: container,
 | 
					      container: container,
 | 
				
			||||||
      current_user: current_user
 | 
					      current_user: current_user
 | 
				
			||||||
    } do
 | 
					    } do
 | 
				
			||||||
      # testing unused ammo type
 | 
					      # testing unused type
 | 
				
			||||||
      %{id: another_ammo_type_id} = another_ammo_type = ammo_type_fixture(current_user)
 | 
					      %{id: another_type_id} = another_type = type_fixture(current_user)
 | 
				
			||||||
      {1, [ammo_group]} = ammo_group_fixture(another_ammo_type, container, current_user)
 | 
					      {1, [pack]} = pack_fixture(another_type, container, current_user)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      assert %{ammo_type_id => 5} ==
 | 
					      assert %{type_id => 5} ==
 | 
				
			||||||
               [ammo_type, another_ammo_type]
 | 
					               [type, another_type]
 | 
				
			||||||
               |> ActivityLog.get_used_count_for_ammo_types(current_user)
 | 
					               |> ActivityLog.get_used_count_for_types(current_user)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      # use generated ammo group
 | 
					      # use generated pack
 | 
				
			||||||
      shot_group_fixture(%{"count" => 5}, current_user, ammo_group)
 | 
					      shot_record_fixture(%{count: 5}, current_user, pack)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      used_counts =
 | 
					      used_counts = [type, another_type] |> ActivityLog.get_used_count_for_types(current_user)
 | 
				
			||||||
        [ammo_type, another_ammo_type] |> ActivityLog.get_used_count_for_ammo_types(current_user)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
      assert %{^ammo_type_id => 5} = used_counts
 | 
					      assert %{^type_id => 5} = used_counts
 | 
				
			||||||
      assert %{^another_ammo_type_id => 5} = used_counts
 | 
					      assert %{^another_type_id => 5} = used_counts
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      # use generated ammo group again
 | 
					      # use generated pack again
 | 
				
			||||||
      shot_group_fixture(%{"count" => 1}, current_user, ammo_group)
 | 
					      shot_record_fixture(%{count: 1}, current_user, pack)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      used_counts =
 | 
					      used_counts = [type, another_type] |> ActivityLog.get_used_count_for_types(current_user)
 | 
				
			||||||
        [ammo_type, another_ammo_type] |> ActivityLog.get_used_count_for_ammo_types(current_user)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
      assert %{^ammo_type_id => 5} = used_counts
 | 
					      assert %{^type_id => 5} = used_counts
 | 
				
			||||||
      assert %{^another_ammo_type_id => 6} = used_counts
 | 
					      assert %{^another_type_id => 6} = used_counts
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  describe "list_shot_records/3" do
 | 
				
			||||||
 | 
					    setup do
 | 
				
			||||||
 | 
					      current_user = user_fixture()
 | 
				
			||||||
 | 
					      container = container_fixture(current_user)
 | 
				
			||||||
 | 
					      type = type_fixture(current_user)
 | 
				
			||||||
 | 
					      {1, [pack]} = pack_fixture(type, container, current_user)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      [
 | 
				
			||||||
 | 
					        current_user: current_user,
 | 
				
			||||||
 | 
					        container: container,
 | 
				
			||||||
 | 
					        type: type,
 | 
				
			||||||
 | 
					        pack: pack
 | 
				
			||||||
 | 
					      ]
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    test "list_shot_records/3 returns relevant shot_records for a type",
 | 
				
			||||||
 | 
					         %{current_user: current_user, container: container} do
 | 
				
			||||||
 | 
					      other_user = user_fixture()
 | 
				
			||||||
 | 
					      other_container = container_fixture(other_user)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      for class <- ["rifle", "shotgun", "pistol"] do
 | 
				
			||||||
 | 
					        other_type = type_fixture(%{class: class}, other_user)
 | 
				
			||||||
 | 
					        {1, [other_pack]} = pack_fixture(other_type, other_container, other_user)
 | 
				
			||||||
 | 
					        shot_record_fixture(other_user, other_pack)
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      rifle_type = type_fixture(%{class: :rifle}, current_user)
 | 
				
			||||||
 | 
					      {1, [rifle_pack]} = pack_fixture(rifle_type, container, current_user)
 | 
				
			||||||
 | 
					      rifle_shot_record = shot_record_fixture(current_user, rifle_pack)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      shotgun_type = type_fixture(%{class: :shotgun}, current_user)
 | 
				
			||||||
 | 
					      {1, [shotgun_pack]} = pack_fixture(shotgun_type, container, current_user)
 | 
				
			||||||
 | 
					      shotgun_shot_record = shot_record_fixture(current_user, shotgun_pack)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      pistol_type = type_fixture(%{class: :pistol}, current_user)
 | 
				
			||||||
 | 
					      {1, [pistol_pack]} = pack_fixture(pistol_type, container, current_user)
 | 
				
			||||||
 | 
					      pistol_shot_record = shot_record_fixture(current_user, pistol_pack)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      assert [^rifle_shot_record] = ActivityLog.list_shot_records(:rifle, current_user)
 | 
				
			||||||
 | 
					      assert [^shotgun_shot_record] = ActivityLog.list_shot_records(:shotgun, current_user)
 | 
				
			||||||
 | 
					      assert [^pistol_shot_record] = ActivityLog.list_shot_records(:pistol, current_user)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      shot_records = ActivityLog.list_shot_records(:all, current_user)
 | 
				
			||||||
 | 
					      assert Enum.count(shot_records) == 3
 | 
				
			||||||
 | 
					      assert rifle_shot_record in shot_records
 | 
				
			||||||
 | 
					      assert shotgun_shot_record in shot_records
 | 
				
			||||||
 | 
					      assert pistol_shot_record in shot_records
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      shot_records = ActivityLog.list_shot_records(nil, current_user)
 | 
				
			||||||
 | 
					      assert Enum.count(shot_records) == 3
 | 
				
			||||||
 | 
					      assert rifle_shot_record in shot_records
 | 
				
			||||||
 | 
					      assert shotgun_shot_record in shot_records
 | 
				
			||||||
 | 
					      assert pistol_shot_record in shot_records
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    test "list_shot_records/3 returns relevant shot_records for a search", %{
 | 
				
			||||||
 | 
					      type: type,
 | 
				
			||||||
 | 
					      pack: pack,
 | 
				
			||||||
 | 
					      container: container,
 | 
				
			||||||
 | 
					      current_user: current_user
 | 
				
			||||||
 | 
					    } do
 | 
				
			||||||
 | 
					      shot_record_a = shot_record_fixture(%{notes: "amazing"}, current_user, pack)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      {1, [another_pack]} = pack_fixture(%{notes: "stupendous"}, type, container, current_user)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      shot_record_b = shot_record_fixture(current_user, another_pack)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      another_type = type_fixture(%{name: "fabulous ammo"}, current_user)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      {1, [yet_another_pack]} = pack_fixture(another_type, container, current_user)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      shot_record_c = shot_record_fixture(current_user, yet_another_pack)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      another_user = user_fixture()
 | 
				
			||||||
 | 
					      another_container = container_fixture(another_user)
 | 
				
			||||||
 | 
					      another_type = type_fixture(another_user)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      {1, [another_pack]} = pack_fixture(another_type, another_container, another_user)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      _shouldnt_return = shot_record_fixture(another_user, another_pack)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      # notes
 | 
				
			||||||
 | 
					      assert ActivityLog.list_shot_records("amazing", :all, current_user) == [shot_record_a]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      # pack attributes
 | 
				
			||||||
 | 
					      assert ActivityLog.list_shot_records("stupendous", :all, current_user) == [shot_record_b]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      # type attributes
 | 
				
			||||||
 | 
					      assert ActivityLog.list_shot_records("fabulous", :all, current_user) == [shot_record_c]
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 
 | 
				
			|||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -10,37 +10,37 @@ defmodule Cannery.ContainersTest do
 | 
				
			|||||||
  @moduletag :containers_test
 | 
					  @moduletag :containers_test
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @valid_attrs %{
 | 
					  @valid_attrs %{
 | 
				
			||||||
    "desc" => "some desc",
 | 
					    desc: "some desc",
 | 
				
			||||||
    "location" => "some location",
 | 
					    location: "some location",
 | 
				
			||||||
    "name" => "some name",
 | 
					    name: "some name",
 | 
				
			||||||
    "type" => "some type"
 | 
					    type: "some type"
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  @update_attrs %{
 | 
					  @update_attrs %{
 | 
				
			||||||
    "desc" => "some updated desc",
 | 
					    desc: "some updated desc",
 | 
				
			||||||
    "location" => "some updated location",
 | 
					    location: "some updated location",
 | 
				
			||||||
    "name" => "some updated name",
 | 
					    name: "some updated name",
 | 
				
			||||||
    "type" => "some updated type"
 | 
					    type: "some updated type"
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  @invalid_attrs %{
 | 
					  @invalid_attrs %{
 | 
				
			||||||
    "desc" => nil,
 | 
					    desc: nil,
 | 
				
			||||||
    "location" => nil,
 | 
					    location: nil,
 | 
				
			||||||
    "name" => nil,
 | 
					    name: nil,
 | 
				
			||||||
    "type" => nil
 | 
					    type: nil
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  @valid_tag_attrs %{
 | 
					  @valid_tag_attrs %{
 | 
				
			||||||
    "bg_color" => "some bg-color",
 | 
					    bg_color: "#100000",
 | 
				
			||||||
    "name" => "some name",
 | 
					    name: "some name",
 | 
				
			||||||
    "text_color" => "some text-color"
 | 
					    text_color: "#000000"
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  @update_tag_attrs %{
 | 
					  @update_tag_attrs %{
 | 
				
			||||||
    "bg_color" => "some updated bg-color",
 | 
					    bg_color: "#100001",
 | 
				
			||||||
    "name" => "some updated name",
 | 
					    name: "some updated name",
 | 
				
			||||||
    "text_color" => "some updated text-color"
 | 
					    text_color: "#000001"
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  @invalid_tag_attrs %{
 | 
					  @invalid_tag_attrs %{
 | 
				
			||||||
    "bg_color" => nil,
 | 
					    bg_color: nil,
 | 
				
			||||||
    "name" => nil,
 | 
					    name: nil,
 | 
				
			||||||
    "text_color" => nil
 | 
					    text_color: nil
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  describe "containers" do
 | 
					  describe "containers" do
 | 
				
			||||||
@@ -57,25 +57,24 @@ defmodule Cannery.ContainersTest do
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    test "list_containers/2 returns relevant containers for a user",
 | 
					    test "list_containers/2 returns relevant containers for a user",
 | 
				
			||||||
         %{current_user: current_user} do
 | 
					         %{current_user: current_user} do
 | 
				
			||||||
      container_a = container_fixture(%{"name" => "my cool container"}, current_user)
 | 
					      container_a = container_fixture(%{name: "my cool container"}, current_user)
 | 
				
			||||||
      container_b = container_fixture(%{"desc" => "a fascinating description"}, current_user)
 | 
					      container_b = container_fixture(%{desc: "a fascinating description"}, current_user)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      %{id: container_c_id} =
 | 
					      %{id: container_c_id} =
 | 
				
			||||||
        container_c = container_fixture(%{"location" => "a secret place"}, current_user)
 | 
					        container_c = container_fixture(%{location: "a secret place"}, current_user)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      tag = tag_fixture(%{"name" => "stupendous tag"}, current_user)
 | 
					      tag = tag_fixture(%{name: "stupendous tag"}, current_user)
 | 
				
			||||||
      Containers.add_tag!(container_c, tag, current_user)
 | 
					      Containers.add_tag!(container_c, tag, current_user)
 | 
				
			||||||
      container_c = container_c_id |> Containers.get_container!(current_user)
 | 
					      container_c = container_c_id |> Containers.get_container!(current_user)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      %{id: container_d_id} =
 | 
					      %{id: container_d_id} =
 | 
				
			||||||
        container_d = container_fixture(%{"type" => "musty old box"}, current_user)
 | 
					        container_d = container_fixture(%{type: "musty old box"}, current_user)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      tag = tag_fixture(%{"name" => "amazing tag"}, current_user)
 | 
					      tag = tag_fixture(%{name: "amazing tag"}, current_user)
 | 
				
			||||||
      Containers.add_tag!(container_d, tag, current_user)
 | 
					      Containers.add_tag!(container_d, tag, current_user)
 | 
				
			||||||
      container_d = container_d_id |> Containers.get_container!(current_user)
 | 
					      container_d = container_d_id |> Containers.get_container!(current_user)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      _shouldnt_return =
 | 
					      _shouldnt_return = container_fixture(%{name: "another person's container"}, user_fixture())
 | 
				
			||||||
        container_fixture(%{"name" => "another person's container"}, user_fixture())
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
      # attributes
 | 
					      # attributes
 | 
				
			||||||
      assert Containers.list_containers("cool", current_user) == [container_a]
 | 
					      assert Containers.list_containers("cool", current_user) == [container_a]
 | 
				
			||||||
@@ -109,7 +108,7 @@ defmodule Cannery.ContainersTest do
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    test "create_container/2 with valid data creates a container", %{current_user: current_user} do
 | 
					    test "create_container/2 with valid data creates a container", %{current_user: current_user} do
 | 
				
			||||||
      assert {:ok, %Container{} = container} =
 | 
					      assert {:ok, %Container{} = container} =
 | 
				
			||||||
               @valid_attrs |> Containers.create_container(current_user)
 | 
					               Containers.create_container(@valid_attrs, current_user)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      assert container.desc == "some desc"
 | 
					      assert container.desc == "some desc"
 | 
				
			||||||
      assert container.location == "some location"
 | 
					      assert container.location == "some location"
 | 
				
			||||||
@@ -120,7 +119,7 @@ defmodule Cannery.ContainersTest do
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    test "create_container/2 with invalid data returns error changeset",
 | 
					    test "create_container/2 with invalid data returns error changeset",
 | 
				
			||||||
         %{current_user: current_user} do
 | 
					         %{current_user: current_user} do
 | 
				
			||||||
      assert {:error, %Changeset{}} = @invalid_attrs |> Containers.create_container(current_user)
 | 
					      assert {:error, %Changeset{}} = Containers.create_container(@invalid_attrs, current_user)
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    test "update_container/3 with valid data updates the container",
 | 
					    test "update_container/3 with valid data updates the container",
 | 
				
			||||||
@@ -163,15 +162,10 @@ defmodule Cannery.ContainersTest do
 | 
				
			|||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    test "list_tags/2 returns relevant tags for a user", %{current_user: current_user} do
 | 
					    test "list_tags/2 returns relevant tags for a user", %{current_user: current_user} do
 | 
				
			||||||
      tag_a = tag_fixture(%{"name" => "bullets"}, current_user)
 | 
					      tag_a = tag_fixture(%{name: "bullets"}, current_user)
 | 
				
			||||||
      tag_b = tag_fixture(%{"name" => "hollows"}, current_user)
 | 
					      tag_b = tag_fixture(%{name: "hollows"}, current_user)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      _shouldnt_return =
 | 
					      tag_fixture(%{name: "bullet", desc: "pews brass shell"}, user_fixture())
 | 
				
			||||||
        %{
 | 
					 | 
				
			||||||
          "name" => "bullet",
 | 
					 | 
				
			||||||
          "desc" => "pews brass shell"
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        |> tag_fixture(user_fixture())
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
      # name
 | 
					      # name
 | 
				
			||||||
      assert Containers.list_tags("bullet", current_user) == [tag_a]
 | 
					      assert Containers.list_tags("bullet", current_user) == [tag_a]
 | 
				
			||||||
@@ -186,9 +180,9 @@ defmodule Cannery.ContainersTest do
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    test "create_tag/2 with valid data creates a tag", %{current_user: current_user} do
 | 
					    test "create_tag/2 with valid data creates a tag", %{current_user: current_user} do
 | 
				
			||||||
      assert {:ok, %Tag{} = tag} = Containers.create_tag(@valid_tag_attrs, current_user)
 | 
					      assert {:ok, %Tag{} = tag} = Containers.create_tag(@valid_tag_attrs, current_user)
 | 
				
			||||||
      assert tag.bg_color == "some bg-color"
 | 
					      assert tag.bg_color == "#100000"
 | 
				
			||||||
      assert tag.name == "some name"
 | 
					      assert tag.name == "some name"
 | 
				
			||||||
      assert tag.text_color == "some text-color"
 | 
					      assert tag.text_color == "#000000"
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    test "create_tag/2 with invalid data returns error changeset",
 | 
					    test "create_tag/2 with invalid data returns error changeset",
 | 
				
			||||||
@@ -198,9 +192,9 @@ defmodule Cannery.ContainersTest do
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    test "update_tag/3 with valid data updates the tag", %{tag: tag, current_user: current_user} do
 | 
					    test "update_tag/3 with valid data updates the tag", %{tag: tag, current_user: current_user} do
 | 
				
			||||||
      assert {:ok, %Tag{} = tag} = Containers.update_tag(tag, @update_tag_attrs, current_user)
 | 
					      assert {:ok, %Tag{} = tag} = Containers.update_tag(tag, @update_tag_attrs, current_user)
 | 
				
			||||||
      assert tag.bg_color == "some updated bg-color"
 | 
					      assert tag.bg_color == "#100001"
 | 
				
			||||||
      assert tag.name == "some updated name"
 | 
					      assert tag.name == "some updated name"
 | 
				
			||||||
      assert tag.text_color == "some updated text-color"
 | 
					      assert tag.text_color == "#000001"
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    test "update_tag/3 with invalid data returns error changeset",
 | 
					    test "update_tag/3 with invalid data returns error changeset",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -11,19 +11,19 @@ defmodule CanneryWeb.ExportControllerTest do
 | 
				
			|||||||
  setup [:register_and_log_in_user]
 | 
					  setup [:register_and_log_in_user]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  defp add_data(%{current_user: current_user}) do
 | 
					  defp add_data(%{current_user: current_user}) do
 | 
				
			||||||
    ammo_type = ammo_type_fixture(current_user)
 | 
					    type = type_fixture(current_user)
 | 
				
			||||||
    container = container_fixture(current_user)
 | 
					    container = container_fixture(current_user)
 | 
				
			||||||
    tag = tag_fixture(current_user)
 | 
					    tag = tag_fixture(current_user)
 | 
				
			||||||
    Containers.add_tag!(container, tag, current_user)
 | 
					    Containers.add_tag!(container, tag, current_user)
 | 
				
			||||||
    {1, [ammo_group]} = ammo_group_fixture(ammo_type, container, current_user)
 | 
					    {1, [pack]} = pack_fixture(type, container, current_user)
 | 
				
			||||||
    shot_group = shot_group_fixture(current_user, ammo_group)
 | 
					    shot_record = shot_record_fixture(current_user, pack)
 | 
				
			||||||
    ammo_group = ammo_group |> Repo.reload!()
 | 
					    pack = pack |> Repo.reload!()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    %{
 | 
					    %{
 | 
				
			||||||
      ammo_type: ammo_type,
 | 
					      type: type,
 | 
				
			||||||
      ammo_group: ammo_group,
 | 
					      pack: pack,
 | 
				
			||||||
      container: container,
 | 
					      container: container,
 | 
				
			||||||
      shot_group: shot_group,
 | 
					      shot_record: shot_record,
 | 
				
			||||||
      tag: tag
 | 
					      tag: tag
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
@@ -35,56 +35,66 @@ defmodule CanneryWeb.ExportControllerTest do
 | 
				
			|||||||
      conn: conn,
 | 
					      conn: conn,
 | 
				
			||||||
      current_user: current_user,
 | 
					      current_user: current_user,
 | 
				
			||||||
      container: container,
 | 
					      container: container,
 | 
				
			||||||
      ammo_type: ammo_type,
 | 
					      type: type,
 | 
				
			||||||
      ammo_group: ammo_group,
 | 
					      pack: pack,
 | 
				
			||||||
      shot_group: shot_group,
 | 
					      shot_record: shot_record,
 | 
				
			||||||
      tag: tag
 | 
					      tag: tag
 | 
				
			||||||
    } do
 | 
					    } do
 | 
				
			||||||
      conn = get(conn, Routes.export_path(conn, :export, :json))
 | 
					      conn = get(conn, Routes.export_path(conn, :export, :json))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      ideal_ammo_group = %{
 | 
					      ideal_pack = %{
 | 
				
			||||||
        "ammo_type_id" => ammo_group.ammo_type_id,
 | 
					        "type_id" => pack.type_id,
 | 
				
			||||||
        "container_id" => ammo_group.container_id,
 | 
					        "container_id" => pack.container_id,
 | 
				
			||||||
        "count" => ammo_group.count,
 | 
					        "count" => pack.count,
 | 
				
			||||||
        "id" => ammo_group.id,
 | 
					        "id" => pack.id,
 | 
				
			||||||
        "notes" => ammo_group.notes,
 | 
					        "notes" => pack.notes,
 | 
				
			||||||
        "price_paid" => ammo_group.price_paid,
 | 
					        "price_paid" => pack.price_paid,
 | 
				
			||||||
        "staged" => ammo_group.staged,
 | 
					        "lot_number" => pack.lot_number,
 | 
				
			||||||
        "used_count" => ammo_group |> ActivityLog.get_used_count(current_user),
 | 
					        "staged" => pack.staged,
 | 
				
			||||||
        "original_count" => ammo_group |> Ammo.get_original_count(current_user),
 | 
					        "used_count" => pack |> ActivityLog.get_used_count(current_user),
 | 
				
			||||||
        "cpr" => ammo_group |> Ammo.get_cpr(current_user),
 | 
					        "original_count" => pack |> Ammo.get_original_count(current_user),
 | 
				
			||||||
        "percentage_remaining" => ammo_group |> Ammo.get_percentage_remaining(current_user)
 | 
					        "cpr" => pack |> Ammo.get_cpr(current_user),
 | 
				
			||||||
 | 
					        "percentage_remaining" => pack |> Ammo.get_percentage_remaining(current_user)
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      ideal_ammo_type = %{
 | 
					      ideal_type = %{
 | 
				
			||||||
        "blank" => ammo_type.blank,
 | 
					        "name" => type.name,
 | 
				
			||||||
        "bullet_core" => ammo_type.bullet_core,
 | 
					        "desc" => type.desc,
 | 
				
			||||||
        "bullet_type" => ammo_type.bullet_type,
 | 
					        "class" => to_string(type.class),
 | 
				
			||||||
        "caliber" => ammo_type.caliber,
 | 
					        "bullet_type" => type.bullet_type,
 | 
				
			||||||
        "cartridge" => ammo_type.cartridge,
 | 
					        "bullet_core" => type.bullet_core,
 | 
				
			||||||
        "case_material" => ammo_type.case_material,
 | 
					        "caliber" => type.caliber,
 | 
				
			||||||
        "corrosive" => ammo_type.corrosive,
 | 
					        "case_material" => type.case_material,
 | 
				
			||||||
        "desc" => ammo_type.desc,
 | 
					        "powder_type" => type.powder_type,
 | 
				
			||||||
        "firing_type" => ammo_type.firing_type,
 | 
					        "grains" => type.grains,
 | 
				
			||||||
        "grains" => ammo_type.grains,
 | 
					        "pressure" => type.pressure,
 | 
				
			||||||
        "id" => ammo_type.id,
 | 
					        "primer_type" => type.primer_type,
 | 
				
			||||||
        "incendiary" => ammo_type.incendiary,
 | 
					        "firing_type" => type.firing_type,
 | 
				
			||||||
        "jacket_type" => ammo_type.jacket_type,
 | 
					        "manufacturer" => type.manufacturer,
 | 
				
			||||||
        "manufacturer" => ammo_type.manufacturer,
 | 
					        "upc" => type.upc,
 | 
				
			||||||
        "muzzle_velocity" => ammo_type.muzzle_velocity,
 | 
					        "tracer" => type.tracer,
 | 
				
			||||||
        "name" => ammo_type.name,
 | 
					        "incendiary" => type.incendiary,
 | 
				
			||||||
        "powder_grains_per_charge" => ammo_type.powder_grains_per_charge,
 | 
					        "blank" => type.blank,
 | 
				
			||||||
        "powder_type" => ammo_type.powder_type,
 | 
					        "corrosive" => type.corrosive,
 | 
				
			||||||
        "pressure" => ammo_type.pressure,
 | 
					        "cartridge" => type.cartridge,
 | 
				
			||||||
        "primer_type" => ammo_type.primer_type,
 | 
					        "jacket_type" => type.jacket_type,
 | 
				
			||||||
        "tracer" => ammo_type.tracer,
 | 
					        "powder_grains_per_charge" => type.powder_grains_per_charge,
 | 
				
			||||||
        "upc" => ammo_type.upc,
 | 
					        "muzzle_velocity" => type.muzzle_velocity,
 | 
				
			||||||
        "average_cost" => ammo_type |> Ammo.get_average_cost_for_ammo_type(current_user),
 | 
					        "wadding" => type.wadding,
 | 
				
			||||||
        "round_count" => ammo_type |> Ammo.get_round_count_for_ammo_type(current_user),
 | 
					        "shot_type" => type.shot_type,
 | 
				
			||||||
        "used_count" => ammo_type |> ActivityLog.get_used_count_for_ammo_type(current_user),
 | 
					        "shot_material" => type.shot_material,
 | 
				
			||||||
        "ammo_group_count" => ammo_type |> Ammo.get_ammo_groups_count_for_type(current_user),
 | 
					        "shot_size" => type.shot_size,
 | 
				
			||||||
        "total_ammo_group_count" =>
 | 
					        "unfired_length" => type.unfired_length,
 | 
				
			||||||
          ammo_type |> Ammo.get_ammo_groups_count_for_type(current_user, true)
 | 
					        "brass_height" => type.brass_height,
 | 
				
			||||||
 | 
					        "chamber_size" => type.chamber_size,
 | 
				
			||||||
 | 
					        "load_grains" => type.load_grains,
 | 
				
			||||||
 | 
					        "shot_charge_weight" => type.shot_charge_weight,
 | 
				
			||||||
 | 
					        "dram_equivalent" => type.dram_equivalent,
 | 
				
			||||||
 | 
					        "average_cost" => type |> Ammo.get_average_cost_for_type(current_user),
 | 
				
			||||||
 | 
					        "round_count" => type |> Ammo.get_round_count_for_type(current_user),
 | 
				
			||||||
 | 
					        "used_count" => type |> ActivityLog.get_used_count_for_type(current_user),
 | 
				
			||||||
 | 
					        "pack_count" => type |> Ammo.get_packs_count_for_type(current_user),
 | 
				
			||||||
 | 
					        "total_pack_count" => type |> Ammo.get_packs_count_for_type(current_user, true)
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      ideal_container = %{
 | 
					      ideal_container = %{
 | 
				
			||||||
@@ -101,17 +111,16 @@ defmodule CanneryWeb.ExportControllerTest do
 | 
				
			|||||||
          }
 | 
					          }
 | 
				
			||||||
        ],
 | 
					        ],
 | 
				
			||||||
        "type" => container.type,
 | 
					        "type" => container.type,
 | 
				
			||||||
        "ammo_group_count" =>
 | 
					        "pack_count" => container |> Ammo.get_packs_count_for_container!(current_user),
 | 
				
			||||||
          container |> Ammo.get_ammo_groups_count_for_container!(current_user),
 | 
					 | 
				
			||||||
        "round_count" => container |> Ammo.get_round_count_for_container!(current_user)
 | 
					        "round_count" => container |> Ammo.get_round_count_for_container!(current_user)
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      ideal_shot_group = %{
 | 
					      ideal_shot_record = %{
 | 
				
			||||||
        "ammo_group_id" => shot_group.ammo_group_id,
 | 
					        "pack_id" => shot_record.pack_id,
 | 
				
			||||||
        "count" => shot_group.count,
 | 
					        "count" => shot_record.count,
 | 
				
			||||||
        "date" => to_string(shot_group.date),
 | 
					        "date" => to_string(shot_record.date),
 | 
				
			||||||
        "id" => shot_group.id,
 | 
					        "id" => shot_record.id,
 | 
				
			||||||
        "notes" => shot_group.notes
 | 
					        "notes" => shot_record.notes
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      ideal_user = %{
 | 
					      ideal_user = %{
 | 
				
			||||||
@@ -126,10 +135,10 @@ defmodule CanneryWeb.ExportControllerTest do
 | 
				
			|||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      json_resp = conn |> json_response(200)
 | 
					      json_resp = conn |> json_response(200)
 | 
				
			||||||
      assert %{"ammo_groups" => [^ideal_ammo_group]} = json_resp
 | 
					      assert %{"packs" => [^ideal_pack]} = json_resp
 | 
				
			||||||
      assert %{"ammo_types" => [^ideal_ammo_type]} = json_resp
 | 
					      assert %{"types" => [^ideal_type]} = json_resp
 | 
				
			||||||
      assert %{"containers" => [^ideal_container]} = json_resp
 | 
					      assert %{"containers" => [^ideal_container]} = json_resp
 | 
				
			||||||
      assert %{"shot_groups" => [^ideal_shot_group]} = json_resp
 | 
					      assert %{"shot_records" => [^ideal_shot_record]} = json_resp
 | 
				
			||||||
      assert %{"user" => ^ideal_user} = json_resp
 | 
					      assert %{"user" => ^ideal_user} = json_resp
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,7 +4,6 @@ defmodule CanneryWeb.UserAuthTest do
 | 
				
			|||||||
  """
 | 
					  """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  use CanneryWeb.ConnCase, async: true
 | 
					  use CanneryWeb.ConnCase, async: true
 | 
				
			||||||
  import CanneryWeb.Gettext
 | 
					 | 
				
			||||||
  alias Cannery.Accounts
 | 
					  alias Cannery.Accounts
 | 
				
			||||||
  alias CanneryWeb.UserAuth
 | 
					  alias CanneryWeb.UserAuth
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -148,7 +147,7 @@ defmodule CanneryWeb.UserAuthTest do
 | 
				
			|||||||
      assert redirected_to(conn) == Routes.user_session_path(conn, :new)
 | 
					      assert redirected_to(conn) == Routes.user_session_path(conn, :new)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      assert get_flash(conn, :error) ==
 | 
					      assert get_flash(conn, :error) ==
 | 
				
			||||||
               dgettext("errors", "You must confirm your account and log in to access this page.")
 | 
					               "You must confirm your account and log in to access this page."
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    test "stores the path to redirect to on GET", %{conn: conn} do
 | 
					    test "stores the path to redirect to on GET", %{conn: conn} do
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,7 +4,6 @@ defmodule CanneryWeb.UserConfirmationControllerTest do
 | 
				
			|||||||
  """
 | 
					  """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  use CanneryWeb.ConnCase, async: true
 | 
					  use CanneryWeb.ConnCase, async: true
 | 
				
			||||||
  import CanneryWeb.Gettext
 | 
					 | 
				
			||||||
  alias Cannery.{Accounts, Repo}
 | 
					  alias Cannery.{Accounts, Repo}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @moduletag :user_confirmation_controller_test
 | 
					  @moduletag :user_confirmation_controller_test
 | 
				
			||||||
@@ -17,7 +16,7 @@ defmodule CanneryWeb.UserConfirmationControllerTest do
 | 
				
			|||||||
    test "renders the confirmation page", %{conn: conn} do
 | 
					    test "renders the confirmation page", %{conn: conn} do
 | 
				
			||||||
      conn = get(conn, Routes.user_confirmation_path(conn, :new))
 | 
					      conn = get(conn, Routes.user_confirmation_path(conn, :new))
 | 
				
			||||||
      response = html_response(conn, 200)
 | 
					      response = html_response(conn, 200)
 | 
				
			||||||
      assert response =~ dgettext("actions", "Resend confirmation instructions")
 | 
					      assert response =~ "Resend confirmation instructions"
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -25,18 +24,12 @@ defmodule CanneryWeb.UserConfirmationControllerTest do
 | 
				
			|||||||
    @tag :capture_log
 | 
					    @tag :capture_log
 | 
				
			||||||
    test "sends a new confirmation token", %{conn: conn, user: user} do
 | 
					    test "sends a new confirmation token", %{conn: conn, user: user} do
 | 
				
			||||||
      conn =
 | 
					      conn =
 | 
				
			||||||
        post(conn, Routes.user_confirmation_path(conn, :create), %{
 | 
					        post(conn, Routes.user_confirmation_path(conn, :create), %{user: %{email: user.email}})
 | 
				
			||||||
          "user" => %{"email" => user.email}
 | 
					 | 
				
			||||||
        })
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
      assert redirected_to(conn) == "/"
 | 
					      assert redirected_to(conn) == "/"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      assert get_flash(conn, :info) =~
 | 
					      assert get_flash(conn, :info) =~
 | 
				
			||||||
               dgettext(
 | 
					               "If your email is in our system and it has not been confirmed yet, you will receive an email with instructions shortly."
 | 
				
			||||||
                 "prompts",
 | 
					 | 
				
			||||||
                 "If your email is in our system and it has not been confirmed yet, " <>
 | 
					 | 
				
			||||||
                   "you will receive an email with instructions shortly."
 | 
					 | 
				
			||||||
               )
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
      assert Repo.get_by!(Accounts.UserToken, user_id: user.id).context == "confirm"
 | 
					      assert Repo.get_by!(Accounts.UserToken, user_id: user.id).context == "confirm"
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
@@ -45,34 +38,24 @@ defmodule CanneryWeb.UserConfirmationControllerTest do
 | 
				
			|||||||
      Repo.update!(Accounts.User.confirm_changeset(user))
 | 
					      Repo.update!(Accounts.User.confirm_changeset(user))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      conn =
 | 
					      conn =
 | 
				
			||||||
        post(conn, Routes.user_confirmation_path(conn, :create), %{
 | 
					        post(conn, Routes.user_confirmation_path(conn, :create), %{user: %{email: user.email}})
 | 
				
			||||||
          "user" => %{"email" => user.email}
 | 
					 | 
				
			||||||
        })
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
      assert redirected_to(conn) == "/"
 | 
					      assert redirected_to(conn) == "/"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      assert get_flash(conn, :info) =~
 | 
					      assert get_flash(conn, :info) =~
 | 
				
			||||||
               dgettext(
 | 
					               "If your email is in our system and it has not been confirmed yet, you will receive an email with instructions shortly."
 | 
				
			||||||
                 "prompts",
 | 
					 | 
				
			||||||
                 "If your email is in our system and it has not been confirmed yet, " <>
 | 
					 | 
				
			||||||
                   "you will receive an email with instructions shortly."
 | 
					 | 
				
			||||||
               )
 | 
					 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    test "does not send confirmation token if email is invalid", %{conn: conn} do
 | 
					    test "does not send confirmation token if email is invalid", %{conn: conn} do
 | 
				
			||||||
      conn =
 | 
					      conn =
 | 
				
			||||||
        post(conn, Routes.user_confirmation_path(conn, :create), %{
 | 
					        post(conn, Routes.user_confirmation_path(conn, :create), %{
 | 
				
			||||||
          "user" => %{"email" => "unknown@example.com"}
 | 
					          user: %{email: "unknown@example.com"}
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      assert redirected_to(conn) == "/"
 | 
					      assert redirected_to(conn) == "/"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      assert get_flash(conn, :info) =~
 | 
					      assert get_flash(conn, :info) =~
 | 
				
			||||||
               dgettext(
 | 
					               "If your email is in our system and it has not been confirmed yet, you will receive an email with instructions shortly."
 | 
				
			||||||
                 "prompts",
 | 
					 | 
				
			||||||
                 "If your email is in our system and it has not been confirmed yet, " <>
 | 
					 | 
				
			||||||
                   "you will receive an email with instructions shortly."
 | 
					 | 
				
			||||||
               )
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
      assert Repo.all(Accounts.UserToken) == []
 | 
					      assert Repo.all(Accounts.UserToken) == []
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
@@ -87,10 +70,7 @@ defmodule CanneryWeb.UserConfirmationControllerTest do
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
      conn = get(conn, Routes.user_confirmation_path(conn, :confirm, token))
 | 
					      conn = get(conn, Routes.user_confirmation_path(conn, :confirm, token))
 | 
				
			||||||
      assert redirected_to(conn) == "/"
 | 
					      assert redirected_to(conn) == "/"
 | 
				
			||||||
 | 
					      assert get_flash(conn, :info) =~ "#{user.email} confirmed successfully"
 | 
				
			||||||
      assert get_flash(conn, :info) =~
 | 
					 | 
				
			||||||
               dgettext("prompts", "%{email} confirmed successfully", email: user.email)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      assert Accounts.get_user!(user.id).confirmed_at
 | 
					      assert Accounts.get_user!(user.id).confirmed_at
 | 
				
			||||||
      refute get_session(conn, :user_token)
 | 
					      refute get_session(conn, :user_token)
 | 
				
			||||||
      assert Repo.all(Accounts.UserToken) == []
 | 
					      assert Repo.all(Accounts.UserToken) == []
 | 
				
			||||||
@@ -99,8 +79,7 @@ defmodule CanneryWeb.UserConfirmationControllerTest do
 | 
				
			|||||||
      conn = get(conn, Routes.user_confirmation_path(conn, :confirm, token))
 | 
					      conn = get(conn, Routes.user_confirmation_path(conn, :confirm, token))
 | 
				
			||||||
      assert redirected_to(conn) == "/"
 | 
					      assert redirected_to(conn) == "/"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      assert get_flash(conn, :error) =~
 | 
					      assert get_flash(conn, :error) =~ "User confirmation link is invalid or it has expired"
 | 
				
			||||||
               dgettext("errors", "User confirmation link is invalid or it has expired")
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
      # When logged in
 | 
					      # When logged in
 | 
				
			||||||
      conn =
 | 
					      conn =
 | 
				
			||||||
@@ -115,10 +94,7 @@ defmodule CanneryWeb.UserConfirmationControllerTest do
 | 
				
			|||||||
    test "does not confirm email with invalid token", %{conn: conn, user: user} do
 | 
					    test "does not confirm email with invalid token", %{conn: conn, user: user} do
 | 
				
			||||||
      conn = get(conn, Routes.user_confirmation_path(conn, :confirm, "oops"))
 | 
					      conn = get(conn, Routes.user_confirmation_path(conn, :confirm, "oops"))
 | 
				
			||||||
      assert redirected_to(conn) == "/"
 | 
					      assert redirected_to(conn) == "/"
 | 
				
			||||||
 | 
					      assert get_flash(conn, :error) =~ "User confirmation link is invalid or it has expired"
 | 
				
			||||||
      assert get_flash(conn, :error) =~
 | 
					 | 
				
			||||||
               dgettext("errors", "User confirmation link is invalid or it has expired")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      refute Accounts.get_user!(user.id).confirmed_at
 | 
					      refute Accounts.get_user!(user.id).confirmed_at
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 
 | 
				
			|||||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user