Compare commits

...

21 Commits

Author SHA1 Message Date
9835fe3f5e bump version
All checks were successful
continuous-integration/drone/push Build is passing
2023-03-30 22:32:53 -04:00
4dee8808f3 improve migrations 2023-03-30 22:24:29 -04:00
65c70ca398 fix name collisions 2023-03-30 22:23:54 -04:00
550f6a6420 add migration for ammo type table and column 2023-03-30 22:02:44 -04:00
88c3f15fc8 rename ammo type files to type 2023-03-30 22:02:36 -04:00
c33f15603b rename ammo type to type 2023-03-30 22:02:36 -04:00
98775359af rename shot groups to shot records in database 2023-03-30 21:39:08 -04:00
e0e7b25bc4 add more text replacements 2023-03-30 21:38:56 -04:00
bdddf65685 remove unnecessary index churn 2023-03-30 21:38:09 -04:00
6f50702b11 rename shot group files to shot record 2023-03-30 20:44:41 -04:00
5f8d1a917f shot groups to shot records 2023-03-30 20:43:30 -04:00
32801828fa fix shot records table disappearing after selecting an empty ammo class
All checks were successful
continuous-integration/drone/push Build is passing
2023-03-30 20:08:37 -04:00
6ed3312ea8 add db migrations for ammo group to pack and ammo type class 2023-03-30 20:08:26 -04:00
b122253b9b improve tests 2023-03-30 20:08:20 -04:00
a68a16bf06 fix ammo type table not displaying class 2023-03-30 20:08:14 -04:00
4b6d0952f8 rename ammo groups to packs everywhere 2023-03-30 20:08:11 -04:00
0544b58ab6 rename ammo group files to pack 2023-03-30 20:07:28 -04:00
6d26103784 rename ammo groups to packs 2023-03-30 20:07:16 -04:00
0cae7c2940 rename ammo_type type to class
All checks were successful
continuous-integration/drone/push Build is passing
2023-03-28 23:08:40 -04:00
1e645b5bb8 generate fonts with correct filename
All checks were successful
continuous-integration/drone/push Build is passing
2023-03-28 22:03:14 -04:00
bab2b26c13 use atom keys in tests
All checks were successful
continuous-integration/drone/push Build is passing
2023-03-28 21:57:29 -04:00
95 changed files with 6408 additions and 6432 deletions

View File

@ -1,3 +1,10 @@
# 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 # v0.9.0
- Add length limits to all string fields - Add length limits to all string fields
- Add selectable ammo types - Add selectable ammo types
@ -51,7 +58,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!)
@ -63,7 +70,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
@ -72,8 +79,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
@ -97,7 +104,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
@ -149,8 +156,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

View File

@ -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

View File

@ -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

View File

@ -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]' }
} }
] ]
}, },

View File

@ -4,50 +4,50 @@ 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, Queryable} alias Ecto.{Multi, Queryable}
@doc """ @doc """
Returns the list of shot_groups. Returns the list of shot_records.
## Examples ## Examples
iex> list_shot_groups(:all, %User{id: 123}) iex> list_shot_records(:all, %User{id: 123})
[%ShotGroup{}, ...] [%ShotRecord{}, ...]
iex> list_shot_groups("cool", :all, %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_groups("cool", :rifle, %User{id: 123}) iex> list_shot_records("cool", :rifle, %User{id: 123})
[%ShotGroup{notes: "Shot some rifle rounds"}, ...] [%ShotRecord{notes: "Shot some rifle rounds"}, ...]
""" """
@spec list_shot_groups(AmmoType.type() | :all, User.t()) :: [ShotGroup.t()] @spec list_shot_records(Type.class() | :all, User.t()) :: [ShotRecord.t()]
@spec list_shot_groups(search :: nil | String.t(), AmmoType.type() | :all, User.t()) :: @spec list_shot_records(search :: nil | String.t(), Type.class() | :all, User.t()) ::
[ShotGroup.t()] [ShotRecord.t()]
def list_shot_groups(search \\ nil, type, %{id: user_id}) do def list_shot_records(search \\ nil, type, %{id: user_id}) do
from(sg in ShotGroup, from(sg in ShotRecord,
as: :sg, as: :sg,
left_join: ag in AmmoGroup, left_join: ag in Pack,
as: :ag, as: :ag,
on: sg.ammo_group_id == ag.id, on: sg.pack_id == ag.id,
left_join: at in AmmoType, left_join: at in Type,
as: :at, as: :at,
on: ag.ammo_type_id == at.id, on: ag.type_id == at.id,
where: sg.user_id == ^user_id, where: sg.user_id == ^user_id,
distinct: sg.id distinct: sg.id
) )
|> list_shot_groups_search(search) |> list_shot_records_search(search)
|> list_shot_groups_filter_type(type) |> list_shot_records_filter_type(type)
|> Repo.all() |> Repo.all()
end end
@spec list_shot_groups_search(Queryable.t(), search :: String.t() | nil) :: @spec list_shot_records_search(Queryable.t(), search :: String.t() | nil) ::
Queryable.t() Queryable.t()
defp list_shot_groups_search(query, search) when search in ["", nil], do: query defp list_shot_records_search(query, search) when search in ["", nil], do: query
defp list_shot_groups_search(query, search) when search |> is_binary() do defp list_shot_records_search(query, search) when search |> is_binary() do
trimmed_search = String.trim(search) trimmed_search = String.trim(search)
query query
@ -79,49 +79,68 @@ defmodule Cannery.ActivityLog do
}) })
end end
@spec list_shot_groups_filter_type(Queryable.t(), AmmoType.type() | :all) :: @spec list_shot_records_filter_type(Queryable.t(), Type.class() | :all) ::
Queryable.t() Queryable.t()
defp list_shot_groups_filter_type(query, :rifle), defp list_shot_records_filter_type(query, :rifle),
do: query |> where([at: at], at.type == :rifle) do: query |> where([at: at], at.class == :rifle)
defp list_shot_groups_filter_type(query, :pistol), defp list_shot_records_filter_type(query, :pistol),
do: query |> where([at: at], at.type == :pistol) do: query |> where([at: at], at.class == :pistol)
defp list_shot_groups_filter_type(query, :shotgun), defp list_shot_records_filter_type(query, :shotgun),
do: query |> where([at: at], at.type == :shotgun) do: query |> where([at: at], at.class == :shotgun)
defp list_shot_groups_filter_type(query, _all), do: query defp list_shot_records_filter_type(query, _all), do: query
@spec list_shot_groups_for_ammo_group(AmmoGroup.t(), User.t()) :: [ShotGroup.t()] @doc """
def list_shot_groups_for_ammo_group( Returns a count of shot records.
%AmmoGroup{id: ammo_group_id, user_id: user_id},
## 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
@ -129,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

View File

@ -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,59 +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_length(:notes, max: 255) |> validate_length(:notes, max: 255)
|> validate_create_shot_group_count(ammo_group) |> validate_create_shot_record_count(pack)
|> validate_required([:date, :ammo_group_id, :user_id]) |> 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_length(:notes, max: 255) |> validate_length(:notes, max: 255)
|> validate_required([:ammo_group_id, :user_id]) |> 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)
@ -97,29 +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_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

File diff suppressed because it is too large Load Diff

View File

@ -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}
@ -20,19 +20,19 @@ defmodule Cannery.Ammo.AmmoGroup do
:notes, :notes,
:price_paid, :price_paid,
: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 :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
@ -46,56 +46,56 @@ defmodule Cannery.Ammo.AmmoGroup do
price_paid: float() | nil, price_paid: float() | nil,
staged: boolean(), staged: boolean(),
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])
|> 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_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")) |> 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, :container_id])
|> validate_number(:count, greater_than_or_equal_to: 0) |> validate_number(:count, greater_than_or_equal_to: 0)
|> validate_container_id(user) |> validate_container_id(user)
@ -113,12 +113,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

View File

@ -1,4 +1,4 @@
defmodule Cannery.Ammo.AmmoType do defmodule Cannery.Ammo.Type do
@moduledoc """ @moduledoc """
An ammunition type. An ammunition type.
@ -8,7 +8,7 @@ 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,
@ -38,11 +38,11 @@ defmodule Cannery.Ammo.AmmoType do
]} ]}
@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
field :type, Ecto.Enum, values: [:rifle, :shotgun, :pistol] field :class, Ecto.Enum, values: [:rifle, :shotgun, :pistol]
# common fields # common fields
# https://shootersreference.com/reloadingdata/bullet_abbreviations/ # https://shootersreference.com/reloadingdata/bullet_abbreviations/
@ -83,7 +83,7 @@ defmodule Cannery.Ammo.AmmoType do
field :dram_equivalent, :string field :dram_equivalent, :string
field :user_id, :binary_id field :user_id, :binary_id
has_many :ammo_groups, AmmoGroup has_many :packs, Pack
timestamps() timestamps()
end end
@ -92,7 +92,7 @@ defmodule Cannery.Ammo.AmmoType do
id: id(), id: id(),
name: String.t(), name: String.t(),
desc: String.t() | nil, desc: String.t() | nil,
type: type(), 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, cartridge: String.t() | nil,
@ -123,21 +123,21 @@ defmodule Cannery.Ammo.AmmoType do
manufacturer: String.t() | nil, manufacturer: String.t() | nil,
upc: String.t() | nil, upc: 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 type :: :rifle | :shotgun | :pistol | nil @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,
:type, :class,
:bullet_type, :bullet_type,
:bullet_core, :bullet_core,
:cartridge, :cartridge,
@ -197,10 +197,10 @@ defmodule Cannery.Ammo.AmmoType do
] ]
@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
changeset = changeset =
ammo_type type
|> change(user_id: user_id) |> change(user_id: user_id)
|> cast(attrs, changeset_fields()) |> cast(attrs, changeset_fields())
@ -210,10 +210,10 @@ defmodule Cannery.Ammo.AmmoType do
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
changeset = changeset =
ammo_type type
|> cast(attrs, changeset_fields()) |> cast(attrs, changeset_fields())
string_fields() string_fields()

View File

@ -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

View File

@ -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

View File

@ -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,7 +37,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: "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, maxlength: 255,
placeholder: gettext("Really great weather"), placeholder: gettext("Really great weather"),

View File

@ -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)
} }

View File

@ -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)

View File

@ -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">

View File

@ -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">

View File

@ -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") %>

View File

@ -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}
/> />

View File

@ -1,9 +1,9 @@
defmodule CanneryWeb.Components.AmmoGroupTableComponent do defmodule CanneryWeb.Components.PackTableComponent do
@moduledoc """ @moduledoc """
A component that displays a list of ammo groups A component that displays a list of packs
""" """
use CanneryWeb, :live_component use CanneryWeb, :live_component
alias Cannery.{Accounts.User, Ammo.AmmoGroup, ComparableDate} alias Cannery.{Accounts.User, Ammo.Pack, ComparableDate}
alias Cannery.{ActivityLog, Ammo, Containers} alias Cannery.{ActivityLog, Ammo, Containers}
alias CanneryWeb.Components.TableComponent alias CanneryWeb.Components.TableComponent
alias Ecto.UUID alias Ecto.UUID
@ -14,9 +14,9 @@ defmodule CanneryWeb.Components.AmmoGroupTableComponent do
%{ %{
required(:id) => UUID.t(), required(:id) => UUID.t(),
required(:current_user) => User.t(), required(:current_user) => User.t(),
required(:ammo_groups) => [AmmoGroup.t()], required(:packs) => [Pack.t()],
required(:show_used) => boolean(), required(:show_used) => boolean(),
optional(:ammo_type) => Rendered.t(), optional(:type) => Rendered.t(),
optional(:range) => Rendered.t(), optional(:range) => Rendered.t(),
optional(:container) => Rendered.t(), optional(:container) => Rendered.t(),
optional(:actions) => Rendered.t(), optional(:actions) => Rendered.t(),
@ -25,28 +25,27 @@ defmodule CanneryWeb.Components.AmmoGroupTableComponent do
Socket.t() Socket.t()
) :: {:ok, Socket.t()} ) :: {:ok, Socket.t()}
def update( def update(
%{id: _id, ammo_groups: _ammo_group, current_user: _current_user, show_used: _show_used} = %{id: _id, packs: _pack, current_user: _current_user, show_used: _show_used} = assigns,
assigns,
socket socket
) do ) do
socket = socket =
socket socket
|> assign(assigns) |> assign(assigns)
|> assign_new(:ammo_type, fn -> [] end) |> assign_new(:type, fn -> [] end)
|> assign_new(:range, fn -> [] end) |> assign_new(:range, fn -> [] end)
|> assign_new(:container, fn -> [] end) |> assign_new(:container, fn -> [] end)
|> assign_new(:actions, fn -> [] end) |> assign_new(:actions, fn -> [] end)
|> display_ammo_groups() |> display_packs()
{:ok, socket} {:ok, socket}
end end
defp display_ammo_groups( defp display_packs(
%{ %{
assigns: %{ assigns: %{
ammo_groups: ammo_groups, packs: packs,
current_user: current_user, current_user: current_user,
ammo_type: ammo_type, type: type,
range: range, range: range,
container: container, container: container,
actions: actions, actions: actions,
@ -93,33 +92,33 @@ defmodule CanneryWeb.Components.AmmoGroupTableComponent do
key: :count key: :count
}) })
|> TableComponent.maybe_compose_columns( |> TableComponent.maybe_compose_columns(
%{label: gettext("Ammo type"), key: :ammo_type}, %{label: gettext("Type"), key: :type},
ammo_type != [] type != []
) )
containers = containers =
ammo_groups packs
|> Enum.map(fn %{container_id: container_id} -> container_id end) |> Enum.map(fn %{container_id: container_id} -> container_id end)
|> Containers.get_containers(current_user) |> Containers.get_containers(current_user)
extra_data = %{ extra_data = %{
current_user: current_user, current_user: current_user,
ammo_type: ammo_type, type: type,
columns: columns, columns: columns,
container: container, container: container,
containers: containers, containers: containers,
original_counts: Ammo.get_original_counts(ammo_groups, current_user), original_counts: Ammo.get_original_counts(packs, current_user),
cprs: Ammo.get_cprs(ammo_groups, current_user), cprs: Ammo.get_cprs(packs, current_user),
last_used_dates: ActivityLog.get_last_used_dates(ammo_groups, current_user), last_used_dates: ActivityLog.get_last_used_dates(packs, current_user),
percentages_remaining: Ammo.get_percentages_remaining(ammo_groups, current_user), percentages_remaining: Ammo.get_percentages_remaining(packs, current_user),
actions: actions, actions: actions,
range: range range: range
} }
rows = rows =
ammo_groups packs
|> Enum.map(fn ammo_group -> |> Enum.map(fn pack ->
ammo_group |> get_row_data_for_ammo_group(extra_data) pack |> get_row_data_for_pack(extra_data)
end) end)
socket |> assign(columns: columns, rows: rows) socket |> assign(columns: columns, rows: rows)
@ -134,26 +133,26 @@ defmodule CanneryWeb.Components.AmmoGroupTableComponent do
""" """
end end
@spec get_row_data_for_ammo_group(AmmoGroup.t(), additional_data :: map()) :: map() @spec get_row_data_for_pack(Pack.t(), additional_data :: map()) :: map()
defp get_row_data_for_ammo_group(ammo_group, %{columns: columns} = additional_data) do defp get_row_data_for_pack(pack, %{columns: columns} = additional_data) do
columns columns
|> Map.new(fn %{key: key} -> |> Map.new(fn %{key: key} ->
{key, get_value_for_key(key, ammo_group, additional_data)} {key, get_value_for_key(key, pack, additional_data)}
end) end)
end end
@spec get_value_for_key(atom(), AmmoGroup.t(), additional_data :: map()) :: @spec get_value_for_key(atom(), Pack.t(), additional_data :: map()) ::
any() | {any(), Rendered.t()} any() | {any(), Rendered.t()}
defp get_value_for_key( defp get_value_for_key(
:ammo_type, :type,
%{ammo_type: %{name: ammo_type_name} = ammo_type}, %{type: %{name: type_name} = type},
%{ammo_type: ammo_type_block} %{type: type_block}
) do ) do
assigns = %{ammo_type: ammo_type, ammo_type_block: ammo_type_block} assigns = %{type: type, type_block: type_block}
{ammo_type_name, {type_name,
~H""" ~H"""
<%= render_slot(@ammo_type_block, @ammo_type) %> <%= render_slot(@type_block, @type) %>
"""} """}
end end
@ -170,9 +169,9 @@ defmodule CanneryWeb.Components.AmmoGroupTableComponent do
"""} """}
end end
defp get_value_for_key(:used_up_on, %{id: ammo_group_id}, %{last_used_dates: last_used_dates}) do 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(ammo_group_id) last_used_date = last_used_dates |> Map.get(pack_id)
assigns = %{id: ammo_group_id, last_used_date: last_used_date} assigns = %{id: pack_id, last_used_date: last_used_date}
{last_used_date, {last_used_date,
~H""" ~H"""
@ -184,29 +183,29 @@ defmodule CanneryWeb.Components.AmmoGroupTableComponent do
"""} """}
end end
defp get_value_for_key(:range, %{staged: staged} = ammo_group, %{range: range}) do defp get_value_for_key(:range, %{staged: staged} = pack, %{range: range}) do
assigns = %{range: range, ammo_group: ammo_group} assigns = %{range: range, pack: pack}
{staged, {staged,
~H""" ~H"""
<%= render_slot(@range, @ammo_group) %> <%= render_slot(@range, @pack) %>
"""} """}
end end
defp get_value_for_key( defp get_value_for_key(
:remaining, :remaining,
%{id: ammo_group_id}, %{id: pack_id},
%{percentages_remaining: percentages_remaining} %{percentages_remaining: percentages_remaining}
) do ) do
percentage = Map.fetch!(percentages_remaining, ammo_group_id) percentage = Map.fetch!(percentages_remaining, pack_id)
{percentage, gettext("%{percentage}%", percentage: percentage)} {percentage, gettext("%{percentage}%", percentage: percentage)}
end end
defp get_value_for_key(:actions, ammo_group, %{actions: actions}) do defp get_value_for_key(:actions, pack, %{actions: actions}) do
assigns = %{actions: actions, ammo_group: ammo_group} assigns = %{actions: actions, pack: pack}
~H""" ~H"""
<%= render_slot(@actions, @ammo_group) %> <%= render_slot(@actions, @pack) %>
""" """
end end
@ -214,7 +213,7 @@ defmodule CanneryWeb.Components.AmmoGroupTableComponent do
defp get_value_for_key( defp get_value_for_key(
:container, :container,
%{container_id: container_id} = ammo_group, %{container_id: container_id} = pack,
%{container: container_block, containers: containers} %{container: container_block, containers: containers}
) do ) do
container = %{name: container_name} = Map.fetch!(containers, container_id) container = %{name: container_name} = Map.fetch!(containers, container_id)
@ -222,35 +221,35 @@ defmodule CanneryWeb.Components.AmmoGroupTableComponent do
assigns = %{ assigns = %{
container: container, container: container,
container_block: container_block, container_block: container_block,
ammo_group: ammo_group pack: pack
} }
{container_name, {container_name,
~H""" ~H"""
<%= render_slot(@container_block, {@ammo_group, @container}) %> <%= render_slot(@container_block, {@pack, @container}) %>
"""} """}
end end
defp get_value_for_key( defp get_value_for_key(
:original_count, :original_count,
%{id: ammo_group_id}, %{id: pack_id},
%{original_counts: original_counts} %{original_counts: original_counts}
) do ) do
Map.fetch!(original_counts, ammo_group_id) Map.fetch!(original_counts, pack_id)
end end
defp get_value_for_key(:cpr, %{price_paid: nil}, _additional_data), defp get_value_for_key(:cpr, %{price_paid: nil}, _additional_data),
do: {0, gettext("No cost information")} do: {0, gettext("No cost information")}
defp get_value_for_key(:cpr, %{id: ammo_group_id}, %{cprs: cprs}) do defp get_value_for_key(:cpr, %{id: pack_id}, %{cprs: cprs}) do
amount = Map.fetch!(cprs, ammo_group_id) amount = Map.fetch!(cprs, pack_id)
{amount, gettext("$%{amount}", amount: display_currency(amount))} {amount, gettext("$%{amount}", amount: display_currency(amount))}
end end
defp get_value_for_key(:count, %{count: count}, _additional_data), defp get_value_for_key(:count, %{count: count}, _additional_data),
do: if(count == 0, do: {0, gettext("Empty")}, else: count) 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) defp get_value_for_key(key, pack, _additional_data), do: pack |> Map.get(key)
@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)

View File

@ -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

View File

@ -1,9 +1,9 @@
defmodule CanneryWeb.Components.AmmoTypeTableComponent do defmodule CanneryWeb.Components.TypeTableComponent do
@moduledoc """ @moduledoc """
A component that displays a list of ammo type A component that displays a list of types
""" """
use CanneryWeb, :live_component use CanneryWeb, :live_component
alias Cannery.{Accounts.User, ActivityLog, Ammo, Ammo.AmmoType} alias Cannery.{Accounts.User, ActivityLog, Ammo, Ammo.Type}
alias CanneryWeb.Components.TableComponent alias CanneryWeb.Components.TableComponent
alias Ecto.UUID alias Ecto.UUID
alias Phoenix.LiveView.{Rendered, Socket} alias Phoenix.LiveView.{Rendered, Socket}
@ -13,33 +13,33 @@ defmodule CanneryWeb.Components.AmmoTypeTableComponent do
%{ %{
required(:id) => UUID.t(), required(:id) => UUID.t(),
required(:current_user) => User.t(), required(:current_user) => User.t(),
optional(:type) => AmmoType.type() | nil, optional(:class) => Type.class() | nil,
optional(:show_used) => boolean(), optional(:show_used) => boolean(),
optional(:ammo_types) => [AmmoType.t()], optional(:types) => [Type.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, ammo_types: _ammo_types, current_user: _current_user} = assigns, socket) do def update(%{id: _id, types: _types, current_user: _current_user} = assigns, socket) do
socket = socket =
socket socket
|> assign(assigns) |> assign(assigns)
|> assign_new(:show_used, fn -> false end) |> assign_new(:show_used, fn -> false end)
|> assign_new(:type, fn -> :all end) |> assign_new(:class, fn -> :all end)
|> assign_new(:actions, fn -> [] end) |> assign_new(:actions, fn -> [] end)
|> display_ammo_types() |> display_types()
{:ok, socket} {:ok, socket}
end end
defp display_ammo_types( defp display_types(
%{ %{
assigns: %{ assigns: %{
ammo_types: ammo_types, types: types,
current_user: current_user, current_user: current_user,
show_used: show_used, show_used: show_used,
type: type, class: class,
actions: actions actions: actions
} }
} = socket } = socket
@ -48,7 +48,7 @@ defmodule CanneryWeb.Components.AmmoTypeTableComponent do
[ [
%{label: gettext("Cartridge"), key: :cartridge, type: :string}, %{label: gettext("Cartridge"), key: :cartridge, type: :string},
%{ %{
label: if(type == :shotgun, do: gettext("Gauge"), else: gettext("Caliber")), label: if(class == :shotgun, do: gettext("Gauge"), else: gettext("Caliber")),
key: :caliber, key: :caliber,
type: :string type: :string
}, },
@ -59,7 +59,7 @@ defmodule CanneryWeb.Components.AmmoTypeTableComponent do
%{label: gettext("Grains"), key: :grains, type: :string}, %{label: gettext("Grains"), key: :grains, type: :string},
%{label: gettext("Bullet type"), key: :bullet_type, type: :string}, %{label: gettext("Bullet type"), key: :bullet_type, type: :string},
%{ %{
label: if(type == :shotgun, do: gettext("Slug core"), else: gettext("Bullet core")), label: if(class == :shotgun, do: gettext("Slug core"), else: gettext("Bullet core")),
key: :bullet_core, key: :bullet_core,
type: :string type: :string
}, },
@ -92,8 +92,8 @@ defmodule CanneryWeb.Components.AmmoTypeTableComponent do
# remove columns if all values match defaults # remove columns if all values match defaults
default_value = if type == :atom, do: false, else: nil default_value = if type == :atom, do: false, else: nil
ammo_types types
|> Enum.any?(fn ammo_type -> Map.get(ammo_type, key, default_value) != default_value end) |> Enum.any?(fn type -> Map.get(type, key, default_value) != default_value end)
end) end)
columns = columns =
@ -147,22 +147,22 @@ defmodule CanneryWeb.Components.AmmoTypeTableComponent do
}) })
|> TableComponent.maybe_compose_columns(filtered_columns) |> TableComponent.maybe_compose_columns(filtered_columns)
|> TableComponent.maybe_compose_columns( |> TableComponent.maybe_compose_columns(
%{label: gettext("Type"), key: :type, type: :atom}, %{label: gettext("Class"), key: :class, type: :atom},
type in [:all, nil] class in [:all, nil]
) )
|> TableComponent.maybe_compose_columns(%{label: gettext("Name"), key: :name, type: :name}) |> TableComponent.maybe_compose_columns(%{label: gettext("Name"), key: :name, type: :name})
round_counts = ammo_types |> Ammo.get_round_count_for_ammo_types(current_user) round_counts = types |> Ammo.get_round_count_for_types(current_user)
packs_count = ammo_types |> Ammo.get_ammo_groups_count_for_types(current_user) packs_count = types |> Ammo.get_packs_count_for_types(current_user)
average_costs = ammo_types |> Ammo.get_average_cost_for_ammo_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] = [used_counts, historical_round_counts, historical_pack_counts, used_pack_counts] =
if show_used do if show_used do
[ [
ammo_types |> ActivityLog.get_used_count_for_ammo_types(current_user), types |> ActivityLog.get_used_count_for_types(current_user),
ammo_types |> Ammo.get_historical_count_for_ammo_types(current_user), types |> Ammo.get_historical_count_for_types(current_user),
ammo_types |> Ammo.get_ammo_groups_count_for_types(current_user, true), types |> Ammo.get_packs_count_for_types(current_user, true),
ammo_types |> Ammo.get_used_ammo_groups_count_for_types(current_user) types |> Ammo.get_used_packs_count_for_types(current_user)
] ]
else else
[nil, nil, nil, nil] [nil, nil, nil, nil]
@ -181,9 +181,9 @@ defmodule CanneryWeb.Components.AmmoTypeTableComponent do
} }
rows = rows =
ammo_types types
|> Enum.map(fn ammo_type -> |> Enum.map(fn type ->
ammo_type |> get_ammo_type_values(columns, extra_data) type |> get_type_values(columns, extra_data)
end) end)
socket |> assign(columns: columns, rows: rows) socket |> assign(columns: columns, rows: rows)
@ -198,92 +198,92 @@ defmodule CanneryWeb.Components.AmmoTypeTableComponent do
""" """
end end
defp get_ammo_type_values(ammo_type, columns, extra_data) do defp get_type_values(type, columns, extra_data) do
columns columns
|> Map.new(fn %{key: key, type: type} -> |> Map.new(fn %{key: key, type: column_type} ->
{key, get_ammo_type_value(type, key, ammo_type, extra_data)} {key, get_type_value(column_type, key, type, extra_data)}
end) end)
end end
defp get_ammo_type_value(:atom, key, ammo_type, _other_data), defp get_type_value(:atom, key, type, _other_data),
do: ammo_type |> Map.get(key) |> humanize() do: type |> Map.get(key) |> humanize()
defp get_ammo_type_value(:round_count, _key, %{id: ammo_type_id}, %{round_counts: round_counts}), defp get_type_value(:round_count, _key, %{id: type_id}, %{round_counts: round_counts}),
do: Map.get(round_counts, ammo_type_id, 0) do: Map.get(round_counts, type_id, 0)
defp get_ammo_type_value( defp get_type_value(
:historical_round_count, :historical_round_count,
_key, _key,
%{id: ammo_type_id}, %{id: type_id},
%{historical_round_counts: historical_round_counts} %{historical_round_counts: historical_round_counts}
) do ) do
Map.get(historical_round_counts, ammo_type_id, 0) Map.get(historical_round_counts, type_id, 0)
end end
defp get_ammo_type_value( defp get_type_value(
:used_round_count, :used_round_count,
_key, _key,
%{id: ammo_type_id}, %{id: type_id},
%{used_counts: used_counts} %{used_counts: used_counts}
) do ) do
Map.get(used_counts, ammo_type_id, 0) Map.get(used_counts, type_id, 0)
end end
defp get_ammo_type_value( defp get_type_value(
:historical_pack_count, :historical_pack_count,
_key, _key,
%{id: ammo_type_id}, %{id: type_id},
%{historical_pack_counts: historical_pack_counts} %{historical_pack_counts: historical_pack_counts}
) do ) do
Map.get(historical_pack_counts, ammo_type_id, 0) Map.get(historical_pack_counts, type_id, 0)
end end
defp get_ammo_type_value( defp get_type_value(
:used_pack_count, :used_pack_count,
_key, _key,
%{id: ammo_type_id}, %{id: type_id},
%{used_pack_counts: used_pack_counts} %{used_pack_counts: used_pack_counts}
) do ) do
Map.get(used_pack_counts, ammo_type_id, 0) Map.get(used_pack_counts, type_id, 0)
end end
defp get_ammo_type_value(:ammo_count, _key, %{id: ammo_type_id}, %{packs_count: packs_count}), defp get_type_value(:ammo_count, _key, %{id: type_id}, %{packs_count: packs_count}),
do: Map.get(packs_count, ammo_type_id) do: Map.get(packs_count, type_id)
defp get_ammo_type_value( defp get_type_value(
:avg_price_paid, :avg_price_paid,
_key, _key,
%{id: ammo_type_id}, %{id: type_id},
%{average_costs: average_costs} %{average_costs: average_costs}
) do ) do
case Map.get(average_costs, ammo_type_id) do case Map.get(average_costs, type_id) do
nil -> {0, gettext("No cost information")} nil -> {0, gettext("No cost information")}
count -> {count, gettext("$%{amount}", amount: display_currency(count))} count -> {count, gettext("$%{amount}", amount: display_currency(count))}
end end
end end
defp get_ammo_type_value(:name, _key, %{name: ammo_type_name} = ammo_type, _other_data) do defp get_type_value(:name, _key, %{name: type_name} = type, _other_data) do
assigns = %{ammo_type: ammo_type} assigns = %{type: type}
{ammo_type_name, {type_name,
~H""" ~H"""
<.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>
"""} """}
end end
defp get_ammo_type_value(:actions, _key, ammo_type, %{actions: actions}) do defp get_type_value(:actions, _key, type, %{actions: actions}) do
assigns = %{actions: actions, ammo_type: ammo_type} assigns = %{actions: actions, type: type}
~H""" ~H"""
<%= render_slot(@actions, @ammo_type) %> <%= render_slot(@actions, @type) %>
""" """
end end
defp get_ammo_type_value(nil, _key, _ammo_type, _other_data), do: nil defp get_type_value(nil, _key, _type, _other_data), do: nil
defp get_ammo_type_value(_other, key, ammo_type, _other_data), do: ammo_type |> Map.get(key) defp get_type_value(_other, key, type, _other_data), do: type |> Map.get(key)
@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)

View File

@ -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, :all) 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, :all, current_user, true) 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(:all, 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

View File

@ -1,114 +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(type: :all, show_used: false, search: search) |> list_ammo_types()}
end
def mount(_params, _session, socket) do
{:ok, socket |> assign(type: :all, 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
def handle_event("change_type", %{"ammo_type" => %{"type" => "rifle"}}, socket) do
{:noreply, socket |> assign(:type, :rifle) |> list_ammo_types()}
end
def handle_event("change_type", %{"ammo_type" => %{"type" => "shotgun"}}, socket) do
{:noreply, socket |> assign(:type, :shotgun) |> list_ammo_types()}
end
def handle_event("change_type", %{"ammo_type" => %{"type" => "pistol"}}, socket) do
{:noreply, socket |> assign(:type, :pistol) |> list_ammo_types()}
end
def handle_event("change_type", %{"ammo_type" => %{"type" => _all}}, socket) do
{:noreply, socket |> assign(:type, :all) |> list_ammo_types()}
end
defp list_ammo_types(
%{assigns: %{type: type, search: search, current_user: current_user}} = socket
) do
socket
|> assign(
ammo_types: Ammo.list_ammo_types(search, current_user, type),
ammo_types_count: Ammo.get_ammo_types_count!(current_user)
)
end
end

View File

@ -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)

View File

@ -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(type: :all, 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)
@ -86,33 +86,33 @@ defmodule CanneryWeb.ContainerLive.Show 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_type", %{"ammo_type" => %{"type" => "rifle"}}, socket) do def handle_event("change_class", %{"type" => %{"class" => "rifle"}}, socket) do
{:noreply, socket |> assign(:type, :rifle) |> render_container()} {:noreply, socket |> assign(:class, :rifle) |> render_container()}
end end
def handle_event("change_type", %{"ammo_type" => %{"type" => "shotgun"}}, socket) do def handle_event("change_class", %{"type" => %{"class" => "shotgun"}}, socket) do
{:noreply, socket |> assign(:type, :shotgun) |> render_container()} {:noreply, socket |> assign(:class, :shotgun) |> render_container()}
end end
def handle_event("change_type", %{"ammo_type" => %{"type" => "pistol"}}, socket) do def handle_event("change_class", %{"type" => %{"class" => "pistol"}}, socket) do
{:noreply, socket |> assign(:type, :pistol) |> render_container()} {:noreply, socket |> assign(:class, :pistol) |> render_container()}
end end
def handle_event("change_type", %{"ammo_type" => %{"type" => _all}}, socket) do def handle_event("change_class", %{"type" => %{"class" => _all}}, socket) do
{:noreply, socket |> assign(:type, :all) |> render_container()} {:noreply, socket |> assign(:class, :all) |> render_container()}
end 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: %{type: type, live_action: live_action}} = 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, type, current_user) 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
@ -125,8 +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_count: Ammo.get_ammo_groups_count_for_container!(container, current_user), packs_count: Ammo.get_packs_count_for_container!(container, current_user),
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,

View File

@ -20,7 +20,7 @@
<span class="rounded-lg title text-lg"> <span class="rounded-lg title text-lg">
<%= gettext("Packs:") %> <%= gettext("Packs:") %>
<%= @ammo_groups_count %> <%= @packs_count %>
</span> </span>
<span class="rounded-lg title text-lg"> <span class="rounded-lg title text-lg">
@ -89,16 +89,16 @@
<.form <.form
:let={f} :let={f}
for={%{}} for={%{}}
as={:ammo_type} as={:type}
phx-change="change_type" phx-change="change_class"
phx-submit="change_type" phx-submit="change_class"
class="flex items-center" class="flex items-center"
> >
<%= label(f, :type, gettext("Type"), class: "title text-primary-600 text-lg text-center") %> <%= label(f, :class, gettext("Class"), class: "title text-primary-600 text-lg text-center") %>
<%= select( <%= select(
f, f,
:type, :class,
[ [
{gettext("All"), :all}, {gettext("All"), :all},
{gettext("Rifle"), :rifle}, {gettext("Rifle"), :rifle},
@ -106,7 +106,7 @@
{gettext("Pistol"), :pistol} {gettext("Pistol"), :pistol}
], ],
class: "mx-2 my-1 min-w-md input input-primary", class: "mx-2 my-1 min-w-md input input-primary",
value: @type value: @class
) %> ) %>
</.form> </.form>
@ -118,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={false} 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>

View File

@ -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, :all)) |> 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",

View File

@ -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,
@ -49,7 +49,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 +68,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"

View File

@ -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(type: :all, 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(type: :all, 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,86 +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
def handle_event("change_type", %{"ammo_type" => %{"type" => "rifle"}}, socket) do def handle_event("change_class", %{"type" => %{"class" => "rifle"}}, socket) do
{:noreply, socket |> assign(:type, :rifle) |> display_ammo_groups()} {:noreply, socket |> assign(:class, :rifle) |> display_packs()}
end end
def handle_event("change_type", %{"ammo_type" => %{"type" => "shotgun"}}, socket) do def handle_event("change_class", %{"type" => %{"class" => "shotgun"}}, socket) do
{:noreply, socket |> assign(:type, :shotgun) |> display_ammo_groups()} {:noreply, socket |> assign(:class, :shotgun) |> display_packs()}
end end
def handle_event("change_type", %{"ammo_type" => %{"type" => "pistol"}}, socket) do def handle_event("change_class", %{"type" => %{"class" => "pistol"}}, socket) do
{:noreply, socket |> assign(:type, :pistol) |> display_ammo_groups()} {:noreply, socket |> assign(:class, :pistol) |> display_packs()}
end end
def handle_event("change_type", %{"ammo_type" => %{"type" => _all}}, socket) do def handle_event("change_class", %{"type" => %{"class" => _all}}, socket) do
{:noreply, socket |> assign(:type, :all) |> display_ammo_groups()} {:noreply, socket |> assign(:class, :all) |> display_packs()}
end end
defp display_ammo_groups( defp display_packs(
%{ %{
assigns: %{ assigns: %{
type: type, class: class,
search: search, search: search,
current_user: current_user, current_user: current_user,
show_used: show_used show_used: show_used
} }
} = socket } = socket
) do ) do
# get total number of ammo groups to determine whether to display onboarding # get total number of packs to determine whether to display onboarding
# prompts # prompts
ammo_groups_count = Ammo.get_ammo_groups_count!(current_user, true) packs_count = Ammo.get_packs_count!(current_user, true)
ammo_groups = Ammo.list_ammo_groups(search, type, current_user, show_used) packs = Ammo.list_packs(search, class, current_user, show_used)
ammo_types_count = Ammo.get_ammo_types_count!(current_user) 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,
ammo_groups_count: ammo_groups_count packs_count: packs_count
) )
end end
end end

View File

@ -14,27 +14,27 @@
<%= dgettext("actions", "add a container first") %> <%= dgettext("actions", "add a container first") %>
</.link> </.link>
</div> </div>
<% @ammo_types_count == 0 -> %> <% @types_count == 0 -> %>
<div class="flex justify-center items-center"> <div class="flex justify-center items-center">
<h2 class="m-2 title text-md text-primary-600"> <h2 class="m-2 title text-md text-primary-600">
<%= dgettext("prompts", "You'll need to") %> <%= dgettext("prompts", "You'll need to") %>
</h2> </h2>
<.link navigate={Routes.ammo_type_index_path(Endpoint, :new)} class="btn btn-primary"> <.link navigate={Routes.type_index_path(Endpoint, :new)} class="btn btn-primary">
<%= dgettext("actions", "add an ammo type first") %> <%= dgettext("actions", "add a type first") %>
</.link> </.link>
</div> </div>
<% @ammo_groups_count == 0 -> %> <% @packs_count == 0 -> %>
<h2 class="title text-xl text-primary-600"> <h2 class="title text-xl text-primary-600">
<%= gettext("No ammo") %> <%= gettext("No ammo") %>
<%= display_emoji("😔") %> <%= display_emoji("😔") %>
</h2> </h2>
<.link patch={Routes.ammo_group_index_path(Endpoint, :new)} class="btn btn-primary"> <.link patch={Routes.pack_index_path(Endpoint, :new)} class="btn btn-primary">
<%= dgettext("actions", "Add your first box!") %> <%= dgettext("actions", "Add your first box!") %>
</.link> </.link>
<% true -> %> <% true -> %>
<.link patch={Routes.ammo_group_index_path(Endpoint, :new)} class="btn btn-primary"> <.link patch={Routes.pack_index_path(Endpoint, :new)} class="btn btn-primary">
<%= dgettext("actions", "Add Ammo") %> <%= dgettext("actions", "Add Ammo") %>
</.link> </.link>
@ -42,16 +42,18 @@
<.form <.form
:let={f} :let={f}
for={%{}} for={%{}}
as={:ammo_type} as={:type}
phx-change="change_type" phx-change="change_class"
phx-submit="change_type" phx-submit="change_class"
class="flex items-center" class="flex items-center"
> >
<%= label(f, :type, gettext("Type"), class: "title text-primary-600 text-lg text-center") %> <%= label(f, :class, gettext("Class"),
class: "title text-primary-600 text-lg text-center"
) %>
<%= select( <%= select(
f, f,
:type, :class,
[ [
{gettext("All"), :all}, {gettext("All"), :all},
{gettext("Rifle"), :rifle}, {gettext("Rifle"), :rifle},
@ -59,7 +61,7 @@
{gettext("Pistol"), :pistol} {gettext("Pistol"), :pistol}
], ],
class: "mx-2 my-1 min-w-md input input-primary", class: "mx-2 my-1 min-w-md input input-primary",
value: @type value: @class
) %> ) %>
</.form> </.form>
@ -87,46 +89,46 @@
</.toggle_button> </.toggle_button>
</div> </div>
<%= if @ammo_groups |> Enum.empty?() do %> <%= if @packs |> Enum.empty?() do %>
<h2 class="title text-xl text-primary-600"> <h2 class="title text-xl text-primary-600">
<%= gettext("No Ammo") %> <%= gettext("No Ammo") %>
<%= display_emoji("😔") %> <%= display_emoji("😔") %>
</h2> </h2>
<% else %> <% else %>
<.live_component <.live_component
module={CanneryWeb.Components.AmmoGroupTableComponent} module={CanneryWeb.Components.PackTableComponent}
id="ammo-group-index-table" id="pack-index-table"
ammo_groups={@ammo_groups} packs={@packs}
current_user={@current_user} current_user={@current_user}
show_used={@show_used} show_used={@show_used}
> >
<: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>
<:range :let={ammo_group}> <:range :let={pack}>
<div class="min-w-20 py-2 px-4 h-full flex flew-wrap justify-center items-center"> <div class="min-w-20 py-2 px-4 h-full flex flew-wrap justify-center items-center">
<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="toggle_staged" phx-click="toggle_staged"
phx-value-ammo_group_id={ammo_group.id} phx-value-pack_id={pack.id}
> >
<%= if ammo_group.staged, <%= if pack.staged,
do: dgettext("actions", "Unstage"), do: dgettext("actions", "Unstage"),
else: dgettext("actions", "Stage") %> else: dgettext("actions", "Stage") %>
</button> </button>
<.link <.link
patch={Routes.ammo_group_index_path(Endpoint, :add_shot_group, ammo_group)} patch={Routes.pack_index_path(Endpoint, :add_shot_record, pack)}
class="mx-2 my-1 text-sm btn btn-primary" class="mx-2 my-1 text-sm btn btn-primary"
> >
<%= dgettext("actions", "Record shots") %> <%= dgettext("actions", "Record shots") %>
</.link> </.link>
</div> </div>
</:range> </:range>
<:container :let={{ammo_group, %{name: container_name} = container}}> <: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"> <div class="min-w-20 py-2 px-4 h-full flex flew-wrap justify-center items-center">
<.link <.link
navigate={Routes.container_show_path(Endpoint, :show, container)} navigate={Routes.container_show_path(Endpoint, :show, container)}
@ -136,45 +138,41 @@
</.link> </.link>
<.link <.link
patch={Routes.ammo_group_index_path(Endpoint, :move, ammo_group)} patch={Routes.pack_index_path(Endpoint, :move, pack)}
class="mx-2 my-1 text-sm btn btn-primary" class="mx-2 my-1 text-sm btn btn-primary"
> >
<%= dgettext("actions", "Move ammo") %> <%= dgettext("actions", "Move ammo") %>
</.link> </.link>
</div> </div>
</: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>
</.link> </.link>
<.link <.link
patch={Routes.ammo_group_index_path(Endpoint, :edit, ammo_group)} patch={Routes.pack_index_path(Endpoint, :edit, pack)}
class="text-primary-600 link" class="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>
</.link> </.link>
<.link <.link
patch={Routes.ammo_group_index_path(Endpoint, :clone, ammo_group)} patch={Routes.pack_index_path(Endpoint, :clone, pack)}
class="text-primary-600 link" class="text-primary-600 link"
aria-label={ aria-label={
dgettext("actions", "Clone ammo group of %{ammo_group_count} bullets", dgettext("actions", "Clone pack of %{pack_count} bullets",
ammo_group_count: ammo_group_count pack_count: pack_count
) )
} }
> >
@ -185,11 +183,11 @@
href="#" href="#"
class="text-primary-600 link" class="text-primary-600 link"
phx-click="delete" phx-click="delete"
phx-value-id={ammo_group.id} phx-value-id={pack.id}
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",
ammo_group_count: ammo_group_count pack_count: pack_count
) )
} }
> >
@ -204,38 +202,38 @@
<%= case @live_action do %> <%= case @live_action do %>
<% create when create in [:new, :edit, :clone] -> %> <% create when create in [:new, :edit, :clone] -> %>
<.modal return_to={Routes.ammo_group_index_path(Endpoint, :index)}> <.modal return_to={Routes.pack_index_path(Endpoint, :index)}>
<.live_component <.live_component
module={CanneryWeb.AmmoGroupLive.FormComponent} module={CanneryWeb.PackLive.FormComponent}
id={@ammo_group.id || :new} id={@pack.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_index_path(Endpoint, :index)} return_to={Routes.pack_index_path(Endpoint, :index)}
current_user={@current_user} current_user={@current_user}
/> />
</.modal> </.modal>
<% :add_shot_group -> %> <% :add_shot_record -> %>
<.modal return_to={Routes.ammo_group_index_path(Endpoint, :index)}> <.modal return_to={Routes.pack_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.ammo_group_index_path(Endpoint, :index)} return_to={Routes.pack_index_path(Endpoint, :index)}
current_user={@current_user} current_user={@current_user}
/> />
</.modal> </.modal>
<% :move -> %> <% :move -> %>
<.modal return_to={Routes.ammo_group_index_path(Endpoint, :index)}> <.modal return_to={Routes.pack_index_path(Endpoint, :index)}>
<.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_index_path(Endpoint, :index)} return_to={Routes.pack_index_path(Endpoint, :index)}
current_user={@current_user} current_user={@current_user}
/> />
</.modal> </.modal>

View File

@ -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}

View File

@ -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>

View File

@ -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 =

View File

@ -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, :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, maxlength: 255,
placeholder: gettext("Really great weather"), placeholder: gettext("Really great weather"),

View File

@ -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(type: :all, 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(type: :all, 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,47 +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
def handle_event("change_type", %{"ammo_type" => %{"type" => "rifle"}}, socket) do def handle_event("change_class", %{"type" => %{"class" => "rifle"}}, socket) do
{:noreply, socket |> assign(:type, :rifle) |> display_shot_groups()} {:noreply, socket |> assign(:class, :rifle) |> display_shot_records()}
end end
def handle_event("change_type", %{"ammo_type" => %{"type" => "shotgun"}}, socket) do def handle_event("change_class", %{"type" => %{"class" => "shotgun"}}, socket) do
{:noreply, socket |> assign(:type, :shotgun) |> display_shot_groups()} {:noreply, socket |> assign(:class, :shotgun) |> display_shot_records()}
end end
def handle_event("change_type", %{"ammo_type" => %{"type" => "pistol"}}, socket) do def handle_event("change_class", %{"type" => %{"class" => "pistol"}}, socket) do
{:noreply, socket |> assign(:type, :pistol) |> display_shot_groups()} {:noreply, socket |> assign(:class, :pistol) |> display_shot_records()}
end end
def handle_event("change_type", %{"ammo_type" => %{"type" => _all}}, socket) do def handle_event("change_class", %{"type" => %{"class" => _all}}, socket) do
{:noreply, socket |> assign(:type, :all) |> display_shot_groups()} {:noreply, socket |> assign(:class, :all) |> display_shot_records()}
end end
@spec display_shot_groups(Socket.t()) :: Socket.t() @spec display_shot_records(Socket.t()) :: Socket.t()
defp display_shot_groups( defp display_shot_records(
%{assigns: %{type: type, search: search, current_user: current_user}} = socket %{assigns: %{class: class, search: search, current_user: current_user}} = socket
) do ) do
shot_groups = ActivityLog.list_shot_groups(search, type, current_user) shot_records = ActivityLog.list_shot_records(search, class, current_user)
ammo_groups = Ammo.list_staged_ammo_groups(current_user) packs = Ammo.list_staged_packs(current_user)
chart_data = shot_groups |> get_chart_data_for_shot_group() chart_data = shot_records |> get_chart_data_for_shot_record()
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)
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)

View File

@ -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("😔") %>
@ -78,16 +78,16 @@
<.form <.form
:let={f} :let={f}
for={%{}} for={%{}}
as={:ammo_type} as={:type}
phx-change="change_type" phx-change="change_class"
phx-submit="change_type" phx-submit="change_class"
class="flex items-center" class="flex items-center"
> >
<%= label(f, :type, gettext("Type"), class: "title text-primary-600 text-lg text-center") %> <%= label(f, :class, gettext("Class"), class: "title text-primary-600 text-lg text-center") %>
<%= select( <%= select(
f, f,
:type, :class,
[ [
{gettext("All"), :all}, {gettext("All"), :all},
{gettext("Rifle"), :rifle}, {gettext("Rifle"), :rifle},
@ -95,7 +95,7 @@
{gettext("Pistol"), :pistol} {gettext("Pistol"), :pistol}
], ],
class: "mx-2 my-1 min-w-md input input-primary", class: "mx-2 my-1 min-w-md input input-primary",
value: @type value: @class
) %> ) %>
</.form> </.form>
@ -117,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
) )
} }
> >
@ -147,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
) )
} }
> >
@ -171,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}
/> />

View File

@ -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} ->

View File

@ -5,7 +5,7 @@
<.form <.form
:let={f} :let={f}
for={@changeset} for={@changeset}
id="ammo_type-form" id="type-form"
phx-target={@myself} phx-target={@myself}
phx-change="validate" phx-change="validate"
phx-submit="save" phx-submit="save"
@ -18,15 +18,15 @@
<%= dgettext("errors", "Oops, something went wrong! Please check the errors below.") %> <%= dgettext("errors", "Oops, something went wrong! Please check the errors below.") %>
</div> </div>
<%= label(f, :type, gettext("Type"), class: "title text-lg text-primary-600") %> <%= label(f, :class, gettext("Class"), class: "title text-lg text-primary-600") %>
<%= select( <%= select(
f, f,
:type, :class,
[{gettext("Rifle"), :rifle}, {gettext("Shotgun"), :shotgun}, {gettext("Pistol"), :pistol}], [{gettext("Rifle"), :rifle}, {gettext("Shotgun"), :shotgun}, {gettext("Pistol"), :pistol}],
class: "text-center col-span-2 input input-primary", class: "text-center col-span-2 input input-primary",
maxlength: 255 maxlength: 255
) %> ) %>
<%= error_tag(f, :type, "col-span-3 text-center") %> <%= error_tag(f, :class, "col-span-3 text-center") %>
<%= 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,
@ -37,7 +37,7 @@
<%= label(f, :desc, gettext("Description"), class: "title text-lg text-primary-600") %> <%= label(f, :desc, gettext("Description"), class: "title text-lg text-primary-600") %>
<%= textarea(f, :desc, <%= textarea(f, :desc,
id: "ammo-type-form-desc", id: "type-form-desc",
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"
@ -48,7 +48,7 @@
<%= gettext("Dimensions") %> <%= gettext("Dimensions") %>
</h2> </h2>
<%= if Changeset.get_field(@changeset, :type) in [:rifle, :pistol] do %> <%= if Changeset.get_field(@changeset, :class) in [:rifle, :pistol] do %>
<%= label(f, :cartridge, gettext("Cartridge"), class: "title text-lg text-primary-600") %> <%= label(f, :cartridge, gettext("Cartridge"), class: "title text-lg text-primary-600") %>
<%= text_input(f, :cartridge, <%= text_input(f, :cartridge,
class: "text-center col-span-2 input input-primary", class: "text-center col-span-2 input input-primary",
@ -63,7 +63,7 @@
<%= label( <%= label(
f, f,
:caliber, :caliber,
if(Changeset.get_field(@changeset, :type) == :shotgun, if(Changeset.get_field(@changeset, :class) == :shotgun,
do: gettext("Gauge"), do: gettext("Gauge"),
else: gettext("Caliber") else: gettext("Caliber")
), ),
@ -76,7 +76,7 @@
) %> ) %>
<%= error_tag(f, :caliber, "col-span-3 text-center") %> <%= error_tag(f, :caliber, "col-span-3 text-center") %>
<%= if Changeset.get_field(@changeset, :type) == :shotgun do %> <%= if Changeset.get_field(@changeset, :class) == :shotgun do %>
<%= label(f, :unfired_length, gettext("Unfired shell length"), <%= label(f, :unfired_length, gettext("Unfired shell length"),
class: "title text-lg text-primary-600" class: "title text-lg text-primary-600"
) %> ) %>
@ -139,7 +139,7 @@
<%= label( <%= label(
f, f,
:bullet_core, :bullet_core,
if(Changeset.get_field(@changeset, :type) == :shotgun, if(Changeset.get_field(@changeset, :class) == :shotgun,
do: gettext("Slug core"), do: gettext("Slug core"),
else: gettext("Bullet core") else: gettext("Bullet core")
), ),
@ -152,7 +152,7 @@
) %> ) %>
<%= error_tag(f, :bullet_core, "col-span-3 text-center") %> <%= error_tag(f, :bullet_core, "col-span-3 text-center") %>
<%= if Changeset.get_field(@changeset, :type) in [:rifle, :pistol] do %> <%= if Changeset.get_field(@changeset, :class) in [:rifle, :pistol] do %>
<%= label(f, :jacket_type, gettext("Jacket type"), class: "title text-lg text-primary-600") %> <%= label(f, :jacket_type, gettext("Jacket type"), class: "title text-lg text-primary-600") %>
<%= text_input(f, :jacket_type, <%= text_input(f, :jacket_type,
class: "text-center col-span-2 input input-primary", class: "text-center col-span-2 input input-primary",
@ -172,7 +172,7 @@
) %> ) %>
<%= error_tag(f, :case_material, "col-span-3 text-center") %> <%= error_tag(f, :case_material, "col-span-3 text-center") %>
<%= if Changeset.get_field(@changeset, :type) == :shotgun do %> <%= if Changeset.get_field(@changeset, :class) == :shotgun do %>
<%= label(f, :wadding, gettext("Wadding"), class: "title text-lg text-primary-600") %> <%= label(f, :wadding, gettext("Wadding"), class: "title text-lg text-primary-600") %>
<%= text_input(f, :wadding, <%= text_input(f, :wadding,
class: "text-center col-span-2 input input-primary", class: "text-center col-span-2 input input-primary",
@ -240,7 +240,7 @@
) %> ) %>
<%= error_tag(f, :powder_type, "col-span-3 text-center") %> <%= error_tag(f, :powder_type, "col-span-3 text-center") %>
<%= if Changeset.get_field(@changeset, :type) in [:rifle, :pistol] do %> <%= if Changeset.get_field(@changeset, :class) in [:rifle, :pistol] do %>
<%= label(f, :powder_grains_per_charge, gettext("Powder grains per charge"), <%= label(f, :powder_grains_per_charge, gettext("Powder grains per charge"),
class: "title text-lg text-primary-600" class: "title text-lg text-primary-600"
) %> ) %>
@ -262,7 +262,7 @@
) %> ) %>
<%= error_tag(f, :pressure, "col-span-3 text-center") %> <%= error_tag(f, :pressure, "col-span-3 text-center") %>
<%= if Changeset.get_field(@changeset, :type) == :shotgun do %> <%= if Changeset.get_field(@changeset, :class) == :shotgun do %>
<%= label(f, :dram_equivalent, gettext("Dram equivalent"), <%= label(f, :dram_equivalent, gettext("Dram equivalent"),
class: "title text-lg text-primary-600" class: "title text-lg text-primary-600"
) %> ) %>
@ -275,7 +275,7 @@
<%= hidden_input(f, :dram_equivalent, value: nil) %> <%= hidden_input(f, :dram_equivalent, value: nil) %>
<% end %> <% end %>
<%= if Changeset.get_field(@changeset, :type) in [:rifle, :pistol] do %> <%= if Changeset.get_field(@changeset, :class) in [:rifle, :pistol] do %>
<%= label(f, :muzzle_velocity, gettext("Muzzle velocity"), <%= label(f, :muzzle_velocity, gettext("Muzzle velocity"),
class: "title text-lg text-primary-600" class: "title text-lg text-primary-600"
) %> ) %>

View 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

View File

@ -3,34 +3,34 @@
<%= gettext("Catalog") %> <%= gettext("Catalog") %>
</h1> </h1>
<%= if @ammo_types_count == 0 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-2xl"> <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={:ammo_type} as={:type}
phx-change="change_type" phx-change="change_class"
phx-submit="change_type" phx-submit="change_class"
class="flex items-center" class="flex items-center"
> >
<%= label(f, :type, gettext("Type"), class: "title text-primary-600 text-lg text-center") %> <%= label(f, :class, gettext("Class"), class: "title text-primary-600 text-lg text-center") %>
<%= select( <%= select(
f, f,
:type, :class,
[ [
{gettext("All"), :all}, {gettext("All"), :all},
{gettext("Rifle"), :rifle}, {gettext("Rifle"), :rifle},
@ -38,7 +38,7 @@
{gettext("Pistol"), :pistol} {gettext("Pistol"), :pistol}
], ],
class: "mx-2 my-1 min-w-md input input-primary", class: "mx-2 my-1 min-w-md input input-primary",
value: @type value: @class
) %> ) %>
</.form> </.form>
@ -66,49 +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}
type={@type} 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>
@ -117,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>
@ -140,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}
} }
/> />

View File

@ -1,10 +1,10 @@
defmodule CanneryWeb.AmmoTypeLive.Show do defmodule CanneryWeb.TypeLive.Show do
@moduledoc """ @moduledoc """
Liveview for showing and editing an Cannery.Ammo.AmmoType Liveview for showing and editing an Cannery.Ammo.Type
""" """
use CanneryWeb, :live_view use CanneryWeb, :live_view
alias Cannery.{ActivityLog, Ammo, Ammo.AmmoType, Containers} alias Cannery.{ActivityLog, Ammo, Ammo.Type, Containers}
alias CanneryWeb.Endpoint alias CanneryWeb.Endpoint
@impl true @impl true
@ -13,49 +13,49 @@ defmodule CanneryWeb.AmmoTypeLive.Show do
@impl true @impl true
def handle_params(%{"id" => id}, _params, socket) do def handle_params(%{"id" => id}, _params, socket) do
{:noreply, socket |> display_ammo_type(id)} {:noreply, socket |> display_type(id)}
end end
@impl true @impl true
def handle_event( def handle_event(
"delete", "delete",
_params, _params,
%{assigns: %{ammo_type: ammo_type, current_user: current_user}} = socket %{assigns: %{type: type, current_user: current_user}} = socket
) do ) do
%{name: ammo_type_name} = ammo_type |> Ammo.delete_ammo_type!(current_user) %{name: type_name} = type |> Ammo.delete_type!(current_user)
prompt = dgettext("prompts", "%{name} deleted succesfully", name: ammo_type_name) prompt = dgettext("prompts", "%{name} deleted succesfully", name: type_name)
redirect_to = Routes.ammo_type_index_path(socket, :index) redirect_to = Routes.type_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
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_type()} {:noreply, socket |> assign(:show_used, !show_used) |> display_type()}
end 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)} {:noreply, socket |> assign(:view_table, !view_table)}
end end
defp display_ammo_type( defp display_type(
%{assigns: %{live_action: live_action, current_user: current_user, show_used: show_used}} = %{assigns: %{live_action: live_action, current_user: current_user, show_used: show_used}} =
socket, socket,
%AmmoType{name: ammo_type_name} = ammo_type %Type{name: type_name} = type
) do ) do
custom_fields? = custom_fields? =
fields_to_display(ammo_type) fields_to_display(type)
|> Enum.any?(fn %{key: field, type: type} -> |> Enum.any?(fn %{key: field, type: column_type} ->
default_value = default_value =
case type do case column_type do
:boolean -> false :boolean -> false
_other_type -> nil _other_type -> nil
end end
ammo_type |> Map.get(field) != default_value type |> Map.get(field) != default_value
end) end)
ammo_groups = ammo_type |> Ammo.list_ammo_groups_for_type(current_user, show_used) packs = type |> Ammo.list_packs_for_type(current_user, show_used)
[ [
original_counts, original_counts,
@ -66,11 +66,11 @@ defmodule CanneryWeb.AmmoTypeLive.Show do
] = ] =
if show_used do if show_used do
[ [
ammo_groups |> Ammo.get_original_counts(current_user), packs |> Ammo.get_original_counts(current_user),
ammo_type |> Ammo.get_used_ammo_groups_count_for_type(current_user), type |> Ammo.get_used_packs_count_for_type(current_user),
ammo_type |> Ammo.get_ammo_groups_count_for_type(current_user, true), type |> Ammo.get_packs_count_for_type(current_user, true),
ammo_type |> ActivityLog.get_used_count_for_ammo_type(current_user), type |> ActivityLog.get_used_count_for_type(current_user),
ammo_type |> Ammo.get_historical_count_for_ammo_type(current_user) type |> Ammo.get_historical_count_for_type(current_user)
] ]
else else
[nil, nil, nil, nil, nil] [nil, nil, nil, nil, nil]
@ -78,49 +78,49 @@ defmodule CanneryWeb.AmmoTypeLive.Show do
page_title = page_title =
case live_action do case live_action do
:show -> ammo_type_name :show -> type_name
:edit -> gettext("Edit %{ammo_type_name}", ammo_type_name: ammo_type_name) :edit -> gettext("Edit %{type_name}", type_name: type_name)
end end
containers = containers =
ammo_groups packs
|> Enum.map(fn %{container_id: container_id} -> container_id end) |> Enum.map(fn %{container_id: container_id} -> container_id end)
|> Containers.get_containers(current_user) |> Containers.get_containers(current_user)
socket socket
|> assign( |> assign(
page_title: page_title, page_title: page_title,
ammo_type: ammo_type, type: type,
ammo_groups: ammo_groups, packs: packs,
containers: containers, containers: containers,
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),
avg_cost_per_round: ammo_type |> Ammo.get_average_cost_for_ammo_type(current_user), avg_cost_per_round: type |> Ammo.get_average_cost_for_type(current_user),
rounds: ammo_type |> Ammo.get_round_count_for_ammo_type(current_user), rounds: type |> Ammo.get_round_count_for_type(current_user),
original_counts: original_counts, original_counts: original_counts,
used_rounds: used_rounds, used_rounds: used_rounds,
historical_round_count: historical_round_count, historical_round_count: historical_round_count,
packs_count: ammo_type |> Ammo.get_ammo_groups_count_for_type(current_user), packs_count: type |> Ammo.get_packs_count_for_type(current_user),
used_packs_count: used_packs_count, used_packs_count: used_packs_count,
historical_packs_count: historical_packs_count, historical_packs_count: historical_packs_count,
fields_to_display: fields_to_display(ammo_type), fields_to_display: fields_to_display(type),
custom_fields?: custom_fields? custom_fields?: custom_fields?
) )
end end
defp display_ammo_type(%{assigns: %{current_user: current_user}} = socket, ammo_type_id) do defp display_type(%{assigns: %{current_user: current_user}} = socket, type_id) do
socket |> display_ammo_type(Ammo.get_ammo_type!(ammo_type_id, current_user)) socket |> display_type(Ammo.get_type!(type_id, current_user))
end end
defp display_ammo_type(%{assigns: %{ammo_type: ammo_type}} = socket) do defp display_type(%{assigns: %{type: type}} = socket) do
socket |> display_ammo_type(ammo_type) socket |> display_type(type)
end end
defp fields_to_display(%AmmoType{type: type}) do defp fields_to_display(%Type{class: class}) do
[ [
%{label: gettext("Cartridge:"), key: :cartridge, type: :string}, %{label: gettext("Cartridge:"), key: :cartridge, type: :string},
%{ %{
label: if(type == :shotgun, do: gettext("Gauge:"), else: gettext("Caliber:")), label: if(class == :shotgun, do: gettext("Gauge:"), else: gettext("Caliber:")),
key: :caliber, key: :caliber,
type: :string type: :string
}, },

View File

@ -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,14 +40,14 @@
<hr class="hr" /> <hr class="hr" />
<%= if @ammo_type.type || @custom_fields? 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">
<h3 class="title text-lg"> <h3 class="title text-lg">
<%= gettext("Type") %> <%= gettext("Class") %>
</h3> </h3>
<span class="text-primary-600"> <span class="text-primary-600">
<%= case @ammo_type.type do %> <%= case @type.class do %>
<% :shotgun -> %> <% :shotgun -> %>
<%= gettext("Shotgun") %> <%= gettext("Shotgun") %>
<% :rifle -> %> <% :rifle -> %>
@ -62,7 +60,7 @@
</span> </span>
<%= for %{label: label, key: key, type: type} <- @fields_to_display do %> <%= for %{label: label, key: key, type: type} <- @fields_to_display do %>
<%= if @ammo_type |> Map.get(key) do %> <%= if @type |> Map.get(key) do %>
<h3 class="title text-lg"> <h3 class="title text-lg">
<%= label %> <%= label %>
</h3> </h3>
@ -70,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 %>
@ -140,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 %>
@ -175,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("😔") %>
@ -183,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"
@ -197,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>
@ -215,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)}
/> />
@ -230,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>

View File

@ -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

View File

@ -4,7 +4,7 @@ defmodule Cannery.MixProject do
def project do def project do
[ [
app: :cannery, app: :cannery,
version: "0.9.0", version: "0.9.1",
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(),

View File

@ -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:38 #: 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:34 #: 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:57 #: 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/ammo_type_live/form_component.html.heex:350
#: lib/cannery_web/live/container_live/form_component.html.heex:57 #: lib/cannery_web/live/container_live/form_component.html.heex:57
#: lib/cannery_web/live/invite_live/form_component.html.heex:35 #: lib/cannery_web/live/invite_live/form_component.html.heex:35
#: lib/cannery_web/live/pack_live/form_component.html.heex:84
#: lib/cannery_web/live/range_live/form_component.html.heex:45 #: lib/cannery_web/live/range_live/form_component.html.heex:45
#: 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 ""
@ -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:125 #: 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:14 #: 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:77
#, 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:24 #: 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:142
#: 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,11 +227,6 @@ msgstr ""
msgid "Export Data as JSON" msgid "Export Data as JSON"
msgstr "" msgstr ""
#: lib/cannery_web/live/ammo_type_live/index.html.heex:110
#, elixir-autogen, elixir-format
msgid "Clone %{ammo_type_name}"
msgstr ""
#: lib/cannery_web/live/container_live/index.html.heex:87 #: lib/cannery_web/live/container_live/index.html.heex:87
#: lib/cannery_web/live/container_live/index.html.heex:145 #: lib/cannery_web/live/container_live/index.html.heex:145
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
@ -253,12 +238,6 @@ 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:129
#: lib/cannery_web/live/ammo_type_live/show.html.heex:36
#, elixir-autogen, elixir-format
msgid "Delete %{ammo_type_name}"
msgstr ""
#: lib/cannery_web/live/container_live/index.html.heex:104 #: lib/cannery_web/live/container_live/index.html.heex:104
#: lib/cannery_web/live/container_live/index.html.heex:162 #: lib/cannery_web/live/container_live/index.html.heex:162
#: lib/cannery_web/live/container_live/show.html.heex:48 #: lib/cannery_web/live/container_live/show.html.heex:48
@ -276,18 +255,6 @@ 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/range_live/index.html.heex:155
#, elixir-autogen, elixir-format
msgid "Delete shot record of %{shot_group_count} shots"
msgstr ""
#: lib/cannery_web/live/ammo_type_live/index.html.heex:100
#: 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:77 #: lib/cannery_web/live/container_live/index.html.heex:77
#: lib/cannery_web/live/container_live/index.html.heex:135 #: lib/cannery_web/live/container_live/index.html.heex:135
#: lib/cannery_web/live/container_live/show.html.heex:35 #: lib/cannery_web/live/container_live/show.html.heex:35
@ -300,28 +267,12 @@ msgstr ""
msgid "Edit %{tag_name}" msgid "Edit %{tag_name}"
msgstr "" msgstr ""
#: lib/cannery_web/live/ammo_group_live/index.html.heex:164
#: 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:138
#, elixir-autogen, elixir-format
msgid "Edit shot record of %{shot_group_count} shots"
msgstr ""
#: lib/cannery_web/live/ammo_group_live/index.html.heex:118
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Stage" msgid "Stage"
msgstr "" msgstr ""
@ -332,29 +283,74 @@ msgstr ""
msgid "Tag %{container_name}" msgid "Tag %{container_name}"
msgstr "" msgstr ""
#: lib/cannery_web/live/ammo_group_live/index.html.heex:117 #: 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:90 #: 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:176 #: 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:191 #: 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:152 #: lib/cannery_web/live/pack_live/index.html.heex:154
#: lib/cannery_web/live/ammo_type_live/show.html.heex:206 #: 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 ""

View File

@ -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:38 #: 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:34 #: 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:57 #: 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/ammo_type_live/form_component.html.heex:350
#: lib/cannery_web/live/container_live/form_component.html.heex:57 #: lib/cannery_web/live/container_live/form_component.html.heex:57
#: lib/cannery_web/live/invite_live/form_component.html.heex:35 #: lib/cannery_web/live/invite_live/form_component.html.heex:35
#: lib/cannery_web/live/pack_live/form_component.html.heex:84
#: lib/cannery_web/live/range_live/form_component.html.heex:45 #: lib/cannery_web/live/range_live/form_component.html.heex:45
#: 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"
@ -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:125 #: 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:14 #: 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:77
#, 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:24 #: 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:142
#: 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,11 +240,6 @@ msgstr ""
msgid "Export Data as JSON" msgid "Export Data as JSON"
msgstr "" msgstr ""
#: lib/cannery_web/live/ammo_type_live/index.html.heex:110
#, elixir-autogen, elixir-format
msgid "Clone %{ammo_type_name}"
msgstr ""
#: lib/cannery_web/live/container_live/index.html.heex:87 #: lib/cannery_web/live/container_live/index.html.heex:87
#: lib/cannery_web/live/container_live/index.html.heex:145 #: lib/cannery_web/live/container_live/index.html.heex:145
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
@ -266,12 +251,6 @@ 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:129
#: lib/cannery_web/live/ammo_type_live/show.html.heex:36
#, elixir-autogen, elixir-format
msgid "Delete %{ammo_type_name}"
msgstr ""
#: lib/cannery_web/live/container_live/index.html.heex:104 #: lib/cannery_web/live/container_live/index.html.heex:104
#: lib/cannery_web/live/container_live/index.html.heex:162 #: lib/cannery_web/live/container_live/index.html.heex:162
#: lib/cannery_web/live/container_live/show.html.heex:48 #: lib/cannery_web/live/container_live/show.html.heex:48
@ -289,18 +268,6 @@ 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/range_live/index.html.heex:155
#, elixir-autogen, elixir-format
msgid "Delete shot record of %{shot_group_count} shots"
msgstr ""
#: lib/cannery_web/live/ammo_type_live/index.html.heex:100
#: 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:77 #: lib/cannery_web/live/container_live/index.html.heex:77
#: lib/cannery_web/live/container_live/index.html.heex:135 #: lib/cannery_web/live/container_live/index.html.heex:135
#: lib/cannery_web/live/container_live/show.html.heex:35 #: lib/cannery_web/live/container_live/show.html.heex:35
@ -313,28 +280,12 @@ msgstr ""
msgid "Edit %{tag_name}" msgid "Edit %{tag_name}"
msgstr "" msgstr ""
#: lib/cannery_web/live/ammo_group_live/index.html.heex:164
#: 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:138
#, elixir-autogen, elixir-format
msgid "Edit shot record of %{shot_group_count} shots"
msgstr ""
#: lib/cannery_web/live/ammo_group_live/index.html.heex:118
#, elixir-autogen, elixir-format, fuzzy #, elixir-autogen, elixir-format, fuzzy
msgid "Stage" msgid "Stage"
msgstr "Munition markieren" msgstr "Munition markieren"
@ -345,29 +296,74 @@ msgstr "Munition markieren"
msgid "Tag %{container_name}" msgid "Tag %{container_name}"
msgstr "" msgstr ""
#: lib/cannery_web/live/ammo_group_live/index.html.heex:117 #: 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:90 #: 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:176 #: 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:191 #: 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:152 #: lib/cannery_web/live/pack_live/index.html.heex:154
#: lib/cannery_web/live/ammo_type_live/show.html.heex:206 #: 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

View File

@ -69,7 +69,7 @@ msgstr "Ungültige Mailadresse oder Passwort"
msgid "Not found" msgid "Not found"
msgstr "Nicht gefunden" msgstr "Nicht gefunden"
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:18 #: 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
@ -161,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:1114 #: 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:74 #: 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:88 #: 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:84 #: 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:122 #: 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:80 #: 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:92
#, elixir-autogen, elixir-format, fuzzy
msgid "Please select a type and container"
msgstr ""

View File

@ -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:27
#: 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"
@ -73,8 +73,8 @@ msgstr ""
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:189 #: 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:59 #: 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/ammo_type_live/form_component.html.heex:351
#: lib/cannery_web/live/container_live/form_component.html.heex:59 #: lib/cannery_web/live/container_live/form_component.html.heex:59
#: lib/cannery_web/live/invite_live/form_component.html.heex:37 #: lib/cannery_web/live/invite_live/form_component.html.heex:37
#: lib/cannery_web/live/pack_live/form_component.html.heex:85
#: lib/cannery_web/live/range_live/form_component.html.heex:47 #: lib/cannery_web/live/range_live/form_component.html.heex:47
#: 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:152 #: 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:10 #: lib/cannery_web/live/pack_live/index.html.heex:10
#: lib/cannery_web/live/ammo_group_live/index.html.heex:20 #: 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:78
#, 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:122 #: 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

View File

@ -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:38 #: 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:34 #: 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:57 #: 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/ammo_type_live/form_component.html.heex:350
#: lib/cannery_web/live/container_live/form_component.html.heex:57 #: lib/cannery_web/live/container_live/form_component.html.heex:57
#: lib/cannery_web/live/invite_live/form_component.html.heex:35 #: lib/cannery_web/live/invite_live/form_component.html.heex:35
#: lib/cannery_web/live/pack_live/form_component.html.heex:84
#: lib/cannery_web/live/range_live/form_component.html.heex:45 #: lib/cannery_web/live/range_live/form_component.html.heex:45
#: 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 ""
@ -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:125 #: 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:14 #: 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:77
#, 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:24 #: 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:142
#: 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,11 +227,6 @@ msgstr ""
msgid "Export Data as JSON" msgid "Export Data as JSON"
msgstr "" msgstr ""
#: lib/cannery_web/live/ammo_type_live/index.html.heex:110
#, elixir-autogen, elixir-format
msgid "Clone %{ammo_type_name}"
msgstr ""
#: lib/cannery_web/live/container_live/index.html.heex:87 #: lib/cannery_web/live/container_live/index.html.heex:87
#: lib/cannery_web/live/container_live/index.html.heex:145 #: lib/cannery_web/live/container_live/index.html.heex:145
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
@ -253,12 +238,6 @@ 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:129
#: lib/cannery_web/live/ammo_type_live/show.html.heex:36
#, elixir-autogen, elixir-format
msgid "Delete %{ammo_type_name}"
msgstr ""
#: lib/cannery_web/live/container_live/index.html.heex:104 #: lib/cannery_web/live/container_live/index.html.heex:104
#: lib/cannery_web/live/container_live/index.html.heex:162 #: lib/cannery_web/live/container_live/index.html.heex:162
#: lib/cannery_web/live/container_live/show.html.heex:48 #: lib/cannery_web/live/container_live/show.html.heex:48
@ -276,18 +255,6 @@ 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/range_live/index.html.heex:155
#, elixir-autogen, elixir-format
msgid "Delete shot record of %{shot_group_count} shots"
msgstr ""
#: lib/cannery_web/live/ammo_type_live/index.html.heex:100
#: 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:77 #: lib/cannery_web/live/container_live/index.html.heex:77
#: lib/cannery_web/live/container_live/index.html.heex:135 #: lib/cannery_web/live/container_live/index.html.heex:135
#: lib/cannery_web/live/container_live/show.html.heex:35 #: lib/cannery_web/live/container_live/show.html.heex:35
@ -300,28 +267,12 @@ msgstr ""
msgid "Edit %{tag_name}" msgid "Edit %{tag_name}"
msgstr "" msgstr ""
#: lib/cannery_web/live/ammo_group_live/index.html.heex:164
#: 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:138
#, elixir-autogen, elixir-format
msgid "Edit shot record of %{shot_group_count} shots"
msgstr ""
#: lib/cannery_web/live/ammo_group_live/index.html.heex:118
#, elixir-autogen, elixir-format, fuzzy #, elixir-autogen, elixir-format, fuzzy
msgid "Stage" msgid "Stage"
msgstr "" msgstr ""
@ -332,29 +283,74 @@ msgstr ""
msgid "Tag %{container_name}" msgid "Tag %{container_name}"
msgstr "" msgstr ""
#: lib/cannery_web/live/ammo_group_live/index.html.heex:117 #: 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:90 #: 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:176 #: 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:191 #: 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:152 #: lib/cannery_web/live/pack_live/index.html.heex:154
#: lib/cannery_web/live/ammo_type_live/show.html.heex:206 #: 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

View File

@ -56,7 +56,7 @@ msgstr ""
msgid "Not found" msgid "Not found"
msgstr "" msgstr ""
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:18 #: 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
@ -146,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:1114 #: 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:74 #: 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:88 #: 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:84 #: 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:122 #: 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:80 #: 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:92
#, elixir-autogen, elixir-format, fuzzy
msgid "Please select a type and container"
msgstr ""

View File

@ -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:27
#: 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 ""
@ -58,8 +58,8 @@ msgstr ""
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:189 #: 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:59 #: 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/ammo_type_live/form_component.html.heex:351
#: lib/cannery_web/live/container_live/form_component.html.heex:59 #: lib/cannery_web/live/container_live/form_component.html.heex:59
#: lib/cannery_web/live/invite_live/form_component.html.heex:37 #: lib/cannery_web/live/invite_live/form_component.html.heex:37
#: lib/cannery_web/live/pack_live/form_component.html.heex:85
#: lib/cannery_web/live/range_live/form_component.html.heex:47 #: lib/cannery_web/live/range_live/form_component.html.heex:47
#: 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:152 #: 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:10 #: lib/cannery_web/live/pack_live/index.html.heex:10
#: lib/cannery_web/live/ammo_group_live/index.html.heex:20 #: 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:78
#, 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:122 #: 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 ""

View File

@ -56,7 +56,7 @@ msgstr ""
msgid "Not found" msgid "Not found"
msgstr "" msgstr ""
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:18 #: 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
@ -145,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:1114 #: 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:74 #: 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:88 #: 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:84 #: 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:122 #: 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:80 #: 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:92
#, elixir-autogen, elixir-format
msgid "Please select a type and container"
msgstr ""

View File

@ -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:38 #: 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:34 #: 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:57 #: 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/ammo_type_live/form_component.html.heex:350
#: lib/cannery_web/live/container_live/form_component.html.heex:57 #: lib/cannery_web/live/container_live/form_component.html.heex:57
#: lib/cannery_web/live/invite_live/form_component.html.heex:35 #: lib/cannery_web/live/invite_live/form_component.html.heex:35
#: lib/cannery_web/live/pack_live/form_component.html.heex:84
#: lib/cannery_web/live/range_live/form_component.html.heex:45 #: lib/cannery_web/live/range_live/form_component.html.heex:45
#: 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"
@ -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:125 #: 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:14 #: 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:77
#, 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:24 #: 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:142
#: 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,11 +240,6 @@ 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:110
#, elixir-autogen, elixir-format
msgid "Clone %{ammo_type_name}"
msgstr ""
#: lib/cannery_web/live/container_live/index.html.heex:87 #: lib/cannery_web/live/container_live/index.html.heex:87
#: lib/cannery_web/live/container_live/index.html.heex:145 #: lib/cannery_web/live/container_live/index.html.heex:145
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
@ -266,12 +251,6 @@ 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:129
#: lib/cannery_web/live/ammo_type_live/show.html.heex:36
#, elixir-autogen, elixir-format
msgid "Delete %{ammo_type_name}"
msgstr ""
#: lib/cannery_web/live/container_live/index.html.heex:104 #: lib/cannery_web/live/container_live/index.html.heex:104
#: lib/cannery_web/live/container_live/index.html.heex:162 #: lib/cannery_web/live/container_live/index.html.heex:162
#: lib/cannery_web/live/container_live/show.html.heex:48 #: lib/cannery_web/live/container_live/show.html.heex:48
@ -289,18 +268,6 @@ 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/range_live/index.html.heex:155
#, elixir-autogen, elixir-format
msgid "Delete shot record of %{shot_group_count} shots"
msgstr ""
#: lib/cannery_web/live/ammo_type_live/index.html.heex:100
#: 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:77 #: lib/cannery_web/live/container_live/index.html.heex:77
#: lib/cannery_web/live/container_live/index.html.heex:135 #: lib/cannery_web/live/container_live/index.html.heex:135
#: lib/cannery_web/live/container_live/show.html.heex:35 #: lib/cannery_web/live/container_live/show.html.heex:35
@ -313,28 +280,12 @@ msgstr ""
msgid "Edit %{tag_name}" msgid "Edit %{tag_name}"
msgstr "" msgstr ""
#: lib/cannery_web/live/ammo_group_live/index.html.heex:164
#: 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:138
#, elixir-autogen, elixir-format
msgid "Edit shot record of %{shot_group_count} shots"
msgstr ""
#: lib/cannery_web/live/ammo_group_live/index.html.heex:118
#, elixir-autogen, elixir-format, fuzzy #, elixir-autogen, elixir-format, fuzzy
msgid "Stage" msgid "Stage"
msgstr "Preparar munición" msgstr "Preparar munición"
@ -345,29 +296,74 @@ msgstr "Preparar munición"
msgid "Tag %{container_name}" msgid "Tag %{container_name}"
msgstr "" msgstr ""
#: lib/cannery_web/live/ammo_group_live/index.html.heex:117 #: 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:90 #: 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:176 #: 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:191 #: 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:152 #: lib/cannery_web/live/pack_live/index.html.heex:154
#: lib/cannery_web/live/ammo_type_live/show.html.heex:206 #: 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

View File

@ -69,7 +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/ammo_type_live/form_component.html.heex:18 #: 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
@ -161,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:1114 #: 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:74 #: 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:88 #: 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:84 #: 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:122 #: 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:80 #: 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:92
#, elixir-autogen, elixir-format, fuzzy
msgid "Please select a type and container"
msgstr "Por favor escoja un tipo de munición y un contenedor"

View File

@ -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:27
#: 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"
@ -73,8 +73,8 @@ msgstr "Está seguro que desea eliminar %{email}? Esta acción es permanente!"
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:189 #: 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:59 #: 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/ammo_type_live/form_component.html.heex:351
#: lib/cannery_web/live/container_live/form_component.html.heex:59 #: lib/cannery_web/live/container_live/form_component.html.heex:59
#: lib/cannery_web/live/invite_live/form_component.html.heex:37 #: lib/cannery_web/live/invite_live/form_component.html.heex:37
#: lib/cannery_web/live/pack_live/form_component.html.heex:85
#: lib/cannery_web/live/range_live/form_component.html.heex:47 #: lib/cannery_web/live/range_live/form_component.html.heex:47
#: 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:152 #: 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:10 #: lib/cannery_web/live/pack_live/index.html.heex:10
#: lib/cannery_web/live/ammo_group_live/index.html.heex:20 #: 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:78
#, 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:122 #: 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 ""

View File

@ -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:38 #: 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:34 #: 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:57 #: 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/ammo_type_live/form_component.html.heex:350
#: lib/cannery_web/live/container_live/form_component.html.heex:57 #: lib/cannery_web/live/container_live/form_component.html.heex:57
#: lib/cannery_web/live/invite_live/form_component.html.heex:35 #: lib/cannery_web/live/invite_live/form_component.html.heex:35
#: lib/cannery_web/live/pack_live/form_component.html.heex:84
#: lib/cannery_web/live/range_live/form_component.html.heex:45 #: lib/cannery_web/live/range_live/form_component.html.heex:45
#: 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"
@ -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:125 #: 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:14 #: 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:77
#, 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:24 #: 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:142
#: 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,11 +240,6 @@ msgstr ""
msgid "Export Data as JSON" msgid "Export Data as JSON"
msgstr "" msgstr ""
#: lib/cannery_web/live/ammo_type_live/index.html.heex:110
#, elixir-autogen, elixir-format
msgid "Clone %{ammo_type_name}"
msgstr ""
#: lib/cannery_web/live/container_live/index.html.heex:87 #: lib/cannery_web/live/container_live/index.html.heex:87
#: lib/cannery_web/live/container_live/index.html.heex:145 #: lib/cannery_web/live/container_live/index.html.heex:145
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
@ -266,12 +251,6 @@ 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:129
#: lib/cannery_web/live/ammo_type_live/show.html.heex:36
#, elixir-autogen, elixir-format
msgid "Delete %{ammo_type_name}"
msgstr ""
#: lib/cannery_web/live/container_live/index.html.heex:104 #: lib/cannery_web/live/container_live/index.html.heex:104
#: lib/cannery_web/live/container_live/index.html.heex:162 #: lib/cannery_web/live/container_live/index.html.heex:162
#: lib/cannery_web/live/container_live/show.html.heex:48 #: lib/cannery_web/live/container_live/show.html.heex:48
@ -289,18 +268,6 @@ 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/range_live/index.html.heex:155
#, elixir-autogen, elixir-format
msgid "Delete shot record of %{shot_group_count} shots"
msgstr ""
#: lib/cannery_web/live/ammo_type_live/index.html.heex:100
#: 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:77 #: lib/cannery_web/live/container_live/index.html.heex:77
#: lib/cannery_web/live/container_live/index.html.heex:135 #: lib/cannery_web/live/container_live/index.html.heex:135
#: lib/cannery_web/live/container_live/show.html.heex:35 #: lib/cannery_web/live/container_live/show.html.heex:35
@ -313,28 +280,12 @@ msgstr ""
msgid "Edit %{tag_name}" msgid "Edit %{tag_name}"
msgstr "" msgstr ""
#: lib/cannery_web/live/ammo_group_live/index.html.heex:164
#: 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:138
#, elixir-autogen, elixir-format
msgid "Edit shot record of %{shot_group_count} shots"
msgstr ""
#: lib/cannery_web/live/ammo_group_live/index.html.heex:118
#, elixir-autogen, elixir-format, fuzzy #, elixir-autogen, elixir-format, fuzzy
msgid "Stage" msgid "Stage"
msgstr "Munition préparée" msgstr "Munition préparée"
@ -345,29 +296,74 @@ msgstr "Munition préparée"
msgid "Tag %{container_name}" msgid "Tag %{container_name}"
msgstr "" msgstr ""
#: lib/cannery_web/live/ammo_group_live/index.html.heex:117 #: 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:90 #: 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:176 #: 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:191 #: 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:152 #: lib/cannery_web/live/pack_live/index.html.heex:154
#: lib/cannery_web/live/ammo_type_live/show.html.heex:206 #: 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

View File

@ -69,7 +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/ammo_type_live/form_component.html.heex:18 #: 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
@ -162,52 +162,52 @@ msgstr ""
msgid "Tag could not be removed" msgid "Tag could not be removed"
msgstr "Le tag na pas pu être retiré" msgstr "Le tag na 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:1114 #: 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:74 #: 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:88 #: 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:84 #: 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:122 #: 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:80 #: 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:92
#, elixir-autogen, elixir-format, fuzzy
msgid "Please select a type and container"
msgstr "Veuillez choisir un type de munitions et un conteneur"

View File

@ -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:27
#: 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"
@ -74,8 +74,8 @@ msgstr ""
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:189 #: 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:59 #: 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/ammo_type_live/form_component.html.heex:351
#: lib/cannery_web/live/container_live/form_component.html.heex:59 #: lib/cannery_web/live/container_live/form_component.html.heex:59
#: lib/cannery_web/live/invite_live/form_component.html.heex:37 #: lib/cannery_web/live/invite_live/form_component.html.heex:37
#: lib/cannery_web/live/pack_live/form_component.html.heex:85
#: lib/cannery_web/live/range_live/form_component.html.heex:47 #: lib/cannery_web/live/range_live/form_component.html.heex:47
#: 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:152 #: 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:10 #: lib/cannery_web/live/pack_live/index.html.heex:10
#: lib/cannery_web/live/ammo_group_live/index.html.heex:20 #: 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:78
#, 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:122 #: 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}?"

View File

@ -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:38 #: 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:34 #: 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:57 #: 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/ammo_type_live/form_component.html.heex:350
#: lib/cannery_web/live/container_live/form_component.html.heex:57 #: lib/cannery_web/live/container_live/form_component.html.heex:57
#: lib/cannery_web/live/invite_live/form_component.html.heex:35 #: lib/cannery_web/live/invite_live/form_component.html.heex:35
#: lib/cannery_web/live/pack_live/form_component.html.heex:84
#: lib/cannery_web/live/range_live/form_component.html.heex:45 #: lib/cannery_web/live/range_live/form_component.html.heex:45
#: 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 ""
@ -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:125 #: 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:14 #: 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:77
#, 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:24 #: 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:142
#: 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,11 +238,6 @@ msgstr ""
msgid "Export Data as JSON" msgid "Export Data as JSON"
msgstr "" msgstr ""
#: lib/cannery_web/live/ammo_type_live/index.html.heex:110
#, elixir-autogen, elixir-format
msgid "Clone %{ammo_type_name}"
msgstr ""
#: lib/cannery_web/live/container_live/index.html.heex:87 #: lib/cannery_web/live/container_live/index.html.heex:87
#: lib/cannery_web/live/container_live/index.html.heex:145 #: lib/cannery_web/live/container_live/index.html.heex:145
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
@ -264,12 +249,6 @@ 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:129
#: lib/cannery_web/live/ammo_type_live/show.html.heex:36
#, elixir-autogen, elixir-format
msgid "Delete %{ammo_type_name}"
msgstr ""
#: lib/cannery_web/live/container_live/index.html.heex:104 #: lib/cannery_web/live/container_live/index.html.heex:104
#: lib/cannery_web/live/container_live/index.html.heex:162 #: lib/cannery_web/live/container_live/index.html.heex:162
#: lib/cannery_web/live/container_live/show.html.heex:48 #: lib/cannery_web/live/container_live/show.html.heex:48
@ -287,18 +266,6 @@ 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/range_live/index.html.heex:155
#, elixir-autogen, elixir-format
msgid "Delete shot record of %{shot_group_count} shots"
msgstr ""
#: lib/cannery_web/live/ammo_type_live/index.html.heex:100
#: 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:77 #: lib/cannery_web/live/container_live/index.html.heex:77
#: lib/cannery_web/live/container_live/index.html.heex:135 #: lib/cannery_web/live/container_live/index.html.heex:135
#: lib/cannery_web/live/container_live/show.html.heex:35 #: lib/cannery_web/live/container_live/show.html.heex:35
@ -311,28 +278,12 @@ msgstr ""
msgid "Edit %{tag_name}" msgid "Edit %{tag_name}"
msgstr "" msgstr ""
#: lib/cannery_web/live/ammo_group_live/index.html.heex:164
#: 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:138
#, elixir-autogen, elixir-format
msgid "Edit shot record of %{shot_group_count} shots"
msgstr ""
#: lib/cannery_web/live/ammo_group_live/index.html.heex:118
#, elixir-autogen, elixir-format, fuzzy #, elixir-autogen, elixir-format, fuzzy
msgid "Stage" msgid "Stage"
msgstr "" msgstr ""
@ -343,29 +294,74 @@ msgstr ""
msgid "Tag %{container_name}" msgid "Tag %{container_name}"
msgstr "" msgstr ""
#: lib/cannery_web/live/ammo_group_live/index.html.heex:117 #: 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:90 #: 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:176 #: 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:191 #: 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:152 #: lib/cannery_web/live/pack_live/index.html.heex:154
#: lib/cannery_web/live/ammo_type_live/show.html.heex:206 #: 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

View File

@ -70,7 +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/ammo_type_live/form_component.html.heex:18 #: 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
@ -161,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:1114 #: 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:74 #: 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:88 #: 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:84 #: 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:122 #: 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:80 #: 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:92
#, elixir-autogen, elixir-format, fuzzy
msgid "Please select a type and container"
msgstr ""

View File

@ -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:27
#: 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 ""
@ -69,8 +69,8 @@ msgstr ""
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:189 #: 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:59 #: 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/ammo_type_live/form_component.html.heex:351
#: lib/cannery_web/live/container_live/form_component.html.heex:59 #: lib/cannery_web/live/container_live/form_component.html.heex:59
#: lib/cannery_web/live/invite_live/form_component.html.heex:37 #: lib/cannery_web/live/invite_live/form_component.html.heex:37
#: lib/cannery_web/live/pack_live/form_component.html.heex:85
#: lib/cannery_web/live/range_live/form_component.html.heex:47 #: lib/cannery_web/live/range_live/form_component.html.heex:47
#: 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:152 #: 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:10 #: lib/cannery_web/live/pack_live/index.html.heex:10
#: lib/cannery_web/live/ammo_group_live/index.html.heex:20 #: 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:78
#, 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:122 #: 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 ""

View File

@ -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:27
#: 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 ""
@ -58,8 +58,8 @@ msgstr ""
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:189 #: 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:59 #: 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/ammo_type_live/form_component.html.heex:351
#: lib/cannery_web/live/container_live/form_component.html.heex:59 #: lib/cannery_web/live/container_live/form_component.html.heex:59
#: lib/cannery_web/live/invite_live/form_component.html.heex:37 #: lib/cannery_web/live/invite_live/form_component.html.heex:37
#: lib/cannery_web/live/pack_live/form_component.html.heex:85
#: lib/cannery_web/live/range_live/form_component.html.heex:47 #: lib/cannery_web/live/range_live/form_component.html.heex:47
#: 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:152 #: 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:10 #: lib/cannery_web/live/pack_live/index.html.heex:10
#: lib/cannery_web/live/ammo_group_live/index.html.heex:20 #: 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:78
#, 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:122 #: 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 ""

View 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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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
) )

View File

@ -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

View File

@ -5,421 +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 "get_shot_group!/2 returns the shot_group with given id", 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.get_shot_group!(shot_group.id, 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 "get_shot_group!/2 does not return a shot_group of another user", test "get_shot_record!/2 returns the shot_record with given id",
%{shot_group: shot_group} do %{shot_record: shot_record, current_user: current_user} do
assert ActivityLog.get_shot_record!(shot_record.id, current_user) == shot_record
end
test "get_shot_record!/2 does not return a shot_record of another user",
%{shot_record: shot_record} 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
end end
describe "list_shot_groups/3" do describe "list_shot_records/3" 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, [ammo_group]} = ammo_group_fixture(ammo_type, container, current_user) {1, [pack]} = pack_fixture(type, container, 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
] ]
end end
test "list_shot_groups/3 returns relevant shot_groups for a type", test "list_shot_records/3 returns relevant shot_records for a type",
%{current_user: current_user, container: container} do %{current_user: current_user, container: container} do
other_user = user_fixture() other_user = user_fixture()
other_container = container_fixture(other_user) other_container = container_fixture(other_user)
for type <- ["rifle", "shotgun", "pistol"] do for class <- ["rifle", "shotgun", "pistol"] do
other_ammo_type = ammo_type_fixture(%{"type" => type}, other_user) other_type = type_fixture(%{class: class}, other_user)
{1, [other_ammo_group]} = ammo_group_fixture(other_ammo_type, other_container, other_user) {1, [other_pack]} = pack_fixture(other_type, other_container, other_user)
shot_group_fixture(other_user, other_ammo_group) shot_record_fixture(other_user, other_pack)
end end
rifle_ammo_type = ammo_type_fixture(%{"type" => "rifle"}, current_user) rifle_type = type_fixture(%{class: :rifle}, current_user)
{1, [rifle_ammo_group]} = ammo_group_fixture(rifle_ammo_type, container, current_user) {1, [rifle_pack]} = pack_fixture(rifle_type, container, current_user)
rifle_shot_group = shot_group_fixture(current_user, rifle_ammo_group) rifle_shot_record = shot_record_fixture(current_user, rifle_pack)
shotgun_ammo_type = ammo_type_fixture(%{"type" => "shotgun"}, current_user) shotgun_type = type_fixture(%{class: :shotgun}, current_user)
{1, [shotgun_ammo_group]} = ammo_group_fixture(shotgun_ammo_type, container, current_user) {1, [shotgun_pack]} = pack_fixture(shotgun_type, container, current_user)
shotgun_shot_group = shot_group_fixture(current_user, shotgun_ammo_group) shotgun_shot_record = shot_record_fixture(current_user, shotgun_pack)
pistol_ammo_type = ammo_type_fixture(%{"type" => "pistol"}, current_user) pistol_type = type_fixture(%{class: :pistol}, current_user)
{1, [pistol_ammo_group]} = ammo_group_fixture(pistol_ammo_type, container, current_user) {1, [pistol_pack]} = pack_fixture(pistol_type, container, current_user)
pistol_shot_group = shot_group_fixture(current_user, pistol_ammo_group) pistol_shot_record = shot_record_fixture(current_user, pistol_pack)
assert [^rifle_shot_group] = ActivityLog.list_shot_groups(:rifle, current_user) assert [^rifle_shot_record] = ActivityLog.list_shot_records(:rifle, current_user)
assert [^shotgun_shot_group] = ActivityLog.list_shot_groups(:shotgun, current_user) assert [^shotgun_shot_record] = ActivityLog.list_shot_records(:shotgun, current_user)
assert [^pistol_shot_group] = ActivityLog.list_shot_groups(:pistol, current_user) assert [^pistol_shot_record] = ActivityLog.list_shot_records(:pistol, current_user)
shot_groups = ActivityLog.list_shot_groups(:all, current_user) shot_records = ActivityLog.list_shot_records(:all, current_user)
assert Enum.count(shot_groups) == 3 assert Enum.count(shot_records) == 3
assert rifle_shot_group in shot_groups assert rifle_shot_record in shot_records
assert shotgun_shot_group in shot_groups assert shotgun_shot_record in shot_records
assert pistol_shot_group in shot_groups assert pistol_shot_record in shot_records
shot_groups = ActivityLog.list_shot_groups(nil, current_user) shot_records = ActivityLog.list_shot_records(nil, current_user)
assert Enum.count(shot_groups) == 3 assert Enum.count(shot_records) == 3
assert rifle_shot_group in shot_groups assert rifle_shot_record in shot_records
assert shotgun_shot_group in shot_groups assert shotgun_shot_record in shot_records
assert pistol_shot_group in shot_groups assert pistol_shot_record in shot_records
end end
test "list_shot_groups/3 returns relevant shot_groups for a search", %{ test "list_shot_records/3 returns relevant shot_records for a search", %{
ammo_type: ammo_type, type: type,
ammo_group: ammo_group, pack: pack,
container: container, container: container,
current_user: current_user current_user: current_user
} do } do
shot_group_a = shot_group_fixture(%{"notes" => "amazing"}, current_user, ammo_group) shot_record_a = shot_record_fixture(%{notes: "amazing"}, current_user, pack)
{1, [another_ammo_group]} = {1, [another_pack]} = pack_fixture(%{notes: "stupendous"}, type, container, current_user)
ammo_group_fixture(%{"notes" => "stupendous"}, ammo_type, container, current_user)
shot_group_b = shot_group_fixture(current_user, another_ammo_group) shot_record_b = shot_record_fixture(current_user, another_pack)
another_ammo_type = ammo_type_fixture(%{"name" => "fabulous ammo"}, current_user) another_type = type_fixture(%{name: "fabulous ammo"}, current_user)
{1, [yet_another_ammo_group]} = {1, [yet_another_pack]} = pack_fixture(another_type, container, current_user)
ammo_group_fixture(another_ammo_type, container, current_user)
shot_group_c = shot_group_fixture(current_user, yet_another_ammo_group) shot_record_c = shot_record_fixture(current_user, yet_another_pack)
another_user = user_fixture() another_user = user_fixture()
another_container = container_fixture(another_user) another_container = container_fixture(another_user)
another_ammo_type = ammo_type_fixture(another_user) another_type = type_fixture(another_user)
{1, [another_ammo_group]} = {1, [another_pack]} = pack_fixture(another_type, another_container, another_user)
ammo_group_fixture(another_ammo_type, another_container, another_user)
_shouldnt_return = shot_group_fixture(another_user, another_ammo_group) _shouldnt_return = shot_record_fixture(another_user, another_pack)
# notes # notes
assert ActivityLog.list_shot_groups("amazing", :all, current_user) == [shot_group_a] assert ActivityLog.list_shot_records("amazing", :all, current_user) == [shot_record_a]
# ammo group attributes # pack attributes
assert ActivityLog.list_shot_groups("stupendous", :all, current_user) == [shot_group_b] assert ActivityLog.list_shot_records("stupendous", :all, current_user) == [shot_record_b]
# ammo type attributes # type attributes
assert ActivityLog.list_shot_groups("fabulous", :all, current_user) == [shot_group_c] 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

View File

@ -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" => "#100000", bg_color: "#100000",
"name" => "some name", name: "some name",
"text_color" => "#000000" text_color: "#000000"
} }
@update_tag_attrs %{ @update_tag_attrs %{
"bg_color" => "#100001", bg_color: "#100001",
"name" => "some updated name", name: "some updated name",
"text_color" => "#000001" 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]

View File

@ -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,55 @@ 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, "staged" => pack.staged,
"used_count" => ammo_group |> ActivityLog.get_used_count(current_user), "used_count" => pack |> ActivityLog.get_used_count(current_user),
"original_count" => ammo_group |> Ammo.get_original_count(current_user), "original_count" => pack |> Ammo.get_original_count(current_user),
"cpr" => ammo_group |> Ammo.get_cpr(current_user), "cpr" => pack |> Ammo.get_cpr(current_user),
"percentage_remaining" => ammo_group |> Ammo.get_percentage_remaining(current_user) "percentage_remaining" => pack |> Ammo.get_percentage_remaining(current_user)
} }
ideal_ammo_type = %{ ideal_type = %{
"blank" => ammo_type.blank, "blank" => type.blank,
"bullet_core" => ammo_type.bullet_core, "bullet_core" => type.bullet_core,
"bullet_type" => ammo_type.bullet_type, "bullet_type" => type.bullet_type,
"caliber" => ammo_type.caliber, "caliber" => type.caliber,
"cartridge" => ammo_type.cartridge, "cartridge" => type.cartridge,
"case_material" => ammo_type.case_material, "case_material" => type.case_material,
"corrosive" => ammo_type.corrosive, "corrosive" => type.corrosive,
"desc" => ammo_type.desc, "desc" => type.desc,
"firing_type" => ammo_type.firing_type, "firing_type" => type.firing_type,
"grains" => ammo_type.grains, "grains" => type.grains,
"id" => ammo_type.id, "id" => type.id,
"incendiary" => ammo_type.incendiary, "incendiary" => type.incendiary,
"jacket_type" => ammo_type.jacket_type, "jacket_type" => type.jacket_type,
"manufacturer" => ammo_type.manufacturer, "manufacturer" => type.manufacturer,
"muzzle_velocity" => ammo_type.muzzle_velocity, "muzzle_velocity" => type.muzzle_velocity,
"name" => ammo_type.name, "name" => type.name,
"powder_grains_per_charge" => ammo_type.powder_grains_per_charge, "powder_grains_per_charge" => type.powder_grains_per_charge,
"powder_type" => ammo_type.powder_type, "powder_type" => type.powder_type,
"pressure" => ammo_type.pressure, "pressure" => type.pressure,
"primer_type" => ammo_type.primer_type, "primer_type" => type.primer_type,
"tracer" => ammo_type.tracer, "tracer" => type.tracer,
"upc" => ammo_type.upc, "upc" => type.upc,
"average_cost" => ammo_type |> Ammo.get_average_cost_for_ammo_type(current_user), "average_cost" => type |> Ammo.get_average_cost_for_type(current_user),
"round_count" => ammo_type |> Ammo.get_round_count_for_ammo_type(current_user), "round_count" => type |> Ammo.get_round_count_for_type(current_user),
"used_count" => ammo_type |> ActivityLog.get_used_count_for_ammo_type(current_user), "used_count" => type |> ActivityLog.get_used_count_for_type(current_user),
"ammo_group_count" => ammo_type |> Ammo.get_ammo_groups_count_for_type(current_user), "pack_count" => type |> Ammo.get_packs_count_for_type(current_user),
"total_ammo_group_count" => "total_pack_count" => type |> Ammo.get_packs_count_for_type(current_user, true)
ammo_type |> Ammo.get_ammo_groups_count_for_type(current_user, true)
} }
ideal_container = %{ ideal_container = %{
@ -101,17 +100,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 +124,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

View File

@ -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

View File

@ -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

View File

@ -4,7 +4,6 @@ defmodule CanneryWeb.UserRegistrationControllerTest do
""" """
use CanneryWeb.ConnCase, async: true use CanneryWeb.ConnCase, async: true
import CanneryWeb.Gettext
@moduletag :user_registration_controller_test @moduletag :user_registration_controller_test
@ -12,8 +11,8 @@ defmodule CanneryWeb.UserRegistrationControllerTest do
test "renders registration page", %{conn: conn} do test "renders registration page", %{conn: conn} do
conn = get(conn, Routes.user_registration_path(conn, :new)) conn = get(conn, Routes.user_registration_path(conn, :new))
response = html_response(conn, 200) response = html_response(conn, 200)
assert response =~ dgettext("actions", "Register") assert response =~ "Register"
assert response =~ dgettext("actions", "Log in") assert response =~ "Log in"
end end
test "redirects if already logged in", %{conn: conn} do test "redirects if already logged in", %{conn: conn} do
@ -29,11 +28,11 @@ defmodule CanneryWeb.UserRegistrationControllerTest do
conn = conn =
post(conn, Routes.user_registration_path(conn, :create), %{ post(conn, Routes.user_registration_path(conn, :create), %{
"user" => valid_user_attributes(email: email) user: valid_user_attributes(email: email)
}) })
assert get_session(conn, :phoenix_flash) == %{ assert get_session(conn, :phoenix_flash) == %{
"info" => dgettext("prompts", "Please check your email to verify your account") "info" => "Please check your email to verify your account"
} }
assert redirected_to(conn) =~ "/" assert redirected_to(conn) =~ "/"
@ -48,11 +47,11 @@ defmodule CanneryWeb.UserRegistrationControllerTest do
test "render errors for invalid data", %{conn: conn} do test "render errors for invalid data", %{conn: conn} do
conn = conn =
post(conn, Routes.user_registration_path(conn, :create), %{ post(conn, Routes.user_registration_path(conn, :create), %{
"user" => %{"email" => "with spaces", "password" => "too short"} user: %{email: "with spaces", password: "too short"}
}) })
response = html_response(conn, 200) response = html_response(conn, 200)
assert response =~ gettext("Register") assert response =~ "Register"
assert response =~ "must have the @ sign and no spaces" assert response =~ "must have the @ sign and no spaces"
assert response =~ "should be at least 12 character" assert response =~ "should be at least 12 character"
end end

View File

@ -4,7 +4,6 @@ defmodule CanneryWeb.UserResetPasswordControllerTest do
""" """
use CanneryWeb.ConnCase, async: true use CanneryWeb.ConnCase, async: true
import CanneryWeb.Gettext
alias Cannery.{Accounts, Repo} alias Cannery.{Accounts, Repo}
@moduletag :user_reset_password_controller_test @moduletag :user_reset_password_controller_test
@ -17,7 +16,7 @@ defmodule CanneryWeb.UserResetPasswordControllerTest do
test "renders the reset password page", %{conn: conn} do test "renders the reset password page", %{conn: conn} do
conn = get(conn, Routes.user_reset_password_path(conn, :new)) conn = get(conn, Routes.user_reset_password_path(conn, :new))
response = html_response(conn, 200) response = html_response(conn, 200)
assert response =~ dgettext("actions", "Forgot your password?") assert response =~ "Forgot your password?"
end end
end end
@ -25,17 +24,12 @@ defmodule CanneryWeb.UserResetPasswordControllerTest do
@tag :capture_log @tag :capture_log
test "sends a new reset password token", %{conn: conn, user: user} do test "sends a new reset password token", %{conn: conn, user: user} do
conn = conn =
post(conn, Routes.user_reset_password_path(conn, :create), %{ post(conn, Routes.user_reset_password_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, you will receive instructions to reset your password shortly."
"prompts",
"If your email is in our system, you will receive instructions to reset your password shortly."
)
assert Repo.get_by!(Accounts.UserToken, user_id: user.id).context == "reset_password" assert Repo.get_by!(Accounts.UserToken, user_id: user.id).context == "reset_password"
end end
@ -43,16 +37,13 @@ defmodule CanneryWeb.UserResetPasswordControllerTest do
test "does not send reset password token if email is invalid", %{conn: conn} do test "does not send reset password token if email is invalid", %{conn: conn} do
conn = conn =
post(conn, Routes.user_reset_password_path(conn, :create), %{ post(conn, Routes.user_reset_password_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, you will receive instructions to reset your password shortly."
"prompts",
"If your email is in our system, you will receive instructions to reset your password shortly."
)
assert Repo.all(Accounts.UserToken) == [] assert Repo.all(Accounts.UserToken) == []
end end
@ -70,15 +61,13 @@ defmodule CanneryWeb.UserResetPasswordControllerTest do
test "renders reset password", %{conn: conn, token: token} do test "renders reset password", %{conn: conn, token: token} do
conn = get(conn, Routes.user_reset_password_path(conn, :edit, token)) conn = get(conn, Routes.user_reset_password_path(conn, :edit, token))
assert html_response(conn, 200) =~ dgettext("actions", "Reset password") assert html_response(conn, 200) =~ "Reset password"
end end
test "does not render reset password with invalid token", %{conn: conn} do test "does not render reset password with invalid token", %{conn: conn} do
conn = get(conn, Routes.user_reset_password_path(conn, :edit, "oops")) conn = get(conn, Routes.user_reset_password_path(conn, :edit, "oops"))
assert redirected_to(conn) == "/" assert redirected_to(conn) == "/"
assert get_flash(conn, :error) =~ "Reset password link is invalid or it has expired"
assert get_flash(conn, :error) =~
dgettext("errors", "Reset password link is invalid or it has expired")
end end
end end
@ -95,39 +84,37 @@ defmodule CanneryWeb.UserResetPasswordControllerTest do
test "resets password once", %{conn: conn, user: user, token: token} do test "resets password once", %{conn: conn, user: user, token: token} do
conn = conn =
put(conn, Routes.user_reset_password_path(conn, :update, token), %{ put(conn, Routes.user_reset_password_path(conn, :update, token), %{
"user" => %{ user: %{
"password" => "new valid password", password: "new valid password",
"password_confirmation" => "new valid password" password_confirmation: "new valid password"
} }
}) })
assert redirected_to(conn) == Routes.user_session_path(conn, :new) assert redirected_to(conn) == Routes.user_session_path(conn, :new)
refute get_session(conn, :user_token) refute get_session(conn, :user_token)
assert get_flash(conn, :info) =~ dgettext("prompts", "Password reset successfully") assert get_flash(conn, :info) =~ "Password reset successfully"
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")
end end
test "does not reset password on invalid data", %{conn: conn, token: token} do test "does not reset password on invalid data", %{conn: conn, token: token} do
conn = conn =
put(conn, Routes.user_reset_password_path(conn, :update, token), %{ put(conn, Routes.user_reset_password_path(conn, :update, token), %{
"user" => %{ user: %{
"password" => "too short", password: "too short",
"password_confirmation" => "does not match" password_confirmation: "does not match"
} }
}) })
response = html_response(conn, 200) response = html_response(conn, 200)
assert response =~ gettext("Reset password") assert response =~ "Reset password"
assert response =~ dgettext("errors", "should be at least 12 character(s)") assert response =~ "should be at least 12 character(s)"
assert response =~ dgettext("errors", "does not match password") assert response =~ "does not match password"
end end
test "does not reset password with invalid token", %{conn: conn} do test "does not reset password with invalid token", %{conn: conn} do
conn = put(conn, Routes.user_reset_password_path(conn, :update, "oops")) conn = put(conn, Routes.user_reset_password_path(conn, :update, "oops"))
assert redirected_to(conn) == "/" assert redirected_to(conn) == "/"
assert get_flash(conn, :error) =~ "Reset password link is invalid or it has expired"
assert get_flash(conn, :error) =~
dgettext("errors", "Reset password link is invalid or it has expired")
end end
end end
end end

View File

@ -4,7 +4,6 @@ defmodule CanneryWeb.UserSessionControllerTest do
""" """
use CanneryWeb.ConnCase, async: true use CanneryWeb.ConnCase, async: true
import CanneryWeb.Gettext
@moduletag :user_session_controller_test @moduletag :user_session_controller_test
@ -16,7 +15,7 @@ defmodule CanneryWeb.UserSessionControllerTest do
test "renders log in page", %{conn: conn} do test "renders log in page", %{conn: conn} do
conn = get(conn, Routes.user_session_path(conn, :new)) conn = get(conn, Routes.user_session_path(conn, :new))
response = html_response(conn, 200) response = html_response(conn, 200)
assert response =~ dgettext("actions", "Log in") assert response =~ "Log in"
end end
test "redirects if already logged in", %{conn: conn, current_user: current_user} do test "redirects if already logged in", %{conn: conn, current_user: current_user} do
@ -29,7 +28,7 @@ defmodule CanneryWeb.UserSessionControllerTest do
test "logs the user in", %{conn: conn, current_user: current_user} do test "logs the user in", %{conn: conn, current_user: current_user} do
conn = conn =
post(conn, Routes.user_session_path(conn, :create), %{ post(conn, Routes.user_session_path(conn, :create), %{
"user" => %{"email" => current_user.email, "password" => valid_user_password()} user: %{email: current_user.email, password: valid_user_password()}
}) })
assert get_session(conn, :user_token) assert get_session(conn, :user_token)
@ -39,16 +38,16 @@ defmodule CanneryWeb.UserSessionControllerTest do
conn = get(conn, "/") conn = get(conn, "/")
response = html_response(conn, 200) response = html_response(conn, 200)
assert response =~ current_user.email assert response =~ current_user.email
assert response =~ dgettext("prompts", "Are you sure you want to log out?") assert response =~ "Are you sure you want to log out?"
end end
test "logs the user in with remember me", %{conn: conn, current_user: current_user} do test "logs the user in with remember me", %{conn: conn, current_user: current_user} do
conn = conn =
post(conn, Routes.user_session_path(conn, :create), %{ post(conn, Routes.user_session_path(conn, :create), %{
"user" => %{ user: %{
"email" => current_user.email, email: current_user.email,
"password" => valid_user_password(), password: valid_user_password(),
"remember_me" => "true" remember_me: "true"
} }
}) })
@ -61,9 +60,9 @@ defmodule CanneryWeb.UserSessionControllerTest do
conn conn
|> init_test_session(user_return_to: "/foo/bar") |> init_test_session(user_return_to: "/foo/bar")
|> post(Routes.user_session_path(conn, :create), %{ |> post(Routes.user_session_path(conn, :create), %{
"user" => %{ user: %{
"email" => current_user.email, email: current_user.email,
"password" => valid_user_password() password: valid_user_password()
} }
}) })
@ -74,12 +73,12 @@ defmodule CanneryWeb.UserSessionControllerTest do
%{conn: conn, current_user: current_user} do %{conn: conn, current_user: current_user} do
conn = conn =
post(conn, Routes.user_session_path(conn, :create), %{ post(conn, Routes.user_session_path(conn, :create), %{
"user" => %{"email" => current_user.email, "password" => "bad"} user: %{email: current_user.email, password: "bad"}
}) })
response = html_response(conn, 200) response = html_response(conn, 200)
assert response =~ dgettext("actions", "Log in") assert response =~ "Log in"
assert response =~ dgettext("errors", "Invalid email or password") assert response =~ "Invalid email or password"
end end
end end
@ -88,14 +87,14 @@ defmodule CanneryWeb.UserSessionControllerTest do
conn = conn |> log_in_user(current_user) |> delete(Routes.user_session_path(conn, :delete)) conn = conn |> log_in_user(current_user) |> delete(Routes.user_session_path(conn, :delete))
assert redirected_to(conn) == "/" assert redirected_to(conn) == "/"
refute get_session(conn, :user_token) refute get_session(conn, :user_token)
assert get_flash(conn, :info) =~ gettext("Logged out successfully") assert get_flash(conn, :info) =~ "Logged out successfully"
end end
test "succeeds even if the user is not logged in", %{conn: conn} do test "succeeds even if the user is not logged in", %{conn: conn} do
conn = delete(conn, Routes.user_session_path(conn, :delete)) conn = delete(conn, Routes.user_session_path(conn, :delete))
assert redirected_to(conn) == "/" assert redirected_to(conn) == "/"
refute get_session(conn, :user_token) refute get_session(conn, :user_token)
assert get_flash(conn, :info) =~ gettext("Logged out successfully") assert get_flash(conn, :info) =~ "Logged out successfully"
end end
end end
end end

View File

@ -4,7 +4,6 @@ defmodule CanneryWeb.UserSettingsControllerTest do
""" """
use CanneryWeb.ConnCase, async: true use CanneryWeb.ConnCase, async: true
import CanneryWeb.Gettext
alias Cannery.Accounts alias Cannery.Accounts
@moduletag :user_settings_controller_test @moduletag :user_settings_controller_test
@ -15,7 +14,7 @@ defmodule CanneryWeb.UserSettingsControllerTest do
test "renders settings page", %{conn: conn} do test "renders settings page", %{conn: conn} do
conn = get(conn, Routes.user_settings_path(conn, :edit)) conn = get(conn, Routes.user_settings_path(conn, :edit))
response = html_response(conn, 200) response = html_response(conn, 200)
assert response =~ gettext("Settings") assert response =~ "Settings"
end end
test "redirects if user is not logged in" do test "redirects if user is not logged in" do
@ -30,40 +29,36 @@ defmodule CanneryWeb.UserSettingsControllerTest do
%{conn: conn, current_user: current_user} do %{conn: conn, current_user: current_user} do
new_password_conn = new_password_conn =
put(conn, Routes.user_settings_path(conn, :update), %{ put(conn, Routes.user_settings_path(conn, :update), %{
"action" => "update_password", action: "update_password",
"current_password" => valid_user_password(), current_password: valid_user_password(),
"user" => %{ user: %{
"password" => "new valid password", password: "new valid password",
"password_confirmation" => "new valid password" password_confirmation: "new valid password"
} }
}) })
assert redirected_to(new_password_conn) == Routes.user_settings_path(conn, :edit) assert redirected_to(new_password_conn) == Routes.user_settings_path(conn, :edit)
assert get_session(new_password_conn, :user_token) != get_session(conn, :user_token) assert get_session(new_password_conn, :user_token) != get_session(conn, :user_token)
assert get_flash(new_password_conn, :info) =~ "Password updated successfully"
assert get_flash(new_password_conn, :info) =~
dgettext("actions", "Password updated successfully")
assert Accounts.get_user_by_email_and_password(current_user.email, "new valid password") assert Accounts.get_user_by_email_and_password(current_user.email, "new valid password")
end end
test "does not update password on invalid data", %{conn: conn} do test "does not update password on invalid data", %{conn: conn} do
old_password_conn = old_password_conn =
put(conn, Routes.user_settings_path(conn, :update), %{ put(conn, Routes.user_settings_path(conn, :update), %{
"action" => "update_password", action: "update_password",
"current_password" => "invalid", current_password: "invalid",
"user" => %{ user: %{
"password" => "too short", password: "too short",
"password_confirmation" => "does not match" password_confirmation: "does not match"
} }
}) })
response = html_response(old_password_conn, 200) response = html_response(old_password_conn, 200)
assert response =~ gettext("Settings") assert response =~ "Settings"
assert response =~ dgettext("errors", "should be at least 12 character(s)") assert response =~ "should be at least 12 character(s)"
assert response =~ dgettext("errors", "does not match password") assert response =~ "does not match password"
assert response =~ dgettext("errors", "is not valid") assert response =~ "is not valid"
assert get_session(old_password_conn, :user_token) == get_session(conn, :user_token) assert get_session(old_password_conn, :user_token) == get_session(conn, :user_token)
end end
end end
@ -73,18 +68,15 @@ defmodule CanneryWeb.UserSettingsControllerTest do
test "updates the user email", %{conn: conn, current_user: current_user} do test "updates the user email", %{conn: conn, current_user: current_user} do
conn = conn =
put(conn, Routes.user_settings_path(conn, :update), %{ put(conn, Routes.user_settings_path(conn, :update), %{
"action" => "update_email", action: "update_email",
"current_password" => valid_user_password(), current_password: valid_user_password(),
"user" => %{"email" => unique_user_email()} user: %{email: unique_user_email()}
}) })
assert redirected_to(conn) == Routes.user_settings_path(conn, :edit) assert redirected_to(conn) == Routes.user_settings_path(conn, :edit)
assert get_flash(conn, :info) =~ assert get_flash(conn, :info) =~
dgettext( "A link to confirm your email change has been sent to the new address."
"prompts",
"A link to confirm your email change has been sent to the new address."
)
assert Accounts.get_user_by_email(current_user.email) assert Accounts.get_user_by_email(current_user.email)
end end
@ -92,15 +84,15 @@ defmodule CanneryWeb.UserSettingsControllerTest do
test "does not update email on invalid data", %{conn: conn} do test "does not update email on invalid data", %{conn: conn} do
conn = conn =
put(conn, Routes.user_settings_path(conn, :update), %{ put(conn, Routes.user_settings_path(conn, :update), %{
"action" => "update_email", action: "update_email",
"current_password" => "invalid", current_password: "invalid",
"user" => %{"email" => "with spaces"} user: %{email: "with spaces"}
}) })
response = html_response(conn, 200) response = html_response(conn, 200)
assert response =~ gettext("Settings") assert response =~ "Settings"
assert response =~ dgettext("errors", "must have the @ sign and no spaces") assert response =~ "must have the @ sign and no spaces"
assert response =~ dgettext("errors", "is not valid") assert response =~ "is not valid"
end end
end end
@ -124,24 +116,19 @@ defmodule CanneryWeb.UserSettingsControllerTest do
%{conn: conn, current_user: current_user, token: token, email: email} do %{conn: conn, current_user: current_user, token: token, email: email} do
conn = get(conn, Routes.user_settings_path(conn, :confirm_email, token)) conn = get(conn, Routes.user_settings_path(conn, :confirm_email, token))
assert redirected_to(conn) == Routes.user_settings_path(conn, :edit) assert redirected_to(conn) == Routes.user_settings_path(conn, :edit)
assert get_flash(conn, :info) =~ dgettext("prompts", "Email changed successfully") assert get_flash(conn, :info) =~ "Email changed successfully"
refute Accounts.get_user_by_email(current_user.email) refute Accounts.get_user_by_email(current_user.email)
assert Accounts.get_user_by_email(email) assert Accounts.get_user_by_email(email)
conn = get(conn, Routes.user_settings_path(conn, :confirm_email, token)) conn = get(conn, Routes.user_settings_path(conn, :confirm_email, token))
assert redirected_to(conn) == Routes.user_settings_path(conn, :edit) assert redirected_to(conn) == Routes.user_settings_path(conn, :edit)
assert get_flash(conn, :error) =~ "Email change link is invalid or it has expired"
assert get_flash(conn, :error) =~
dgettext("errors", "Email change link is invalid or it has expired")
end end
test "does not update email with invalid token", %{conn: conn, current_user: current_user} do test "does not update email with invalid token", %{conn: conn, current_user: current_user} do
conn = get(conn, Routes.user_settings_path(conn, :confirm_email, "oops")) conn = get(conn, Routes.user_settings_path(conn, :confirm_email, "oops"))
assert redirected_to(conn) == Routes.user_settings_path(conn, :edit) assert redirected_to(conn) == Routes.user_settings_path(conn, :edit)
assert get_flash(conn, :error) =~ "Email change link is invalid or it has expired"
assert get_flash(conn, :error) =~
dgettext("errors", "Email change link is invalid or it has expired")
assert Accounts.get_user_by_email(current_user.email) assert Accounts.get_user_by_email(current_user.email)
end end

View File

@ -1,481 +0,0 @@
defmodule CanneryWeb.AmmoGroupLiveTest do
@moduledoc """
Tests ammo group live pages
"""
use CanneryWeb.ConnCase
import Phoenix.LiveViewTest
import CanneryWeb.Gettext
alias Cannery.{Ammo, Repo}
@moduletag :ammo_group_live_test
@shot_group_create_attrs %{"ammo_left" => 5, "notes" => "some notes"}
@shot_group_update_attrs %{
"count" => 5,
"date" => ~N[2022-02-13 03:17:00],
"notes" => "some updated notes"
}
@create_attrs %{"count" => 42, "notes" => "some notes", "price_paid" => 120.5}
@update_attrs %{"count" => 43, "notes" => "some updated notes", "price_paid" => 456.7}
@ammo_group_create_limit 10_000
@empty_attrs %{
"price_paid" => 50,
"count" => 20
}
@shot_group_attrs %{
"price_paid" => 50,
"count" => 20
}
# @invalid_attrs %{count: -1, notes: nil, price_paid: nil}
defp create_ammo_group(%{current_user: current_user}) do
ammo_type = ammo_type_fixture(current_user)
container = container_fixture(current_user)
{1, [ammo_group]} = ammo_group_fixture(@create_attrs, ammo_type, container, current_user)
%{ammo_type: ammo_type, ammo_group: ammo_group, container: container}
end
defp create_shot_group(%{current_user: current_user, ammo_group: ammo_group}) do
shot_group = shot_group_fixture(@shot_group_update_attrs, current_user, ammo_group)
ammo_group = ammo_group |> Repo.reload!()
%{ammo_group: ammo_group, shot_group: shot_group}
end
defp create_empty_ammo_group(%{
current_user: current_user,
ammo_type: ammo_type,
container: container
}) do
{1, [ammo_group]} = ammo_group_fixture(@empty_attrs, ammo_type, container, current_user)
shot_group = shot_group_fixture(@shot_group_attrs, current_user, ammo_group)
ammo_group = ammo_group |> Repo.reload!()
%{empty_ammo_group: ammo_group, shot_group: shot_group}
end
describe "Index of ammo group" do
setup [:register_and_log_in_user, :create_ammo_group]
test "lists all ammo_groups", %{conn: conn, ammo_group: ammo_group} do
{:ok, _index_live, html} = live(conn, Routes.ammo_group_index_path(conn, :index))
ammo_group = ammo_group |> Repo.preload(:ammo_type)
assert html =~ gettext("Ammo")
assert html =~ ammo_group.ammo_type.name
end
test "can sort by type",
%{conn: conn, container: container, current_user: current_user} do
rifle_type = ammo_type_fixture(%{"type" => "rifle"}, current_user)
{1, [rifle_ammo_group]} = ammo_group_fixture(rifle_type, container, current_user)
shotgun_type = ammo_type_fixture(%{"type" => "shotgun"}, current_user)
{1, [shotgun_ammo_group]} = ammo_group_fixture(shotgun_type, container, current_user)
pistol_type = ammo_type_fixture(%{"type" => "pistol"}, current_user)
{1, [pistol_ammo_group]} = ammo_group_fixture(pistol_type, container, current_user)
{:ok, index_live, html} = live(conn, Routes.ammo_group_index_path(conn, :index))
assert html =~ "All"
assert html =~ rifle_ammo_group.ammo_type.name
assert html =~ shotgun_ammo_group.ammo_type.name
assert html =~ pistol_ammo_group.ammo_type.name
html =
index_live
|> form(~s/form[phx-change="change_type"]/)
|> render_change(ammo_type: %{type: :rifle})
assert html =~ rifle_ammo_group.ammo_type.name
refute html =~ shotgun_ammo_group.ammo_type.name
refute html =~ pistol_ammo_group.ammo_type.name
html =
index_live
|> form(~s/form[phx-change="change_type"]/)
|> render_change(ammo_type: %{type: :shotgun})
refute html =~ rifle_ammo_group.ammo_type.name
assert html =~ shotgun_ammo_group.ammo_type.name
refute html =~ pistol_ammo_group.ammo_type.name
html =
index_live
|> form(~s/form[phx-change="change_type"]/)
|> render_change(ammo_type: %{type: :pistol})
refute html =~ rifle_ammo_group.ammo_type.name
refute html =~ shotgun_ammo_group.ammo_type.name
assert html =~ pistol_ammo_group.ammo_type.name
html =
index_live
|> form(~s/form[phx-change="change_type"]/)
|> render_change(ammo_type: %{type: :all})
assert html =~ rifle_ammo_group.ammo_type.name
assert html =~ shotgun_ammo_group.ammo_type.name
assert html =~ pistol_ammo_group.ammo_type.name
end
test "can search for ammo_groups", %{conn: conn, ammo_group: ammo_group} do
{:ok, index_live, html} = live(conn, Routes.ammo_group_index_path(conn, :index))
ammo_group = ammo_group |> Repo.preload(:ammo_type)
assert html =~ ammo_group.ammo_type.name
assert index_live
|> form(~s/form[phx-change="search"]/,
search: %{search_term: ammo_group.ammo_type.name}
)
|> render_change() =~ ammo_group.ammo_type.name
assert_patch(
index_live,
Routes.ammo_group_index_path(conn, :search, ammo_group.ammo_type.name)
)
refute index_live
|> form(~s/form[phx-change="search"]/, search: %{search_term: "something_else"})
|> render_change() =~ ammo_group.ammo_type.name
assert_patch(index_live, Routes.ammo_group_index_path(conn, :search, "something_else"))
assert index_live
|> form(~s/form[phx-change="search"]/, search: %{search_term: ""})
|> render_change() =~ ammo_group.ammo_type.name
assert_patch(index_live, Routes.ammo_group_index_path(conn, :index))
end
test "saves a single new ammo_group", %{conn: conn} do
{:ok, index_live, _html} = live(conn, Routes.ammo_group_index_path(conn, :index))
assert index_live |> element("a", dgettext("actions", "Add Ammo")) |> render_click() =~
dgettext("actions", "Add Ammo")
assert_patch(index_live, Routes.ammo_group_index_path(conn, :new))
# assert index_live
# |> form("#ammo_group-form", ammo_group: @invalid_attrs)
# |> render_change() =~ dgettext("errors", "can't be blank")
{:ok, _view, html} =
index_live
|> form("#ammo_group-form", ammo_group: @create_attrs)
|> render_submit()
|> follow_redirect(conn, Routes.ammo_group_index_path(conn, :index))
assert html =~ dgettext("prompts", "Ammo added successfully")
assert html =~ "\n42\n"
end
test "saves multiple new ammo_groups", %{conn: conn, current_user: current_user} do
multiplier = 25
{:ok, index_live, _html} = live(conn, Routes.ammo_group_index_path(conn, :index))
assert index_live |> element("a", dgettext("actions", "Add Ammo")) |> render_click() =~
dgettext("actions", "Add Ammo")
assert_patch(index_live, Routes.ammo_group_index_path(conn, :new))
# assert index_live
# |> form("#ammo_group-form", ammo_group: @invalid_attrs)
# |> render_change() =~ dgettext("errors", "can't be blank")
{:ok, _view, html} =
index_live
|> form("#ammo_group-form",
ammo_group: @create_attrs |> Map.put("multiplier", to_string(multiplier))
)
|> render_submit()
|> follow_redirect(conn, Routes.ammo_group_index_path(conn, :index))
assert html =~ dgettext("prompts", "Ammo added successfully")
assert Ammo.list_ammo_groups(nil, :all, current_user) |> Enum.count() == multiplier + 1
end
test "does not save invalid number of new ammo_groups", %{conn: conn} do
{:ok, index_live, _html} = live(conn, Routes.ammo_group_index_path(conn, :index))
assert index_live |> element("a", dgettext("actions", "Add Ammo")) |> render_click() =~
dgettext("actions", "Add Ammo")
assert_patch(index_live, Routes.ammo_group_index_path(conn, :new))
# assert index_live
# |> form("#ammo_group-form", ammo_group: @invalid_attrs)
# |> render_change() =~ dgettext("errors", "can't be blank")
assert index_live
|> form("#ammo_group-form", ammo_group: @create_attrs |> Map.put("multiplier", "0"))
|> render_submit() =~
dgettext(
"errors",
"Invalid number of copies, must be between 1 and %{max}. Was %{multiplier}",
multiplier: 0,
max: @ammo_group_create_limit
)
assert index_live
|> form("#ammo_group-form",
ammo_group:
@create_attrs |> Map.put("multiplier", to_string(@ammo_group_create_limit + 1))
)
|> render_submit() =~
dgettext(
"errors",
"Invalid number of copies, must be between 1 and %{max}. Was %{multiplier}",
multiplier: @ammo_group_create_limit + 1,
max: @ammo_group_create_limit
)
end
test "updates ammo_group in listing", %{conn: conn, ammo_group: ammo_group} do
{:ok, index_live, _html} = live(conn, Routes.ammo_group_index_path(conn, :index))
assert index_live
|> element(~s/a[aria-label="Edit ammo group of #{ammo_group.count} bullets"]/)
|> render_click() =~
gettext("Edit ammo")
assert_patch(index_live, Routes.ammo_group_index_path(conn, :edit, ammo_group))
# assert index_live
# |> form("#ammo_group-form", ammo_group: @invalid_attrs)
# |> render_change() =~ dgettext("errors", "can't be blank")
{:ok, _view, html} =
index_live
|> form("#ammo_group-form", ammo_group: @update_attrs)
|> render_submit()
|> follow_redirect(conn, Routes.ammo_group_index_path(conn, :index))
assert html =~ dgettext("prompts", "Ammo updated successfully")
assert html =~ "\n43\n"
end
test "clones ammo_group in listing", %{conn: conn, ammo_group: ammo_group} do
{:ok, index_live, _html} = live(conn, Routes.ammo_group_index_path(conn, :index))
html =
index_live
|> element(~s/a[aria-label="Clone ammo group of #{ammo_group.count} bullets"]/)
|> render_click()
assert html =~ dgettext("actions", "Add Ammo")
assert html =~ gettext("$%{amount}", amount: display_currency(120.5))
assert_patch(index_live, Routes.ammo_group_index_path(conn, :clone, ammo_group))
# assert index_live
# |> form("#ammo_group-form", ammo_group: @invalid_attrs)
# |> render_change() =~ dgettext("errors", "can't be blank")
{:ok, _view, html} =
index_live
|> form("#ammo_group-form")
|> render_submit()
|> follow_redirect(conn, Routes.ammo_group_index_path(conn, :index))
assert html =~ dgettext("prompts", "Ammo added successfully")
assert html =~ "\n42\n"
assert html =~ gettext("$%{amount}", amount: display_currency(120.5))
end
test "clones ammo_group in listing with updates", %{conn: conn, ammo_group: ammo_group} do
{:ok, index_live, _html} = live(conn, Routes.ammo_group_index_path(conn, :index))
html =
index_live
|> element(~s/a[aria-label="Clone ammo group of #{ammo_group.count} bullets"]/)
|> render_click()
assert html =~ dgettext("actions", "Add Ammo")
assert html =~ gettext("$%{amount}", amount: display_currency(120.5))
assert_patch(index_live, Routes.ammo_group_index_path(conn, :clone, ammo_group))
# assert index_live
# |> form("#ammo_group-form", ammo_group: @invalid_attrs)
# |> render_change() =~ dgettext("errors", "can't be blank")
{:ok, _view, html} =
index_live
|> form("#ammo_group-form", ammo_group: Map.merge(@create_attrs, %{"count" => 43}))
|> render_submit()
|> follow_redirect(conn, Routes.ammo_group_index_path(conn, :index))
assert html =~ dgettext("prompts", "Ammo added successfully")
assert html =~ "\n43\n"
assert html =~ gettext("$%{amount}", amount: display_currency(120.5))
end
test "deletes ammo_group in listing", %{conn: conn, ammo_group: ammo_group} do
{:ok, index_live, _html} = live(conn, Routes.ammo_group_index_path(conn, :index))
assert index_live
|> element(~s/a[aria-label="Delete ammo group of #{ammo_group.count} bullets"]/)
|> render_click()
refute has_element?(index_live, "#ammo_group-#{ammo_group.id}")
end
test "saves new shot_group", %{conn: conn, ammo_group: ammo_group} do
{:ok, index_live, _html} = live(conn, Routes.ammo_group_index_path(conn, :index))
assert index_live |> element("a", dgettext("actions", "Record shots")) |> render_click() =~
gettext("Record shots")
assert_patch(index_live, Routes.ammo_group_index_path(conn, :add_shot_group, ammo_group))
# assert index_live
# |> form("#shot_group-form", shot_group: @invalid_attrs)
# |> render_change() =~ dgettext("errors", "is invalid")
{:ok, _view, html} =
index_live
|> form("#shot-group-form", shot_group: @shot_group_create_attrs)
|> render_submit()
|> follow_redirect(conn, Routes.ammo_group_index_path(conn, :index))
assert html =~ dgettext("prompts", "Shots recorded successfully")
end
@spec display_currency(float()) :: String.t()
defp display_currency(float), do: :erlang.float_to_binary(float, decimals: 2)
end
describe "Index of empty ammo group" do
setup [:register_and_log_in_user, :create_ammo_group, :create_empty_ammo_group]
test "hides empty ammo groups by default", %{
conn: conn,
empty_ammo_group: ammo_group,
current_user: current_user
} do
{:ok, show_live, html} = live(conn, Routes.ammo_group_index_path(conn, :index))
assert html =~ dgettext("actions", "Show used")
refute html =~ gettext("$%{amount}", amount: display_currency(50.00))
percentage = ammo_group |> Ammo.get_percentage_remaining(current_user)
refute html =~ "\n#{gettext("%{percentage}%", percentage: percentage)}\n"
html =
show_live
|> element(~s/input[type="checkbox"][aria-labelledby="toggle_show_used-label"}]/)
|> render_click()
assert html =~ gettext("$%{amount}", amount: display_currency(50.00))
percentage = ammo_group |> Ammo.get_percentage_remaining(current_user)
assert html =~ "\n#{gettext("%{percentage}%", percentage: percentage)}\n"
end
end
describe "Show ammo group" do
setup [:register_and_log_in_user, :create_ammo_group]
test "displays ammo_group", %{conn: conn, ammo_group: ammo_group} do
{:ok, _show_live, html} = live(conn, Routes.ammo_group_show_path(conn, :show, ammo_group))
ammo_group = ammo_group |> Repo.preload(:ammo_type)
assert html =~ gettext("Show Ammo")
assert html =~ ammo_group.ammo_type.name
end
test "updates ammo_group within modal", %{conn: conn, ammo_group: ammo_group} do
{:ok, show_live, _html} = live(conn, Routes.ammo_group_show_path(conn, :show, ammo_group))
assert show_live
|> element(~s/a[aria-label="Edit ammo group of #{ammo_group.count} bullets"]/)
|> render_click() =~
gettext("Edit Ammo")
assert_patch(show_live, Routes.ammo_group_show_path(conn, :edit, ammo_group))
# assert show_live
# |> form("#ammo_group-form", ammo_group: @invalid_attrs)
# |> render_change() =~ dgettext("errors", "can't be blank")
{:ok, _view, html} =
show_live
|> form("#ammo_group-form", ammo_group: @update_attrs)
|> render_submit()
|> follow_redirect(conn, Routes.ammo_group_show_path(conn, :show, ammo_group))
assert html =~ dgettext("prompts", "Ammo updated successfully")
assert html =~ "some updated notes"
end
test "saves new shot_group", %{conn: conn, ammo_group: ammo_group} do
{:ok, index_live, _html} = live(conn, Routes.ammo_group_show_path(conn, :show, ammo_group))
assert index_live |> element("a", dgettext("actions", "Record shots")) |> render_click() =~
gettext("Record shots")
assert_patch(index_live, Routes.ammo_group_show_path(conn, :add_shot_group, ammo_group))
# assert index_live
# |> form("#shot_group-form", shot_group: @invalid_attrs)
# |> render_change() =~ dgettext("errors", "is invalid")
{:ok, _view, html} =
index_live
|> form("#shot-group-form", shot_group: @shot_group_create_attrs)
|> render_submit()
|> follow_redirect(conn, Routes.ammo_group_show_path(conn, :show, ammo_group))
assert html =~ dgettext("prompts", "Shots recorded successfully")
end
end
describe "Show ammo group with shot group" do
setup [:register_and_log_in_user, :create_ammo_group, :create_shot_group]
test "updates shot_group in listing",
%{conn: conn, ammo_group: ammo_group, shot_group: shot_group} do
{:ok, index_live, _html} = live(conn, Routes.ammo_group_show_path(conn, :edit, ammo_group))
assert index_live
|> element(~s/a[aria-label="Edit shot group of #{shot_group.count} shots"]/)
|> render_click() =~
gettext("Edit Shot Records")
assert_patch(
index_live,
Routes.ammo_group_show_path(conn, :edit_shot_group, ammo_group, shot_group)
)
# assert index_live
# |> form("#shot_group-form", shot_group: @invalid_attrs)
# |> render_change() =~ dgettext("errors", "is invalid")
{:ok, _view, html} =
index_live
|> form("#shot-group-form", shot_group: @shot_group_update_attrs)
|> render_submit()
|> follow_redirect(conn, Routes.ammo_group_show_path(conn, :show, ammo_group))
assert html =~ dgettext("actions", "Shot records updated successfully")
assert html =~ "some updated notes"
end
test "deletes shot_group in listing",
%{conn: conn, ammo_group: ammo_group, shot_group: shot_group} do
{:ok, index_live, _html} =
live(conn, Routes.ammo_group_show_path(conn, :edit_shot_group, ammo_group, shot_group))
assert index_live
|> element(~s/a[aria-label="Delete shot record of #{shot_group.count} shots"]/)
|> render_click()
refute has_element?(index_live, "#shot_group-#{shot_group.id}")
end
end
end

View File

@ -1,409 +0,0 @@
defmodule CanneryWeb.AmmoTypeLiveTest do
@moduledoc """
Tests the ammo type liveview
"""
use CanneryWeb.ConnCase
import Phoenix.LiveViewTest
import CanneryWeb.Gettext
alias Cannery.{Ammo, Repo}
@moduletag :ammo_type_live_test
@create_attrs %{
"bullet_type" => "some bullet_type",
"case_material" => "some case_material",
"desc" => "some desc",
"manufacturer" => "some manufacturer",
"name" => "some name",
"grains" => 120
}
@update_attrs %{
"bullet_type" => "some updated bullet_type",
"case_material" => "some updated case_material",
"desc" => "some updated desc",
"manufacturer" => "some updated manufacturer",
"name" => "some updated name",
"grains" => 456
}
@ammo_group_attrs %{
"notes" => "some ammo group",
"count" => 20
}
@shot_group_attrs %{
"notes" => "some shot group",
"count" => 20
}
# @invalid_attrs %{
# "bullet_type" => nil,
# "case_material" => nil,
# "desc" => nil,
# "manufacturer" => nil,
# "name" => nil,
# "grains" => nil
# }
defp create_ammo_type(%{current_user: current_user}) do
%{ammo_type: ammo_type_fixture(@create_attrs, current_user)}
end
defp create_ammo_group(%{ammo_type: ammo_type, current_user: current_user}) do
container = container_fixture(current_user)
{1, [ammo_group]} = ammo_group_fixture(@ammo_group_attrs, ammo_type, container, current_user)
%{ammo_group: ammo_group, container: container}
end
defp create_empty_ammo_group(%{ammo_type: ammo_type, current_user: current_user}) do
container = container_fixture(current_user)
{1, [ammo_group]} = ammo_group_fixture(@ammo_group_attrs, ammo_type, container, current_user)
shot_group = shot_group_fixture(@shot_group_attrs, current_user, ammo_group)
ammo_group = ammo_group |> Repo.reload!()
%{ammo_group: ammo_group, container: container, shot_group: shot_group}
end
describe "Index" do
setup [:register_and_log_in_user, :create_ammo_type]
test "lists all ammo_types", %{conn: conn, ammo_type: ammo_type} do
{:ok, _index_live, html} = live(conn, Routes.ammo_type_index_path(conn, :index))
assert html =~ gettext("Catalog")
assert html =~ ammo_type.bullet_type
end
test "can sort by type", %{conn: conn, current_user: current_user} do
rifle_type = ammo_type_fixture(%{"type" => "rifle"}, current_user)
shotgun_type = ammo_type_fixture(%{"type" => "shotgun"}, current_user)
pistol_type = ammo_type_fixture(%{"type" => "pistol"}, current_user)
{:ok, index_live, html} = live(conn, Routes.ammo_type_index_path(conn, :index))
assert html =~ "All"
assert html =~ rifle_type.name
assert html =~ shotgun_type.name
assert html =~ pistol_type.name
html =
index_live
|> form(~s/form[phx-change="change_type"]/)
|> render_change(ammo_type: %{type: :rifle})
assert html =~ rifle_type.name
refute html =~ shotgun_type.name
refute html =~ pistol_type.name
html =
index_live
|> form(~s/form[phx-change="change_type"]/)
|> render_change(ammo_type: %{type: :shotgun})
refute html =~ rifle_type.name
assert html =~ shotgun_type.name
refute html =~ pistol_type.name
html =
index_live
|> form(~s/form[phx-change="change_type"]/)
|> render_change(ammo_type: %{type: :pistol})
refute html =~ rifle_type.name
refute html =~ shotgun_type.name
assert html =~ pistol_type.name
html =
index_live
|> form(~s/form[phx-change="change_type"]/)
|> render_change(ammo_type: %{type: :all})
assert html =~ rifle_type.name
assert html =~ shotgun_type.name
assert html =~ pistol_type.name
end
test "can search for ammo_type", %{conn: conn, ammo_type: ammo_type} do
{:ok, index_live, html} = live(conn, Routes.ammo_type_index_path(conn, :index))
assert html =~ ammo_type.bullet_type
assert index_live
|> form(~s/form[phx-change="search"]/)
|> render_change(search: %{search_term: ammo_type.bullet_type}) =~
ammo_type.bullet_type
assert_patch(index_live, Routes.ammo_type_index_path(conn, :search, ammo_type.bullet_type))
refute index_live
|> form(~s/form[phx-change="search"]/)
|> render_change(search: %{search_term: "something_else"}) =~ ammo_type.bullet_type
assert_patch(index_live, Routes.ammo_type_index_path(conn, :search, "something_else"))
assert index_live
|> form(~s/form[phx-change="search"]/)
|> render_change(search: %{search_term: ""}) =~ ammo_type.bullet_type
assert_patch(index_live, Routes.ammo_type_index_path(conn, :index))
end
test "saves new ammo_type", %{conn: conn, current_user: current_user, ammo_type: ammo_type} do
{:ok, index_live, _html} = live(conn, Routes.ammo_type_index_path(conn, :index))
assert index_live |> element("a", dgettext("actions", "New Ammo type")) |> render_click() =~
gettext("New Ammo type")
assert_patch(index_live, Routes.ammo_type_index_path(conn, :new))
# assert index_live
# |> form("#ammo_type-form", ammo_type: @invalid_attrs)
# |> render_change() =~ dgettext("errors", "can't be blank")
{:ok, _view, html} =
index_live
|> form("#ammo_type-form")
|> render_submit(ammo_type: @create_attrs)
|> follow_redirect(conn, Routes.ammo_type_index_path(conn, :index))
ammo_type = ammo_type.id |> Ammo.get_ammo_type!(current_user)
assert html =~ dgettext("prompts", "%{name} created successfully", name: ammo_type.name)
assert html =~ "some bullet_type"
end
test "updates ammo_type in listing",
%{conn: conn, current_user: current_user, ammo_type: ammo_type} do
{:ok, index_live, _html} = live(conn, Routes.ammo_type_index_path(conn, :index))
assert index_live |> element(~s/a[aria-label="Edit #{ammo_type.name}"]/) |> render_click() =~
gettext("Edit %{ammo_type_name}", ammo_type_name: ammo_type.name)
assert_patch(index_live, Routes.ammo_type_index_path(conn, :edit, ammo_type))
# assert index_live
# |> form("#ammo_type-form", ammo_type: @invalid_attrs)
# |> render_change() =~ dgettext("errors", "can't be blank")
{:ok, _view, html} =
index_live
|> form("#ammo_type-form")
|> render_submit(ammo_type: @update_attrs)
|> follow_redirect(conn, Routes.ammo_type_index_path(conn, :index))
ammo_type = ammo_type.id |> Ammo.get_ammo_type!(current_user)
assert html =~ dgettext("prompts", "%{name} updated successfully", name: ammo_type.name)
assert html =~ "some updated bullet_type"
end
test "clones ammo_type in listing",
%{conn: conn, current_user: current_user, ammo_type: ammo_type} do
{:ok, index_live, _html} = live(conn, Routes.ammo_type_index_path(conn, :index))
html = index_live |> element(~s/a[aria-label="Clone #{ammo_type.name}"]/) |> render_click()
assert html =~ gettext("New Ammo type")
assert html =~ "some bullet_type"
assert_patch(index_live, Routes.ammo_type_index_path(conn, :clone, ammo_type))
# assert index_live
# |> form("#ammo_type-form", ammo_type: @invalid_attrs)
# |> render_change() =~ dgettext("errors", "can't be blank")
{:ok, _view, html} =
index_live
|> form("#ammo_type-form")
|> render_submit(ammo_type: @create_attrs)
|> follow_redirect(conn, Routes.ammo_type_index_path(conn, :index))
ammo_type = ammo_type.id |> Ammo.get_ammo_type!(current_user)
assert html =~ dgettext("prompts", "%{name} created successfully", name: ammo_type.name)
assert html =~ "some bullet_type"
end
test "clones ammo_type in listing with updates",
%{conn: conn, current_user: current_user, ammo_type: ammo_type} do
{:ok, index_live, _html} = live(conn, Routes.ammo_type_index_path(conn, :index))
html = index_live |> element(~s/a[aria-label="Clone #{ammo_type.name}"]/) |> render_click()
assert html =~ gettext("New Ammo type")
assert html =~ "some bullet_type"
assert_patch(index_live, Routes.ammo_type_index_path(conn, :clone, ammo_type))
# assert index_live
# |> form("#ammo_type-form", ammo_type: @invalid_attrs)
# |> render_change() =~ dgettext("errors", "can't be blank")
{:ok, _view, html} =
index_live
|> form("#ammo_type-form")
|> render_submit(
ammo_type: Map.merge(@create_attrs, %{"bullet_type" => "some updated bullet_type"})
)
|> follow_redirect(conn, Routes.ammo_type_index_path(conn, :index))
ammo_type = ammo_type.id |> Ammo.get_ammo_type!(current_user)
assert html =~ dgettext("prompts", "%{name} created successfully", name: ammo_type.name)
assert html =~ "some updated bullet_type"
end
test "deletes ammo_type in listing", %{conn: conn, ammo_type: ammo_type} do
{:ok, index_live, _html} = live(conn, Routes.ammo_type_index_path(conn, :index))
assert index_live |> element(~s/a[aria-label="Delete #{ammo_type.name}"]/) |> render_click()
refute has_element?(index_live, "#ammo_type-#{ammo_type.id}")
end
end
describe "Index with ammo group" do
setup [:register_and_log_in_user, :create_ammo_type, :create_ammo_group]
test "shows used ammo groups on toggle",
%{conn: conn, ammo_group: ammo_group, current_user: current_user} do
{:ok, index_live, html} = live(conn, Routes.ammo_type_index_path(conn, :index))
assert html =~ dgettext("actions", "Show used")
refute html =~ gettext("Used rounds")
refute html =~ gettext("Total ever rounds")
refute html =~ gettext("Used packs")
refute html =~ gettext("Total ever packs")
html =
index_live
|> element(~s/input[type="checkbox"][aria-labelledby="toggle_show_used-label"}]/)
|> render_click()
assert html =~ gettext("Used rounds")
assert html =~ gettext("Total ever rounds")
assert html =~ gettext("Used packs")
assert html =~ gettext("Total ever packs")
assert html =~ "\n20\n"
assert html =~ "\n0\n"
assert html =~ "\n1\n"
shot_group_fixture(%{"count" => 5}, current_user, ammo_group)
{:ok, index_live, _html} = live(conn, Routes.ammo_type_index_path(conn, :index))
html =
index_live
|> element(~s/input[type="checkbox"][aria-labelledby="toggle_show_used-label"}]/)
|> render_click()
assert html =~ "\n15\n"
assert html =~ "\n5\n"
end
end
describe "Show ammo type" do
setup [:register_and_log_in_user, :create_ammo_type]
test "displays ammo_type", %{
conn: conn,
ammo_type: %{name: name, bullet_type: bullet_type} = ammo_type
} do
{:ok, _show_live, html} = live(conn, Routes.ammo_type_show_path(conn, :show, ammo_type))
assert html =~ name
assert html =~ bullet_type
end
test "updates ammo_type within modal",
%{conn: conn, current_user: current_user, ammo_type: %{name: name} = ammo_type} do
{:ok, show_live, _html} = live(conn, Routes.ammo_type_show_path(conn, :show, ammo_type))
assert show_live |> element(~s/a[aria-label="Edit #{ammo_type.name}"]/) |> render_click() =~
gettext("Edit %{ammo_type_name}", ammo_type_name: name)
assert_patch(show_live, Routes.ammo_type_show_path(conn, :edit, ammo_type))
# assert show_live
# |> form("#ammo_type-form", ammo_type: @invalid_attrs)
# |> render_change() =~ dgettext("errors", "can't be blank")
{:ok, _view, html} =
show_live
|> form("#ammo_type-form")
|> render_submit(ammo_type: @update_attrs)
|> follow_redirect(conn, Routes.ammo_type_show_path(conn, :show, ammo_type))
ammo_type = ammo_type.id |> Ammo.get_ammo_type!(current_user)
assert html =~ dgettext("prompts", "%{name} updated successfully", name: ammo_type.name)
assert html =~ "some updated bullet_type"
end
end
describe "Show ammo type with ammo group" do
setup [:register_and_log_in_user, :create_ammo_type, :create_ammo_group]
test "displays ammo group", %{
conn: conn,
ammo_type: %{name: ammo_type_name} = ammo_type,
container: %{name: container_name}
} do
{:ok, _show_live, html} = live(conn, Routes.ammo_type_show_path(conn, :show, ammo_type))
assert html =~ ammo_type_name
assert html =~ "\n20\n"
assert html =~ container_name
end
test "displays ammo group in table",
%{conn: conn, ammo_type: ammo_type, container: %{name: container_name}} do
{:ok, show_live, _html} = live(conn, Routes.ammo_type_show_path(conn, :show, ammo_type))
html =
show_live
|> element(~s/input[type="checkbox"][aria-labelledby="toggle_table-label"}]/)
|> render_click()
assert html =~ "\n20\n"
assert html =~ container_name
end
end
describe "Show ammo type with empty ammo group" do
setup [:register_and_log_in_user, :create_ammo_type, :create_empty_ammo_group]
test "displays empty ammo groups on toggle",
%{conn: conn, ammo_type: ammo_type, container: %{name: container_name}} do
{:ok, show_live, html} = live(conn, Routes.ammo_type_show_path(conn, :show, ammo_type))
assert html =~ dgettext("actions", "Show used")
refute html =~ "\n20\n"
html =
show_live
|> element(~s/input[type="checkbox"][aria-labelledby="toggle_show_used-label"}]/)
|> render_click()
assert html =~ "\n20\n"
assert html =~ "Empty"
assert html =~ container_name
end
test "displays empty ammo groups in table on toggle",
%{conn: conn, ammo_type: ammo_type, container: %{name: container_name}} do
{:ok, show_live, _html} = live(conn, Routes.ammo_type_show_path(conn, :show, ammo_type))
html =
show_live
|> element(~s/input[type="checkbox"][aria-labelledby="toggle_table-label"}]/)
|> render_click()
assert html =~ dgettext("actions", "Show used")
refute html =~ "\n20\n"
html =
show_live
|> element(~s/input[type="checkbox"][aria-labelledby="toggle_show_used-label"}]/)
|> render_click()
assert html =~ "\n20\n"
assert html =~ "Empty"
assert html =~ container_name
end
end
end

View File

@ -5,48 +5,46 @@ defmodule CanneryWeb.ContainerLiveTest do
use CanneryWeb.ConnCase use CanneryWeb.ConnCase
import Phoenix.LiveViewTest import Phoenix.LiveViewTest
import CanneryWeb.Gettext
alias Cannery.Containers alias Cannery.Containers
@moduletag :container_live_test @moduletag :container_live_test
@create_attrs %{ @create_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"
} }
@ammo_type_attrs %{ @invalid_attrs %{desc: nil, location: nil, name: nil, type: nil}
"bullet_type" => "some bullet_type", @type_attrs %{
"case_material" => "some case_material", bullet_type: "some bullet_type",
"desc" => "some desc", case_material: "some case_material",
"manufacturer" => "some manufacturer", desc: "some desc",
"name" => "some name", manufacturer: "some manufacturer",
"grains" => 120 name: "some name",
grains: 120
} }
@ammo_group_attrs %{ @pack_attrs %{
"notes" => "some ammo group", notes: "some pack",
"count" => 20 count: 20
} }
# @invalid_attrs %{desc: nil, location: nil, name: nil, type: nil}
defp create_container(%{current_user: current_user}) do defp create_container(%{current_user: current_user}) do
container = container_fixture(@create_attrs, current_user) container = container_fixture(@create_attrs, current_user)
%{container: container} [container: container]
end end
defp create_ammo_group(%{container: container, current_user: current_user}) do defp create_pack(%{container: container, current_user: current_user}) do
ammo_type = ammo_type_fixture(@ammo_type_attrs, current_user) type = type_fixture(@type_attrs, current_user)
{1, [ammo_group]} = ammo_group_fixture(@ammo_group_attrs, ammo_type, container, current_user) {1, [pack]} = pack_fixture(@pack_attrs, type, container, current_user)
%{ammo_type: ammo_type, ammo_group: ammo_group} [type: type, pack: pack]
end end
describe "Index" do describe "Index" do
@ -55,7 +53,7 @@ defmodule CanneryWeb.ContainerLiveTest do
test "lists all containers", %{conn: conn, container: container} do test "lists all containers", %{conn: conn, container: container} do
{:ok, _index_live, html} = live(conn, Routes.container_index_path(conn, :index)) {:ok, _index_live, html} = live(conn, Routes.container_index_path(conn, :index))
assert html =~ gettext("Containers") assert html =~ "Containers"
assert html =~ container.location assert html =~ container.location
end end
@ -67,7 +65,7 @@ defmodule CanneryWeb.ContainerLiveTest do
|> element(~s/input[type="checkbox"][aria-labelledby="toggle_table-label"}]/) |> element(~s/input[type="checkbox"][aria-labelledby="toggle_table-label"}]/)
|> render_click() |> render_click()
assert html =~ gettext("Containers") assert html =~ "Containers"
assert html =~ container.location assert html =~ container.location
end end
@ -77,22 +75,20 @@ defmodule CanneryWeb.ContainerLiveTest do
assert html =~ container.location assert html =~ container.location
assert index_live assert index_live
|> form(~s/form[phx-change="search"]/, |> form(~s/form[phx-change="search"]/)
search: %{search_term: container.location} |> render_change(search: %{search_term: container.location}) =~ container.location
)
|> render_change() =~ container.location
assert_patch(index_live, Routes.container_index_path(conn, :search, container.location)) assert_patch(index_live, Routes.container_index_path(conn, :search, container.location))
refute index_live refute index_live
|> form(~s/form[phx-change="search"]/, search: %{search_term: "something_else"}) |> form(~s/form[phx-change="search"]/)
|> render_change() =~ container.location |> render_change(search: %{search_term: "something_else"}) =~ container.location
assert_patch(index_live, Routes.container_index_path(conn, :search, "something_else")) assert_patch(index_live, Routes.container_index_path(conn, :search, "something_else"))
assert index_live assert index_live
|> form(~s/form[phx-change="search"]/, search: %{search_term: ""}) |> form(~s/form[phx-change="search"]/)
|> render_change() =~ container.location |> render_change(search: %{search_term: ""}) =~ container.location
assert_patch(index_live, Routes.container_index_path(conn, :index)) assert_patch(index_live, Routes.container_index_path(conn, :index))
end end
@ -100,22 +96,20 @@ defmodule CanneryWeb.ContainerLiveTest do
test "saves new container", %{conn: conn, container: container} do test "saves new container", %{conn: conn, container: container} do
{:ok, index_live, _html} = live(conn, Routes.container_index_path(conn, :index)) {:ok, index_live, _html} = live(conn, Routes.container_index_path(conn, :index))
assert index_live |> element("a", dgettext("actions", "New Container")) |> render_click() =~ assert index_live |> element("a", "New Container") |> render_click() =~ "New Container"
gettext("New Container")
assert_patch(index_live, Routes.container_index_path(conn, :new)) assert_patch(index_live, Routes.container_index_path(conn, :new))
# assert index_live assert index_live
# |> form("#container-form", container: @invalid_attrs) |> form("#container-form")
# |> render_change() =~ dgettext("errors", "can't be blank") |> render_change(container: @invalid_attrs) =~ "can&#39;t be blank"
{:ok, _view, html} = {:ok, _view, html} =
index_live index_live
|> form("#container-form", container: @create_attrs) |> form("#container-form")
|> render_submit() |> render_submit(container: @create_attrs)
|> follow_redirect(conn, Routes.container_index_path(conn, :index)) |> follow_redirect(conn, Routes.container_index_path(conn, :index))
assert html =~ dgettext("prompts", "%{name} created successfully", name: container.name) assert html =~ "#{container.name} created successfully"
assert html =~ "some location" assert html =~ "some location"
end end
@ -127,22 +121,22 @@ defmodule CanneryWeb.ContainerLiveTest do
{:ok, index_live, _html} = live(conn, Routes.container_index_path(conn, :index)) {:ok, index_live, _html} = live(conn, Routes.container_index_path(conn, :index))
assert index_live |> element(~s/a[aria-label="Edit #{container.name}"]/) |> render_click() =~ assert index_live |> element(~s/a[aria-label="Edit #{container.name}"]/) |> render_click() =~
gettext("Edit %{name}", name: container.name) "Edit #{container.name}"
assert_patch(index_live, Routes.container_index_path(conn, :edit, container)) assert_patch(index_live, Routes.container_index_path(conn, :edit, container))
# assert index_live assert index_live
# |> form("#container-form", container: @invalid_attrs) |> form("#container-form")
# |> render_change() =~ dgettext("errors", "can't be blank") |> render_change(container: @invalid_attrs) =~ "can&#39;t be blank"
{:ok, _view, html} = {:ok, _view, html} =
index_live index_live
|> form("#container-form", container: @update_attrs) |> form("#container-form")
|> render_submit() |> render_submit(container: @update_attrs)
|> follow_redirect(conn, Routes.container_index_path(conn, :index)) |> follow_redirect(conn, Routes.container_index_path(conn, :index))
container = container.id |> Containers.get_container!(current_user) container = container.id |> Containers.get_container!(current_user)
assert html =~ dgettext("prompts", "%{name} updated successfully", name: container.name) assert html =~ "#{container.name} updated successfully"
assert html =~ "some updated location" assert html =~ "some updated location"
end end
@ -154,23 +148,23 @@ defmodule CanneryWeb.ContainerLiveTest do
{:ok, index_live, _html} = live(conn, Routes.container_index_path(conn, :index)) {:ok, index_live, _html} = live(conn, Routes.container_index_path(conn, :index))
html = index_live |> element(~s/a[aria-label="Clone #{container.name}"]/) |> render_click() html = index_live |> element(~s/a[aria-label="Clone #{container.name}"]/) |> render_click()
assert html =~ gettext("New Container") assert html =~ "New Container"
assert html =~ "some location" assert html =~ "some location"
assert_patch(index_live, Routes.container_index_path(conn, :clone, container)) assert_patch(index_live, Routes.container_index_path(conn, :clone, container))
# assert index_live assert index_live
# |> form("#container-form", container: @invalid_attrs) |> form("#container-form")
# |> render_change() =~ dgettext("errors", "can't be blank") |> render_change(container: @invalid_attrs) =~ "can&#39;t be blank"
{:ok, _view, html} = {:ok, _view, html} =
index_live index_live
|> form("#container-form", container: @create_attrs) |> form("#container-form")
|> render_submit() |> render_submit(container: @create_attrs)
|> follow_redirect(conn, Routes.container_index_path(conn, :index)) |> follow_redirect(conn, Routes.container_index_path(conn, :index))
container = container.id |> Containers.get_container!(current_user) container = container.id |> Containers.get_container!(current_user)
assert html =~ dgettext("prompts", "%{name} created successfully", name: container.name) assert html =~ "#{container.name} created successfully"
assert html =~ "some location" assert html =~ "some location"
end end
@ -182,30 +176,29 @@ defmodule CanneryWeb.ContainerLiveTest do
{:ok, index_live, _html} = live(conn, Routes.container_index_path(conn, :index)) {:ok, index_live, _html} = live(conn, Routes.container_index_path(conn, :index))
assert index_live |> element(~s/a[aria-label="Clone #{container.name}"]/) |> render_click() =~ assert index_live |> element(~s/a[aria-label="Clone #{container.name}"]/) |> render_click() =~
gettext("New Container") "New Container"
assert_patch(index_live, Routes.container_index_path(conn, :clone, container)) assert_patch(index_live, Routes.container_index_path(conn, :clone, container))
# assert index_live assert index_live
# |> form("#container-form", container: @invalid_attrs) |> form("#container-form")
# |> render_change() =~ dgettext("errors", "can't be blank") |> render_change(container: @invalid_attrs) =~ "can&#39;t be blank"
{:ok, _view, html} = {:ok, _view, html} =
index_live index_live
|> form("#container-form", |> form("#container-form")
|> render_submit(
container: Map.merge(@create_attrs, %{location: "some updated location"}) container: Map.merge(@create_attrs, %{location: "some updated location"})
) )
|> render_submit()
|> follow_redirect(conn, Routes.container_index_path(conn, :index)) |> follow_redirect(conn, Routes.container_index_path(conn, :index))
container = container.id |> Containers.get_container!(current_user) container = container.id |> Containers.get_container!(current_user)
assert html =~ dgettext("prompts", "%{name} created successfully", name: container.name) assert html =~ "#{container.name} created successfully"
assert html =~ "some updated location" assert html =~ "some updated location"
end end
test "deletes container in listing", %{conn: conn, container: container} do test "deletes container in listing", %{conn: conn, container: container} do
{:ok, index_live, _html} = live(conn, Routes.container_index_path(conn, :index)) {:ok, index_live, _html} = live(conn, Routes.container_index_path(conn, :index))
assert index_live |> element(~s/a[aria-label="Delete #{container.name}"]/) |> render_click() assert index_live |> element(~s/a[aria-label="Delete #{container.name}"]/) |> render_click()
refute has_element?(index_live, "#container-#{container.id}") refute has_element?(index_live, "#container-#{container.id}")
end end
@ -219,7 +212,6 @@ defmodule CanneryWeb.ContainerLiveTest do
container: %{name: name, location: location} = container container: %{name: name, location: location} = container
} do } do
{:ok, _show_live, html} = live(conn, Routes.container_show_path(conn, :show, container)) {:ok, _show_live, html} = live(conn, Routes.container_show_path(conn, :show, container))
assert html =~ name assert html =~ name
assert html =~ location assert html =~ location
end end
@ -232,93 +224,93 @@ defmodule CanneryWeb.ContainerLiveTest do
{:ok, show_live, _html} = live(conn, Routes.container_show_path(conn, :show, container)) {:ok, show_live, _html} = live(conn, Routes.container_show_path(conn, :show, container))
assert show_live |> element(~s/a[aria-label="Edit #{container.name}"]/) |> render_click() =~ assert show_live |> element(~s/a[aria-label="Edit #{container.name}"]/) |> render_click() =~
gettext("Edit %{name}", name: container.name) "Edit #{container.name}"
assert_patch(show_live, Routes.container_show_path(conn, :edit, container)) assert_patch(show_live, Routes.container_show_path(conn, :edit, container))
# assert show_live assert show_live
# |> form("#container-form", container: @invalid_attrs) |> form("#container-form")
# |> render_change() =~ dgettext("errors", "can't be blank") |> render_change(container: @invalid_attrs) =~ "can&#39;t be blank"
{:ok, _view, html} = {:ok, _view, html} =
show_live show_live
|> form("#container-form", container: @update_attrs) |> form("#container-form")
|> render_submit() |> render_submit(container: @update_attrs)
|> follow_redirect(conn, Routes.container_show_path(conn, :show, container)) |> follow_redirect(conn, Routes.container_show_path(conn, :show, container))
container = container.id |> Containers.get_container!(current_user) container = container.id |> Containers.get_container!(current_user)
assert html =~ dgettext("prompts", "%{name} updated successfully", name: container.name) assert html =~ "#{container.name} updated successfully"
assert html =~ "some updated location" assert html =~ "some updated location"
end end
test "can sort by type", test "can sort by type",
%{conn: conn, container: container, current_user: current_user} do %{conn: conn, container: container, current_user: current_user} do
rifle_type = ammo_type_fixture(%{"type" => "rifle"}, current_user) rifle_type = type_fixture(%{class: :rifle}, current_user)
{1, [rifle_ammo_group]} = ammo_group_fixture(rifle_type, container, current_user) {1, [rifle_pack]} = pack_fixture(rifle_type, container, current_user)
shotgun_type = ammo_type_fixture(%{"type" => "shotgun"}, current_user) shotgun_type = type_fixture(%{class: :shotgun}, current_user)
{1, [shotgun_ammo_group]} = ammo_group_fixture(shotgun_type, container, current_user) {1, [shotgun_pack]} = pack_fixture(shotgun_type, container, current_user)
pistol_type = ammo_type_fixture(%{"type" => "pistol"}, current_user) pistol_type = type_fixture(%{class: :pistol}, current_user)
{1, [pistol_ammo_group]} = ammo_group_fixture(pistol_type, container, current_user) {1, [pistol_pack]} = pack_fixture(pistol_type, container, current_user)
{:ok, index_live, html} = live(conn, Routes.container_show_path(conn, :show, container)) {:ok, index_live, html} = live(conn, Routes.container_show_path(conn, :show, container))
assert html =~ "All" assert html =~ "All"
assert html =~ rifle_ammo_group.ammo_type.name assert html =~ rifle_pack.type.name
assert html =~ shotgun_ammo_group.ammo_type.name assert html =~ shotgun_pack.type.name
assert html =~ pistol_ammo_group.ammo_type.name assert html =~ pistol_pack.type.name
html = html =
index_live index_live
|> form(~s/form[phx-change="change_type"]/) |> form(~s/form[phx-change="change_class"]/)
|> render_change(ammo_type: %{type: :rifle}) |> render_change(type: %{class: :rifle})
assert html =~ rifle_ammo_group.ammo_type.name assert html =~ rifle_pack.type.name
refute html =~ shotgun_ammo_group.ammo_type.name refute html =~ shotgun_pack.type.name
refute html =~ pistol_ammo_group.ammo_type.name refute html =~ pistol_pack.type.name
html = html =
index_live index_live
|> form(~s/form[phx-change="change_type"]/) |> form(~s/form[phx-change="change_class"]/)
|> render_change(ammo_type: %{type: :shotgun}) |> render_change(type: %{class: :shotgun})
refute html =~ rifle_ammo_group.ammo_type.name refute html =~ rifle_pack.type.name
assert html =~ shotgun_ammo_group.ammo_type.name assert html =~ shotgun_pack.type.name
refute html =~ pistol_ammo_group.ammo_type.name refute html =~ pistol_pack.type.name
html = html =
index_live index_live
|> form(~s/form[phx-change="change_type"]/) |> form(~s/form[phx-change="change_class"]/)
|> render_change(ammo_type: %{type: :pistol}) |> render_change(type: %{class: :pistol})
refute html =~ rifle_ammo_group.ammo_type.name refute html =~ rifle_pack.type.name
refute html =~ shotgun_ammo_group.ammo_type.name refute html =~ shotgun_pack.type.name
assert html =~ pistol_ammo_group.ammo_type.name assert html =~ pistol_pack.type.name
html = html =
index_live index_live
|> form(~s/form[phx-change="change_type"]/) |> form(~s/form[phx-change="change_class"]/)
|> render_change(ammo_type: %{type: :all}) |> render_change(type: %{class: :all})
assert html =~ rifle_ammo_group.ammo_type.name assert html =~ rifle_pack.type.name
assert html =~ shotgun_ammo_group.ammo_type.name assert html =~ shotgun_pack.type.name
assert html =~ pistol_ammo_group.ammo_type.name assert html =~ pistol_pack.type.name
end end
end end
describe "Show with ammo group" do describe "Show with pack" do
setup [:register_and_log_in_user, :create_container, :create_ammo_group] setup [:register_and_log_in_user, :create_container, :create_pack]
test "displays ammo group", test "displays pack",
%{conn: conn, ammo_type: %{name: ammo_type_name}, container: container} do %{conn: conn, type: %{name: type_name}, container: container} do
{:ok, _show_live, html} = live(conn, Routes.container_show_path(conn, :show, container)) {:ok, _show_live, html} = live(conn, Routes.container_show_path(conn, :show, container))
assert html =~ ammo_type_name assert html =~ type_name
assert html =~ "\n20\n" assert html =~ "\n20\n"
end end
test "displays ammo group in table", test "displays pack in table",
%{conn: conn, ammo_type: %{name: ammo_type_name}, container: container} do %{conn: conn, type: %{name: type_name}, container: container} do
{:ok, show_live, _html} = live(conn, Routes.container_show_path(conn, :show, container)) {:ok, show_live, _html} = live(conn, Routes.container_show_path(conn, :show, container))
html = html =
@ -326,7 +318,7 @@ defmodule CanneryWeb.ContainerLiveTest do
|> element(~s/input[type="checkbox"][aria-labelledby="toggle_table-label"}]/) |> element(~s/input[type="checkbox"][aria-labelledby="toggle_table-label"}]/)
|> render_click() |> render_click()
assert html =~ ammo_type_name assert html =~ type_name
assert html =~ "\n20\n" assert html =~ "\n20\n"
end end
end end

View File

@ -5,14 +5,13 @@ defmodule CanneryWeb.HomeLiveTest do
use CanneryWeb.ConnCase use CanneryWeb.ConnCase
import Phoenix.LiveViewTest import Phoenix.LiveViewTest
import CanneryWeb.Gettext
@moduletag :home_live_test @moduletag :home_live_test
test "disconnected and connected render", %{conn: conn} do test "disconnected and connected render", %{conn: conn} do
{:ok, home_live, disconnected_html} = live(conn, "/") {:ok, home_live, disconnected_html} = live(conn, "/")
assert disconnected_html =~ gettext("Welcome to %{name}", name: "Cannery") assert disconnected_html =~ "Welcome to Cannery"
assert render(home_live) =~ gettext("Welcome to %{name}", name: "Cannery") assert render(home_live) =~ "Welcome to Cannery"
end end
test "displays version number", %{conn: conn} do test "displays version number", %{conn: conn} do

View File

@ -5,13 +5,12 @@ defmodule CanneryWeb.InviteLiveTest do
use CanneryWeb.ConnCase use CanneryWeb.ConnCase
import Phoenix.LiveViewTest import Phoenix.LiveViewTest
import CanneryWeb.Gettext
alias Cannery.Accounts.Invites alias Cannery.Accounts.Invites
@moduletag :invite_live_test @moduletag :invite_live_test
@create_attrs %{"name" => "some name"} @create_attrs %{name: "some name"}
@update_attrs %{"name" => "some updated name"} @update_attrs %{name: "some updated name"}
# @invalid_attrs %{"name" => nil} @invalid_attrs %{name: nil}
describe "Index" do describe "Index" do
setup [:register_and_log_in_user] setup [:register_and_log_in_user]
@ -24,32 +23,27 @@ defmodule CanneryWeb.InviteLiveTest do
test "lists all invites", %{conn: conn, invite: invite} do test "lists all invites", %{conn: conn, invite: invite} do
{:ok, _index_live, html} = live(conn, Routes.invite_index_path(conn, :index)) {:ok, _index_live, html} = live(conn, Routes.invite_index_path(conn, :index))
assert html =~ gettext("Invites") assert html =~ "Invites"
assert html =~ invite.name assert html =~ invite.name
end end
test "saves new invite", %{conn: conn} do test "saves new invite", %{conn: conn} do
{:ok, index_live, _html} = live(conn, Routes.invite_index_path(conn, :index)) {:ok, index_live, _html} = live(conn, Routes.invite_index_path(conn, :index))
assert index_live |> element("a", dgettext("actions", "Create Invite")) |> render_click() =~ assert index_live |> element("a", "Create Invite") |> render_click() =~ "New Invite"
gettext("New Invite")
assert_patch(index_live, Routes.invite_index_path(conn, :new)) assert_patch(index_live, Routes.invite_index_path(conn, :new))
# assert index_live assert index_live
# |> form("#invite-form", invite: @invalid_attrs) |> form("#invite-form")
# |> render_change() =~ dgettext("errors", "can't be blank") |> render_change(invite: @invalid_attrs) =~ "can&#39;t be blank"
{:ok, _live, html} = {:ok, _live, html} =
index_live index_live
|> form("#invite-form", invite: @create_attrs) |> form("#invite-form")
|> render_submit() |> render_submit(invite: @create_attrs)
|> follow_redirect(conn, Routes.invite_index_path(conn, :index)) |> follow_redirect(conn, Routes.invite_index_path(conn, :index))
assert html =~ assert html =~ "some name created successfully"
dgettext("prompts", "%{invite_name} created successfully", invite_name: "some name")
assert html =~ "some name"
end end
test "updates invite in listing", %{conn: conn, invite: invite} do test "updates invite in listing", %{conn: conn, invite: invite} do
@ -57,27 +51,21 @@ defmodule CanneryWeb.InviteLiveTest do
assert index_live assert index_live
|> element(~s/a[aria-label="Edit invite for #{invite.name}"]/) |> element(~s/a[aria-label="Edit invite for #{invite.name}"]/)
|> render_click() =~ |> render_click() =~ "Edit Invite"
gettext("Edit Invite")
assert_patch(index_live, Routes.invite_index_path(conn, :edit, invite)) assert_patch(index_live, Routes.invite_index_path(conn, :edit, invite))
# assert index_live assert index_live
# |> form("#invite-form", invite: @invalid_attrs) |> form("#invite-form")
# |> render_change() =~ dgettext("errors", "can't be blank") |> render_change(invite: @invalid_attrs) =~ "can&#39;t be blank"
{:ok, _live, html} = {:ok, _live, html} =
index_live index_live
|> form("#invite-form", invite: @update_attrs) |> form("#invite-form")
|> render_submit() |> render_submit(invite: @update_attrs)
|> follow_redirect(conn, Routes.invite_index_path(conn, :index)) |> follow_redirect(conn, Routes.invite_index_path(conn, :index))
assert html =~ assert html =~ "some updated name updated successfully"
dgettext("prompts", "%{invite_name} updated successfully",
invite_name: "some updated name"
)
assert html =~ "some updated name"
end end
test "deletes invite in listing", %{conn: conn, invite: invite} do test "deletes invite in listing", %{conn: conn, invite: invite} do

View File

@ -0,0 +1,459 @@
defmodule CanneryWeb.PackLiveTest do
@moduledoc """
Tests pack live pages
"""
use CanneryWeb.ConnCase
import Phoenix.LiveViewTest
alias Cannery.{Ammo, Repo}
@moduletag :pack_live_test
@create_attrs %{count: 42, notes: "some notes", price_paid: 120.5}
@update_attrs %{count: 43, notes: "some updated notes", price_paid: 456.7}
@invalid_attrs %{count: nil, notes: nil, price_paid: nil}
@pack_create_limit 10_000
@shot_record_create_attrs %{ammo_left: 5, notes: "some notes"}
@shot_record_update_attrs %{
count: 5,
date: ~N[2022-02-13 03:17:00],
notes: "some updated notes"
}
@shot_record_invalid_attrs %{ammo_left: nil, count: nil, notes: nil}
@empty_attrs %{
price_paid: 50,
count: 20
}
@shot_record_attrs %{
price_paid: 50,
count: 20
}
defp create_pack(%{current_user: current_user}) do
type = type_fixture(current_user)
container = container_fixture(current_user)
{1, [pack]} = pack_fixture(@create_attrs, type, container, current_user)
[type: type, pack: pack, container: container]
end
defp create_shot_record(%{current_user: current_user, pack: pack}) do
shot_record = shot_record_fixture(@shot_record_update_attrs, current_user, pack)
pack = pack |> Repo.reload!()
[pack: pack, shot_record: shot_record]
end
defp create_empty_pack(%{
current_user: current_user,
type: type,
container: container
}) do
{1, [pack]} = pack_fixture(@empty_attrs, type, container, current_user)
shot_record = shot_record_fixture(@shot_record_attrs, current_user, pack)
pack = pack |> Repo.reload!()
[empty_pack: pack, shot_record: shot_record]
end
describe "Index of pack" do
setup [:register_and_log_in_user, :create_pack]
test "lists all packs", %{conn: conn, pack: pack} do
{:ok, _index_live, html} = live(conn, Routes.pack_index_path(conn, :index))
pack = pack |> Repo.preload(:type)
assert html =~ "Ammo"
assert html =~ pack.type.name
end
test "can sort by type",
%{conn: conn, container: container, current_user: current_user} do
rifle_type = type_fixture(%{class: :rifle}, current_user)
{1, [rifle_pack]} = pack_fixture(rifle_type, container, current_user)
shotgun_type = type_fixture(%{class: :shotgun}, current_user)
{1, [shotgun_pack]} = pack_fixture(shotgun_type, container, current_user)
pistol_type = type_fixture(%{class: :pistol}, current_user)
{1, [pistol_pack]} = pack_fixture(pistol_type, container, current_user)
{:ok, index_live, html} = live(conn, Routes.pack_index_path(conn, :index))
assert html =~ "All"
assert html =~ rifle_pack.type.name
assert html =~ shotgun_pack.type.name
assert html =~ pistol_pack.type.name
html =
index_live
|> form(~s/form[phx-change="change_class"]/)
|> render_change(type: %{class: :rifle})
assert html =~ rifle_pack.type.name
refute html =~ shotgun_pack.type.name
refute html =~ pistol_pack.type.name
html =
index_live
|> form(~s/form[phx-change="change_class"]/)
|> render_change(type: %{class: :shotgun})
refute html =~ rifle_pack.type.name
assert html =~ shotgun_pack.type.name
refute html =~ pistol_pack.type.name
html =
index_live
|> form(~s/form[phx-change="change_class"]/)
|> render_change(type: %{class: :pistol})
refute html =~ rifle_pack.type.name
refute html =~ shotgun_pack.type.name
assert html =~ pistol_pack.type.name
html =
index_live
|> form(~s/form[phx-change="change_class"]/)
|> render_change(type: %{class: :all})
assert html =~ rifle_pack.type.name
assert html =~ shotgun_pack.type.name
assert html =~ pistol_pack.type.name
end
test "can search for packs", %{conn: conn, pack: pack} do
{:ok, index_live, html} = live(conn, Routes.pack_index_path(conn, :index))
pack = pack |> Repo.preload(:type)
assert html =~ pack.type.name
assert index_live
|> form(~s/form[phx-change="search"]/)
|> render_change(search: %{search_term: pack.type.name}) =~
pack.type.name
assert_patch(
index_live,
Routes.pack_index_path(conn, :search, pack.type.name)
)
refute index_live
|> form(~s/form[phx-change="search"]/)
|> render_change(search: %{search_term: "something_else"}) =~
pack.type.name
assert_patch(index_live, Routes.pack_index_path(conn, :search, "something_else"))
assert index_live
|> form(~s/form[phx-change="search"]/)
|> render_change(search: %{search_term: ""}) =~ pack.type.name
assert_patch(index_live, Routes.pack_index_path(conn, :index))
end
test "saves a single new pack", %{conn: conn} do
{:ok, index_live, _html} = live(conn, Routes.pack_index_path(conn, :index))
assert index_live |> element("a", "Add Ammo") |> render_click() =~ "Add Ammo"
assert_patch(index_live, Routes.pack_index_path(conn, :new))
assert index_live
|> form("#pack-form")
|> render_change(pack: @invalid_attrs) =~ "can&#39;t be blank"
{:ok, _view, html} =
index_live
|> form("#pack-form")
|> render_submit(pack: @create_attrs)
|> follow_redirect(conn, Routes.pack_index_path(conn, :index))
assert html =~ "Ammo added successfully"
assert html =~ "\n42\n"
end
test "saves multiple new packs", %{conn: conn, current_user: current_user} do
multiplier = 25
{:ok, index_live, _html} = live(conn, Routes.pack_index_path(conn, :index))
assert index_live |> element("a", "Add Ammo") |> render_click() =~ "Add Ammo"
assert_patch(index_live, Routes.pack_index_path(conn, :new))
assert index_live
|> form("#pack-form")
|> render_change(pack: @invalid_attrs) =~ "can&#39;t be blank"
{:ok, _view, html} =
index_live
|> form("#pack-form")
|> render_submit(pack: @create_attrs |> Map.put(:multiplier, multiplier))
|> follow_redirect(conn, Routes.pack_index_path(conn, :index))
assert html =~ "Ammo added successfully"
assert Ammo.list_packs(nil, :all, current_user) |> Enum.count() == multiplier + 1
end
test "does not save invalid number of new packs", %{conn: conn} do
{:ok, index_live, _html} = live(conn, Routes.pack_index_path(conn, :index))
assert index_live |> element("a", "Add Ammo") |> render_click() =~ "Add Ammo"
assert_patch(index_live, Routes.pack_index_path(conn, :new))
assert index_live
|> form("#pack-form")
|> render_change(pack: @invalid_attrs) =~ "can&#39;t be blank"
assert index_live
|> form("#pack-form")
|> render_submit(pack: @create_attrs |> Map.put(:multiplier, "0")) =~
"Invalid number of copies, must be between 1 and #{@pack_create_limit}. Was 0"
assert index_live
|> form("#pack-form")
|> render_submit(pack: @create_attrs |> Map.put(:multiplier, @pack_create_limit + 1)) =~
"Invalid number of copies, must be between 1 and #{@pack_create_limit}. Was #{@pack_create_limit + 1}"
end
test "updates pack in listing", %{conn: conn, pack: pack} do
{:ok, index_live, _html} = live(conn, Routes.pack_index_path(conn, :index))
assert index_live
|> element(~s/a[aria-label="Edit pack of #{pack.count} bullets"]/)
|> render_click() =~ "Edit ammo"
assert_patch(index_live, Routes.pack_index_path(conn, :edit, pack))
assert index_live
|> form("#pack-form")
|> render_change(pack: @invalid_attrs) =~ "can&#39;t be blank"
{:ok, _view, html} =
index_live
|> form("#pack-form")
|> render_submit(pack: @update_attrs)
|> follow_redirect(conn, Routes.pack_index_path(conn, :index))
assert html =~ "Ammo updated successfully"
assert html =~ "\n43\n"
end
test "clones pack in listing", %{conn: conn, pack: pack} do
{:ok, index_live, _html} = live(conn, Routes.pack_index_path(conn, :index))
html =
index_live
|> element(~s/a[aria-label="Clone pack of #{pack.count} bullets"]/)
|> render_click()
assert html =~ "Add Ammo"
assert html =~ "$#{display_currency(120.5)}"
assert_patch(index_live, Routes.pack_index_path(conn, :clone, pack))
{:ok, _index_live, html} =
index_live
|> form("#pack-form")
|> render_submit()
|> follow_redirect(conn, Routes.pack_index_path(conn, :index))
assert html =~ "Ammo added successfully"
assert html =~ "\n42\n"
assert html =~ "$#{display_currency(120.5)}"
end
test "checks validity when cloning", %{conn: conn, pack: pack} do
{:ok, index_live, _html} = live(conn, Routes.pack_index_path(conn, :index))
html =
index_live
|> element(~s/a[aria-label="Clone pack of #{pack.count} bullets"]/)
|> render_click()
assert html =~ "Add Ammo"
assert html =~ "$#{display_currency(120.5)}"
assert_patch(index_live, Routes.pack_index_path(conn, :clone, pack))
assert index_live
|> form("#pack-form")
|> render_change(pack: @invalid_attrs) =~ "can&#39;t be blank"
end
test "clones pack in listing with updates", %{conn: conn, pack: pack} do
{:ok, index_live, _html} = live(conn, Routes.pack_index_path(conn, :index))
html =
index_live
|> element(~s/a[aria-label="Clone pack of #{pack.count} bullets"]/)
|> render_click()
assert html =~ "Add Ammo"
assert html =~ "$#{display_currency(120.5)}"
assert_patch(index_live, Routes.pack_index_path(conn, :clone, pack))
assert index_live
|> form("#pack-form")
|> render_change(pack: @invalid_attrs) =~ "can&#39;t be blank"
{:ok, _view, html} =
index_live
|> form("#pack-form")
|> render_submit(pack: @create_attrs |> Map.put(:count, 43))
|> follow_redirect(conn, Routes.pack_index_path(conn, :index))
assert html =~ "Ammo added successfully"
assert html =~ "\n43\n"
assert html =~ "$#{display_currency(120.5)}"
end
test "deletes pack in listing", %{conn: conn, pack: pack} do
{:ok, index_live, _html} = live(conn, Routes.pack_index_path(conn, :index))
assert index_live
|> element(~s/a[aria-label="Delete pack of #{pack.count} bullets"]/)
|> render_click()
refute has_element?(index_live, "#pack-#{pack.id}")
end
test "saves new shot_record", %{conn: conn, pack: pack} do
{:ok, index_live, _html} = live(conn, Routes.pack_index_path(conn, :index))
assert index_live |> element("a", "Record shots") |> render_click() =~ "Record shots"
assert_patch(index_live, Routes.pack_index_path(conn, :add_shot_record, pack))
assert index_live
|> form("#shot-record-form")
|> render_change(shot_record: @shot_record_invalid_attrs) =~ "can&#39;t be blank"
{:ok, _view, html} =
index_live
|> form("#shot-record-form")
|> render_submit(shot_record: @shot_record_create_attrs)
|> follow_redirect(conn, Routes.pack_index_path(conn, :index))
assert html =~ "Shots recorded successfully"
end
@spec display_currency(float()) :: String.t()
defp display_currency(float), do: :erlang.float_to_binary(float, decimals: 2)
end
describe "Index of empty pack" do
setup [:register_and_log_in_user, :create_pack, :create_empty_pack]
test "hides empty packs by default", %{
conn: conn,
empty_pack: pack,
current_user: current_user
} do
{:ok, show_live, html} = live(conn, Routes.pack_index_path(conn, :index))
assert html =~ "Show used"
refute html =~ "$#{display_currency(50.00)}"
percentage = pack |> Ammo.get_percentage_remaining(current_user)
refute html =~ "\n#{"#{percentage}%"}\n"
html =
show_live
|> element(~s/input[type="checkbox"][aria-labelledby="toggle_show_used-label"}]/)
|> render_click()
assert html =~ "$#{display_currency(50.00)}"
percentage = pack |> Ammo.get_percentage_remaining(current_user)
assert html =~ "\n#{"#{percentage}%"}\n"
end
end
describe "Show pack" do
setup [:register_and_log_in_user, :create_pack]
test "displays pack", %{conn: conn, pack: pack} do
{:ok, _show_live, html} = live(conn, Routes.pack_show_path(conn, :show, pack))
pack = pack |> Repo.preload(:type)
assert html =~ "Show Ammo"
assert html =~ pack.type.name
end
test "updates pack within modal", %{conn: conn, pack: pack} do
{:ok, show_live, _html} = live(conn, Routes.pack_show_path(conn, :show, pack))
assert show_live
|> element(~s/a[aria-label="Edit pack of #{pack.count} bullets"]/)
|> render_click() =~ "Edit Ammo"
assert_patch(show_live, Routes.pack_show_path(conn, :edit, pack))
assert show_live
|> form("#pack-form")
|> render_change(pack: @invalid_attrs) =~ "can&#39;t be blank"
{:ok, _view, html} =
show_live
|> form("#pack-form")
|> render_submit(pack: @update_attrs)
|> follow_redirect(conn, Routes.pack_show_path(conn, :show, pack))
assert html =~ "Ammo updated successfully"
assert html =~ "some updated notes"
end
test "saves new shot_record", %{conn: conn, pack: pack} do
{:ok, index_live, _html} = live(conn, Routes.pack_show_path(conn, :show, pack))
assert index_live |> element("a", "Record shots") |> render_click() =~ "Record shots"
assert_patch(index_live, Routes.pack_show_path(conn, :add_shot_record, pack))
assert index_live
|> form("#shot-record-form")
|> render_change(shot_record: @shot_record_invalid_attrs) =~ "can&#39;t be blank"
{:ok, _view, html} =
index_live
|> form("#shot-record-form")
|> render_submit(shot_record: @shot_record_create_attrs)
|> follow_redirect(conn, Routes.pack_show_path(conn, :show, pack))
assert html =~ "Shots recorded successfully"
end
end
describe "Show pack with shot record" do
setup [:register_and_log_in_user, :create_pack, :create_shot_record]
test "updates shot_record in listing",
%{conn: conn, pack: pack, shot_record: shot_record} do
{:ok, index_live, _html} = live(conn, Routes.pack_show_path(conn, :edit, pack))
assert index_live
|> element(~s/a[aria-label="Edit shot record of #{shot_record.count} shots"]/)
|> render_click() =~ "Edit Shot Record"
assert_patch(
index_live,
Routes.pack_show_path(conn, :edit_shot_record, pack, shot_record)
)
assert index_live
|> form("#shot-record-form")
|> render_change(shot_record: @shot_record_invalid_attrs) =~ "can&#39;t be blank"
{:ok, _view, html} =
index_live
|> form("#shot-record-form")
|> render_submit(shot_record: @shot_record_update_attrs)
|> follow_redirect(conn, Routes.pack_show_path(conn, :show, pack))
assert html =~ "Shot records updated successfully"
assert html =~ "some updated notes"
end
test "deletes shot_record in listing",
%{conn: conn, pack: pack, shot_record: shot_record} do
{:ok, index_live, _html} =
live(conn, Routes.pack_show_path(conn, :edit_shot_record, pack, shot_record))
assert index_live
|> element(~s/a[aria-label="Delete shot record of #{shot_record.count} shots"]/)
|> render_click()
refute has_element?(index_live, "#shot_record-#{shot_record.id}")
end
end
end

View File

@ -6,187 +6,177 @@ defmodule CanneryWeb.RangeLiveTest do
use CanneryWeb.ConnCase use CanneryWeb.ConnCase
import Phoenix.LiveViewTest import Phoenix.LiveViewTest
import Cannery.Fixtures import Cannery.Fixtures
import CanneryWeb.Gettext
@moduletag :range_live_test @moduletag :range_live_test
@create_attrs %{"ammo_left" => 5, "notes" => "some notes"} @create_attrs %{ammo_left: 5, notes: "some notes"}
@update_attrs %{"count" => 16, "notes" => "some updated notes"} @update_attrs %{count: 16, notes: "some updated notes"}
# @invalid_attrs %{"count" => nil, "notes" => nil} @invalid_attrs %{count: nil, notes: nil}
defp create_shot_group(%{current_user: current_user}) do defp create_shot_record(%{current_user: current_user}) do
container = container_fixture(%{"staged" => true}, current_user) container = container_fixture(%{staged: true}, current_user)
ammo_type = ammo_type_fixture(current_user) type = type_fixture(current_user)
{1, [ammo_group]} = {1, [pack]} = pack_fixture(%{staged: true}, type, container, current_user)
ammo_group_fixture(%{"staged" => true}, 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)
[ [
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
describe "Index" do describe "Index" do
setup [:register_and_log_in_user, :create_shot_group] setup [:register_and_log_in_user, :create_shot_record]
test "lists all shot_groups", %{conn: conn, shot_group: shot_group} do test "lists all shot_records", %{conn: conn, shot_record: shot_record} do
{:ok, _index_live, html} = live(conn, Routes.range_index_path(conn, :index)) {:ok, _index_live, html} = live(conn, Routes.range_index_path(conn, :index))
assert html =~ gettext("Range day") assert html =~ "Range day"
assert html =~ shot_group.notes assert html =~ shot_record.notes
end end
test "can sort by type", test "can sort by type",
%{conn: conn, container: container, current_user: current_user} do %{conn: conn, container: container, current_user: current_user} do
rifle_ammo_type = ammo_type_fixture(%{"type" => "rifle"}, current_user) rifle_type = type_fixture(%{class: :rifle}, current_user)
{1, [rifle_ammo_group]} = ammo_group_fixture(rifle_ammo_type, container, current_user) {1, [rifle_pack]} = pack_fixture(rifle_type, container, current_user)
rifle_shot_group = rifle_shot_record = shot_record_fixture(%{notes: "group_one"}, current_user, rifle_pack)
shot_group_fixture(%{"notes" => "group_one"}, current_user, rifle_ammo_group)
shotgun_ammo_type = ammo_type_fixture(%{"type" => "shotgun"}, current_user) shotgun_type = type_fixture(%{class: :shotgun}, current_user)
{1, [shotgun_ammo_group]} = ammo_group_fixture(shotgun_ammo_type, container, current_user) {1, [shotgun_pack]} = pack_fixture(shotgun_type, container, current_user)
shotgun_shot_group = shotgun_shot_record = shot_record_fixture(%{notes: "group_two"}, current_user, shotgun_pack)
shot_group_fixture(%{"notes" => "group_two"}, current_user, shotgun_ammo_group)
pistol_ammo_type = ammo_type_fixture(%{"type" => "pistol"}, current_user) pistol_type = type_fixture(%{class: :pistol}, current_user)
{1, [pistol_ammo_group]} = ammo_group_fixture(pistol_ammo_type, container, current_user) {1, [pistol_pack]} = pack_fixture(pistol_type, container, current_user)
pistol_shot_group = pistol_shot_record = shot_record_fixture(%{notes: "group_three"}, current_user, pistol_pack)
shot_group_fixture(%{"notes" => "group_three"}, current_user, pistol_ammo_group)
{:ok, index_live, html} = live(conn, Routes.range_index_path(conn, :index)) {:ok, index_live, html} = live(conn, Routes.range_index_path(conn, :index))
assert html =~ "All" assert html =~ "All"
assert html =~ rifle_shot_group.notes assert html =~ rifle_shot_record.notes
assert html =~ shotgun_shot_group.notes assert html =~ shotgun_shot_record.notes
assert html =~ pistol_shot_group.notes assert html =~ pistol_shot_record.notes
html = html =
index_live index_live
|> form(~s/form[phx-change="change_type"]/) |> form(~s/form[phx-change="change_class"]/)
|> render_change(ammo_type: %{type: :rifle}) |> render_change(type: %{class: :rifle})
assert html =~ rifle_shot_group.notes assert html =~ rifle_shot_record.notes
refute html =~ shotgun_shot_group.notes refute html =~ shotgun_shot_record.notes
refute html =~ pistol_shot_group.notes refute html =~ pistol_shot_record.notes
html = html =
index_live index_live
|> form(~s/form[phx-change="change_type"]/) |> form(~s/form[phx-change="change_class"]/)
|> render_change(ammo_type: %{type: :shotgun}) |> render_change(type: %{class: :shotgun})
refute html =~ rifle_shot_group.notes refute html =~ rifle_shot_record.notes
assert html =~ shotgun_shot_group.notes assert html =~ shotgun_shot_record.notes
refute html =~ pistol_shot_group.notes refute html =~ pistol_shot_record.notes
html = html =
index_live index_live
|> form(~s/form[phx-change="change_type"]/) |> form(~s/form[phx-change="change_class"]/)
|> render_change(ammo_type: %{type: :pistol}) |> render_change(type: %{class: :pistol})
refute html =~ rifle_shot_group.notes refute html =~ rifle_shot_record.notes
refute html =~ shotgun_shot_group.notes refute html =~ shotgun_shot_record.notes
assert html =~ pistol_shot_group.notes assert html =~ pistol_shot_record.notes
html = html =
index_live index_live
|> form(~s/form[phx-change="change_type"]/) |> form(~s/form[phx-change="change_class"]/)
|> render_change(ammo_type: %{type: :all}) |> render_change(type: %{class: :all})
assert html =~ rifle_shot_group.notes assert html =~ rifle_shot_record.notes
assert html =~ shotgun_shot_group.notes assert html =~ shotgun_shot_record.notes
assert html =~ pistol_shot_group.notes assert html =~ pistol_shot_record.notes
end end
test "can search for shot_group", %{conn: conn, shot_group: shot_group} do test "can search for shot_record", %{conn: conn, shot_record: shot_record} do
{:ok, index_live, html} = live(conn, Routes.range_index_path(conn, :index)) {:ok, index_live, html} = live(conn, Routes.range_index_path(conn, :index))
assert html =~ shot_group.notes assert html =~ shot_record.notes
assert index_live assert index_live
|> form(~s/form[phx-change="search"]/, |> form(~s/form[phx-change="search"]/)
search: %{search_term: shot_group.notes} |> render_change(search: %{search_term: shot_record.notes}) =~ shot_record.notes
)
|> render_change() =~ shot_group.notes
assert_patch(index_live, Routes.range_index_path(conn, :search, shot_group.notes)) assert_patch(index_live, Routes.range_index_path(conn, :search, shot_record.notes))
refute index_live refute index_live
|> form(~s/form[phx-change="search"]/, search: %{search_term: "something_else"}) |> form(~s/form[phx-change="search"]/)
|> render_change() =~ shot_group.notes |> render_change(search: %{search_term: "something_else"}) =~ shot_record.notes
assert_patch(index_live, Routes.range_index_path(conn, :search, "something_else")) assert_patch(index_live, Routes.range_index_path(conn, :search, "something_else"))
assert index_live assert index_live
|> form(~s/form[phx-change="search"]/, search: %{search_term: ""}) |> form(~s/form[phx-change="search"]/)
|> render_change() =~ shot_group.notes |> render_change(search: %{search_term: ""}) =~ shot_record.notes
assert_patch(index_live, Routes.range_index_path(conn, :index)) assert_patch(index_live, Routes.range_index_path(conn, :index))
end end
test "saves new shot_group", %{conn: conn, ammo_group: ammo_group} do test "saves new shot_record", %{conn: conn, pack: pack} do
{:ok, index_live, _html} = live(conn, Routes.range_index_path(conn, :index)) {:ok, index_live, _html} = live(conn, Routes.range_index_path(conn, :index))
assert index_live |> element("a", dgettext("actions", "Record shots")) |> render_click() =~ assert index_live |> element("a", "Record shots") |> render_click() =~ "Record shots"
gettext("Record shots") assert_patch(index_live, Routes.range_index_path(conn, :add_shot_record, pack))
assert_patch(index_live, Routes.range_index_path(conn, :add_shot_group, ammo_group)) assert index_live
|> form("#shot-record-form")
# assert index_live |> render_change(shot_record: @invalid_attrs) =~ "can&#39;t be blank"
# |> form("#shot_group-form", shot_group: @invalid_attrs)
# |> render_change() =~ dgettext("errors", "is invalid")
{:ok, _view, html} = {:ok, _view, html} =
index_live index_live
|> form("#shot-group-form", shot_group: @create_attrs) |> form("#shot-record-form")
|> render_submit() |> render_submit(shot_record: @create_attrs)
|> follow_redirect(conn, Routes.range_index_path(conn, :index)) |> follow_redirect(conn, Routes.range_index_path(conn, :index))
assert html =~ dgettext("prompts", "Shots recorded successfully") assert html =~ "Shots recorded successfully"
assert html =~ "some notes" assert html =~ "some notes"
end end
test "updates shot_group in listing", %{conn: conn, shot_group: shot_group} do test "updates shot_record in listing", %{conn: conn, shot_record: shot_record} do
{:ok, index_live, _html} = live(conn, Routes.range_index_path(conn, :index)) {:ok, index_live, _html} = live(conn, Routes.range_index_path(conn, :index))
assert index_live assert index_live
|> element(~s/a[aria-label="Edit shot record of #{shot_group.count} shots"]/) |> element(~s/a[aria-label="Edit shot record of #{shot_record.count} shots"]/)
|> render_click() =~ |> render_click() =~ "Edit Shot Record"
gettext("Edit Shot Records")
assert_patch(index_live, Routes.range_index_path(conn, :edit, shot_group)) assert_patch(index_live, Routes.range_index_path(conn, :edit, shot_record))
# assert index_live assert index_live
# |> form("#shot_group-form", shot_group: @invalid_attrs) |> form("#shot-record-form")
# |> render_change() =~ dgettext("errors", "is invalid") |> render_change(shot_record: @invalid_attrs) =~ "can&#39;t be blank"
{:ok, _view, html} = {:ok, _view, html} =
index_live index_live
|> form("#shot-group-form", shot_group: @update_attrs) |> form("#shot-record-form", shot_record: @update_attrs)
|> render_submit() |> render_submit()
|> follow_redirect(conn, Routes.range_index_path(conn, :index)) |> follow_redirect(conn, Routes.range_index_path(conn, :index))
assert html =~ dgettext("actions", "Shot records updated successfully") assert html =~ "Shot records updated successfully"
assert html =~ "some updated notes" assert html =~ "some updated notes"
end end
test "deletes shot_group in listing", %{conn: conn, shot_group: shot_group} do test "deletes shot_record in listing", %{conn: conn, shot_record: shot_record} do
{:ok, index_live, _html} = live(conn, Routes.range_index_path(conn, :index)) {:ok, index_live, _html} = live(conn, Routes.range_index_path(conn, :index))
assert index_live assert index_live
|> element(~s/a[aria-label="Delete shot record of #{shot_group.count} shots"]/) |> element(~s/a[aria-label="Delete shot record of #{shot_record.count} shots"]/)
|> render_click() |> render_click()
refute has_element?(index_live, "#shot_group-#{shot_group.id}") refute has_element?(index_live, "#shot_record-#{shot_record.id}")
end end
end end
end end

View File

@ -5,26 +5,24 @@ defmodule CanneryWeb.TagLiveTest do
use CanneryWeb.ConnCase use CanneryWeb.ConnCase
import Phoenix.LiveViewTest import Phoenix.LiveViewTest
import CanneryWeb.Gettext
@moduletag :tag_live_test @moduletag :tag_live_test
@create_attrs %{ @create_attrs %{
"bg_color" => "#100000", bg_color: "#100000",
"name" => "some name", name: "some name",
"text_color" => "#000000" text_color: "#000000"
} }
@update_attrs %{ @update_attrs %{
"bg_color" => "#100001", bg_color: "#100001",
"name" => "some updated name", name: "some updated name",
"text_color" => "#000001" text_color: "#000001"
}
@invalid_attrs %{
bg_color: nil,
name: nil,
text_color: nil
} }
# @invalid_attrs %{
# "bg_color" => nil,
# "name" => nil,
# "text_color" => nil
# }
def create_tag(%{current_user: current_user}) do def create_tag(%{current_user: current_user}) do
tag = tag_fixture(current_user) tag = tag_fixture(current_user)
@ -37,7 +35,7 @@ defmodule CanneryWeb.TagLiveTest do
test "lists all tags", %{conn: conn, tag: tag} do test "lists all tags", %{conn: conn, tag: tag} do
{:ok, _index_live, html} = live(conn, Routes.tag_index_path(conn, :index)) {:ok, _index_live, html} = live(conn, Routes.tag_index_path(conn, :index))
assert html =~ gettext("Tags") assert html =~ "Tags"
assert html =~ tag.bg_color assert html =~ tag.bg_color
end end
@ -47,22 +45,20 @@ defmodule CanneryWeb.TagLiveTest do
assert html =~ tag.name assert html =~ tag.name
assert index_live assert index_live
|> form(~s/form[phx-change="search"]/, |> form(~s/form[phx-change="search"]/)
search: %{search_term: tag.name} |> render_change(search: %{search_term: tag.name}) =~ tag.name
)
|> render_change() =~ tag.name
assert_patch(index_live, Routes.tag_index_path(conn, :search, tag.name)) assert_patch(index_live, Routes.tag_index_path(conn, :search, tag.name))
refute index_live refute index_live
|> form(~s/form[phx-change="search"]/, search: %{search_term: "something_else"}) |> form(~s/form[phx-change="search"]/)
|> render_change() =~ tag.name |> render_change(search: %{search_term: "something_else"}) =~ tag.name
assert_patch(index_live, Routes.tag_index_path(conn, :search, "something_else")) assert_patch(index_live, Routes.tag_index_path(conn, :search, "something_else"))
assert index_live assert index_live
|> form(~s/form[phx-change="search"]/, search: %{search_term: ""}) |> form(~s/form[phx-change="search"]/)
|> render_change() =~ tag.name |> render_change(search: %{search_term: ""}) =~ tag.name
assert_patch(index_live, Routes.tag_index_path(conn, :index)) assert_patch(index_live, Routes.tag_index_path(conn, :index))
end end
@ -70,22 +66,20 @@ defmodule CanneryWeb.TagLiveTest do
test "saves new tag", %{conn: conn} do test "saves new tag", %{conn: conn} do
{:ok, index_live, _html} = live(conn, Routes.tag_index_path(conn, :index)) {:ok, index_live, _html} = live(conn, Routes.tag_index_path(conn, :index))
assert index_live |> element("a", dgettext("actions", "New Tag")) |> render_click() =~ assert index_live |> element("a", "New Tag") |> render_click() =~ "New Tag"
dgettext("actions", "New Tag")
assert_patch(index_live, Routes.tag_index_path(conn, :new)) assert_patch(index_live, Routes.tag_index_path(conn, :new))
# assert index_live assert index_live
# |> form("#tag-form", tag: @invalid_attrs) |> form("#tag-form")
# |> render_change() =~ dgettext("errors", "can't be blank") |> render_change(tag: @invalid_attrs) =~ "can&#39;t be blank"
{:ok, _view, html} = {:ok, _view, html} =
index_live index_live
|> form("#tag-form", tag: @create_attrs) |> form("#tag-form")
|> render_submit() |> render_submit(tag: @create_attrs)
|> follow_redirect(conn, Routes.tag_index_path(conn, :index)) |> follow_redirect(conn, Routes.tag_index_path(conn, :index))
assert html =~ dgettext("actions", "%{name} created successfully", name: "some name") assert html =~ "some name created successfully"
assert html =~ "#100000" assert html =~ "#100000"
end end
@ -93,23 +87,21 @@ defmodule CanneryWeb.TagLiveTest do
{:ok, index_live, _html} = live(conn, Routes.tag_index_path(conn, :index)) {:ok, index_live, _html} = live(conn, Routes.tag_index_path(conn, :index))
assert index_live |> element(~s/a[aria-label="Edit #{tag.name}"]/) |> render_click() =~ assert index_live |> element(~s/a[aria-label="Edit #{tag.name}"]/) |> render_click() =~
dgettext("actions", "Edit Tag") "Edit Tag"
assert_patch(index_live, Routes.tag_index_path(conn, :edit, tag)) assert_patch(index_live, Routes.tag_index_path(conn, :edit, tag))
# assert index_live assert index_live
# |> form("#tag-form", tag: @invalid_attrs) |> form("#tag-form")
# |> render_change() =~ dgettext("errors", "can't be blank") |> render_change(tag: @invalid_attrs) =~ "can&#39;t be blank"
{:ok, _view, html} = {:ok, _view, html} =
index_live index_live
|> form("#tag-form", tag: @update_attrs) |> form("#tag-form")
|> render_submit() |> render_submit(tag: @update_attrs)
|> follow_redirect(conn, Routes.tag_index_path(conn, :index)) |> follow_redirect(conn, Routes.tag_index_path(conn, :index))
assert html =~ assert html =~ "some updated name updated successfully"
dgettext("prompts", "%{name} updated successfully", name: "some updated name")
assert html =~ "#100001" assert html =~ "#100001"
end end

View File

@ -0,0 +1,400 @@
defmodule CanneryWeb.TypeLiveTest do
@moduledoc """
Tests the type liveview
"""
use CanneryWeb.ConnCase
import Phoenix.LiveViewTest
alias Cannery.{Ammo, Repo}
@moduletag :type_live_test
@create_attrs %{
bullet_type: "some bullet_type",
case_material: "some case_material",
desc: "some desc",
manufacturer: "some manufacturer",
name: "some name",
grains: 120
}
@update_attrs %{
bullet_type: "some updated bullet_type",
case_material: "some updated case_material",
desc: "some updated desc",
manufacturer: "some updated manufacturer",
name: "some updated name",
grains: 456
}
@invalid_attrs %{
bullet_type: nil,
case_material: nil,
desc: nil,
manufacturer: nil,
name: nil,
grains: nil
}
@pack_attrs %{
notes: "some pack",
count: 20
}
@shot_record_attrs %{
notes: "some shot record",
count: 20
}
defp create_type(%{current_user: current_user}) do
[type: type_fixture(@create_attrs, current_user)]
end
defp create_pack(%{type: type, current_user: current_user}) do
container = container_fixture(current_user)
{1, [pack]} = pack_fixture(@pack_attrs, type, container, current_user)
[pack: pack, container: container]
end
defp create_empty_pack(%{type: type, current_user: current_user}) do
container = container_fixture(current_user)
{1, [pack]} = pack_fixture(@pack_attrs, type, container, current_user)
shot_record = shot_record_fixture(@shot_record_attrs, current_user, pack)
pack = pack |> Repo.reload!()
[pack: pack, container: container, shot_record: shot_record]
end
describe "Index" do
setup [:register_and_log_in_user, :create_type]
test "lists all types", %{conn: conn, type: type} do
{:ok, _index_live, html} = live(conn, Routes.type_index_path(conn, :index))
assert html =~ "Catalog"
assert html =~ type.bullet_type
end
test "can sort by class", %{conn: conn, current_user: current_user} do
rifle_type = type_fixture(%{class: :rifle}, current_user)
shotgun_type = type_fixture(%{class: :shotgun}, current_user)
pistol_type = type_fixture(%{class: :pistol}, current_user)
{:ok, index_live, html} = live(conn, Routes.type_index_path(conn, :index))
assert html =~ "All"
assert html =~ rifle_type.name
assert html =~ shotgun_type.name
assert html =~ pistol_type.name
html =
index_live
|> form(~s/form[phx-change="change_class"]/)
|> render_change(type: %{class: :rifle})
assert html =~ rifle_type.name
refute html =~ shotgun_type.name
refute html =~ pistol_type.name
html =
index_live
|> form(~s/form[phx-change="change_class"]/)
|> render_change(type: %{class: :shotgun})
refute html =~ rifle_type.name
assert html =~ shotgun_type.name
refute html =~ pistol_type.name
html =
index_live
|> form(~s/form[phx-change="change_class"]/)
|> render_change(type: %{class: :pistol})
refute html =~ rifle_type.name
refute html =~ shotgun_type.name
assert html =~ pistol_type.name
html =
index_live
|> form(~s/form[phx-change="change_class"]/)
|> render_change(type: %{class: :all})
assert html =~ rifle_type.name
assert html =~ shotgun_type.name
assert html =~ pistol_type.name
end
test "can search for type", %{conn: conn, type: type} do
{:ok, index_live, html} = live(conn, Routes.type_index_path(conn, :index))
assert html =~ type.bullet_type
assert index_live
|> form(~s/form[phx-change="search"]/)
|> render_change(search: %{search_term: type.bullet_type}) =~
type.bullet_type
assert_patch(index_live, Routes.type_index_path(conn, :search, type.bullet_type))
refute index_live
|> form(~s/form[phx-change="search"]/)
|> render_change(search: %{search_term: "something_else"}) =~ type.bullet_type
assert_patch(index_live, Routes.type_index_path(conn, :search, "something_else"))
assert index_live
|> form(~s/form[phx-change="search"]/)
|> render_change(search: %{search_term: ""}) =~ type.bullet_type
assert_patch(index_live, Routes.type_index_path(conn, :index))
end
test "saves new type", %{conn: conn, current_user: current_user, type: type} do
{:ok, index_live, _html} = live(conn, Routes.type_index_path(conn, :index))
assert index_live |> element("a", "New Type") |> render_click() =~ "New Type"
assert_patch(index_live, Routes.type_index_path(conn, :new))
assert index_live
|> form("#type-form")
|> render_change(type: @invalid_attrs) =~ "can&#39;t be blank"
{:ok, _view, html} =
index_live
|> form("#type-form")
|> render_submit(type: @create_attrs)
|> follow_redirect(conn, Routes.type_index_path(conn, :index))
type = type.id |> Ammo.get_type!(current_user)
assert html =~ "#{type.name} created successfully"
assert html =~ "some bullet_type"
end
test "updates type in listing",
%{conn: conn, current_user: current_user, type: type} do
{:ok, index_live, _html} = live(conn, Routes.type_index_path(conn, :index))
assert index_live |> element(~s/a[aria-label="Edit #{type.name}"]/) |> render_click() =~
"Edit #{type.name}"
assert_patch(index_live, Routes.type_index_path(conn, :edit, type))
assert index_live
|> form("#type-form")
|> render_change(type: @invalid_attrs) =~ "can&#39;t be blank"
{:ok, _view, html} =
index_live
|> form("#type-form")
|> render_submit(type: @update_attrs)
|> follow_redirect(conn, Routes.type_index_path(conn, :index))
type = type.id |> Ammo.get_type!(current_user)
assert html =~ "#{type.name} updated successfully"
assert html =~ "some updated bullet_type"
end
test "clones type in listing",
%{conn: conn, current_user: current_user, type: type} do
{:ok, index_live, _html} = live(conn, Routes.type_index_path(conn, :index))
html = index_live |> element(~s/a[aria-label="Clone #{type.name}"]/) |> render_click()
assert html =~ "New Type"
assert html =~ "some bullet_type"
assert_patch(index_live, Routes.type_index_path(conn, :clone, type))
assert index_live
|> form("#type-form")
|> render_change(type: @invalid_attrs) =~ "can&#39;t be blank"
{:ok, _view, html} =
index_live
|> form("#type-form")
|> render_submit(type: @create_attrs)
|> follow_redirect(conn, Routes.type_index_path(conn, :index))
type = type.id |> Ammo.get_type!(current_user)
assert html =~ "#{type.name} created successfully"
assert html =~ "some bullet_type"
end
test "clones type in listing with updates",
%{conn: conn, current_user: current_user, type: type} do
{:ok, index_live, _html} = live(conn, Routes.type_index_path(conn, :index))
html = index_live |> element(~s/a[aria-label="Clone #{type.name}"]/) |> render_click()
assert html =~ "New Type"
assert html =~ "some bullet_type"
assert_patch(index_live, Routes.type_index_path(conn, :clone, type))
assert index_live
|> form("#type-form")
|> render_change(type: @invalid_attrs) =~ "can&#39;t be blank"
{:ok, _view, html} =
index_live
|> form("#type-form")
|> render_submit(
type: Map.merge(@create_attrs, %{bullet_type: "some updated bullet_type"})
)
|> follow_redirect(conn, Routes.type_index_path(conn, :index))
type = type.id |> Ammo.get_type!(current_user)
assert html =~ "#{type.name} created successfully"
assert html =~ "some updated bullet_type"
end
test "deletes type in listing", %{conn: conn, type: type} do
{:ok, index_live, _html} = live(conn, Routes.type_index_path(conn, :index))
assert index_live |> element(~s/a[aria-label="Delete #{type.name}"]/) |> render_click()
refute has_element?(index_live, "#type-#{type.id}")
end
end
describe "Index with pack" do
setup [:register_and_log_in_user, :create_type, :create_pack]
test "shows used packs on toggle",
%{conn: conn, pack: pack, current_user: current_user} do
{:ok, index_live, html} = live(conn, Routes.type_index_path(conn, :index))
assert html =~ "Show used"
refute html =~ "Used rounds"
refute html =~ "Total ever rounds"
refute html =~ "Used packs"
refute html =~ "Total ever packs"
html =
index_live
|> element(~s/input[type="checkbox"][aria-labelledby="toggle_show_used-label"}]/)
|> render_click()
assert html =~ "Used rounds"
assert html =~ "Total ever rounds"
assert html =~ "Used packs"
assert html =~ "Total ever packs"
assert html =~ "\n20\n"
assert html =~ "\n0\n"
assert html =~ "\n1\n"
shot_record_fixture(%{count: 5}, current_user, pack)
{:ok, index_live, _html} = live(conn, Routes.type_index_path(conn, :index))
html =
index_live
|> element(~s/input[type="checkbox"][aria-labelledby="toggle_show_used-label"}]/)
|> render_click()
assert html =~ "\n15\n"
assert html =~ "\n5\n"
end
end
describe "Show type" do
setup [:register_and_log_in_user, :create_type]
test "displays type", %{
conn: conn,
type: %{name: name, bullet_type: bullet_type} = type
} do
{:ok, _show_live, html} = live(conn, Routes.type_show_path(conn, :show, type))
assert html =~ name
assert html =~ bullet_type
end
test "updates type within modal",
%{conn: conn, current_user: current_user, type: %{name: name} = type} do
{:ok, show_live, _html} = live(conn, Routes.type_show_path(conn, :show, type))
assert show_live |> element(~s/a[aria-label="Edit #{type.name}"]/) |> render_click() =~
"Edit #{name}"
assert_patch(show_live, Routes.type_show_path(conn, :edit, type))
assert show_live
|> form("#type-form")
|> render_change(type: @invalid_attrs) =~ "can&#39;t be blank"
{:ok, _view, html} =
show_live
|> form("#type-form")
|> render_submit(type: @update_attrs)
|> follow_redirect(conn, Routes.type_show_path(conn, :show, type))
type = type.id |> Ammo.get_type!(current_user)
assert html =~ "#{type.name} updated successfully"
assert html =~ "some updated bullet_type"
end
end
describe "Show type with pack" do
setup [:register_and_log_in_user, :create_type, :create_pack]
test "displays pack", %{
conn: conn,
type: %{name: type_name} = type,
container: %{name: container_name}
} do
{:ok, _show_live, html} = live(conn, Routes.type_show_path(conn, :show, type))
assert html =~ type_name
assert html =~ "\n20\n"
assert html =~ container_name
end
test "displays pack in table",
%{conn: conn, type: type, container: %{name: container_name}} do
{:ok, show_live, _html} = live(conn, Routes.type_show_path(conn, :show, type))
html =
show_live
|> element(~s/input[type="checkbox"][aria-labelledby="toggle_table-label"}]/)
|> render_click()
assert html =~ "\n20\n"
assert html =~ container_name
end
end
describe "Show type with empty pack" do
setup [:register_and_log_in_user, :create_type, :create_empty_pack]
test "displays empty packs on toggle",
%{conn: conn, type: type, container: %{name: container_name}} do
{:ok, show_live, html} = live(conn, Routes.type_show_path(conn, :show, type))
assert html =~ "Show used"
refute html =~ "\n20\n"
html =
show_live
|> element(~s/input[type="checkbox"][aria-labelledby="toggle_show_used-label"}]/)
|> render_click()
assert html =~ "\n20\n"
assert html =~ "Empty"
assert html =~ container_name
end
test "displays empty packs in table on toggle",
%{conn: conn, type: type, container: %{name: container_name}} do
{:ok, show_live, _html} = live(conn, Routes.type_show_path(conn, :show, type))
html =
show_live
|> element(~s/input[type="checkbox"][aria-labelledby="toggle_table-label"}]/)
|> render_click()
assert html =~ "Show used"
refute html =~ "\n20\n"
html =
show_live
|> element(~s/input[type="checkbox"][aria-labelledby="toggle_show_used-label"}]/)
|> render_click()
assert html =~ "\n20\n"
assert html =~ "Empty"
assert html =~ container_name
end
end
end

View File

@ -4,19 +4,16 @@ defmodule CanneryWeb.ErrorViewTest do
""" """
use CanneryWeb.ConnCase, async: true use CanneryWeb.ConnCase, async: true
import CanneryWeb.Gettext
# Bring render/3 and render_to_string/3 for testing custom views # Bring render/3 and render_to_string/3 for testing custom views
import Phoenix.View import Phoenix.View
@moduletag :error_view_test @moduletag :error_view_test
test "renders 404.html" do test "renders 404.html" do
assert render_to_string(CanneryWeb.ErrorView, "404.html", []) =~ assert render_to_string(CanneryWeb.ErrorView, "404.html", []) =~ "Not found"
dgettext("errors", "Not found")
end end
test "renders 500.html" do test "renders 500.html" do
assert render_to_string(CanneryWeb.ErrorView, "500.html", []) =~ assert render_to_string(CanneryWeb.ErrorView, "500.html", []) =~ "Internal Server Error"
dgettext("errors", "Internal Server Error")
end end
end end

View File

@ -8,10 +8,10 @@ defmodule Cannery.Fixtures do
alias Cannery.{ alias Cannery.{
Accounts, Accounts,
Accounts.User, Accounts.User,
ActivityLog.ShotGroup, ActivityLog.ShotRecord,
Ammo, Ammo,
Ammo.AmmoGroup, Ammo.Pack,
Ammo.AmmoType, Ammo.Type,
Containers, Containers,
Containers.Container, Containers.Container,
Containers.Tag, Containers.Tag,
@ -24,8 +24,8 @@ defmodule Cannery.Fixtures do
def user_fixture(attrs \\ %{}) do def user_fixture(attrs \\ %{}) do
attrs attrs
|> Enum.into(%{ |> Enum.into(%{
"email" => unique_user_email(), email: unique_user_email(),
"password" => valid_user_password() password: valid_user_password()
}) })
|> Accounts.register_user() |> Accounts.register_user()
|> unwrap_ok_tuple() |> unwrap_ok_tuple()
@ -36,8 +36,8 @@ defmodule Cannery.Fixtures do
def admin_fixture(attrs \\ %{}) do def admin_fixture(attrs \\ %{}) do
attrs attrs
|> Enum.into(%{ |> Enum.into(%{
"email" => unique_user_email(), email: unique_user_email(),
"password" => valid_user_password() password: valid_user_password()
}) })
|> Accounts.register_user() |> Accounts.register_user()
|> unwrap_ok_tuple() |> unwrap_ok_tuple()
@ -69,18 +69,18 @@ defmodule Cannery.Fixtures do
end end
@doc """ @doc """
Generate a ShotGroup Generate a ShotRecord
""" """
@spec shot_group_fixture(User.t(), AmmoGroup.t()) :: ShotGroup.t() @spec shot_record_fixture(User.t(), Pack.t()) :: ShotRecord.t()
@spec shot_group_fixture(attrs :: map(), User.t(), AmmoGroup.t()) :: ShotGroup.t() @spec shot_record_fixture(attrs :: map(), User.t(), Pack.t()) :: ShotRecord.t()
def shot_group_fixture(attrs \\ %{}, %User{} = user, %AmmoGroup{} = ammo_group) do def shot_record_fixture(attrs \\ %{}, %User{} = user, %Pack{} = pack) do
attrs attrs
|> Enum.into(%{ |> Enum.into(%{
"count" => 20, count: 20,
"date" => ~N[2022-02-13 03:17:00], date: ~N[2022-02-13 03:17:00],
"notes" => random_string() notes: random_string()
}) })
|> Cannery.ActivityLog.create_shot_group(user, ammo_group) |> Cannery.ActivityLog.create_shot_record(user, pack)
|> unwrap_ok_tuple() |> unwrap_ok_tuple()
end end
@ -91,52 +91,90 @@ defmodule Cannery.Fixtures do
@spec container_fixture(attrs :: map(), User.t()) :: Container.t() @spec container_fixture(attrs :: map(), User.t()) :: Container.t()
def container_fixture(attrs \\ %{}, %User{} = user) do def container_fixture(attrs \\ %{}, %User{} = user) do
attrs attrs
|> Enum.into(%{"name" => random_string(), "type" => "Ammo can"}) |> Enum.into(%{
name: random_string(),
type: "Ammo can",
location: random_string(),
desc: random_string()
})
|> Containers.create_container(user) |> Containers.create_container(user)
|> unwrap_ok_tuple() |> unwrap_ok_tuple()
end end
@doc """ @doc """
Generate a AmmoType Generate a Type
""" """
@spec ammo_type_fixture(User.t()) :: AmmoType.t() @spec type_fixture(User.t()) :: Type.t()
@spec ammo_type_fixture(attrs :: map(), User.t()) :: AmmoType.t() @spec type_fixture(attrs :: map(), User.t()) :: Type.t()
def ammo_type_fixture(attrs \\ %{}, %User{} = user) do def type_fixture(attrs \\ %{}, %User{} = user) do
attrs attrs
|> Enum.into(%{"name" => random_string(), "type" => "rifle"}) |> Enum.into(%{
|> Ammo.create_ammo_type(user) name: random_string(),
class: :rifle,
desc: random_string(),
bullet_type: random_string(),
bullet_core: random_string(),
cartridge: random_string(),
caliber: random_string(),
case_material: random_string(),
jacket_type: random_string(),
muzzle_velocity: 3,
powder_type: random_string(),
powder_grains_per_charge: 5,
grains: 7,
pressure: random_string(),
primer_type: random_string(),
firing_type: random_string(),
wadding: random_string(),
shot_type: random_string(),
shot_material: random_string(),
shot_size: random_string(),
unfired_length: random_string(),
brass_height: random_string(),
chamber_size: random_string(),
load_grains: 9,
shot_charge_weight: random_string(),
dram_equivalent: random_string(),
tracer: false,
incendiary: false,
blank: false,
corrosive: false,
manufacturer: random_string(),
upc: random_string()
})
|> Ammo.create_type(user)
|> unwrap_ok_tuple() |> unwrap_ok_tuple()
end end
@doc """ @doc """
Generate a AmmoGroup Generate a Pack
""" """
@spec ammo_group_fixture(AmmoType.t(), Container.t(), User.t()) :: @spec pack_fixture(Type.t(), Container.t(), User.t()) ::
{count :: non_neg_integer(), [AmmoGroup.t()]} {count :: non_neg_integer(), [Pack.t()]}
@spec ammo_group_fixture(attrs :: map(), AmmoType.t(), Container.t(), User.t()) :: @spec pack_fixture(attrs :: map(), Type.t(), Container.t(), User.t()) ::
{count :: non_neg_integer(), [AmmoGroup.t()]} {count :: non_neg_integer(), [Pack.t()]}
@spec ammo_group_fixture( @spec pack_fixture(
attrs :: map(), attrs :: map(),
multiplier :: non_neg_integer(), multiplier :: non_neg_integer(),
AmmoType.t(), Type.t(),
Container.t(), Container.t(),
User.t() User.t()
) :: {count :: non_neg_integer(), [AmmoGroup.t()]} ) :: {count :: non_neg_integer(), [Pack.t()]}
def ammo_group_fixture( def pack_fixture(
attrs \\ %{}, attrs \\ %{},
multiplier \\ 1, multiplier \\ 1,
%AmmoType{id: ammo_type_id}, %Type{id: type_id},
%Container{id: container_id}, %Container{id: container_id},
%User{} = user %User{} = user
) do ) do
attrs attrs
|> Enum.into(%{ |> Enum.into(%{
"ammo_type_id" => ammo_type_id, type_id: type_id,
"container_id" => container_id, container_id: container_id,
"count" => 20, count: 20,
"purchased_on" => Date.utc_today() purchased_on: Date.utc_today()
}) })
|> Ammo.create_ammo_groups(multiplier, user) |> Ammo.create_packs(multiplier, user)
|> unwrap_ok_tuple() |> unwrap_ok_tuple()
end end
@ -148,9 +186,9 @@ defmodule Cannery.Fixtures do
def tag_fixture(attrs \\ %{}, %User{} = user) do def tag_fixture(attrs \\ %{}, %User{} = user) do
attrs attrs
|> Enum.into(%{ |> Enum.into(%{
"bg_color" => "#100000", bg_color: "#100000",
"name" => random_string(), name: random_string(),
"text_color" => "#000000" text_color: "#000000"
}) })
|> Containers.create_tag(user) |> Containers.create_tag(user)
|> unwrap_ok_tuple() |> unwrap_ok_tuple()