Compare commits

...

73 Commits
0.2.1 ... 0.5.0

Author SHA1 Message Date
c555022ea7 use elixir 1.13.4 2022-04-19 20:23:31 -04:00
0917aff37b run mix format 2022-04-19 20:08:12 -04:00
7f9e6f9eff fix tests 2022-04-19 20:08:10 -04:00
9e754fe630 Show average price per round on ammo type table 2022-04-19 19:42:48 -04:00
45d905b384 Fix bug with average price per round calculation 2022-04-19 19:42:48 -04:00
3297130890 Fix not being able to edit ammo group when fully used up 2022-04-19 19:42:48 -04:00
d27b54386d remove unneeded formatter dep 2022-04-19 19:42:48 -04:00
ebf32c49bf add translation properly 2022-04-19 18:16:06 -04:00
119f2af6bb Translated using Weblate (German)
Currently translated at 100.0% (15 of 15 strings)

Translation: cannery/emails
Translate-URL: https://weblate.bubbletea.dev/projects/cannery/emails/de/
2022-04-19 21:44:13 +00:00
9db6b2c316 Translated using Weblate (German)
Currently translated at 100.0% (33 of 33 strings)

Translation: cannery/actions
Translate-URL: https://weblate.bubbletea.dev/projects/cannery/actions/de/
2022-04-19 21:32:54 +00:00
22281486e0 Translated using Weblate (German)
Currently translated at 100.0% (30 of 30 strings)

Translation: cannery/errors
Translate-URL: https://weblate.bubbletea.dev/projects/cannery/errors/de/
2022-04-19 21:32:54 +00:00
1b7546aede Translated using Weblate (German)
Currently translated at 100.0% (146 of 146 strings)

Translation: cannery/default
Translate-URL: https://weblate.bubbletea.dev/projects/cannery/default/de/
2022-04-19 21:32:54 +00:00
e153893a5b Translated using Weblate (German)
Currently translated at 100.0% (44 of 44 strings)

Translation: cannery/prompts
Translate-URL: https://weblate.bubbletea.dev/projects/cannery/prompts/de/
2022-04-19 21:32:53 +00:00
2f7c17aad3 Translated using Weblate (German)
Currently translated at 100.0% (15 of 15 strings)

Translation: cannery/emails
Translate-URL: https://weblate.bubbletea.dev/projects/cannery/emails/de/
2022-04-19 21:32:53 +00:00
664c65d136 Translated using Weblate (German)
Currently translated at 96.6% (29 of 30 strings)

Translation: cannery/errors
Translate-URL: https://weblate.bubbletea.dev/projects/cannery/errors/de/
2022-04-19 21:32:22 +00:00
ef76eb002d Translated using Weblate (German)
Currently translated at 96.6% (29 of 30 strings)

Translation: cannery/errors
Translate-URL: https://weblate.bubbletea.dev/projects/cannery/errors/de/
2022-04-19 21:32:22 +00:00
5b40ac4137 Translated using Weblate (German)
Currently translated at 98.6% (144 of 146 strings)

Translation: cannery/default
Translate-URL: https://weblate.bubbletea.dev/projects/cannery/default/de/
2022-04-19 21:30:00 +00:00
ed20cdd858 Translated using Weblate (German)
Currently translated at 96.9% (32 of 33 strings)

Translation: cannery/actions
Translate-URL: https://weblate.bubbletea.dev/projects/cannery/actions/de/
2022-04-19 21:29:42 +00:00
1e0ec82f3e Translated using Weblate (German)
Currently translated at 83.3% (25 of 30 strings)

Translation: cannery/errors
Translate-URL: https://weblate.bubbletea.dev/projects/cannery/errors/de/
2022-04-19 21:18:06 +00:00
d07ac801aa Added translation using Weblate (German) 2022-04-19 19:32:18 +00:00
420e7c2d71 Added translation using Weblate (German) 2022-04-19 19:32:16 +00:00
40877d1ac0 Added translation using Weblate (German) 2022-04-19 19:32:15 +00:00
1dd30e6a5b Added translation using Weblate (German) 2022-04-19 19:32:15 +00:00
eedaf33e25 Added translation using Weblate (German) 2022-04-19 19:32:14 +00:00
b0a100cd6c Added translation using Weblate (German) 2022-04-19 19:32:14 +00:00
6455e2710d bump version 2022-03-28 23:58:16 -04:00
6523b28aa2 update translations 2022-03-28 23:57:08 -04:00
bad1a23dfe fix ammo group overflow 2022-03-28 23:56:56 -04:00
e0ddefe1d7 fix tag and container overflow 2022-03-28 23:56:45 -04:00
5d6ecba9f7 display inline block, add min width to buttons and links 2022-03-28 23:56:15 -04:00
a2d1ff9b89 fix credo 2022-03-28 23:05:12 -04:00
34288a0070 make drone cache persistent 2022-03-04 23:36:19 -05:00
f9b08222e1 bump version 2022-03-04 23:19:11 -05:00
c0179f48bd mix format 2022-03-04 23:17:53 -05:00
8bb4aab49c Fix ammo group create form error bug 2022-03-04 23:16:37 -05:00
9f2cc54738 fix maintain attrs hook 2022-03-04 22:56:52 -05:00
0309e9d714 fix credo 2022-03-04 22:28:05 -05:00
af4af84515 use table component for shot group table 2022-03-04 22:06:01 -05:00
ec6946068e fix view helpers display bug 2022-03-04 22:05:08 -05:00
f120e54c3e use table component for ammo group show table 2022-03-04 21:57:22 -05:00
3d115c6383 fixup! use table component for move ammo group component 2022-03-04 21:56:48 -05:00
1d4622a285 fixup! use table component for ammo group table 2022-03-04 21:09:05 -05:00
d9e7948bb0 fixup! use new table component for ammo type index table 2022-03-04 21:07:32 -05:00
da8c788992 use table component for move ammo group component 2022-03-04 20:53:18 -05:00
bd20820361 use table component for ammo group table 2022-03-04 20:00:09 -05:00
d0ee81093a use new table component for ammo type index table 2022-03-04 18:28:10 -05:00
6080fdbe64 add table component 2022-03-04 18:26:57 -05:00
f42aaf9099 fix bug with move ammo group component 2022-03-04 00:06:08 -05:00
a6aa6f3386 fix elements flashing black 2022-02-26 00:16:36 -05:00
8405513337 add link to changelog 2022-02-24 20:42:27 -05:00
d0857eccc1 remove "listing" from titles 2022-02-24 00:52:46 -05:00
4c9e707181 merge translations 2022-02-24 00:30:23 -05:00
e6a4fbcfb5 bump version 2022-02-24 00:18:33 -05:00
a6b2c6181e add multiple ammo groups at one time 2022-02-24 00:17:23 -05:00
d79d0fa179 use today's date when adding new shot groups 2022-02-23 20:52:12 -05:00
46387e8d7a update changelog 2022-02-23 20:47:23 -05:00
dccea1b9de edit and delete shot groups from ammo group page 2022-02-23 20:45:58 -05:00
5ca21c64fd fix text styling 2022-02-23 20:35:18 -05:00
9773ccc6ff add prompt to create container before creating ammo group 2022-02-23 20:34:07 -05:00
9cd2bc574b conditionally load containers list 2022-02-23 19:51:07 -05:00
ee28de1178 fix not showing 0 if ammo type with 0 rounds 2022-02-23 19:41:21 -05:00
91cf9d0eb5 bump version 2022-02-20 20:43:04 -05:00
3ce8eda712 mix format 2022-02-20 20:40:24 -05:00
1a78e88b34 add page titles to registration and setting pages 2022-02-20 20:39:27 -05:00
968abd04ee fix grids having uneven margins in phone mode 2022-02-20 20:28:42 -05:00
dc209fa192 fix modals with overflowing content 2022-02-20 20:28:34 -05:00
a80df49fdd bump version 2022-02-20 15:20:09 -05:00
92d1d21d00 add changelog 2022-02-20 15:17:38 -05:00
917f627933 add back modal click-away 2022-02-20 15:17:12 -05:00
4946a6b119 fixes template error on modal refreshes 2022-02-20 15:01:15 -05:00
9f784c3190 fix closing modal without triggering reload 2022-02-20 15:00:53 -05:00
aa08e212ee fix loading and reconnecting pages 2022-02-19 21:29:36 -05:00
80ad939aab fix docker image tag for latest builds 2022-02-19 21:29:29 -05:00
94 changed files with 3333 additions and 974 deletions

View File

@ -157,17 +157,17 @@
#
# Controversial and experimental checks (opt-in, just replace `false` with `[]`)
#
{Credo.Check.Consistency.MultiAliasImportRequireUse, false},
{Credo.Check.Consistency.UnusedVariableNames, false},
{Credo.Check.Consistency.MultiAliasImportRequireUse, []},
{Credo.Check.Consistency.UnusedVariableNames, [force: :meaningful]},
{Credo.Check.Design.DuplicatedCode, false},
{Credo.Check.Readability.AliasAs, false},
{Credo.Check.Readability.BlockPipe, false},
{Credo.Check.Readability.ImplTrue, false},
{Credo.Check.Readability.MultiAlias, false},
{Credo.Check.Readability.SeparateAliasRequire, false},
{Credo.Check.Readability.SeparateAliasRequire, []},
{Credo.Check.Readability.SinglePipe, false},
{Credo.Check.Readability.Specs, false},
{Credo.Check.Readability.StrictModuleLayout, false},
{Credo.Check.Readability.StrictModuleLayout, []},
{Credo.Check.Readability.WithCustomTaggedTuple, false},
{Credo.Check.Refactor.ABCSize, false},
{Credo.Check.Refactor.AppendSingleItem, false},
@ -176,9 +176,9 @@
{Credo.Check.Refactor.NegatedIsNil, false},
{Credo.Check.Refactor.PipeChainStart, false},
{Credo.Check.Refactor.VariableRebinding, false},
{Credo.Check.Warning.LeakyEnvironment, false},
{Credo.Check.Warning.MapGetUnsafePass, false},
{Credo.Check.Warning.UnsafeToAtom, false}
{Credo.Check.Warning.LeakyEnvironment, []},
{Credo.Check.Warning.MapGetUnsafePass, []},
{Credo.Check.Warning.UnsafeToAtom, []}
#
# Custom checks can be created using `mix credo.gen.check`.

View File

@ -16,15 +16,19 @@ steps:
- assets/node_modules/
- name: test
image: bitwalker/alpine-elixir-phoenix:1.13
image: elixir:1.13.4-alpine
environment:
TEST_DATABASE_URL: ecto://postgres:postgres@database/cannery_test
HOST: testing.example.tld
commands:
- apk add --no-cache build-base npm git python3
- mix local.rebar --force
- mix local.hex --force
- mix deps.get
- npm install --prefix assets
- mix deps.compile
- npm --prefix ./assets ci --progress=false --no-audit --loglevel=error
- npm run --prefix ./assets deploy
- mix do phx.digest, gettext.extract
- mix test
- name: build and publish stable
@ -35,9 +39,7 @@ steps:
from_secret: docker_username
password:
from_secret: docker_password
tags:
- latest
- ${DRONE_TAG}
tags: latest
when:
branch:
- stable
@ -79,7 +81,7 @@ services:
volumes:
- name: cache
host:
path: /tmp/drone-cache
path: /run/media/default/ssdsrv/gitea/drone-cache
- name: docker_sock
host:
path: /var/run/docker.sock

View File

@ -2,5 +2,5 @@
import_deps: [:ecto, :phoenix],
inputs: ["*.{heex,ex,exs}", "priv/*/seeds.exs", "{config,lib,test}/**/*.{heex,ex,exs}"],
subdirectories: ["priv/*/migrations"],
plugins: [HeexFormatter]
plugins: [Phoenix.LiveView.HTMLFormatter]
]

View File

@ -1,3 +1,3 @@
elixir 1.13.2-otp-24
elixir 1.13.4-otp-24
erlang 24.2
nodejs 16.13.2

View File

@ -1,3 +1,38 @@
# v0.5.0
- Add German translation: Thank you [Kaia](https://shitposter.club/users/kaia)!
- Fix not being able to edit ammo group when fully used up
- Fix bug with average price per round calculation
- Show average price per round on ammo type table
- Use Elixir v1.13.4
# v0.4.1
- Fix button and tag text wrapping
- Code quality fixes
# v0.4.0
- Make tables sortable
- Add link to changelog from version number
- Fix some elements flashing with black background
- Fix bug with moving ammo group to new container
- Fix bug with no error showing up for create ammo group form
# v0.3.0
- Fix ammo type counts not showing when count is 0
- Add prompt to create first container before first ammo group
- Edit and delete shot groups from ammo group show page
- Use today's date when adding new shot groups
- Create multiple ammo groups at one time
# v0.2.3
- Fix modals with overflowing forms
- Fix grids having uneven margins in phone mode
- Add page titles to registration and setting pages
# v0.2.2
- Fix loading and reconnecting pages not being fixed
- Fix closing modal in some cases not triggering a page reload
- Fix error when display container and tag edit routes from a fresh reload
# v0.2.1
- Fix checkbox spacing for mobile view
- Fix spacing with form elements in mobile view

View File

@ -141,3 +141,4 @@ In `prod` mode (or in the Docker container), Cannery will listen for the same en
Thank you so much for your contributions!
- shibao (https://misskey.bubbletea.dev/@shibao)
- kaia (https://shitposter.club/users/kaia)

View File

@ -1,4 +1,4 @@
FROM elixir:1.13-alpine AS build
FROM elixir:1.13.4-alpine AS build
# install build dependencies
RUN apk add --no-cache build-base npm git python3

View File

@ -25,6 +25,7 @@
}
.btn {
@apply inline-block break-all min-w-4;
@apply focus:outline-none px-4 py-2 rounded-lg;
@apply shadow-sm focus:shadow-lg;
@apply transition-all duration-300 ease-in-out;
@ -51,6 +52,7 @@
}
.link {
@apply inline-block break-all min-w-4;
@apply hover:underline;
@apply transition-colors duration-500 ease-in-out;
}

View File

@ -2,7 +2,10 @@
// update. https://github.com/phoenixframework/phoenix_live_view/issues/1011
export default {
attrs () { return this.el.getAttribute('data-attrs').split(', ') },
attrs () {
const attrs = this.el.getAttribute('data-attrs')
if (attrs) { return attrs.split(', ') } else { return [] }
},
beforeUpdate () { this.prevAttrs = this.attrs().map(name => [name, this.el.getAttribute(name)]) },
updated () { this.prevAttrs.forEach(([name, val]) => this.el.setAttribute(name, val)) }
}

View File

@ -28,6 +28,20 @@ module.exports = {
128: '32rem',
192: '48rem',
256: '64rem'
},
minWidth: {
4: '1rem',
8: '2rem',
12: '3rem',
16: '4rem',
20: '8rem'
},
maxWidth: {
4: '1rem',
8: '2rem',
12: '3rem',
16: '4rem',
20: '8rem'
}
}
},

View File

@ -14,8 +14,8 @@ end
config :cannery, CanneryWeb.ViewHelpers, shibao_mode: System.get_env("SHIBAO_MODE") == "true"
# Set locale
Gettext.put_locale(System.get_env("LOCALE") || "en_US")
# Set default locale
config :gettext, :default_locale, System.get_env("LOCALE") || "en_US"
maybe_ipv6 = if System.get_env("ECTO_IPV6") == "true", do: [:inet6], else: []

View File

@ -196,7 +196,7 @@ defmodule Cannery.Accounts do
{:ok, _} <- Repo.transaction(user_email_multi(user, email, context)) do
:ok
else
_ -> :error
_error_tuple -> :error
end
end
@ -265,7 +265,7 @@ defmodule Cannery.Accounts do
|> Repo.transaction()
|> case do
{:ok, %{user: user}} -> {:ok, user}
{:error, :user, changeset, _} -> {:error, changeset}
{:error, :user, changeset, _changes_so_far} -> {:error, changeset}
end
end
@ -372,7 +372,7 @@ defmodule Cannery.Accounts do
{:ok, %{user: user}} <- Repo.transaction(confirm_user_multi(user)) do
{:ok, user}
else
_ -> :error
_error_tuple -> :error
end
end
@ -420,7 +420,7 @@ defmodule Cannery.Accounts do
%User{} = user <- Repo.one(query) do
user
else
_ -> nil
_error_tuple -> nil
end
end
@ -444,7 +444,7 @@ defmodule Cannery.Accounts do
|> Repo.transaction()
|> case do
{:ok, %{user: user}} -> {:ok, user}
{:error, :user, changeset, _} -> {:error, changeset}
{:error, :user, changeset, _changes_so_far} -> {:error, changeset}
end
end
end

View File

@ -171,7 +171,7 @@ defmodule Cannery.Accounts.User do
Bcrypt.verify_pass(password, hashed_password)
end
def valid_password?(_, _) do
def valid_password?(_invalid_user, _invalid_password) do
Bcrypt.no_user_verify()
false
end

View File

@ -5,9 +5,12 @@ defmodule Cannery.Ammo do
import Ecto.Query, warn: false
alias Cannery.{Accounts.User, Containers, Repo}
alias Cannery.ActivityLog.ShotGroup
alias Cannery.Ammo.{AmmoGroup, AmmoType}
alias Ecto.Changeset
@ammo_group_create_limit 10_000
@doc """
Returns the list of ammo_types.
@ -42,28 +45,31 @@ defmodule Cannery.Ammo do
@doc """
Gets the average cost of a single ammo type
Raises `Ecto.NoResultsError` if the Ammo type does not exist.
## Examples
iex> get_ammo_type!(123, %User{id: 123})
%AmmoType{}
iex> get_ammo_type!(456, %User{id: 123})
** (Ecto.NoResultsError)
iex> get_average_cost_for_ammo_type!(%AmmoType{id: 123}, %User{id: 123})
1.50
"""
@spec get_average_cost_for_ammo_type!(AmmoType.t(), User.t()) :: float()
@spec get_average_cost_for_ammo_type!(AmmoType.t(), User.t()) :: float() | nil
def get_average_cost_for_ammo_type!(
%AmmoType{id: ammo_type_id, user_id: user_id},
%User{id: user_id}
) do
sg_total_query =
from sg in ShotGroup,
where: not (sg.count |> is_nil()),
group_by: sg.ammo_group_id,
select: %{ammo_group_id: sg.ammo_group_id, total: sum(sg.count)}
Repo.one!(
from ag in AmmoGroup,
left_join: sg in assoc(ag, :shot_groups),
as: :ammo_group,
left_join: sg_query in subquery(sg_total_query),
on: ag.id == sg_query.ammo_group_id,
where: ag.ammo_type_id == ^ammo_type_id,
where: not (ag.price_paid |> is_nil()),
select: sum(ag.price_paid) / (sum(ag.count) + sum(sg.count))
select: sum(ag.price_paid) / sum(ag.count + coalesce(sg_query.total, 0))
)
end
@ -90,7 +96,7 @@ defmodule Cannery.Ammo do
from ag in AmmoGroup,
where: ag.ammo_type_id == ^ammo_type_id,
select: sum(ag.count)
)
) || 0
end
@doc """
@ -117,7 +123,7 @@ defmodule Cannery.Ammo do
left_join: sg in assoc(ag, :shot_groups),
where: ag.ammo_type_id == ^ammo_type_id,
select: sum(sg.count)
)
) || 0
end
@doc """
@ -306,7 +312,7 @@ defmodule Cannery.Ammo do
def get_used_count(%AmmoGroup{} = ammo_group) do
ammo_group
|> Repo.preload(:shot_groups)
|> Map.get(:shot_groups)
|> Map.fetch!(:shot_groups)
|> Enum.map(fn %{count: count} -> count end)
|> Enum.sum()
end
@ -327,36 +333,61 @@ defmodule Cannery.Ammo do
end
@doc """
Creates a ammo_group.
Creates multiple ammo_groups at once.
## Examples
iex> create_ammo_group(%{field: value}, %User{id: 123})
{:ok, %AmmoGroup{}}
iex> create_ammo_groups(%{field: value}, 3, %User{id: 123})
{:ok, {3, [%AmmoGroup{}]}}
iex> create_ammo_group(%{field: bad_value}, %User{id: 123})
iex> create_ammo_groups(%{field: bad_value}, 3, %User{id: 123})
{:error, %Changeset{}}
"""
@spec create_ammo_group(attrs :: map(), User.t()) ::
{:ok, AmmoGroup.t()} | {:error, Changeset.t(AmmoGroup.new_ammo_group())}
def create_ammo_group(
@spec create_ammo_groups(attrs :: map(), multiplier :: non_neg_integer(), User.t()) ::
{:ok, {count :: non_neg_integer(), [AmmoGroup.t()] | nil}}
| {:error, Changeset.t(AmmoGroup.new_ammo_group())}
def create_ammo_groups(
%{"ammo_type_id" => ammo_type_id, "container_id" => container_id} = attrs,
multiplier,
%User{id: user_id} = user
) do
)
when multiplier >= 1 and multiplier <= @ammo_group_create_limit do
# validate ammo type and container ids belong to user
_valid_ammo_type = get_ammo_type!(ammo_type_id, user)
_valid_container = Containers.get_container!(container_id, user)
%AmmoGroup{}
|> AmmoGroup.create_changeset(attrs |> Map.put("user_id", user_id))
|> Repo.insert()
now = NaiveDateTime.utc_now() |> NaiveDateTime.truncate(:second)
changesets =
Enum.map(1..multiplier, fn _count ->
%AmmoGroup{} |> AmmoGroup.create_changeset(attrs |> Map.put("user_id", user_id))
end)
if changesets |> Enum.all?(fn %{valid?: valid} -> valid end) do
{count, inserted_ammo_groups} =
Repo.insert_all(
AmmoGroup,
changesets
|> Enum.map(fn changeset ->
changeset
|> Map.get(:changes)
|> Map.merge(%{inserted_at: now, updated_at: now})
end),
returning: true
)
{:ok, {count, inserted_ammo_groups}}
else
changesets
|> Enum.reject(fn %{valid?: valid} -> valid end)
|> List.first()
|> Changeset.apply_action(:insert)
end
end
def create_ammo_group(invalid_attrs, _user) do
%AmmoGroup{}
|> AmmoGroup.create_changeset(invalid_attrs |> Map.put("user_id", "-1"))
|> Repo.insert()
def create_ammo_groups(invalid_attrs, _multiplier, _user) do
{:error, %AmmoGroup{} |> AmmoGroup.create_changeset(invalid_attrs)}
end
@doc """

View File

@ -62,7 +62,7 @@ defmodule Cannery.Ammo.AmmoGroup do
def update_changeset(ammo_group, attrs) do
ammo_group
|> cast(attrs, [:count, :price_paid, :notes, :staged, :ammo_type_id, :container_id])
|> validate_number(:count, greater_than: 0)
|> validate_number(:count, greater_than_or_equal_to: 0)
|> validate_required([:count, :staged, :ammo_type_id, :container_id, :user_id])
end

View File

@ -215,7 +215,7 @@ defmodule Cannery.Containers do
def get_container_rounds!(%Container{} = container) do
container
|> Repo.preload(:ammo_groups)
|> Map.get(:ammo_groups)
|> Map.fetch!(:ammo_groups)
|> Enum.map(fn %{count: count} -> count end)
|> Enum.sum()
end

View File

@ -9,7 +9,7 @@ defmodule Cannery.Release do
def rollback(repo, version) do
load_app()
{:ok, _, _} = Ecto.Migrator.with_repo(repo, &Ecto.Migrator.run(&1, :down, to: version))
{:ok, _fun, _opts} = Ecto.Migrator.with_repo(repo, &Ecto.Migrator.run(&1, :down, to: version))
end
defp load_app do
@ -20,7 +20,7 @@ defmodule Cannery.Release do
load_app()
for repo <- Application.fetch_env!(@app, :ecto_repos) do
{:ok, _, _} = Ecto.Migrator.with_repo(repo, &Ecto.Migrator.run(&1, :up, all: true))
{:ok, _fun, _opts} = Ecto.Migrator.with_repo(repo, &Ecto.Migrator.run(&1, :up, all: true))
end
end
end

View File

@ -6,11 +6,11 @@ defmodule Cannery.Repo.Migrator do
use GenServer
require Logger
def start_link(_) do
def start_link(_opts) do
GenServer.start_link(__MODULE__, [], [])
end
def init(_) do
def init(_opts) do
migrate!()
{:ok, nil}
end

View File

@ -71,6 +71,7 @@ defmodule CanneryWeb do
quote do
use Phoenix.Router
# credo:disable-for-next-line Credo.Check.Consistency.MultiAliasImportRequireUse
import Plug.Conn
import Phoenix.Controller
import Phoenix.LiveView.Router
@ -79,7 +80,9 @@ defmodule CanneryWeb do
def channel do
quote do
# credo:disable-for-next-line Credo.Check.Consistency.MultiAliasImportRequireUse
use Phoenix.Channel
# credo:disable-for-next-line Credo.Check.Consistency.MultiAliasImportRequireUse
import CanneryWeb.Gettext
end
end
@ -87,14 +90,18 @@ defmodule CanneryWeb do
defp view_helpers do
quote do
# Use all HTML functionality (forms, tags, etc)
# credo:disable-for-next-line Credo.Check.Consistency.MultiAliasImportRequireUse
use Phoenix.HTML
# Import LiveView and .heex helpers (live_render, live_patch, <.form>, etc)
# credo:disable-for-next-line Credo.Check.Consistency.MultiAliasImportRequireUse
import Phoenix.LiveView.Helpers
# Import basic rendering functionality (render, render_layout, etc)
# credo:disable-for-next-line Credo.Check.Consistency.MultiAliasImportRequireUse
import Phoenix.View
# credo:disable-for-next-line Credo.Check.Consistency.MultiAliasImportRequireUse
import CanneryWeb.{ErrorHelpers, Gettext, LiveHelpers, ViewHelpers}
alias CanneryWeb.Router.Helpers, as: Routes
end

View File

@ -36,7 +36,11 @@
<%= error_tag(f, :notes, "col-span-3") %>
<%= label(f, :date, gettext("Date (UTC)"), class: "title text-lg text-primary-600") %>
<%= date_input(f, :date, class: "input input-primary col-span-2") %>
<%= date_input(f, :date,
class: "input input-primary col-span-2",
phx_update: "ignore",
value: Date.utc_today()
) %>
<%= error_tag(f, :notes, "col-span-3") %>
<%= submit(dgettext("actions", "Save"),

View File

@ -14,11 +14,11 @@ defmodule CanneryWeb.Components.ContainerCard do
~H"""
<div
id={"container-#{@container.id}"}
class="mx-4 my-2 px-8 py-4 flex flex-col justify-center items-center space-y-4
class="overflow-hidden max-w-full mx-4 my-2 px-8 py-4 flex flex-col justify-center items-center space-y-4
border border-gray-400 rounded-lg shadow-lg hover:shadow-md
transition-all duration-300 ease-in-out"
>
<div class="mb-4 flex flex-col justify-center items-center space-y-2">
<div class="max-w-full mb-4 flex flex-col justify-center items-center space-y-2">
<%= live_redirect to: Routes.container_show_path(Endpoint, :show, @container),
class: "link" do %>
<h1 class="px-4 py-2 rounded-lg title text-xl">

View File

@ -8,11 +8,9 @@ defmodule CanneryWeb.Components.InviteCard do
def invite_card(assigns) do
~H"""
<div
class="mx-4 my-2 px-8 py-4 flex flex-col justify-center items-center space-y-4
<div class="mx-4 my-2 px-8 py-4 flex flex-col justify-center items-center space-y-4
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">
<h1 class="title text-xl">
<%= @invite.name %>
</h1>

View File

@ -4,7 +4,8 @@ defmodule CanneryWeb.Components.MoveAmmoGroupComponent do
"""
use CanneryWeb, :live_component
alias Cannery.{Accounts.User, Ammo, Ammo.AmmoGroup, Containers}
alias Cannery.{Accounts.User, Ammo, Ammo.AmmoGroup, Containers, Containers.Container}
alias CanneryWeb.Endpoint
alias Phoenix.LiveView.Socket
@impl true
@ -27,7 +28,12 @@ defmodule CanneryWeb.Components.MoveAmmoGroupComponent do
Containers.list_containers(current_user)
|> Enum.reject(fn %{id: id} -> id == container_id end)
{:ok, socket |> assign(assigns) |> assign(changeset: changeset, containers: containers)}
socket =
socket
|> assign(assigns)
|> assign(changeset: changeset, containers: containers)
{:ok, socket}
end
@impl true
@ -54,4 +60,76 @@ defmodule CanneryWeb.Components.MoveAmmoGroupComponent do
{:noreply, socket}
end
@impl true
def render(%{containers: containers} = assigns) do
columns = [
%{label: gettext("Container"), key: "name"},
%{label: gettext("Type"), key: "type"},
%{label: gettext("Location"), key: "location"},
%{label: nil, key: "actions", sortable: false}
]
rows = containers |> get_rows_for_containers(assigns, columns)
assigns = assigns |> Map.merge(%{columns: columns, rows: rows})
~H"""
<div class="w-full flex flex-col space-y-8 justify-center items-center">
<h2 class="mb-8 text-center title text-xl text-primary-600">
<%= gettext("Move ammo") %>
</h2>
<%= if @containers |> Enum.empty?() do %>
<h2 class="title text-xl text-primary-600">
<%= gettext("No other containers") %>
<%= display_emoji("😔") %>
</h2>
<%= live_patch(dgettext("actions", "Add another container!"),
to: Routes.container_index_path(Endpoint, :new),
class: "btn btn-primary"
) %>
<% else %>
<.live_component
module={CanneryWeb.Components.TableComponent}
id="move_ammo_group_table"
columns={@columns}
rows={@rows}
/>
<% end %>
</div>
"""
end
@spec get_rows_for_containers([Container.t()], map(), [map()]) :: [map()]
defp get_rows_for_containers(containers, assigns, columns) do
containers
|> Enum.map(fn container ->
columns
|> Enum.into(%{}, fn %{key: key} -> {key, get_row_value_by_key(key, container, assigns)} end)
end)
end
@spec get_row_value_by_key(String.t(), Container.t(), map()) :: any()
defp get_row_value_by_key("actions", container, assigns) do
assigns = assigns |> Map.put(:container, container)
~H"""
<div class="px-4 py-2 space-x-4 flex justify-center items-center">
<button
type="button"
class="btn btn-primary"
phx-click="move"
phx-target={@myself}
phx-value-container_id={container.id}
>
<%= dgettext("actions", "Select") %>
</button>
</div>
"""
end
defp get_row_value_by_key(key, container, _assigns),
do: container |> Map.get(key |> String.to_existing_atom())
end

View File

@ -1,70 +0,0 @@
<div class="w-full flex flex-col space-y-8 justify-center items-center">
<h2 class="mb-8 text-center title text-xl text-primary-600">
<%= gettext("Move ammo") %>
</h2>
<%= if @containers |> Enum.empty?() do %>
<h2 class="title text-xl text-primary-600">
<%= gettext("No other containers") %>
<%= display_emoji("😔") %>
</h2>
<%= live_patch(dgettext("actions", "Add another container!"),
to: Routes.container_index_path(Endpoint, :new),
class: "btn btn-primary"
) %>
<% else %>
<div class="w-full overflow-x-auto border border-gray-600 rounded-lg shadow-lg bg-black">
<table class="min-w-full table-auto text-center bg-white">
<thead class="border-b border-primary-600">
<tr>
<th class="p-2">
<%= gettext("Container") %>
</th>
<th class="p-2">
<%= gettext("Type") %>
</th>
<th class="p-2">
<%= gettext("Location") %>
</th>
<th class="p-2"></th>
</tr>
</thead>
<tbody id="containers">
<%= for container <- @containers do %>
<tr id={"container-#{container.id}"}>
<td class="p-2">
<%= container.name %>
</td>
<td class="p-2">
<%= container.type %>
</td>
<td class="p-2">
<%= container.location %>
</td>
<td class="p-2">
<div class="px-4 py-2 space-x-4 flex justify-center items-center">
<button
type="button"
class="btn btn-primary"
phx-click="move"
phx-target={@myself}
phx-value-container_id={container.id}
>
<%= dgettext("actions", "Select") %>
</button>
</div>
</td>
</tr>
<% end %>
</tbody>
</table>
</div>
<% end %>
</div>

View File

@ -0,0 +1,87 @@
defmodule CanneryWeb.Components.TableComponent do
@moduledoc """
Livecomponent that presents a resortable table
It takes the following required assigns:
- `:columns`: An array of maps containing the following keys
- `:label`: A gettext'd or otherwise user-facing string label for the
column. Can be nil
- `:key`: A string key used for sorting
- `:class`: Extra classes to be applied to the column element, if desired.
Optional
- `:sortable`: If false, will prevent the user from sorting with it.
Optional
- `:values`: An array of maps containing data for each row. Each map is
string-keyed with the associated column key to the following values:
- A single element, like string, integer or Phoenix.LiveView.Rendered
object, like returned from the ~H sigil
- A tuple, containing a custom value used for sorting, and the displayed
content.
"""
use CanneryWeb, :live_component
alias Phoenix.LiveView.Socket
@impl true
@spec update(
%{
required(:columns) =>
list(%{
required(:label) => String.t() | nil,
required(:key) => String.t() | nil,
optional(:class) => String.t(),
optional(:sortable) => false
}),
required(:rows) =>
list(%{
(key :: String.t()) => any() | {custom_sort_value :: String.t(), value :: any()}
}),
optional(any()) => any()
},
Socket.t()
) :: {:ok, Socket.t()}
def update(%{columns: columns, rows: rows} = assigns, socket) do
initial_key = columns |> List.first() |> Map.get(:key)
rows = rows |> Enum.sort_by(fn row -> row |> Map.get(initial_key) end, :asc)
socket =
socket
|> assign(assigns)
|> assign(columns: columns, rows: rows, last_sort_key: initial_key, sort_mode: :asc)
{:ok, socket}
end
@impl true
def handle_event(
"sort_by",
%{"sort-key" => key},
%{assigns: %{rows: rows, last_sort_key: key, sort_mode: sort_mode}} = socket
) do
sort_mode = if sort_mode == :asc, do: :desc, else: :asc
rows = rows |> sort_by_custom_sort_value_or_value(key, sort_mode)
{:noreply, socket |> assign(sort_mode: sort_mode, rows: rows)}
end
def handle_event(
"sort_by",
%{"sort-key" => key},
%{assigns: %{rows: rows}} = socket
) do
rows = rows |> sort_by_custom_sort_value_or_value(key, :asc)
{:noreply, socket |> assign(last_sort_key: key, sort_mode: :asc, rows: rows)}
end
defp sort_by_custom_sort_value_or_value(rows, key, sort_mode) do
rows
|> Enum.sort_by(
fn row ->
case row |> Map.get(key) do
{custom_sort_key, _value} -> custom_sort_key
value -> value
end
end,
sort_mode
)
end
end

View File

@ -0,0 +1,52 @@
<div class="w-full overflow-x-auto border border-gray-600 rounded-lg shadow-lg bg-black">
<table class="min-w-full table-auto text-center bg-white">
<thead class="border-b border-primary-600">
<tr>
<%= for %{key: key, label: label} = column <- @columns do %>
<%= if column |> Map.get(:sortable, true) do %>
<th class={"p-2 #{column[:class]}"}>
<span
class="cursor-pointer"
phx-click="sort_by"
phx-value-sort-key={key}
phx-target={@myself}
>
<span class="underline"><%= label %></span>
<%= if @last_sort_key == key do %>
<%= case @sort_mode do %>
<% :asc -> %>
<i class="fas fa-sm fa-chevron-down"></i>
<% :desc -> %>
<i class="fas fa-sm fa-chevron-up"></i>
<% end %>
<% else %>
<i class="fas fa-sm fa-chevron-up opacity-0"></i>
<% end %>
</span>
</th>
<% else %>
<th class={"p-2 #{column[:class]}"}>
<%= label %>
</th>
<% end %>
<% end %>
</tr>
</thead>
<tbody>
<%= for values <- @rows do %>
<tr>
<%= for %{key: key} = value <- @columns do %>
<td class={"p-2 #{value[:class]}"}>
<%= case values |> Map.get(key) do %>
<% {_custom_sort_value, value} -> %>
<%= value %>
<% value -> %>
<%= value %>
<% end %>
</td>
<% end %>
</tr>
<% end %>
</tbody>
</table>
</div>

View File

@ -22,7 +22,7 @@ defmodule CanneryWeb.Components.TagCard do
def simple_tag_card(assigns) do
~H"""
<h1
class="mx-2 my-1 px-4 py-2 rounded-lg title text-xl"
class="inline-block break-all mx-2 my-1 px-4 py-2 rounded-lg title text-xl"
style={"color: #{@tag.text_color}; background-color: #{@tag.bg_color}"}
>
<%= @tag.name %>

View File

@ -31,10 +31,8 @@ defmodule CanneryWeb.Components.Topbar do
<hr class="mb-2 sm:hidden hr-light" />
<ul
class="flex flex-row flex-wrap justify-center items-center
text-lg text-white text-ellipsis"
>
<ul class="flex flex-row flex-wrap justify-center items-center
text-lg text-white text-ellipsis">
<%= if @current_user do %>
<li class="mx-2 my-1">
<%= live_redirect(gettext("Tags"),

View File

@ -1,10 +1,11 @@
defmodule CanneryWeb.UserConfirmationController do
use CanneryWeb, :controller
import CanneryWeb.Gettext
alias Cannery.Accounts
def new(conn, _params) do
render(conn, "new.html")
render(conn, "new.html", page_title: gettext("Confirm your account"))
end
def create(conn, %{"user" => %{"email" => email}}) do

View File

@ -29,8 +29,11 @@ defmodule CanneryWeb.UserRegistrationController do
# renders new user registration page
defp render_new(conn, invite \\ nil) do
changeset = Accounts.change_user_registration(%User{})
conn |> render("new.html", changeset: changeset, invite: invite)
render(conn, "new.html",
changeset: Accounts.change_user_registration(%User{}),
invite: invite,
page_title: gettext("Register")
)
end
def create(conn, %{"user" => %{"invite_token" => invite_token}} = attrs) do

View File

@ -6,7 +6,7 @@ defmodule CanneryWeb.UserResetPasswordController do
plug :get_user_by_reset_password_token when action in [:edit, :update]
def new(conn, _params) do
render(conn, "new.html")
render(conn, "new.html", page_title: gettext("Forgot your password?"))
end
def create(conn, %{"user" => %{"email" => email}}) do
@ -31,7 +31,10 @@ defmodule CanneryWeb.UserResetPasswordController do
end
def edit(conn, _params) do
render(conn, "edit.html", changeset: Accounts.change_user_password(conn.assigns.user))
render(conn, "edit.html",
changeset: Accounts.change_user_password(conn.assigns.user),
page_title: gettext("Reset your password")
)
end
# Do not log in the user after reset password to avoid a

View File

@ -5,7 +5,7 @@ defmodule CanneryWeb.UserSessionController do
alias CanneryWeb.UserAuth
def new(conn, _params) do
render(conn, "new.html", error_message: nil)
render(conn, "new.html", error_message: nil, page_title: gettext("Log in"))
end
def create(conn, %{"user" => user_params}) do

View File

@ -1,13 +1,13 @@
defmodule CanneryWeb.UserSettingsController do
use CanneryWeb, :controller
import CanneryWeb.Gettext
alias Cannery.Accounts
alias CanneryWeb.{HomeLive, UserAuth}
plug :assign_email_and_password_changesets
def edit(conn, _params) do
render(conn, "edit.html")
render(conn, "edit.html", page_title: gettext("Settings"))
end
def update(conn, %{"action" => "update_email"} = params) do

View File

@ -9,6 +9,8 @@ defmodule CanneryWeb.AmmoGroupLive.FormComponent do
alias Ecto.Changeset
alias Phoenix.LiveView.Socket
@ammo_group_create_limit 10_000
@impl true
@spec update(
%{:ammo_group => AmmoGroup.t(), :current_user => User.t(), optional(any) => any},
@ -20,20 +22,37 @@ defmodule CanneryWeb.AmmoGroupLive.FormComponent do
@spec update(Socket.t()) :: {:ok, Socket.t()}
def update(%{assigns: %{ammo_group: ammo_group, current_user: current_user}} = socket) do
changeset = Ammo.change_ammo_group(ammo_group)
containers = Containers.list_containers(current_user)
ammo_types = Ammo.list_ammo_types(current_user)
{:ok, socket |> assign(changeset: changeset, containers: containers, ammo_types: ammo_types)}
socket =
socket
|> assign(:ammo_group_create_limit, @ammo_group_create_limit)
|> assign(:changeset, Ammo.change_ammo_group(ammo_group))
|> assign(:ammo_types, Ammo.list_ammo_types(current_user))
|> assign_new(:containers, fn -> Containers.list_containers(current_user) end)
{:ok, socket}
end
@impl true
def handle_event(
"validate",
%{"ammo_group" => ammo_group_params},
%{assigns: %{ammo_group: ammo_group}} = socket
%{assigns: %{action: action, ammo_group: ammo_group}} = socket
) do
socket = socket |> assign(:changeset, ammo_group |> Ammo.change_ammo_group(ammo_group_params))
{:noreply, socket}
changeset_action =
case action do
:new -> :insert
:edit -> :update
end
changeset = ammo_group |> Ammo.change_ammo_group(ammo_group_params)
changeset =
case changeset |> Changeset.apply_action(changeset_action) do
{:ok, _data} -> changeset
{:error, changeset} -> changeset
end
{:noreply, socket |> assign(:changeset, changeset)}
end
def handle_event(
@ -77,20 +96,65 @@ defmodule CanneryWeb.AmmoGroupLive.FormComponent do
end
defp save_ammo_group(
%{assigns: %{current_user: current_user, return_to: return_to}} = socket,
%{assigns: %{changeset: changeset}} = socket,
:new,
ammo_group_params
%{"multiplier" => multiplier_str} = ammo_group_params
) do
socket =
case Ammo.create_ammo_group(ammo_group_params, current_user) do
{:ok, _ammo_group} ->
prompt = dgettext("prompts", "Ammo group created successfully")
socket |> put_flash(:info, prompt) |> push_redirect(to: return_to)
case multiplier_str |> Integer.parse() do
{multiplier, _remainder}
when multiplier >= 1 and multiplier <= @ammo_group_create_limit ->
socket |> create_multiple(ammo_group_params, multiplier)
{:error, %Changeset{} = changeset} ->
socket |> assign(changeset: changeset)
{multiplier, _remainder} ->
error_msg =
dgettext(
"errors",
"Invalid number of copies, must be between 1 and %{max}. Was %{multiplier}",
max: @ammo_group_create_limit,
multiplier: multiplier
)
{:error, changeset} =
changeset
|> Changeset.add_error(:multiplier, error_msg)
|> Changeset.apply_action(:insert)
socket |> assign(:changeset, changeset)
:error ->
error_msg = dgettext("errors", "Could not parse number of copies")
{:error, changeset} =
changeset
|> Changeset.add_error(:multiplier, error_msg)
|> Changeset.apply_action(:insert)
socket |> assign(:changeset, changeset)
end
{:noreply, socket}
end
defp create_multiple(
%{assigns: %{current_user: current_user, return_to: return_to}} = socket,
ammo_group_params,
multiplier
) do
case Ammo.create_ammo_groups(ammo_group_params, multiplier, current_user) do
{:ok, {count, _ammo_groups}} ->
prompt =
dngettext(
"prompts",
"Ammo group created successfully",
"Ammo groups created successfully",
count
)
socket |> put_flash(:info, prompt) |> push_redirect(to: return_to)
{:error, %Changeset{} = changeset} ->
socket |> assign(changeset: changeset)
end
end
end

View File

@ -18,42 +18,62 @@
</div>
<% end %>
<%= label(f, :ammo_type_id, gettext("Ammo type"), class: "mr-4 title text-lg text-primary-600") %>
<%= label(f, :ammo_type_id, gettext("Ammo type"), class: "title text-lg text-primary-600") %>
<%= select(f, :ammo_type_id, ammo_type_options(@ammo_types),
class: "text-center col-span-2 input input-primary"
) %>
<%= error_tag(f, :ammo_type_id, "col-span-3 text-center") %>
<%= label(f, :count, gettext("Count"), class: "mr-4 title text-lg text-primary-600") %>
<%= label(f, :count, gettext("Count"), class: "title text-lg text-primary-600") %>
<%= number_input(f, :count,
class: "text-center col-span-2 input input-primary",
min: 1
min: 0
) %>
<%= error_tag(f, :count, "col-span-3 text-center") %>
<%= label(f, :price_paid, gettext("Price paid"), class: "mr-4 title text-lg text-primary-600") %>
<%= label(f, :price_paid, gettext("Price paid"), class: "title text-lg text-primary-600") %>
<%= number_input(f, :price_paid,
step: "0.01",
step: 0.01,
class: "text-center col-span-2 input input-primary"
) %>
<%= error_tag(f, :price_paid, "col-span-3 text-center") %>
<%= label(f, :notes, gettext("Notes"), class: "mr-4 title text-lg text-primary-600") %>
<%= label(f, :notes, gettext("Notes"), class: "title text-lg text-primary-600") %>
<%= textarea(f, :notes,
class: "text-center col-span-2 input input-primary",
phx_hook: "MaintainAttrs"
) %>
<%= error_tag(f, :notes, "col-span-3 text-center") %>
<%= label(f, :container, gettext("Container"), class: "mr-4 title text-lg text-primary-600") %>
<%= label(f, :container, gettext("Container"), class: "title text-lg text-primary-600") %>
<%= select(f, :container_id, container_options(@containers),
class: "text-center col-span-2 input input-primary"
) %>
<%= error_tag(f, :container_id, "col-span-3 text-center") %>
<%= submit(dgettext("actions", "Save"),
phx_disable_with: dgettext("prompts", "Saving..."),
class: "mx-auto col-span-3 btn btn-primary"
) %>
<%= case @action do %>
<% :new -> %>
<hr class="hr col-span-3" />
<%= label(f, :multiplier, gettext("Copies"), class: "title text-lg text-primary-600") %>
<%= number_input(f, :multiplier,
max: @ammo_group_create_limit,
class: "text-center input input-primary",
value: 1,
phx_update: "ignore"
) %>
<%= submit(dgettext("actions", "Create"),
phx_disable_with: dgettext("prompts", "Creating..."),
class: "mx-auto btn btn-primary"
) %>
<%= error_tag(f, :multiplier, "col-span-3 text-center") %>
<% :edit -> %>
<%= submit(dgettext("actions", "Save"),
phx_disable_with: dgettext("prompts", "Saving..."),
class: "mx-auto col-span-3 btn btn-primary"
) %>
<% end %>
</.form>
</div>

View File

@ -4,7 +4,7 @@ defmodule CanneryWeb.AmmoGroupLive.Index do
"""
use CanneryWeb, :live_view
alias Cannery.{Ammo, Ammo.AmmoGroup, Repo}
alias Cannery.{Ammo, Ammo.AmmoGroup, Containers, Repo}
alias CanneryWeb.Endpoint
@impl true
@ -17,9 +17,11 @@ defmodule CanneryWeb.AmmoGroupLive.Index do
{:noreply, apply_action(socket, live_action, params)}
end
defp apply_action(%{assigns: %{current_user: current_user}} = socket, :add_shot_group, %{
"id" => id
}) do
defp apply_action(
%{assigns: %{current_user: current_user}} = socket,
:add_shot_group,
%{"id" => id}
) do
socket
|> assign(:page_title, gettext("Record shots"))
|> assign(:ammo_group, Ammo.get_ammo_group!(id, current_user))
@ -72,6 +74,121 @@ defmodule CanneryWeb.AmmoGroupLive.Index do
defp display_ammo_groups(%{assigns: %{current_user: current_user}} = socket) do
ammo_groups = Ammo.list_ammo_groups(current_user) |> Repo.preload([:ammo_type, :container])
socket |> assign(:ammo_groups, ammo_groups)
containers = Containers.list_containers(current_user)
columns = [
%{label: gettext("Ammo type"), key: "ammo_type"},
%{label: gettext("Count"), key: "count"},
%{label: gettext("Price paid"), key: "price_paid"},
%{label: gettext("% left"), key: "remaining"},
%{label: gettext("Range"), key: "range"},
%{label: gettext("Container"), key: "container"},
%{label: nil, key: "actions", sortable: false}
]
rows =
ammo_groups
|> Enum.map(fn ammo_group -> ammo_group |> get_row_data_for_ammo_group(columns) end)
socket
|> assign(ammo_groups: ammo_groups, containers: containers, columns: columns, rows: rows)
end
@spec get_row_data_for_ammo_group(AmmoGroup.t(), [map()]) :: [map()]
defp get_row_data_for_ammo_group(ammo_group, columns) do
ammo_group = ammo_group |> Repo.preload([:ammo_type, :container])
columns
|> Enum.into(%{}, fn %{key: key} -> {key, get_value_for_key(key, ammo_group)} end)
end
@spec get_value_for_key(String.t(), AmmoGroup.t()) :: any()
defp get_value_for_key("ammo_type", %{ammo_type: ammo_type}) do
{ammo_type.name,
live_patch(ammo_type.name,
to: Routes.ammo_type_show_path(Endpoint, :show, ammo_type),
class: "link"
)}
end
defp get_value_for_key("price_paid", %{price_paid: nil}), do: {"a", nil}
defp get_value_for_key("price_paid", %{price_paid: price_paid}),
do: gettext("$%{amount}", amount: price_paid |> :erlang.float_to_binary(decimals: 2))
defp get_value_for_key("range", %{staged: staged} = ammo_group) do
assigns = %{ammo_group: ammo_group}
{staged,
~H"""
<div class="min-w-20 py-2 px-4 h-full flex flex-col justify-center items-center">
<button
type="button"
class="mx-2 my-1 btn btn-primary"
phx-click="toggle_staged"
phx-value-ammo_group_id={ammo_group.id}
>
<%= if ammo_group.staged, do: gettext("Unstage"), else: gettext("Stage") %>
</button>
<%= live_patch(dgettext("actions", "Record shots"),
to: Routes.ammo_group_index_path(Endpoint, :add_shot_group, ammo_group),
class: "mx-2 my-1 btn btn-primary"
) %>
</div>
"""}
end
defp get_value_for_key("remaining", ammo_group),
do: "#{ammo_group |> Ammo.get_percentage_remaining()}%"
defp get_value_for_key("actions", ammo_group) do
assigns = %{ammo_group: ammo_group}
~H"""
<div class="py-2 px-4 h-full space-x-4 flex justify-center items-center">
<%= live_redirect to: Routes.ammo_group_show_path(Endpoint, :show, ammo_group),
class: "text-primary-600 link",
data: [qa: "view-#{ammo_group.id}"] do %>
<i class="fa-fw fa-lg fas fa-eye"></i>
<% end %>
<%= live_patch to: Routes.ammo_group_index_path(Endpoint, :edit, ammo_group),
class: "text-primary-600 link",
data: [qa: "edit-#{ammo_group.id}"] do %>
<i class="fa-fw fa-lg fas fa-edit"></i>
<% end %>
<%= link to: "#",
class: "text-primary-600 link",
phx_click: "delete",
phx_value_id: ammo_group.id,
data: [
confirm: dgettext("prompts", "Are you sure you want to delete this ammo?"),
qa: "delete-#{ammo_group.id}"
] do %>
<i class="fa-fw fa-lg fas fa-trash"></i>
<% end %>
</div>
"""
end
defp get_value_for_key("container", %{container: nil}), do: {nil, nil}
defp get_value_for_key("container", %{container: %{name: container_name}} = ammo_group) do
assigns = %{ammo_group: ammo_group}
{container_name,
~H"""
<div class="min-w-20 py-2 px-4 h-full space-x-4 flex justify-center items-center">
<%= live_patch(@ammo_group.container.name,
to: Routes.ammo_group_index_path(Endpoint, :move, @ammo_group),
class: "btn btn-primary"
) %>
</div>
"""}
end
defp get_value_for_key(key, ammo_group),
do: ammo_group |> Map.get(key |> String.to_existing_atom())
end

View File

@ -9,126 +9,49 @@
<%= display_emoji("😔") %>
</h2>
<%= live_patch(dgettext("actions", "Add your first box!"),
to: Routes.ammo_group_index_path(Endpoint, :new),
class: "btn btn-primary"
) %>
<%= if @containers |> Enum.empty?() do %>
<div class="flex justify-center items-center">
<h2 class="m-2 title text-md text-primary-600">
<%= dgettext("prompts", "You'll need to") %>
</h2>
<%= live_patch(dgettext("actions", "add a container first"),
to: Routes.container_index_path(Endpoint, :new),
class: "btn btn-primary"
) %>
</div>
<% else %>
<%= live_patch(dgettext("actions", "Add your first box!"),
to: Routes.ammo_group_index_path(Endpoint, :new),
class: "btn btn-primary"
) %>
<% end %>
<% else %>
<%= live_patch(dgettext("actions", "New Ammo group"),
to: Routes.ammo_group_index_path(Endpoint, :new),
class: "btn btn-primary"
) %>
<%= if @containers |> Enum.empty?() do %>
<div class="flex justify-center items-center">
<h2 class="m-2 title text-md text-primary-600">
<%= dgettext("prompts", "You'll need to") %>
</h2>
<div class="w-full overflow-x-auto border border-gray-600 rounded-lg shadow-lg bg-black">
<table class="min-w-full table-auto text-center bg-white">
<thead class="border-b border-primary-600">
<tr>
<th class="p-2">
<%= gettext("Ammo type") %>
</th>
<th class="p-2">
<%= gettext("Count") %>
</th>
<th class="p-2">
<%= gettext("Price paid") %>
</th>
<th class="p-2">
<%= gettext("% left") %>
</th>
<th class="p-2">
<%= gettext("Range") %>
</th>
<th class="p-2">
<%= gettext("Container") %>
</th>
<%= live_patch(dgettext("actions", "add a container first"),
to: Routes.container_index_path(Endpoint, :new),
class: "btn btn-primary"
) %>
</div>
<% else %>
<%= live_patch(dgettext("actions", "New Ammo group"),
to: Routes.ammo_group_index_path(Endpoint, :new),
class: "btn btn-primary"
) %>
<% end %>
<th class="p-2"></th>
</tr>
</thead>
<tbody id="ammo_groups">
<%= for ammo_group <- @ammo_groups do %>
<tr id={"ammo_group-#{ammo_group.id}"}>
<td class="p-2">
<%= live_patch(ammo_group.ammo_type.name,
to: Routes.ammo_type_show_path(Endpoint, :show, ammo_group.ammo_type),
class: "link"
) %>
</td>
<td class="p-2">
<%= ammo_group.count %>
</td>
<td class="p-2">
<%= if ammo_group.price_paid do %>
<%= gettext("$%{amount}",
amount: ammo_group.price_paid |> :erlang.float_to_binary(decimals: 2)
) %>
<% end %>
</td>
<td class="p-2">
<%= "#{ammo_group |> Ammo.get_percentage_remaining()}%" %>
</td>
<td class="p-2">
<div class="px-4 py-2 space-x-4 flex justify-center items-center">
<button
type="button"
class="btn btn-primary"
phx-click="toggle_staged"
phx-value-ammo_group_id={ammo_group.id}
>
<%= if ammo_group.staged, do: gettext("Unstage"), else: gettext("Stage") %>
</button>
<%= live_patch(dgettext("actions", "Record shots"),
to: Routes.ammo_group_index_path(Endpoint, :add_shot_group, ammo_group),
class: "btn btn-primary"
) %>
</div>
</td>
<td class="p-2">
<%= if ammo_group.container do %>
<%= live_patch(ammo_group.container.name,
to: Routes.ammo_group_index_path(Endpoint, :move, ammo_group),
class: "btn btn-primary"
) %>
<% end %>
</td>
<td class="p-2">
<div class="px-4 py-2 space-x-4 flex justify-center items-center">
<%= live_redirect to: Routes.ammo_group_show_path(Endpoint, :show, ammo_group),
class: "text-primary-600 link",
data: [qa: "view-#{ammo_group.id}"] do %>
<i class="fa-fw fa-lg fas fa-eye"></i>
<% end %>
<%= live_patch to: Routes.ammo_group_index_path(Endpoint, :edit, ammo_group),
class: "text-primary-600 link",
data: [qa: "edit-#{ammo_group.id}"] do %>
<i class="fa-fw fa-lg fas fa-edit"></i>
<% end %>
<%= link to: "#",
class: "text-primary-600 link",
phx_click: "delete",
phx_value_id: ammo_group.id,
data: [
confirm: dgettext("prompts", "Are you sure you want to delete this ammo?"),
qa: "delete-#{ammo_group.id}"
] do %>
<i class="fa-fw fa-lg fas fa-trash"></i>
<% end %>
</div>
</td>
</tr>
<% end %>
</tbody>
</table>
</div>
<.live_component
module={CanneryWeb.Components.TableComponent}
id="ammo_groups_index_table"
action={@live_action}
columns={@columns}
rows={@rows}
/>
<% end %>
</div>
@ -143,6 +66,7 @@
ammo_group={@ammo_group}
return_to={Routes.ammo_group_index_path(Endpoint, :index)}
current_user={@current_user}
containers={@containers}
/>
</.modal>
<% @live_action == :add_shot_group -> %>
@ -170,4 +94,5 @@
/>
</.modal>
<% true -> %>
<% end %>
<%= nil %>
<% end %>

View File

@ -5,8 +5,9 @@ defmodule CanneryWeb.AmmoGroupLive.Show do
use CanneryWeb, :live_view
import CanneryWeb.Components.ContainerCard
alias Cannery.{Ammo, Repo}
alias Cannery.{ActivityLog, ActivityLog.ShotGroup, Ammo, Ammo.AmmoGroup, Repo}
alias CanneryWeb.Endpoint
alias Phoenix.LiveView.Socket
@impl true
def mount(_params, session, socket) do
@ -15,18 +16,35 @@ defmodule CanneryWeb.AmmoGroupLive.Show do
@impl true
def handle_params(
%{"id" => id},
%{"id" => id, "shot_group_id" => shot_group_id},
_url,
%{assigns: %{live_action: live_action, current_user: current_user}} = socket
) do
ammo_group = Ammo.get_ammo_group!(id, current_user) |> Repo.preload([:container, :ammo_type])
{:noreply, socket |> assign(page_title: page_title(live_action), ammo_group: ammo_group)}
shot_group = ActivityLog.get_shot_group!(shot_group_id, current_user)
socket =
socket
|> assign(page_title: page_title(live_action), shot_group: shot_group)
|> display_ammo_group(id)
{:noreply, socket}
end
@impl true
def handle_params(%{"id" => id}, _url, %{assigns: %{live_action: live_action}} = socket) do
{:noreply, socket |> assign(page_title: page_title(live_action)) |> display_ammo_group(id)}
end
defp page_title(:add_shot_group), do: gettext("Record Shots")
defp page_title(:edit_shot_group), do: gettext("Edit Shot Records")
defp page_title(:move), do: gettext("Move Ammo group")
defp page_title(:show), do: gettext("Show Ammo group")
defp page_title(:edit), do: gettext("Edit Ammo group")
@impl true
def handle_event(
"delete",
_,
_params,
%{assigns: %{ammo_group: ammo_group, current_user: current_user}} = socket
) do
ammo_group |> Ammo.delete_ammo_group!(current_user)
@ -40,17 +58,90 @@ defmodule CanneryWeb.AmmoGroupLive.Show do
@impl true
def handle_event(
"toggle_staged",
_,
_params,
%{assigns: %{ammo_group: ammo_group, current_user: current_user}} = socket
) do
{:ok, ammo_group} =
ammo_group |> Ammo.update_ammo_group(%{"staged" => !ammo_group.staged}, current_user)
{:noreply, socket |> assign(ammo_group: ammo_group)}
{:noreply, socket |> display_ammo_group(ammo_group)}
end
defp page_title(:add_shot_group), do: gettext("Add Shot group")
defp page_title(:move), do: gettext("Move Ammo group")
defp page_title(:show), do: gettext("Show Ammo group")
defp page_title(:edit), do: gettext("Edit Ammo group")
@impl true
def handle_event(
"delete_shot_group",
%{"id" => id},
%{assigns: %{ammo_group: ammo_group, current_user: current_user}} = socket
) do
{:ok, _} =
ActivityLog.get_shot_group!(id, current_user)
|> ActivityLog.delete_shot_group(current_user)
prompt = dgettext("prompts", "Shot records deleted succesfully")
{:noreply, socket |> put_flash(:info, prompt) |> display_ammo_group(ammo_group)}
end
@spec display_ammo_group(Socket.t(), AmmoGroup.t() | AmmoGroup.id()) :: Socket.t()
defp display_ammo_group(socket, %AmmoGroup{} = ammo_group) do
ammo_group = ammo_group |> Repo.preload([:container, :ammo_type, :shot_groups], force: true)
columns = [
%{label: gettext("Rounds shot"), key: "count"},
%{label: gettext("Notes"), key: "notes"},
%{label: gettext("Date"), key: "date"},
%{label: nil, key: "actions", sortable: false}
]
rows =
ammo_group.shot_groups
|> Enum.map(fn shot_group ->
ammo_group |> get_table_row_for_shot_group(shot_group, columns)
end)
socket |> assign(ammo_group: ammo_group, columns: columns, rows: rows)
end
defp display_ammo_group(%{assigns: %{current_user: current_user}} = socket, id),
do: display_ammo_group(socket, Ammo.get_ammo_group!(id, current_user))
@spec get_table_row_for_shot_group(AmmoGroup.t(), ShotGroup.t(), [map()]) :: [map()]
defp get_table_row_for_shot_group(ammo_group, %{date: date} = shot_group, columns) do
assigns = %{ammo_group: ammo_group, shot_group: shot_group}
columns
|> Enum.into(%{}, fn %{key: key} ->
value =
case key do
"date" ->
{date, date |> display_date()}
"actions" ->
~H"""
<div class="px-4 py-2 space-x-4 flex justify-center items-center">
<%= live_patch to: Routes.ammo_group_show_path(Endpoint, :edit_shot_group, @ammo_group, shot_group),
class: "text-primary-600 link",
data: [qa: "edit-#{shot_group.id}"] do %>
<i class="fa-fw fa-lg fas fa-edit"></i>
<% end %>
<%= link to: "#",
class: "text-primary-600 link",
phx_click: "delete_shot_group",
phx_value_id: shot_group.id,
data: [
confirm: dgettext("prompts", "Are you sure you want to delete this shot record?"),
qa: "delete-#{shot_group.id}"
] do %>
<i class="fa-fw fa-lg fas fa-trash"></i>
<% end %>
</div>
"""
key ->
shot_group |> Map.get(key |> String.to_existing_atom())
end
{key, value}
end)
end
end

View File

@ -111,38 +111,12 @@
<%= gettext("Rounds used") %>
</h1>
<div class="w-full overflow-x-auto border border-gray-600 rounded-lg shadow-lg bg-black">
<table class="min-w-full table-auto text-center bg-white">
<thead class="border-b border-primary-600">
<tr>
<th class="p-2">
<%= gettext("Rounds shot") %>
</th>
<th class="p-2">
<%= gettext("Notes") %>
</th>
<th class="p-2">
<%= gettext("Date") %>
</th>
</tr>
</thead>
<tbody id="shot_groups">
<%= for shot_group <- @ammo_group.shot_groups do %>
<tr id={"shot_group-#{shot_group.id}"}>
<td class="p-2">
<%= shot_group.count %>
</td>
<td class="p-2">
<%= shot_group.notes %>
</td>
<td class="p-2">
<%= shot_group.date |> display_date() %>
</td>
</tr>
<% end %>
</tbody>
</table>
</div>
<.live_component
module={CanneryWeb.Components.TableComponent}
id="ammo_group_shot_groups_table"
columns={@columns}
rows={@rows}
/>
<% end %>
</div>
@ -159,6 +133,18 @@
current_user={@current_user}
/>
</.modal>
<% :edit_shot_group -> %>
<.modal return_to={Routes.ammo_group_show_path(Endpoint, :show, @ammo_group)}>
<.live_component
module={CanneryWeb.RangeLive.FormComponent}
id={@shot_group.id}
title={@page_title}
action={@live_action}
shot_group={@shot_group}
return_to={Routes.ammo_group_show_path(Endpoint, :show, @ammo_group)}
current_user={@current_user}
/>
</.modal>
<% :add_shot_group -> %>
<.modal return_to={Routes.ammo_group_show_path(Endpoint, :show, @ammo_group)}>
<.live_component
@ -184,4 +170,4 @@
/>
</.modal>
<% _show -> %>
<% end %>
<% end %>

View File

@ -17,11 +17,11 @@
</div>
<% end %>
<%= label(f, :name, gettext("Name"), class: "mr-4 title text-lg text-primary-600") %>
<%= label(f, :name, gettext("Name"), class: "title text-lg text-primary-600") %>
<%= text_input(f, :name, class: "text-center col-span-2 input input-primary") %>
<%= error_tag(f, :name, "col-span-3 text-center") %>
<%= label(f, :desc, gettext("Description"), class: "mr-4 title text-lg text-primary-600") %>
<%= label(f, :desc, gettext("Description"), class: "title text-lg text-primary-600") %>
<%= textarea(f, :desc,
class: "text-center col-span-2 input input-primary",
phx_hook: "MaintainAttrs"
@ -34,50 +34,42 @@
>
<%= gettext("Example bullet type abbreviations") %>
</a>
<%= label(f, :bullet_type, gettext("Bullet type"),
class: "mr-4 title text-lg text-primary-600"
) %>
<%= label(f, :bullet_type, gettext("Bullet type"), class: "title text-lg text-primary-600") %>
<%= text_input(f, :bullet_type,
class: "text-center col-span-2 input input-primary",
placeholder: gettext("FMJ")
) %>
<%= error_tag(f, :bullet_type, "col-span-3 text-center") %>
<%= label(f, :bullet_core, gettext("Bullet core"),
class: "mr-4 title text-lg text-primary-600"
) %>
<%= label(f, :bullet_core, gettext("Bullet core"), class: "title text-lg text-primary-600") %>
<%= text_input(f, :bullet_core,
class: "text-center col-span-2 input input-primary",
placeholder: gettext("Steel")
) %>
<%= error_tag(f, :bullet_core, "col-span-3 text-center") %>
<%= label(f, :cartridge, gettext("Cartridge"), class: "mr-4 title text-lg text-primary-600") %>
<%= label(f, :cartridge, gettext("Cartridge"), class: "title text-lg text-primary-600") %>
<%= text_input(f, :cartridge,
class: "text-center col-span-2 input input-primary",
placeholder: "5.56x46mm NATO"
) %>
<%= error_tag(f, :cartridge, "col-span-3 text-center") %>
<%= label(f, :caliber, gettext("Caliber"), class: "mr-4 title text-lg text-primary-600") %>
<%= label(f, :caliber, gettext("Caliber"), class: "title text-lg text-primary-600") %>
<%= text_input(f, :caliber,
class: "text-center col-span-2 input input-primary",
placeholder: ".223"
) %>
<%= error_tag(f, :caliber, "col-span-3 text-center") %>
<%= label(f, :case_material, gettext("Case material"),
class: "mr-4 title text-lg text-primary-600"
) %>
<%= label(f, :case_material, gettext("Case material"), class: "title text-lg text-primary-600") %>
<%= text_input(f, :case_material,
class: "text-center col-span-2 input input-primary",
placeholder: gettext("Brass")
) %>
<%= error_tag(f, :case_material, "col-span-3 text-center") %>
<%= label(f, :jacket_type, gettext("Jacket type"),
class: "mr-4 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,
class: "text-center col-span-2 input input-primary",
placeholder: gettext("Bimetal")
@ -85,7 +77,7 @@
<%= error_tag(f, :case_material, "col-span-3 text-center") %>
<%= label(f, :muzzle_velocity, gettext("Muzzle velocity"),
class: "mr-4 title text-lg text-primary-600"
class: "title text-lg text-primary-600"
) %>
<%= number_input(f, :muzzle_velocity,
step: "1",
@ -94,14 +86,12 @@
) %>
<%= error_tag(f, :muzzle_velocity, "col-span-3 text-center") %>
<%= label(f, :powder_type, gettext("Powder type"),
class: "mr-4 title text-lg text-primary-600"
) %>
<%= label(f, :powder_type, gettext("Powder type"), class: "title text-lg text-primary-600") %>
<%= text_input(f, :powder_type, class: "text-center col-span-2 input input-primary") %>
<%= error_tag(f, :powder_type, "col-span-3 text-center") %>
<%= label(f, :powder_grains_per_charge, gettext("Powder grains per charge"),
class: "mr-4 title text-lg text-primary-600"
class: "title text-lg text-primary-600"
) %>
<%= number_input(f, :powder_grains_per_charge,
step: "1",
@ -110,7 +100,7 @@
) %>
<%= error_tag(f, :powder_grains_per_charge, "col-span-3 text-center") %>
<%= label(f, :grains, gettext("Grains"), class: "mr-4 title text-lg text-primary-600") %>
<%= label(f, :grains, gettext("Grains"), class: "title text-lg text-primary-600") %>
<%= number_input(f, :grains,
step: "1",
class: "text-center col-span-2 input input-primary",
@ -118,54 +108,48 @@
) %>
<%= error_tag(f, :grains, "col-span-3 text-center") %>
<%= label(f, :pressure, gettext("Pressure"), class: "mr-4 title text-lg text-primary-600") %>
<%= label(f, :pressure, gettext("Pressure"), class: "title text-lg text-primary-600") %>
<%= text_input(f, :pressure,
class: "text-center col-span-2 input input-primary",
placeholder: "+P"
) %>
<%= error_tag(f, :pressure, "col-span-3 text-center") %>
<%= label(f, :primer_type, gettext("Primer type"),
class: "mr-4 title text-lg text-primary-600"
) %>
<%= label(f, :primer_type, gettext("Primer type"), class: "title text-lg text-primary-600") %>
<%= text_input(f, :primer_type,
class: "text-center col-span-2 input input-primary",
placeholder: "Boxer"
) %>
<%= error_tag(f, :primer_type, "col-span-3 text-center") %>
<%= label(f, :firing_type, gettext("Firing type"),
class: "mr-4 title text-lg text-primary-600"
) %>
<%= label(f, :firing_type, gettext("Firing type"), class: "title text-lg text-primary-600") %>
<%= text_input(f, :firing_type,
class: "text-center col-span-2 input input-primary",
placeholder: "Centerfire"
) %>
<%= error_tag(f, :firing_type, "col-span-3 text-center") %>
<%= label(f, :tracer, gettext("Tracer"), class: "mr-4 title text-lg text-primary-600") %>
<%= label(f, :tracer, gettext("Tracer"), class: "title text-lg text-primary-600") %>
<%= checkbox(f, :tracer, class: "text-center col-span-2 checkbox") %>
<%= error_tag(f, :tracer, "col-span-3 text-center") %>
<%= label(f, :incendiary, gettext("Incendiary"), class: "mr-4 title text-lg text-primary-600") %>
<%= label(f, :incendiary, gettext("Incendiary"), class: "title text-lg text-primary-600") %>
<%= checkbox(f, :incendiary, class: "text-center col-span-2 checkbox") %>
<%= error_tag(f, :incendiary, "col-span-3 text-center") %>
<%= label(f, :blank, gettext("Blank"), class: "mr-4 title text-lg text-primary-600") %>
<%= label(f, :blank, gettext("Blank"), class: "title text-lg text-primary-600") %>
<%= checkbox(f, :blank, class: "text-center col-span-2 checkbox") %>
<%= error_tag(f, :blank, "col-span-3 text-center") %>
<%= label(f, :corrosive, gettext("Corrosive"), class: "mr-4 title text-lg text-primary-600") %>
<%= label(f, :corrosive, gettext("Corrosive"), class: "title text-lg text-primary-600") %>
<%= checkbox(f, :corrosive, class: "text-center col-span-2 checkbox") %>
<%= error_tag(f, :corrosive, "col-span-3 text-center") %>
<%= label(f, :manufacturer, gettext("Manufacturer"),
class: "mr-4 title text-lg text-primary-600"
) %>
<%= label(f, :manufacturer, gettext("Manufacturer"), class: "title text-lg text-primary-600") %>
<%= text_input(f, :manufacturer, class: "text-center col-span-2 input input-primary") %>
<%= error_tag(f, :manufacturer, "col-span-3 text-center") %>
<%= label(f, :upc, gettext("UPC"), class: "mr-4 title text-lg text-primary-600") %>
<%= label(f, :upc, gettext("UPC"), class: "title text-lg text-primary-600") %>
<%= text_input(f, :upc, class: "text-center col-span-2 input input-primary") %>
<%= error_tag(f, :upc, "col-span-3 text-center") %>

View File

@ -31,7 +31,7 @@ defmodule CanneryWeb.AmmoTypeLive.Index do
end
defp apply_action(socket, :index, _params) do
socket |> assign(:page_title, gettext("Listing Ammo types")) |> assign(:ammo_type, nil)
socket |> assign(:page_title, gettext("Ammo types")) |> assign(:ammo_type, nil)
end
@impl true
@ -46,37 +46,108 @@ defmodule CanneryWeb.AmmoTypeLive.Index do
defp list_ammo_types(%{assigns: %{current_user: current_user}} = socket) do
ammo_types = Ammo.list_ammo_types(current_user)
columns_to_display =
columns =
[
{gettext("Name"), :name, :string},
{gettext("Bullet type"), :bullet_type, :string},
{gettext("Bullet core"), :bullet_core, :string},
{gettext("Cartridge"), :cartridge, :string},
{gettext("Caliber"), :caliber, :string},
{gettext("Case material"), :case_material, :string},
{gettext("Jacket type"), :jacket_type, :string},
{gettext("Muzzle velocity"), :muzzle_velocity, :string},
{gettext("Powder type"), :powder_type, :string},
{gettext("Powder grains per charge"), :powder_grains_per_charge, :string},
{gettext("Grains"), :grains, :string},
{gettext("Pressure"), :pressure, :string},
{gettext("Primer type"), :primer_type, :string},
{gettext("Firing type"), :firing_type, :string},
{gettext("Tracer"), :tracer, :boolean},
{gettext("Incendiary"), :incendiary, :boolean},
{gettext("Blank"), :blank, :boolean},
{gettext("Corrosive"), :corrosive, :boolean},
{gettext("Manufacturer"), :manufacturer, :string},
{gettext("UPC"), :upc, :string}
%{label: gettext("Name"), key: "name", type: :string},
%{label: gettext("Bullet type"), key: "bullet_type", type: :string},
%{label: gettext("Bullet core"), key: "bullet_core", type: :string},
%{label: gettext("Cartridge"), key: "cartridge", type: :string},
%{label: gettext("Caliber"), key: "caliber", type: :string},
%{label: gettext("Case material"), key: "case_material", type: :string},
%{label: gettext("Jacket type"), key: "jacket_type", type: :string},
%{label: gettext("Muzzle velocity"), key: "muzzle_velocity", type: :string},
%{label: gettext("Powder type"), key: "powder_type", type: :string},
%{
label: gettext("Powder grains per charge"),
key: "powder_grains_per_charge",
type: :string
},
%{label: gettext("Grains"), key: "grains", type: :string},
%{label: gettext("Pressure"), key: "pressure", type: :string},
%{label: gettext("Primer type"), key: "primer_type", type: :string},
%{label: gettext("Firing type"), key: "firing_type", type: :string},
%{label: gettext("Tracer"), key: "tracer", type: :boolean},
%{label: gettext("Incendiary"), key: "incendiary", type: :boolean},
%{label: gettext("Blank"), key: "blank", type: :boolean},
%{label: gettext("Corrosive"), key: "corrosive", type: :boolean},
%{label: gettext("Manufacturer"), key: "manufacturer", type: :string},
%{label: gettext("UPC"), key: "upc", type: :string}
]
|> Enum.filter(fn {_label, field, type} ->
|> Enum.filter(fn %{key: key, type: type} ->
# remove columns if all values match defaults
default_value = if type == :boolean, do: false, else: nil
ammo_types
|> Enum.any?(fn ammo_type -> not (ammo_type |> Map.get(field) == default_value) end)
|> Enum.any?(fn ammo_type ->
not (ammo_type |> Map.get(key |> String.to_existing_atom()) == default_value)
end)
end)
|> Kernel.++([
%{label: gettext("Total # of rounds"), key: "round_count", type: :round_count},
%{label: gettext("Average Price paid"), key: "avg_price_paid", type: :avg_price_paid},
%{label: nil, key: "actions", type: :actions, sortable: false}
])
socket |> assign(ammo_types: ammo_types, columns_to_display: columns_to_display)
rows =
ammo_types
|> Enum.map(fn ammo_type -> ammo_type |> get_ammo_type_values(columns, current_user) end)
socket |> assign(columns: columns, rows: rows)
end
defp get_ammo_type_values(ammo_type, columns, current_user) do
columns
|> Enum.into(%{}, fn %{key: key, type: type} ->
{key, get_ammo_type_value(type, key, ammo_type, current_user)}
end)
end
defp get_ammo_type_value(:boolean, key, ammo_type, _current_user),
do: ammo_type |> Map.get(key |> String.to_existing_atom()) |> humanize()
defp get_ammo_type_value(:round_count, _key, ammo_type, current_user),
do: ammo_type |> Ammo.get_round_count_for_ammo_type(current_user)
defp get_ammo_type_value(:avg_price_paid, _key, ammo_type, current_user) do
case ammo_type |> Ammo.get_average_cost_for_ammo_type!(current_user) do
nil -> gettext("No cost information")
count -> gettext("$%{amount}", amount: count |> :erlang.float_to_binary(decimals: 2))
end
end
defp get_ammo_type_value(:actions, _key, ammo_type, _current_user) do
assigns = %{ammo_type: ammo_type}
~H"""
<div class="px-4 py-2 space-x-4 flex justify-center items-center">
<%= live_redirect to: Routes.ammo_type_show_path(Endpoint, :show, ammo_type),
class: "text-primary-600 link",
data: [qa: "view-#{ammo_type.id}"] do %>
<i class="fa-fw fa-lg fas fa-eye"></i>
<% end %>
<%= live_patch to: Routes.ammo_type_index_path(Endpoint, :edit, ammo_type),
class: "text-primary-600 link",
data: [qa: "edit-#{ammo_type.id}"] do %>
<i class="fa-fw fa-lg fas fa-edit"></i>
<% end %>
<%= link to: "#",
class: "text-primary-600 link",
phx_click: "delete",
phx_value_id: ammo_type.id,
data: [
confirm: dgettext("prompts", "Are you sure you want to delete this ammo?"),
qa: "delete-#{ammo_type.id}"
] do %>
<i class="fa-lg fas fa-trash"></i>
<% end %>
</div>
"""
end
defp get_ammo_type_value(nil, _key, _ammo_type, _current_user), do: nil
defp get_ammo_type_value(_other, key, ammo_type, _current_user),
do: ammo_type |> Map.get(key |> String.to_existing_atom())
end

View File

@ -3,7 +3,7 @@
<%= gettext("Ammo Types") %>
</h1>
<%= if @ammo_types |> Enum.empty?() do %>
<%= if @rows |> Enum.empty?() do %>
<h2 class="title text-xl text-primary-600">
<%= gettext("No Ammo Types") %>
<%= display_emoji("😔") %>
@ -19,71 +19,13 @@
class: "btn btn-primary"
) %>
<div class="w-full overflow-x-auto border border-gray-600 rounded-lg shadow-lg bg-black">
<table class="min-w-full table-auto text-center bg-white">
<thead class="border-b border-primary-600">
<tr>
<%= for {field_name, _field, _type} <- @columns_to_display do %>
<th class="p-2">
<%= field_name %>
</th>
<% end %>
<th class="p-2">
<%= gettext("Total # of rounds") %>
</th>
<th class="p-2"></th>
</tr>
</thead>
<tbody>
<%= for ammo_type <- @ammo_types do %>
<tr id={"ammo_type-#{ammo_type.id}"}>
<%= for {_label, field, type} <- @columns_to_display do %>
<td class="p-2">
<%= case type do %>
<% :boolean -> %>
<%= ammo_type |> Map.get(field) |> humanize() %>
<% _other -> %>
<%= ammo_type |> Map.get(field) %>
<% end %>
</td>
<% end %>
<td class="p-2">
<%= ammo_type |> Ammo.get_round_count_for_ammo_type(@current_user) %>
</td>
<td class="p-2">
<div class="px-4 py-2 space-x-4 flex justify-center items-center">
<%= live_redirect to: Routes.ammo_type_show_path(Endpoint, :show, ammo_type),
class: "text-primary-600 link",
data: [qa: "view-#{ammo_type.id}"] do %>
<i class="fa-fw fa-lg fas fa-eye"></i>
<% end %>
<%= live_patch to: Routes.ammo_type_index_path(Endpoint, :edit, ammo_type),
class: "text-primary-600 link",
data: [qa: "edit-#{ammo_type.id}"] do %>
<i class="fa-fw fa-lg fas fa-edit"></i>
<% end %>
<%= link to: "#",
class: "text-primary-600 link",
phx_click: "delete",
phx_value_id: ammo_type.id,
data: [
confirm: dgettext("prompts", "Are you sure you want to delete this ammo?"),
qa: "delete-#{ammo_type.id}"
] do %>
<i class="fa-lg fas fa-trash"></i>
<% end %>
</div>
</td>
</tr>
<% end %>
</tbody>
</table>
</div>
<.live_component
module={CanneryWeb.Components.TableComponent}
id="ammo_types_index_table"
action={@live_action}
columns={@columns}
rows={@rows}
/>
<% end %>
</div>

View File

@ -14,7 +14,7 @@ defmodule CanneryWeb.AmmoTypeLive.Show do
end
@impl true
def handle_params(%{"id" => id}, _, %{assigns: %{current_user: current_user}} = socket) do
def handle_params(%{"id" => id}, _params, %{assigns: %{current_user: current_user}} = socket) do
ammo_type = Ammo.get_ammo_type!(id, current_user)
socket =
@ -32,7 +32,7 @@ defmodule CanneryWeb.AmmoTypeLive.Show do
@impl true
def handle_event(
"delete",
_,
_params,
%{assigns: %{ammo_type: ammo_type, current_user: current_user}} = socket
) do
%{name: ammo_type_name} = ammo_type |> Ammo.delete_ammo_type!(current_user)

View File

@ -5,11 +5,9 @@
</h1>
<%= if @ammo_type.desc do %>
<span
class="max-w-2xl w-full px-8 py-4 rounded-lg
<span class="max-w-2xl w-full px-8 py-4 rounded-lg
text-center title text-lg
border border-primary-600"
>
border border-primary-600">
<%= @ammo_type.desc %>
</span>
<% end %>
@ -100,9 +98,8 @@
) %>
</span>
<% else %>
<h3 class="title text-lg col-span-2">
<h3 class="mx-8 my-4 title text-lg text-primary-600 col-span-2">
<%= gettext("No cost information") %>
<%= display_emoji("😔") %>
</h3>
<% end %>
</div>
@ -111,8 +108,10 @@
<div>
<%= if @ammo_groups |> Enum.empty?() do %>
<%= gettext("No ammo for this type") %>
<%= display_emoji("😔") %>
<h2 class="mx-8 my-4 title text-lg text-primary-600">
<%= gettext("No ammo for this type") %>
<%= display_emoji("😔") %>
</h2>
<% else %>
<div class="flex flex-wrap justify-center items-center">
<%= for ammo_group <- @ammo_groups do %>

View File

@ -16,7 +16,7 @@ defmodule CanneryWeb.ContainerLive.Index do
@impl true
def handle_params(params, _url, %{assigns: %{live_action: live_action}} = socket) do
{:noreply, apply_action(socket, live_action, params)}
{:noreply, apply_action(socket, live_action, params) |> display_containers()}
end
defp apply_action(%{assigns: %{current_user: current_user}} = socket, :edit, %{"id" => id}) do
@ -35,7 +35,7 @@ defmodule CanneryWeb.ContainerLive.Index do
defp apply_action(socket, :index, _params) do
socket
|> assign(:page_title, gettext("Listing Containers"))
|> assign(:page_title, gettext("Containers"))
|> assign(:container, nil)
|> display_containers()
end

View File

@ -20,7 +20,7 @@
) %>
<% end %>
<div class="flex flex-row flex-wrap justify-center items-center">
<div class="max-w-full flex flex-row flex-wrap justify-center items-center">
<%= for container <- @containers do %>
<.container_card container={container}>
<:tag_actions>

View File

@ -18,7 +18,7 @@ defmodule CanneryWeb.ContainerLive.Show do
@impl true
def handle_params(
%{"id" => id},
_,
_session,
%{assigns: %{current_user: current_user}} = socket
) do
{:noreply, socket |> render_container(id, current_user)}
@ -53,7 +53,7 @@ defmodule CanneryWeb.ContainerLive.Show do
@impl true
def handle_event(
"delete_container",
_,
_params,
%{assigns: %{container: container, current_user: current_user}} = socket
) do
socket =

View File

@ -72,9 +72,11 @@
<hr class="mb-4 hr" />
<p>
<div>
<%= if @container.ammo_groups |> Enum.empty?() do %>
<%= gettext("No ammo groups in this container") %>
<h2 class="mx-8 my-4 title text-lg text-primary-600">
<%= gettext("No ammo groups in this container") %>
</h2>
<% else %>
<div class="flex flex-wrap justify-center items-center">
<%= for ammo_group <- @container.ammo_groups do %>
@ -82,7 +84,7 @@
<% end %>
</div>
<% end %>
</p>
</div>
</div>
<%= if @live_action in [:edit] do %>

View File

@ -29,7 +29,7 @@ defmodule CanneryWeb.HomeLive do
%{^query => vsn} ->
{:noreply, redirect(socket, external: "https://hexdocs.pm/#{query}/#{vsn}")}
_ ->
_no_query ->
{:noreply,
socket
|> put_flash(:error, "No dependencies found matching \"#{query}\"")
@ -40,9 +40,7 @@ defmodule CanneryWeb.HomeLive do
@impl true
def render(assigns) do
~H"""
<div
class="mx-auto px-8 sm:px-16 flex flex-col justify-center items-center text-center space-y-4 max-w-3xl"
>
<div class="mx-auto px-8 sm:px-16 flex flex-col justify-center items-center text-center space-y-4 max-w-3xl">
<h1 class="title text-primary-600 text-2xl">
<%= gettext("Welcome to %{name}", name: "Cannery") %>
</h1>
@ -127,11 +125,15 @@ defmodule CanneryWeb.HomeLive do
</p>
</li>
<li class="flex flex-row justify-center space-x-2">
<li class="flex flex-row justify-center items-center space-x-2">
<b>Version:</b>
<p>
0.2.1
</p>
<%= link class: "flex flex-row justify-center items-center space-x-2 hover:underline",
to: "https://gitea.bubbletea.dev/shibao/cannery/src/branch/stable/CHANGELOG.md",
target: "_blank",
rel: "noopener noreferrer" do %>
<p>0.5.0</p>
<i class="fas fa-md fa-info-circle"></i>
<% end %>
</li>
</ul>
</div>

View File

@ -40,7 +40,7 @@ defmodule CanneryWeb.InviteLive.Index do
end
defp apply_action(socket, :index, _params) do
socket |> assign(page_title: gettext("Listing Invites"), invite: nil)
socket |> assign(page_title: gettext("Invites"), invite: nil)
end
@impl true
@ -119,7 +119,7 @@ defmodule CanneryWeb.InviteLive.Index do
end
@impl true
def handle_event("copy_to_clipboard", _, socket) do
def handle_event("copy_to_clipboard", _params, socket) do
prompt = dgettext("prompts", "Copied to clipboard")
{:noreply, socket |> put_flash(:info, prompt)}
end

View File

@ -38,32 +38,43 @@ defmodule CanneryWeb.LiveHelpers do
"""
def modal(assigns) do
~H"""
<%= live_patch to: @return_to,
id: "modal-bg",
class:
"fade-in fixed z-10 left-0 top-0
w-full h-full overflow-hidden
p-8 flex flex-col justify-center items-center cursor-auto",
style: "background-color: rgba(0,0,0,0.4);",
phx_remove: hide_modal()
do %>
<span class="hidden"></span>
<% end %>
<div
id="modal"
class="fade-in fixed z-10 left-0 top-0
w-full h-full overflow-hidden
p-8 flex flex-col justify-center items-center"
style="opacity: 1 !important; background-color: rgba(0,0,0,0.4);"
phx-remove={hide_modal()}
class="fixed z-10 left-0 top-0 pointer-events-none
w-full h-full overflow-hidden
p-4 sm:p-8 flex flex-col justify-center items-center"
>
<div
id="modal-content"
class="fade-in-scale w-full max-w-3xl max-h-128 relative overflow-y-auto
class="fade-in-scale w-full max-w-3xl relative
pointer-events-auto overflow-hidden
px-8 py-4 sm:py-8 flex flex-col justify-center items-center
flex flex-col justify-start items-center
bg-white border-2 rounded-lg"
phx-click-away={hide_modal()}
phx-window-keydown={hide_modal()}
phx-key="escape"
>
<%= live_patch to: @return_to,
id: "close",
class:
"absolute top-8 right-10 text-gray-500 hover:text-gray-800 transition-all duration-500 ease-in-out",
phx_click: hide_modal() do %>
"absolute top-8 right-10
text-gray-500 hover:text-gray-800
transition-all duration-500 ease-in-out",
phx_remove: hide_modal() do %>
<i class="fa-fw fa-lg fas fa-times"></i>
<% end %>
<div class="w-full p-8 flex flex-col space-y-4 justify-start items-center">
<div class="overflow-x-hidden overflow-y-auto w-full p-8 flex flex-col space-y-4 justify-start items-center">
<%= render_slot(@inner_block) %>
</div>
</div>
@ -74,6 +85,7 @@ defmodule CanneryWeb.LiveHelpers do
def hide_modal(js \\ %JS{}) do
js
|> JS.hide(to: "#modal", transition: "fade-out")
|> JS.hide(to: "#modal-bg", transition: "fade-out")
|> JS.hide(to: "#modal-content", transition: "fade-out-scale")
end
end

View File

@ -25,7 +25,7 @@ defmodule CanneryWeb.RangeLive.Index do
%{"id" => id}
) do
socket
|> assign(:page_title, gettext("Record shots"))
|> assign(:page_title, gettext("Record Shots"))
|> assign(:ammo_group, Ammo.get_ammo_group!(id, current_user))
end
@ -77,6 +77,69 @@ defmodule CanneryWeb.RangeLive.Index do
ActivityLog.list_shot_groups(current_user) |> Repo.preload(ammo_group: :ammo_type)
ammo_groups = Ammo.list_staged_ammo_groups(current_user)
socket |> assign(shot_groups: shot_groups, ammo_groups: ammo_groups)
columns = [
%{label: gettext("Ammo"), key: "name"},
%{label: gettext("Rounds shot"), key: "count"},
%{label: gettext("Notes"), key: "notes"},
%{label: gettext("Date"), key: "date"},
%{label: nil, key: "actions", sortable: false}
]
rows =
shot_groups
|> Enum.map(fn shot_group -> shot_group |> get_row_data_for_shot_group(columns) end)
socket
|> assign(ammo_groups: ammo_groups, columns: columns, rows: rows, shot_groups: shot_groups)
end
@spec get_row_data_for_shot_group(ShotGroup.t(), [map()]) :: [map()]
defp get_row_data_for_shot_group(%{date: date} = shot_group, columns) do
shot_group = shot_group |> Repo.preload(ammo_group: :ammo_type)
assigns = %{shot_group: shot_group}
columns
|> Enum.into(%{}, fn %{key: key} ->
value =
case key do
"name" ->
{shot_group.ammo_group.ammo_type.name,
live_patch(shot_group.ammo_group.ammo_type.name,
to: Routes.ammo_group_show_path(Endpoint, :show, shot_group.ammo_group),
class: "link"
)}
"date" ->
date |> display_date()
"actions" ->
~H"""
<div class="px-4 py-2 space-x-4 flex justify-center items-center">
<%= live_patch to: Routes.range_index_path(Endpoint, :edit, shot_group),
class: "text-primary-600 link",
data: [qa: "edit-#{shot_group.id}"] do %>
<i class="fa-fw fa-lg fas fa-edit"></i>
<% end %>
<%= link to: "#",
class: "text-primary-600 link",
phx_click: "delete",
phx_value_id: shot_group.id,
data: [
confirm: dgettext("prompts", "Are you sure you want to delete this shot record?"),
qa: "delete-#{shot_group.id}"
] do %>
<i class="fa-fw fa-lg fas fa-trash"></i>
<% end %>
</div>
"""
key ->
shot_group |> Map.get(key |> String.to_existing_atom())
end
{key, value}
end)
end
end

View File

@ -53,70 +53,12 @@
<%= gettext("Shot log") %>
</h1>
<div class="w-full overflow-x-auto border border-gray-600 rounded-lg shadow-lg bg-black">
<table class="min-w-full table-auto text-center bg-white">
<thead class="border-b border-primary-600">
<tr>
<th class="p-2">
<%= gettext("Ammo") %>
</th>
<th class="p-2">
<%= gettext("Rounds shot") %>
</th>
<th class="p-2">
<%= gettext("Notes") %>
</th>
<th class="p-2">
<%= gettext("Date") %>
</th>
<th class="p-2"></th>
</tr>
</thead>
<tbody id="shot_groups">
<%= for shot_group <- @shot_groups do %>
<tr id={"shot_group-#{shot_group.id}"}>
<td class="p-2">
<%= live_patch(shot_group.ammo_group.ammo_type.name,
to: Routes.ammo_group_show_path(Endpoint, :show, shot_group.ammo_group),
class: "link"
) %>
</td>
<td class="p-2">
<%= shot_group.count %>
</td>
<td class="p-2">
<%= shot_group.notes %>
</td>
<td class="p-2">
<%= shot_group.date |> display_date() %>
</td>
<td class="p-2 w-full h-full space-x-2 flex justify-center items-center">
<div class="px-4 py-2 space-x-4 flex justify-center items-center">
<%= live_patch to: Routes.range_index_path(Endpoint, :edit, shot_group),
class: "text-primary-600 link",
data: [qa: "edit-#{shot_group.id}"] do %>
<i class="fa-fw fa-lg fas fa-edit"></i>
<% end %>
<%= link to: "#",
class: "text-primary-600 link",
phx_click: "delete",
phx_value_id: shot_group.id,
data: [
confirm: dgettext("prompts", "Are you sure you want to delete this shot record?"),
qa: "delete-#{shot_group.id}"
] do %>
<i class="fa-fw fa-lg fas fa-trash"></i>
<% end %>
</div>
</td>
</tr>
<% end %>
</tbody>
</table>
</div>
<.live_component
module={CanneryWeb.Components.TableComponent}
id="shot_groups_index_table"
columns={@columns}
rows={@rows}
/>
<% end %>
</div>

View File

@ -15,7 +15,7 @@ defmodule CanneryWeb.TagLive.Index do
@impl true
def handle_params(params, _url, %{assigns: %{live_action: live_action}} = socket) do
{:noreply, apply_action(socket, live_action, params)}
{:noreply, apply_action(socket, live_action, params) |> display_tags}
end
defp apply_action(%{assigns: %{current_user: current_user}} = socket, :edit, %{"id" => id}) do
@ -31,7 +31,7 @@ defmodule CanneryWeb.TagLive.Index do
end
defp apply_action(socket, :index, _params) do
socket |> assign(:page_title, gettext("Listing Tags")) |> assign(:tag, nil)
socket |> assign(:page_title, gettext("Tags")) |> assign(:tag, nil)
end
@impl true

View File

@ -11,6 +11,8 @@ defmodule CanneryWeb.Router do
plug :protect_from_forgery
plug :put_secure_browser_headers
plug :fetch_current_user
Gettext.put_locale(Application.get_env(:gettext, :default_locale, "en_US"))
end
pipeline :require_admin do
@ -80,6 +82,7 @@ defmodule CanneryWeb.Router do
live "/ammo_groups/:id/show/edit", AmmoGroupLive.Show, :edit
live "/ammo_groups/:id/show/add_shot_group", AmmoGroupLive.Show, :add_shot_group
live "/ammo_groups/:id/show/move", AmmoGroupLive.Show, :move
live "/ammo_groups/:id/show/:shot_group_id/edit", AmmoGroupLive.Show, :edit_shot_group
live "/range", RangeLive.Index, :index
live "/range/:id/edit", RangeLive.Index, :edit

View File

@ -8,7 +8,8 @@
<%= dgettext("errors", "Error") %>| Cannery
</title>
<link rel="stylesheet" href="/css/app.css" />
<script defer type="text/javascript" src="/js/app.js"></script>
<script defer type="text/javascript" src="/js/app.js">
</script>
</head>
<body class="pb-8 m-0 p-0 w-full h-full">
<header>
@ -16,9 +17,7 @@
</header>
<div class="pb-8 w-full flex flex-col justify-center items-center text-center">
<div
class="p-8 sm:p-16 w-full flex flex-col justify-center items-center space-y-4 max-w-3xl"
>
<div class="p-8 sm:p-16 w-full flex flex-col justify-center items-center space-y-4 max-w-3xl">
<h1 class="title text-primary-600 text-3xl">
<%= @error_string %>
</h1>

View File

@ -4,14 +4,10 @@
<%= @email.subject %>
</title>
</head>
<body
style="padding: 2em; color: rgb(31, 31, 31); background-color: rgb(220, 220, 228); font-family: 'Lucida Sans', 'Lucida Sans Regular', 'Lucida Grande', 'Lucida Sans Unicode', Geneva, Verdana, sans-serif; text-align: center;"
>
<body style="padding: 2em; color: rgb(31, 31, 31); background-color: rgb(220, 220, 228); font-family: 'Lucida Sans', 'Lucida Sans Regular', 'Lucida Grande', 'Lucida Sans Unicode', Geneva, Verdana, sans-serif; text-align: center;">
<%= @inner_content %>
<hr
style="margin: 2em auto; border-width: 1px; border-color: rgb(212, 212, 216); width: 100%; max-width: 42rem;"
/>
<hr style="margin: 2em auto; border-width: 1px; border-color: rgb(212, 212, 216); width: 100%; max-width: 42rem;" />
<a style="color: rgb(31, 31, 31);" href={Routes.live_url(Endpoint, HomeLive)}>
<%= dgettext(

View File

@ -29,7 +29,7 @@
<div
id="loading"
class="absolute opacity-0 top-0 left-0 w-screen h-screen bg-white z-50
class="fixed opacity-0 top-0 left-0 w-screen h-screen bg-white z-50
flex flex-col justify-center items-center space-y-4
transition-opacity ease-in-out duration-500"
>
@ -42,7 +42,7 @@
<div
id="disconnect"
class="absolute opacity-0 top-0 left-0 w-screen h-screen bg-white z-50
class="fixed opacity-0 top-0 left-0 w-screen h-screen bg-white z-50
flex flex-col justify-center items-center space-y-4
transition-opacity ease-in-out duration-500"
>

View File

@ -1,15 +1,12 @@
<!DOCTYPE html>
<html lang="en" class="m-0 p-0 w-full h-full">
<html lang="en" class="m-0 p-0 w-full h-full bg-white">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<%= csrf_meta_tag() %>
<%= if(assigns |> Map.has_key?(:page_title),
do: "#{assigns.page_title} | Cannery",
else: "Cannery"
)
|> live_title_tag(suffix: "") %>
<%= if(assigns |> Map.has_key?(:page_title), do: @page_title, else: "Cannery")
|> live_title_tag(suffix: " | Cannery") %>
<link phx-track-static rel="stylesheet" href={Routes.static_path(@conn, "/css/app.css")} />
<script
defer
@ -20,7 +17,7 @@
</script>
</head>
<body class="m-0 p-0 w-full h-full">
<body class="m-0 p-0 w-full h-full bg-white">
<%= @inner_content %>
</body>
</html>

View File

@ -2,7 +2,6 @@ defmodule CanneryWeb.EmailView do
@moduledoc """
A view for email-related helper functions
"""
alias CanneryWeb.{Endpoint, HomeLive}
use CanneryWeb, :view
alias CanneryWeb.{Endpoint, HomeLive}
end

View File

@ -8,7 +8,7 @@ defmodule CanneryWeb.ErrorView do
case error_path do
"404.html" -> dgettext("errors", "Not found")
"401.html" -> dgettext("errors", "Unauthorized")
_ -> dgettext("errors", "Internal Server Error")
_other_template -> dgettext("errors", "Internal Server Error")
end
render("error.html", %{error_string: error_string})

View File

@ -7,6 +7,8 @@ defmodule CanneryWeb.ViewHelpers do
import Phoenix.LiveView.Helpers
@id_length 16
@doc """
Returns a <time> element that renders the naivedatetime in the user's local
timezone with Alpine.js
@ -16,11 +18,12 @@ defmodule CanneryWeb.ViewHelpers do
def display_datetime(datetime) do
assigns = %{
id: :crypto.strong_rand_bytes(@id_length) |> Base.url_encode64(),
datetime: datetime |> DateTime.from_naive!("Etc/UTC") |> DateTime.to_iso8601(:extended)
}
~H"""
<time datetime={@datetime} x-data={"{
<time id={@id} datetime={@datetime} x-data={"{
date:
Intl.DateTimeFormat([], {dateStyle: 'short', timeStyle: 'long'})
.format(new Date(\"#{@datetime}\"))
@ -38,10 +41,13 @@ defmodule CanneryWeb.ViewHelpers do
def display_date(nil), do: ""
def display_date(date) do
assigns = %{date: date |> Date.to_iso8601(:extended)}
assigns = %{
id: :crypto.strong_rand_bytes(@id_length) |> Base.url_encode64(),
date: date |> Date.to_iso8601(:extended)
}
~H"""
<time datetime={@date} x-data={"{
<time id={@id} datetime={@date} x-data={"{
date:
Intl.DateTimeFormat([], {timeZone: 'Etc/UTC', dateStyle: 'short'}).format(new Date(\"#{@date}\"))
}"} x-text="date">

13
mix.exs
View File

@ -4,8 +4,8 @@ defmodule Cannery.MixProject do
def project do
[
app: :cannery,
version: "0.2.1",
elixir: "~> 1.12",
version: "0.5.0",
elixir: "1.13.4",
elixirc_paths: elixirc_paths(Mix.env()),
compilers: [:gettext] ++ Mix.compilers(),
start_permanent: Mix.env() == :prod,
@ -49,14 +49,14 @@ defmodule Cannery.MixProject do
{:bcrypt_elixir, "~> 2.0"},
{:phoenix, "~> 1.6"},
{:phoenix_ecto, "~> 4.4"},
{:ecto_sql, "~> 3.6"},
{:postgrex, ">= 0.0.0"},
{:phoenix_html, "~> 3.0"},
{:phoenix_live_reload, "~> 1.2", only: :dev},
{:phoenix_live_view, "~> 0.17"},
{:phoenix_view, "~> 1.1"},
{:floki, ">= 0.30.0", only: :test},
{:phoenix_live_dashboard, "~> 0.6"},
{:ecto_sql, "~> 3.6"},
{:postgrex, ">= 0.0.0"},
{:floki, ">= 0.30.0", only: :test},
# {:esbuild, "~> 0.3", runtime: Mix.env() == :dev},
{:ex_doc, "~> 0.27", only: :dev, runtime: false},
{:swoosh, "~> 1.6"},
@ -70,8 +70,7 @@ defmodule Cannery.MixProject do
{:plug_cowboy, "~> 2.5"},
{:ecto_psql_extras, "~> 0.6"},
{:credo, "~> 1.5", only: [:dev, :test], runtime: false},
{:dialyxir, "~> 1.0", only: [:dev, :test], runtime: false},
{:heex_formatter, github: "feliperenan/heex_formatter"}
{:dialyxir, "~> 1.0", only: [:dev, :test], runtime: false}
]
end

View File

@ -7,49 +7,50 @@
"cowboy": {:hex, :cowboy, "2.9.0", "865dd8b6607e14cf03282e10e934023a1bd8be6f6bacf921a7e2a96d800cd452", [:make, :rebar3], [{:cowlib, "2.11.0", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "1.8.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "2c729f934b4e1aa149aff882f57c6372c15399a20d54f65c8d67bef583021bde"},
"cowboy_telemetry": {:hex, :cowboy_telemetry, "0.4.0", "f239f68b588efa7707abce16a84d0d2acf3a0f50571f8bb7f56a15865aae820c", [:rebar3], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7d98bac1ee4565d31b62d59f8823dfd8356a169e7fcbb83831b8a5397404c9de"},
"cowlib": {:hex, :cowlib, "2.11.0", "0b9ff9c346629256c42ebe1eeb769a83c6cb771a6ee5960bd110ab0b9b872063", [:make, :rebar3], [], "hexpm", "2b3e9da0b21c4565751a6d4901c20d1b4cc25cbb7fd50d91d2ab6dd287bc86a9"},
"credo": {:hex, :credo, "1.6.3", "0a9f8925dbc8f940031b789f4623fc9a0eea99d3eed600fe831e403eb96c6a83", [:mix], [{:bunt, "~> 0.2.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2.8", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "1167cde00e6661d740fc54da2ee268e35d3982f027399b64d3e2e83af57a1180"},
"db_connection": {:hex, :db_connection, "2.4.1", "6411f6e23f1a8b68a82fa3a36366d4881f21f47fc79a9efb8c615e62050219da", [:mix], [{:connection, "~> 1.0", [hex: :connection, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "ea36d226ec5999781a9a8ad64e5d8c4454ecedc7a4d643e4832bf08efca01f00"},
"credo": {:hex, :credo, "1.6.4", "ddd474afb6e8c240313f3a7b0d025cc3213f0d171879429bf8535d7021d9ad78", [:mix], [{:bunt, "~> 0.2.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2.8", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "c28f910b61e1ff829bffa056ef7293a8db50e87f2c57a9b5c3f57eee124536b7"},
"db_connection": {:hex, :db_connection, "2.4.2", "f92e79aff2375299a16bcb069a14ee8615c3414863a6fef93156aee8e86c2ff3", [:mix], [{:connection, "~> 1.0", [hex: :connection, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "4fe53ca91b99f55ea249693a0229356a08f4d1a7931d8ffa79289b145fe83668"},
"decimal": {:hex, :decimal, "2.0.0", "a78296e617b0f5dd4c6caf57c714431347912ffb1d0842e998e9792b5642d697", [:mix], [], "hexpm", "34666e9c55dea81013e77d9d87370fe6cb6291d1ef32f46a1600230b1d44f577"},
"dialyxir": {:hex, :dialyxir, "1.1.0", "c5aab0d6e71e5522e77beff7ba9e08f8e02bad90dfbeffae60eaf0cb47e29488", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "07ea8e49c45f15264ebe6d5b93799d4dd56a44036cf42d0ad9c960bc266c0b9a"},
"earmark_parser": {:hex, :earmark_parser, "1.4.19", "de0d033d5ff9fc396a24eadc2fcf2afa3d120841eb3f1004d138cbf9273210e8", [:mix], [], "hexpm", "527ab6630b5c75c3a3960b75844c314ec305c76d9899bb30f71cb85952a9dc45"},
"ecto": {:hex, :ecto, "3.7.1", "a20598862351b29f80f285b21ec5297da1181c0442687f9b8329f0445d228892", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "d36e5b39fc479e654cffd4dbe1865d9716e4a9b6311faff799b6f90ab81b8638"},
"earmark_parser": {:hex, :earmark_parser, "1.4.25", "2024618731c55ebfcc5439d756852ec4e85978a39d0d58593763924d9a15916f", [:mix], [], "hexpm", "56749c5e1c59447f7b7a23ddb235e4b3defe276afc220a6227237f3efe83f51e"},
"ecto": {:hex, :ecto, "3.7.2", "44c034f88e1980754983cc4400585970b4206841f6f3780967a65a9150ef09a8", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "a600da5772d1c31abbf06f3e4a1ffb150e74ed3e2aa92ff3cee95901657a874e"},
"ecto_psql_extras": {:hex, :ecto_psql_extras, "0.7.4", "5d43fd088d39a158c860b17e8d210669587f63ec89ea122a4654861c8c6e2db4", [:mix], [{:ecto_sql, "~> 3.4", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:postgrex, ">= 0.15.7", [hex: :postgrex, repo: "hexpm", optional: false]}, {:table_rex, "~> 3.1.1", [hex: :table_rex, repo: "hexpm", optional: false]}], "hexpm", "311db02f1b772e3d0dc7f56a05044b5e1499d78ed6abf38885e1ca70059449e5"},
"ecto_sql": {:hex, :ecto_sql, "3.7.2", "55c60aa3a06168912abf145c6df38b0295c34118c3624cf7a6977cd6ce043081", [:mix], [{:db_connection, "~> 2.2", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.7.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.4.0 or ~> 0.5.0 or ~> 0.6.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.15.0 or ~> 0.16.0 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "3c218ea62f305dcaef0b915fb56583195e7b91c91dcfb006ba1f669bfacbff2a"},
"elixir_make": {:hex, :elixir_make, "0.6.3", "bc07d53221216838d79e03a8019d0839786703129599e9619f4ab74c8c096eac", [:mix], [], "hexpm", "f5cbd651c5678bcaabdbb7857658ee106b12509cd976c2c2fca99688e1daf716"},
"erlex": {:hex, :erlex, "0.2.6", "c7987d15e899c7a2f34f5420d2a2ea0d659682c06ac607572df55a43753aa12e", [:mix], [], "hexpm", "2ed2e25711feb44d52b17d2780eabf998452f6efda104877a3881c2f8c0c0c75"},
"esbuild": {:hex, :esbuild, "0.4.0", "9f17db148aead4cf1e6e6a584214357287a93407b5fb51a031f122b61385d4c2", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}], "hexpm", "b61e4e6b92ffe45e4ee4755a22de6211a67c67987dc02afb35a425a0add1d447"},
"ex_doc": {:hex, :ex_doc, "0.28.0", "7eaf526dd8c80ae8c04d52ac8801594426ae322b52a6156cd038f30bafa8226f", [:mix], [{:earmark_parser, "~> 1.4.19", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "e55cdadf69a5d1f4cfd8477122ebac5e1fadd433a8c1022dafc5025e48db0131"},
"ex_doc": {:hex, :ex_doc, "0.28.3", "6eea2f69995f5fba94cd6dd398df369fe4e777a47cd887714a0976930615c9e6", [:mix], [{:earmark_parser, "~> 1.4.19", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "05387a6a2655b5f9820f3f627450ed20b4325c25977b2ee69bed90af6688e718"},
"file_system": {:hex, :file_system, "0.2.10", "fb082005a9cd1711c05b5248710f8826b02d7d1784e7c3451f9c1231d4fc162d", [:mix], [], "hexpm", "41195edbfb562a593726eda3b3e8b103a309b733ad25f3d642ba49696bf715dc"},
"floki": {:hex, :floki, "0.32.0", "f915dc15258bc997d49be1f5ef7d3992f8834d6f5695270acad17b41f5bcc8e2", [:mix], [{:html_entities, "~> 0.5.0", [hex: :html_entities, repo: "hexpm", optional: false]}], "hexpm", "1c5a91cae1fd8931c26a4826b5e2372c284813904c8bacb468b5de39c7ececbd"},
"gen_smtp": {:hex, :gen_smtp, "1.1.1", "bf9303c31735100631b1d708d629e4c65944319d1143b5c9952054f4a1311d85", [:rebar3], [{:hut, "1.3.0", [hex: :hut, repo: "hexpm", optional: false]}, {:ranch, ">= 1.7.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "51bc50cc017efd4a4248cbc39ea30fb60efa7d4a49688986fafad84434ff9ab7"},
"floki": {:hex, :floki, "0.32.1", "dfe3b8db3b793939c264e6f785bca01753d17318d144bd44b407fb3493acaa87", [:mix], [{:html_entities, "~> 0.5.0", [hex: :html_entities, repo: "hexpm", optional: false]}], "hexpm", "d4b91c713e4a784a3f7b1e3cc016eefc619f6b1c3898464222867cafd3c681a3"},
"gen_smtp": {:hex, :gen_smtp, "1.2.0", "9cfc75c72a8821588b9b9fe947ae5ab2aed95a052b81237e0928633a13276fd3", [:rebar3], [{:ranch, ">= 1.8.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "5ee0375680bca8f20c4d85f58c2894441443a743355430ff33a783fe03296779"},
"gettext": {:hex, :gettext, "0.19.1", "564953fd21f29358e68b91634799d9d26989f8d039d7512622efb3c3b1c97892", [:mix], [], "hexpm", "10c656c0912b8299adba9b061c06947511e3f109ab0d18b44a866a4498e77222"},
"heex_formatter": {:git, "https://github.com/feliperenan/heex_formatter.git", "dfefc9ae267fb0874c287ceb6c47dda106c59552", []},
"html_entities": {:hex, :html_entities, "0.5.2", "9e47e70598da7de2a9ff6af8758399251db6dbb7eebe2b013f2bbd2515895c3c", [:mix], [], "hexpm", "c53ba390403485615623b9531e97696f076ed415e8d8058b1dbaa28181f4fdcc"},
"hut": {:hex, :hut, "1.3.0", "71f2f054e657c03f959cf1acc43f436ea87580696528ca2a55c8afb1b06c85e7", [:"erlang.mk", :rebar, :rebar3], [], "hexpm", "7e15d28555d8a1f2b5a3a931ec120af0753e4853a4c66053db354f35bf9ab563"},
"jason": {:hex, :jason, "1.3.0", "fa6b82a934feb176263ad2df0dbd91bf633d4a46ebfdffea0c8ae82953714946", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "53fc1f51255390e0ec7e50f9cb41e751c260d065dcba2bf0d08dc51a4002c2ac"},
"makeup": {:hex, :makeup, "1.1.0", "6b67c8bc2882a6b6a445859952a602afc1a41c2e08379ca057c0f525366fc3ca", [:mix], [{:nimble_parsec, "~> 1.2.2 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "0a45ed501f4a8897f580eabf99a2e5234ea3e75a4373c8a52824f6e873be57a6"},
"makeup_elixir": {:hex, :makeup_elixir, "0.15.2", "dc72dfe17eb240552857465cc00cce390960d9a0c055c4ccd38b70629227e97c", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.1", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "fd23ae48d09b32eff49d4ced2b43c9f086d402ee4fd4fcb2d7fad97fa8823e75"},
"makeup_elixir": {:hex, :makeup_elixir, "0.16.0", "f8c570a0d33f8039513fbccaf7108c5d750f47d8defd44088371191b76492b0b", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "28b2cbdc13960a46ae9a8858c4bebdec3c9a6d7b4b9e7f4ed1502f8159f338e7"},
"makeup_erlang": {:hex, :makeup_erlang, "0.1.1", "3fcb7f09eb9d98dc4d208f49cc955a34218fc41ff6b84df7c75b3e6e533cc65f", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "174d0809e98a4ef0b3309256cbf97101c6ec01c4ab0b23e926a9e17df2077cbb"},
"mime": {:hex, :mime, "2.0.2", "0b9e1a4c840eafb68d820b0e2158ef5c49385d17fb36855ac6e7e087d4b1dcc5", [:mix], [], "hexpm", "e6a3f76b4c277739e36c2e21a2c640778ba4c3846189d5ab19f97f126df5f9b7"},
"nimble_parsec": {:hex, :nimble_parsec, "1.2.2", "b99ca56bbce410e9d5ee4f9155a212e942e224e259c7ebbf8f2c86ac21d4fa3c", [:mix], [], "hexpm", "98d51bd64d5f6a2a9c6bb7586ee8129e27dfaab1140b5a4753f24dac0ba27d2f"},
"oban": {:hex, :oban, "2.11.0", "5cc4800829b995bfa1c3841d8b0c1037b4a6444b2a76896edd2215c4c4d047a8", [:mix], [{:ecto_sql, "~> 3.6", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.16", [hex: :postgrex, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "4ec90805d04562e83cc798f3ecd514d24f4479a14883e1e8973d5123ec087e35"},
"phoenix": {:hex, :phoenix, "1.6.6", "281c8ce8dccc9f60607346b72cdfc597c3dde134dd9df28dff08282f0b751754", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.0", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 1.0", [hex: :phoenix_view, repo: "hexpm", optional: false]}, {:plug, "~> 1.10", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.2", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "807bd646e64cd9dc83db016199715faba72758e6db1de0707eef0a2da4924364"},
"nimble_parsec": {:hex, :nimble_parsec, "1.2.3", "244836e6e3f1200c7f30cb56733fd808744eca61fd182f731eac4af635cc6d0b", [:mix], [], "hexpm", "c8d789e39b9131acf7b99291e93dae60ab48ef14a7ee9d58c6964f59efb570b0"},
"oban": {:hex, :oban, "2.11.3", "f431f2f0c251b8490a7fa00d2cce7197a1cf4d3f04a3305e80411f083392998f", [:mix], [{:ecto_sql, "~> 3.6", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.16", [hex: :postgrex, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "26529da52bfca27740c984bfc70e7f954d6411ceeae0c7c94d2c8aa7c00b513d"},
"phoenix": {:hex, :phoenix, "1.6.7", "f1de32418bbbcd471f4fe74d3860ee9c8e8c6c36a0ec173be8ff468a5d72ac90", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.0", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 1.0", [hex: :phoenix_view, repo: "hexpm", optional: false]}, {:plug, "~> 1.10", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.2", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "b354a4f11d9a2f3a380fb731042dae064f22d7aed8c7e7c024a2459f12994aad"},
"phoenix_ecto": {:hex, :phoenix_ecto, "4.4.0", "0672ed4e4808b3fbed494dded89958e22fb882de47a97634c0b13e7b0b5f7720", [:mix], [{:ecto, "~> 3.3", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "09864e558ed31ee00bd48fcc1d4fc58ae9678c9e81649075431e69dbabb43cc1"},
"phoenix_html": {:hex, :phoenix_html, "3.2.0", "1c1219d4b6cb22ac72f12f73dc5fad6c7563104d083f711c3fcd8551a1f4ae11", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "36ec97ba56d25c0136ef1992c37957e4246b649d620958a1f9fa86165f8bc54f"},
"phoenix_live_dashboard": {:hex, :phoenix_live_dashboard, "0.6.4", "d7ff34b2c8dd5fa950748496697da01ae1b6b259891ce1103e300bdc7abfbb99", [:mix], [{:ecto, "~> 3.6.2 or ~> 3.7", [hex: :ecto, repo: "hexpm", optional: true]}, {:ecto_mysql_extras, "~> 0.3", [hex: :ecto_mysql_extras, repo: "hexpm", optional: true]}, {:ecto_psql_extras, "~> 0.7", [hex: :ecto_psql_extras, repo: "hexpm", optional: true]}, {:mime, "~> 1.6 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:phoenix_live_view, "~> 0.17.1", [hex: :phoenix_live_view, repo: "hexpm", optional: false]}, {:telemetry_metrics, "~> 0.6.0", [hex: :telemetry_metrics, repo: "hexpm", optional: false]}], "hexpm", "ce2505256ab459663258ecba4158af130e6b7a5b85783fe442541fbb1236e1b2"},
"phoenix_live_dashboard": {:hex, :phoenix_live_dashboard, "0.6.5", "1495bb014be12c9a9252eca04b9af54246f6b5c1e4cd1f30210cd00ec540cf8e", [:mix], [{:ecto, "~> 3.6.2 or ~> 3.7", [hex: :ecto, repo: "hexpm", optional: true]}, {:ecto_mysql_extras, "~> 0.3", [hex: :ecto_mysql_extras, repo: "hexpm", optional: true]}, {:ecto_psql_extras, "~> 0.7", [hex: :ecto_psql_extras, repo: "hexpm", optional: true]}, {:mime, "~> 1.6 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:phoenix_live_view, "~> 0.17.7", [hex: :phoenix_live_view, repo: "hexpm", optional: false]}, {:telemetry_metrics, "~> 0.6.0", [hex: :telemetry_metrics, repo: "hexpm", optional: false]}], "hexpm", "ef4fa50dd78364409039c99cf6f98ab5209b4c5f8796c17f4db118324f0db852"},
"phoenix_live_reload": {:hex, :phoenix_live_reload, "1.3.3", "3a53772a6118d5679bf50fc1670505a290e32a1d195df9e069d8c53ab040c054", [:mix], [{:file_system, "~> 0.2.1 or ~> 0.3", [hex: :file_system, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.4", [hex: :phoenix, repo: "hexpm", optional: false]}], "hexpm", "766796676e5f558dbae5d1bdb066849673e956005e3730dfd5affd7a6da4abac"},
"phoenix_live_view": {:hex, :phoenix_live_view, "0.17.7", "05a42377075868a678d446361effba80cefef19ab98941c01a7a4c7560b29121", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.5.9 or ~> 1.6.0", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 3.1", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "25eaf41028eb351b90d4f69671874643a09944098fefd0d01d442f40a6091b6f"},
"phoenix_pubsub": {:hex, :phoenix_pubsub, "2.0.0", "a1ae76717bb168cdeb10ec9d92d1480fec99e3080f011402c0a2d68d47395ffb", [:mix], [], "hexpm", "c52d948c4f261577b9c6fa804be91884b381a7f8f18450c5045975435350f771"},
"phoenix_live_view": {:hex, :phoenix_live_view, "0.17.9", "36b5aa812bc3ccd64c9630f6b3234d9ea21105493237e927aae19d0ba758f0db", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.6.0", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 3.1", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "f7ebc3e0ba0c5f6b6996ed6c901ddbfdaba59a6d09b569e7cb2f2f7d693b4455"},
"phoenix_pubsub": {:hex, :phoenix_pubsub, "2.1.1", "ba04e489ef03763bf28a17eb2eaddc2c20c6d217e2150a61e3298b0f4c2012b5", [:mix], [], "hexpm", "81367c6d1eea5878ad726be80808eb5a787a23dee699f96e72b1109c57cdd8d9"},
"phoenix_swoosh": {:hex, :phoenix_swoosh, "1.0.1", "0db6eb6405a6b06cae4fdf4144659b3f4fee4553e2856fe8a53ba12e9fb21a74", [:mix], [{:finch, "~> 0.8", [hex: :finch, repo: "hexpm", optional: true]}, {:hackney, "~> 1.10", [hex: :hackney, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.6", [hex: :phoenix, repo: "hexpm", optional: true]}, {:phoenix_html, "~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:phoenix_view, "~> 1.0", [hex: :phoenix_view, repo: "hexpm", optional: false]}, {:swoosh, "~> 1.5", [hex: :swoosh, repo: "hexpm", optional: false]}], "hexpm", "e34890004baec08f0fa12bd8c77bf64bfb4156b84a07fb79da9322fa94bc3781"},
"phoenix_view": {:hex, :phoenix_view, "1.1.2", "1b82764a065fb41051637872c7bd07ed2fdb6f5c3bd89684d4dca6e10115c95a", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}], "hexpm", "7ae90ad27b09091266f6adbb61e1d2516a7c3d7062c6789d46a7554ec40f3a56"},
"plug": {:hex, :plug, "1.13.3", "93b299039c21a8b82cc904d13812bce4ced45cf69153e8d35ca16ffb3e8c5d98", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "98c8003e4faf7b74a9ac41bee99e328b08f069bf932747d4a7532e97ae837a17"},
"plug": {:hex, :plug, "1.13.6", "187beb6b67c6cec50503e940f0434ea4692b19384d47e5fdfd701e93cadb4cc2", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "02b9c6b9955bce92c829f31d6284bf53c591ca63c4fb9ff81dfd0418667a34ff"},
"plug_cowboy": {:hex, :plug_cowboy, "2.5.2", "62894ccd601cf9597e2c23911ff12798a8a18d237e9739f58a6b04e4988899fe", [:mix], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:cowboy_telemetry, "~> 0.3", [hex: :cowboy_telemetry, repo: "hexpm", optional: false]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "ea6e87f774c8608d60c8d34022a7d073bd7680a0a013f049fc62bf35efea1044"},
"plug_crypto": {:hex, :plug_crypto, "1.2.2", "05654514ac717ff3a1843204b424477d9e60c143406aa94daf2274fdd280794d", [:mix], [], "hexpm", "87631c7ad914a5a445f0a3809f99b079113ae4ed4b867348dd9eec288cecb6db"},
"postgrex": {:hex, :postgrex, "0.16.1", "f94628a32c571266f53cd1e5fca705e626e2417bf1eee6f868985d14e874160a", [:mix], [{:connection, "~> 1.1", [hex: :connection, repo: "hexpm", optional: false]}, {:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "6b225df32c857b9430619dbe30200a7ae664e23415a771ae9209396ee8eeee64"},
"postgrex": {:hex, :postgrex, "0.16.2", "0f83198d0e73a36e8d716b90f45f3bde75b5eebf4ade4f43fa1f88c90a812f74", [:mix], [{:connection, "~> 1.1", [hex: :connection, repo: "hexpm", optional: false]}, {:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "a9ea589754d9d4d076121090662b7afe155b374897a6550eb288f11d755acfa0"},
"ranch": {:hex, :ranch, "1.8.0", "8c7a100a139fd57f17327b6413e4167ac559fbc04ca7448e9be9057311597a1d", [:make, :rebar3], [], "hexpm", "49fbcfd3682fab1f5d109351b61257676da1a2fdbe295904176d5e521a2ddfe5"},
"swoosh": {:hex, :swoosh, "1.6.3", "598d3f07641004bedb3eede40057760ae18be1073cff72f079ca1e1fc9cd97b9", [:mix], [{:cowboy, "~> 1.1 or ~> 2.4", [hex: :cowboy, repo: "hexpm", optional: true]}, {:finch, "~> 0.6", [hex: :finch, repo: "hexpm", optional: true]}, {:gen_smtp, "~> 0.13 or ~> 1.0", [hex: :gen_smtp, repo: "hexpm", optional: true]}, {:hackney, "~> 1.9", [hex: :hackney, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mail, "~> 0.2", [hex: :mail, repo: "hexpm", optional: true]}, {:mime, "~> 1.1 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_cowboy, ">= 1.0.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "81ff9d7c7c4005a57465a7eb712edd71db51829aef94c8a34c30c5b9e9964adf"},
"set_locale": {:hex, :set_locale, "0.2.9", "33350ba3c66f1c560dffc43019eea4b573f91c5cbe3e461fe0e5395d2d6ba2c3", [:mix], [{:gettext, "~>0.14", [hex: :gettext, repo: "hexpm", optional: false]}, {:phoenix, ">1.3.0", [hex: :phoenix, repo: "hexpm", optional: false]}], "hexpm", "e46348b64b7c5d725d0c90a6524942a19b65e6ce27372ddf9a727dfb64ba236c"},
"swoosh": {:hex, :swoosh, "1.6.4", "ce3a4bf3e5276fd114178ebc5ed072ee0c177a7b3a09e5992aa005778ac143c2", [:mix], [{:cowboy, "~> 1.1 or ~> 2.4", [hex: :cowboy, repo: "hexpm", optional: true]}, {:finch, "~> 0.6", [hex: :finch, repo: "hexpm", optional: true]}, {:gen_smtp, "~> 0.13 or ~> 1.0", [hex: :gen_smtp, repo: "hexpm", optional: true]}, {:hackney, "~> 1.9", [hex: :hackney, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mail, "~> 0.2", [hex: :mail, repo: "hexpm", optional: true]}, {:mime, "~> 1.1 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_cowboy, ">= 1.0.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "ad4c8b534812433730b6241a1d9df38b1da75fdfa340f51887a31d7e9343fffe"},
"table_rex": {:hex, :table_rex, "3.1.1", "0c67164d1714b5e806d5067c1e96ff098ba7ae79413cc075973e17c38a587caa", [:mix], [], "hexpm", "678a23aba4d670419c23c17790f9dcd635a4a89022040df7d5d772cb21012490"},
"telemetry": {:hex, :telemetry, "1.0.0", "0f453a102cdf13d506b7c0ab158324c337c41f1cc7548f0bc0e130bbf0ae9452", [:rebar3], [], "hexpm", "73bc09fa59b4a0284efb4624335583c528e07ec9ae76aca96ea0673850aec57a"},
"telemetry": {:hex, :telemetry, "1.1.0", "a589817034a27eab11144ad24d5c0f9fab1f58173274b1e9bae7074af9cbee51", [:rebar3], [], "hexpm", "b727b2a1f75614774cff2d7565b64d0dfa5bd52ba517f16543e6fc7efcc0df48"},
"telemetry_metrics": {:hex, :telemetry_metrics, "0.6.1", "315d9163a1d4660aedc3fee73f33f1d355dcc76c5c3ab3d59e76e3edf80eef1f", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7be9e0871c41732c233be71e4be11b96e56177bf15dde64a8ac9ce72ac9834c6"},
"telemetry_poller": {:hex, :telemetry_poller, "1.0.0", "db91bb424e07f2bb6e73926fcafbfcbcb295f0193e0a00e825e589a0a47e8453", [:rebar3], [{:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "b3a24eafd66c3f42da30fc3ca7dda1e9d546c12250a2d60d7b81d264fbec4f6e"},
}

View File

@ -11,12 +11,12 @@ msgid ""
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_group_live/index.ex:42
#: lib/cannery_web/live/ammo_group_live/index.ex:44
msgid "Add Ammo"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_group_live/index.html.heex:12
#: lib/cannery_web/live/ammo_group_live/index.html.heex:24
msgid "Add your first box!"
msgstr ""
@ -65,7 +65,7 @@ msgid "Invite someone new!"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/components/topbar.ex:108
#: lib/cannery_web/components/topbar.ex:106
#: lib/cannery_web/templates/user_confirmation/new.html.heex:30
#: lib/cannery_web/templates/user_registration/new.html.heex:39
#: lib/cannery_web/templates/user_reset_password/edit.html.heex:48
@ -81,7 +81,7 @@ msgid "Make your first tag!"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_group_live/index.html.heex:17
#: lib/cannery_web/live/ammo_group_live/index.html.heex:42
msgid "New Ammo group"
msgstr ""
@ -101,7 +101,7 @@ msgid "New Tag"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/components/topbar.ex:101
#: lib/cannery_web/components/topbar.ex:99
#: lib/cannery_web/templates/user_confirmation/new.html.heex:25
#: lib/cannery_web/templates/user_registration/new.html.heex:3
#: lib/cannery_web/templates/user_registration/new.html.heex:33
@ -124,9 +124,9 @@ msgid "Reset password"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/components/add_shot_group_component.html.heex:42
#: lib/cannery_web/live/ammo_group_live/form_component.html.heex:54
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:172
#: lib/cannery_web/components/add_shot_group_component.html.heex:46
#: lib/cannery_web/live/ammo_group_live/form_component.html.heex:73
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:156
#: lib/cannery_web/live/container_live/form_component.html.heex:50
#: lib/cannery_web/live/invite_live/form_component.html.heex:28
#: lib/cannery_web/live/range_live/form_component.html.heex:40
@ -160,7 +160,7 @@ msgid "Why not get some ready to shoot?"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_group_live/index.html.heex:85
#: lib/cannery_web/live/ammo_group_live/index.ex:134
#: lib/cannery_web/live/ammo_group_live/show.html.heex:86
#: lib/cannery_web/live/range_live/index.html.heex:36
msgid "Record shots"
@ -172,7 +172,7 @@ msgid "Ammo Details"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/components/move_ammo_group_component.html.heex:12
#: lib/cannery_web/components/move_ammo_group_component.ex:89
msgid "Add another container!"
msgstr ""
@ -182,7 +182,7 @@ msgid "Move containers"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/components/move_ammo_group_component.html.heex:60
#: lib/cannery_web/components/move_ammo_group_component.ex:127
msgid "Select"
msgstr ""
@ -190,3 +190,14 @@ msgstr ""
#: lib/cannery_web/live/invite_live/index.html.heex:33
msgid "Copy to clipboard"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_group_live/index.html.heex:18
#: lib/cannery_web/live/ammo_group_live/index.html.heex:36
msgid "add a container first"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_group_live/form_component.html.heex:66
msgid "Create"
msgstr ""

View File

@ -0,0 +1,216 @@
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-04-19 19:32+0000\n"
"PO-Revision-Date: 2022-04-19 21:32+0000\n"
"Last-Translator: shibao <shibao@bubbletea.dev>\n"
"Language-Team: German <https://weblate.bubbletea.dev/projects/cannery/"
"actions/de/>\n"
"Language: de\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 4.11.2\n"
## This file is a PO Template file.
##
## "msgid"s here are often extracted from source code.
## Add new translations manually only if they're dynamic
## translations that can't be statically extracted.
##
## Run "mix gettext.extract" to bring this file up to
## date. Leave "msgstr"s empty as changing them here has no
## effect: edit them in PO (.po) files instead.
#: lib/cannery_web/live/ammo_group_live/index.ex:44
#, elixir-autogen, elixir-format
msgid "Add Ammo"
msgstr "Munition hinzufügen"
#: lib/cannery_web/live/ammo_group_live/index.html.heex:24
#, elixir-autogen, elixir-format
msgid "Add your first box!"
msgstr "Fügen Sie ihre erste Box hinzu!"
#: lib/cannery_web/live/container_live/index.html.heex:12
#, elixir-autogen, elixir-format
msgid "Add your first container!"
msgstr "Fügen Sie ihren ersten Behälter hinzu!"
#: lib/cannery_web/live/ammo_type_live/index.html.heex:12
#, elixir-autogen, elixir-format
msgid "Add your first type!"
msgstr "Fügen Sie ihre erste Munitionsart hinzu!"
#: lib/cannery_web/templates/user_settings/edit.html.heex:16
#: lib/cannery_web/templates/user_settings/edit.html.heex:45
#, elixir-autogen, elixir-format
msgid "Change email"
msgstr "Mailadresse ändern"
#: lib/cannery_web/templates/user_settings/edit.html.heex:60
#: lib/cannery_web/templates/user_settings/edit.html.heex:101
#, elixir-autogen, elixir-format
msgid "Change password"
msgstr "Passwort ändern"
#: lib/cannery_web/live/invite_live/index.html.heex:17
#, elixir-autogen, elixir-format
msgid "Create Invite"
msgstr "Einladung erstellen"
#: lib/cannery_web/templates/user_settings/edit.html.heex:108
#, elixir-autogen, elixir-format
msgid "Delete User"
msgstr "Benutzer löschen"
#: lib/cannery_web/templates/user_registration/new.html.heex:43
#: lib/cannery_web/templates/user_reset_password/new.html.heex:3
#: lib/cannery_web/templates/user_session/new.html.heex:45
#, elixir-autogen, elixir-format
msgid "Forgot your password?"
msgstr "Passwort vergessen?"
#: lib/cannery_web/live/invite_live/index.html.heex:12
#, elixir-autogen, elixir-format
msgid "Invite someone new!"
msgstr "Laden Sie jemanden ein!"
#: lib/cannery_web/components/topbar.ex:108
#: lib/cannery_web/templates/user_confirmation/new.html.heex:30
#: lib/cannery_web/templates/user_registration/new.html.heex:39
#: lib/cannery_web/templates/user_reset_password/edit.html.heex:48
#: lib/cannery_web/templates/user_reset_password/new.html.heex:30
#: lib/cannery_web/templates/user_session/new.html.heex:3
#: lib/cannery_web/templates/user_session/new.html.heex:33
#, elixir-autogen, elixir-format
msgid "Log in"
msgstr "Einloggen"
#: lib/cannery_web/live/tag_live/index.html.heex:14
#, elixir-autogen, elixir-format
msgid "Make your first tag!"
msgstr "Erstellen Sie ihren ersten Tag!"
#: lib/cannery_web/live/ammo_group_live/index.html.heex:42
#, elixir-autogen, elixir-format
msgid "New Ammo group"
msgstr "Neue Munitionsgruppe"
#: 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
#, elixir-autogen, elixir-format
msgid "New Container"
msgstr "Neuer Behälter"
#: lib/cannery_web/live/tag_live/index.html.heex:19
#, elixir-autogen, elixir-format
msgid "New Tag"
msgstr "Neuer Tag"
#: lib/cannery_web/components/topbar.ex:101
#: lib/cannery_web/templates/user_confirmation/new.html.heex:25
#: lib/cannery_web/templates/user_registration/new.html.heex:3
#: lib/cannery_web/templates/user_registration/new.html.heex:33
#: lib/cannery_web/templates/user_reset_password/edit.html.heex:43
#: lib/cannery_web/templates/user_reset_password/new.html.heex:25
#: lib/cannery_web/templates/user_session/new.html.heex:40
#, elixir-autogen, elixir-format
msgid "Register"
msgstr "Registrieren"
#: lib/cannery_web/templates/user_confirmation/new.html.heex:3
#: lib/cannery_web/templates/user_confirmation/new.html.heex:16
#, elixir-autogen, elixir-format
msgid "Resend confirmation instructions"
msgstr "Bestätigungsmail erneut senden"
#: lib/cannery_web/templates/user_reset_password/edit.html.heex:3
#: lib/cannery_web/templates/user_reset_password/edit.html.heex:34
#, elixir-autogen, elixir-format
msgid "Reset password"
msgstr "Passwort zurücksetzen"
#: lib/cannery_web/components/add_shot_group_component.html.heex:46
#: lib/cannery_web/live/ammo_group_live/form_component.html.heex:73
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:156
#: lib/cannery_web/live/container_live/form_component.html.heex:50
#: lib/cannery_web/live/invite_live/form_component.html.heex:28
#: lib/cannery_web/live/range_live/form_component.html.heex:40
#: lib/cannery_web/live/tag_live/form_component.ex:66
#, elixir-autogen, elixir-format
msgid "Save"
msgstr "Speichern"
#: lib/cannery_web/templates/user_reset_password/new.html.heex:16
#, elixir-autogen, elixir-format
msgid "Send instructions to reset password"
msgstr "Anleitung zum Passwort zurücksetzen zusenden"
#: lib/cannery_web/live/container_live/show.html.heex:53
#, elixir-autogen, elixir-format
msgid "Why not add one?"
msgstr "Warum fügen Sie keine hinzu?"
#: lib/cannery_web/live/container_live/edit_tags_component.html.heex:52
#, elixir-autogen, elixir-format
msgid "Add"
msgstr "Hinzufügen"
#: lib/cannery_web/live/range_live/index.html.heex:17
#, elixir-autogen, elixir-format
msgid "Stage ammo"
msgstr "Munition markieren"
#: lib/cannery_web/live/range_live/index.html.heex:12
#, elixir-autogen, elixir-format
msgid "Why not get some ready to shoot?"
msgstr "Warum nicht einige für den Schießstand auswählen?"
#: lib/cannery_web/live/ammo_group_live/index.ex:134
#: lib/cannery_web/live/ammo_group_live/show.html.heex:86
#: lib/cannery_web/live/range_live/index.html.heex:36
#, elixir-autogen, elixir-format
msgid "Record shots"
msgstr "Schüsse dokumentieren"
#: lib/cannery_web/live/ammo_group_live/show.html.heex:50
#, elixir-autogen, elixir-format
msgid "Ammo Details"
msgstr "Munitionsdetails"
#: lib/cannery_web/components/move_ammo_group_component.ex:89
#, elixir-autogen, elixir-format
msgid "Add another container!"
msgstr "Einen weiteren Behälter hinzufügen!"
#: lib/cannery_web/live/ammo_group_live/show.html.heex:80
#, elixir-autogen, elixir-format
msgid "Move containers"
msgstr "Behälter verschieben"
#: lib/cannery_web/components/move_ammo_group_component.ex:127
#, elixir-autogen, elixir-format
msgid "Select"
msgstr "Markieren"
#: lib/cannery_web/live/invite_live/index.html.heex:33
#, elixir-autogen, elixir-format
msgid "Copy to clipboard"
msgstr "In die Zwischenablage kopieren"
#: lib/cannery_web/live/ammo_group_live/index.html.heex:18
#: lib/cannery_web/live/ammo_group_live/index.html.heex:36
#, elixir-autogen, elixir-format
msgid "add a container first"
msgstr "Zuerst einen Behälter hinzufügen"
#: lib/cannery_web/live/ammo_group_live/form_component.html.heex:66
#, elixir-autogen, elixir-format
msgid "Create"
msgstr "Erstellen"

View File

@ -0,0 +1,846 @@
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-04-19 19:32+0000\n"
"PO-Revision-Date: 2022-04-19 21:32+0000\n"
"Last-Translator: shibao <shibao@bubbletea.dev>\n"
"Language-Team: German <https://weblate.bubbletea.dev/projects/cannery/"
"default/de/>\n"
"Language: de\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 4.11.2\n"
## This file is a PO Template file.
##
## "msgid"s here are often extracted from source code.
## Add new translations manually only if they're dynamic
## translations that can't be statically extracted.
##
## Run "mix gettext.extract" to bring this file up to
## date. Leave "msgstr"s empty as changing them here has no
## effect: edit them in PO (.po) files instead.
#: lib/cannery_web/live/home_live.ex:63
#, elixir-autogen, elixir-format
msgid "%{name} lets you easily keep an eye on your ammo levels before and after range day"
msgstr ""
"Mit %{name} können Sie ihren Munitionsbestand vor und nach dem Schießen "
"leicht im Auge behalten"
#: lib/cannery_web/live/home_live.ex:85
#, elixir-autogen, elixir-format
msgid "Access from any internet-capable device"
msgstr "Zugriff von jedem Internet-fähigen Gerät"
#: lib/cannery_web/live/invite_live/index.html.heex:90
#, elixir-autogen, elixir-format
msgid "Admins"
msgstr "Admins"
#: lib/cannery_web/live/home_live.ex:99
#, elixir-autogen, elixir-format
msgid "Admins:"
msgstr "Admins:"
#: lib/cannery_web/components/topbar.ex:52
#: lib/cannery_web/live/ammo_group_live/index.html.heex:3
#: lib/cannery_web/live/range_live/index.ex:82
#, elixir-autogen, elixir-format
msgid "Ammo"
msgstr "Munition"
#: lib/cannery_web/live/ammo_group_live/form_component.html.heex:21
#: lib/cannery_web/live/ammo_group_live/index.ex:80
#, elixir-autogen, elixir-format
msgid "Ammo type"
msgstr "Munitionsarten"
#: lib/cannery_web/live/ammo_type_live/show.html.heex:94
#, elixir-autogen, elixir-format
msgid "Average Price paid"
msgstr "Durchschnittlicher Kaufpreis"
#: lib/cannery_web/live/tag_live/form_component.ex:54
#, elixir-autogen, elixir-format
msgid "Background color"
msgstr "Hintergrundfarbe"
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:140
#: lib/cannery_web/live/ammo_type_live/index.ex:71
#: lib/cannery_web/live/ammo_type_live/show.html.heex:55
#, elixir-autogen, elixir-format
msgid "Blank"
msgstr "Knallpatrone"
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:68
#, elixir-autogen, elixir-format
msgid "Brass"
msgstr "Messing"
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:44
#: lib/cannery_web/live/ammo_type_live/index.ex:53
#: lib/cannery_web/live/ammo_type_live/show.html.heex:41
#, elixir-autogen, elixir-format
msgid "Bullet core"
msgstr "Projektilkern"
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:37
#: lib/cannery_web/live/ammo_type_live/index.ex:52
#: lib/cannery_web/live/ammo_type_live/show.html.heex:40
#, elixir-autogen, elixir-format
msgid "Bullet type"
msgstr "Patronenart"
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:58
#: lib/cannery_web/live/ammo_type_live/index.ex:55
#: lib/cannery_web/live/ammo_type_live/show.html.heex:43
#, elixir-autogen, elixir-format
msgid "Caliber"
msgstr "Kaliber"
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:51
#: lib/cannery_web/live/ammo_type_live/index.ex:54
#: lib/cannery_web/live/ammo_type_live/show.html.heex:42
#, elixir-autogen, elixir-format
msgid "Cartridge"
msgstr "Patrone"
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:65
#: lib/cannery_web/live/ammo_type_live/index.ex:56
#: lib/cannery_web/live/ammo_type_live/show.html.heex:44
#, elixir-autogen, elixir-format
msgid "Case material"
msgstr "Gehäusematerial"
#: lib/cannery_web/components/move_ammo_group_component.ex:67
#: lib/cannery_web/live/ammo_group_live/form_component.html.heex:48
#: lib/cannery_web/live/ammo_group_live/index.ex:85
#, elixir-autogen, elixir-format
msgid "Container"
msgstr "Behälter"
#: lib/cannery_web/components/topbar.ex:46
#: lib/cannery_web/live/container_live/index.ex:38
#: lib/cannery_web/live/container_live/index.html.heex:3
#, elixir-autogen, elixir-format
msgid "Containers"
msgstr "Behälter"
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:144
#: lib/cannery_web/live/ammo_type_live/index.ex:72
#: lib/cannery_web/live/ammo_type_live/show.html.heex:56
#, elixir-autogen, elixir-format
msgid "Corrosive"
msgstr "Korrosiv"
#: lib/cannery_web/live/ammo_group_live/form_component.html.heex:27
#: lib/cannery_web/live/ammo_group_live/index.ex:81
#, elixir-autogen, elixir-format
msgid "Count"
msgstr "Anzahl"
#: lib/cannery_web/components/ammo_group_card.ex:29
#: lib/cannery_web/live/ammo_group_live/show.html.heex:8
#, elixir-autogen, elixir-format
msgid "Count:"
msgstr "Anzahl:"
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:24
#: lib/cannery_web/live/container_live/form_component.html.heex:27
#, elixir-autogen, elixir-format
msgid "Description"
msgstr "Beschreibung"
#: lib/cannery_web/components/container_card.ex:31
#: lib/cannery_web/live/container_live/show.html.heex:8
#, elixir-autogen, elixir-format
msgid "Description:"
msgstr "Beschreibung:"
#: lib/cannery_web/live/invite_live/index.html.heex:59
#, elixir-autogen, elixir-format
msgid "Disable"
msgstr "Deaktivieren"
#: lib/cannery_web/live/home_live.ex:60
#, elixir-autogen, elixir-format
msgid "Easy to Use:"
msgstr "Einfache Anwendung:"
#: lib/cannery_web/live/ammo_group_live/index.ex:38
#: lib/cannery_web/live/ammo_group_live/show.ex:42
#, elixir-autogen, elixir-format
msgid "Edit Ammo group"
msgstr "Munitionsgruppe bearbeiten"
#: lib/cannery_web/live/ammo_type_live/index.ex:23
#: lib/cannery_web/live/ammo_type_live/show.ex:47
#, elixir-autogen, elixir-format
msgid "Edit Ammo type"
msgstr "Munitionstyp bearbeiten"
#: lib/cannery_web/live/invite_live/index.ex:35
#, elixir-autogen, elixir-format
msgid "Edit Invite"
msgstr "Einladung bearbeiten"
#: lib/cannery_web/live/tag_live/index.ex:23
#, elixir-autogen, elixir-format
msgid "Edit Tag"
msgstr "Tag bearbeiten"
#: lib/cannery_web/live/invite_live/index.html.heex:63
#, elixir-autogen, elixir-format
msgid "Enable"
msgstr "Aktivieren"
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:35
#, elixir-autogen, elixir-format
msgid "Example bullet type abbreviations"
msgstr "Beispiel Munitionstyp Abkürzungen"
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:40
#, elixir-autogen, elixir-format
msgid "FMJ"
msgstr "VM"
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:103
#: lib/cannery_web/live/ammo_type_live/index.ex:65
#: lib/cannery_web/live/ammo_type_live/show.html.heex:49
#, elixir-autogen, elixir-format
msgid "Grains"
msgstr "Körner"
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:136
#: lib/cannery_web/live/ammo_type_live/index.ex:70
#: lib/cannery_web/live/ammo_type_live/show.html.heex:54
#, elixir-autogen, elixir-format
msgid "Incendiary"
msgstr "Brandmunition"
#: lib/cannery_web/live/home_live.ex:94
#, elixir-autogen, elixir-format
msgid "Instance Information"
msgstr "Instanzinformationen"
#: lib/cannery_web/components/invite_card.ex:27
#, elixir-autogen, elixir-format
msgid "Invite Disabled"
msgstr "Einladung deaktiviert"
#: lib/cannery_web/live/home_live.ex:125
#, elixir-autogen, elixir-format
msgid "Invite Only"
msgstr "Nur mit Einladung"
#: lib/cannery_web/components/topbar.ex:71
#: lib/cannery_web/live/invite_live/index.ex:43
#: lib/cannery_web/live/invite_live/index.html.heex:3
#, elixir-autogen, elixir-format
msgid "Invites"
msgstr "Einladungen"
#: lib/cannery_web/templates/user_session/new.html.heex:28
#, elixir-autogen, elixir-format
msgid "Keep me logged in for 60 days"
msgstr "Für 60 Tage eingeloggt bleiben"
#: lib/cannery_web/components/move_ammo_group_component.ex:69
#: lib/cannery_web/live/container_live/form_component.html.heex:42
#, elixir-autogen, elixir-format
msgid "Location"
msgstr "Standort"
#: lib/cannery_web/components/container_card.ex:43
#: lib/cannery_web/live/container_live/show.html.heex:20
#, elixir-autogen, elixir-format
msgid "Location:"
msgstr "Standort:"
#: lib/cannery_web/live/container_live/form_component.html.heex:38
#, elixir-autogen, elixir-format
msgid "Magazine, Clip, Ammo Box, etc"
msgstr "Magazin, Ladestreifen, Munitionskiste usw."
#: lib/cannery_web/components/topbar.ex:58
#, elixir-autogen, elixir-format
msgid "Manage"
msgstr "Verwalten"
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:148
#: lib/cannery_web/live/ammo_type_live/index.ex:73
#: lib/cannery_web/live/ammo_type_live/show.html.heex:57
#, elixir-autogen, elixir-format
msgid "Manufacturer"
msgstr "Hersteller"
#: lib/cannery_web/live/container_live/form_component.html.heex:31
#, elixir-autogen, elixir-format
msgid "Metal ammo can with the anime girl sticker"
msgstr "Metallene Munitionskiste mit Anime-Girl-Sticker"
#: lib/cannery_web/live/container_live/form_component.html.heex:23
#, elixir-autogen, elixir-format
msgid "My cool ammo can"
msgstr "Meine coole Munitionskiste"
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:20
#: lib/cannery_web/live/ammo_type_live/index.ex:51
#: lib/cannery_web/live/container_live/form_component.html.heex:20
#: lib/cannery_web/live/invite_live/form_component.html.heex:20
#: lib/cannery_web/live/tag_live/form_component.ex:50
#, elixir-autogen, elixir-format
msgid "Name"
msgstr "Name"
#: lib/cannery_web/live/ammo_type_live/index.ex:29
#, elixir-autogen, elixir-format
msgid "New Ammo type"
msgstr "Neuer Munitionstyp"
#: lib/cannery_web/live/container_live/index.ex:33
#, elixir-autogen, elixir-format
msgid "New Container"
msgstr "Neuer Behälter"
#: lib/cannery_web/live/invite_live/index.ex:39
#, elixir-autogen, elixir-format
msgid "New Invite"
msgstr "Neue Einladung"
#: lib/cannery_web/live/tag_live/index.ex:29
#, elixir-autogen, elixir-format
msgid "New Tag"
msgstr "Neuer Tag"
#: lib/cannery_web/live/ammo_group_live/index.html.heex:8
#, elixir-autogen, elixir-format
msgid "No Ammo"
msgstr "Keine Munition"
#: lib/cannery_web/live/ammo_type_live/index.html.heex:8
#, elixir-autogen, elixir-format
msgid "No Ammo Types"
msgstr "Keine Munitionsarten"
#: lib/cannery_web/live/ammo_type_live/show.html.heex:114
#, elixir-autogen, elixir-format
msgid "No ammo for this type"
msgstr "Keine Munition dieser Art"
#: lib/cannery_web/live/container_live/show.html.heex:78
#, elixir-autogen, elixir-format
msgid "No ammo groups in this container"
msgstr "Keine Munitionsgruppe in diesem Behälter"
#: lib/cannery_web/live/container_live/index.html.heex:8
#, elixir-autogen, elixir-format
msgid "No containers"
msgstr "Kein Behälter"
#: lib/cannery_web/live/invite_live/index.html.heex:8
#, elixir-autogen, elixir-format
msgid "No invites"
msgstr "Keine Einladung"
#: lib/cannery_web/live/container_live/edit_tags_component.html.heex:30
#: lib/cannery_web/live/tag_live/index.html.heex:10
#, elixir-autogen, elixir-format
msgid "No tags"
msgstr "Keine Tags"
#: lib/cannery_web/components/add_shot_group_component.html.heex:30
#: lib/cannery_web/live/ammo_group_live/form_component.html.heex:41
#: lib/cannery_web/live/ammo_group_live/show.ex:90
#: lib/cannery_web/live/range_live/form_component.html.heex:29
#: lib/cannery_web/live/range_live/index.ex:84
#, elixir-autogen, elixir-format
msgid "Notes"
msgstr "Bemerkungen"
#: lib/cannery_web/components/ammo_group_card.ex:35
#: lib/cannery_web/live/ammo_group_live/show.html.heex:24
#, elixir-autogen, elixir-format
msgid "Notes:"
msgstr "Bemerkungen:"
#: lib/cannery_web/live/container_live/form_component.html.heex:46
#, elixir-autogen, elixir-format
msgid "On the bookshelf"
msgstr "Auf dem Bücherregal"
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:111
#: lib/cannery_web/live/ammo_type_live/index.ex:66
#: lib/cannery_web/live/ammo_type_live/show.html.heex:50
#, elixir-autogen, elixir-format
msgid "Pressure"
msgstr "Druck"
#: lib/cannery_web/live/ammo_group_live/form_component.html.heex:34
#: lib/cannery_web/live/ammo_group_live/index.ex:82
#, elixir-autogen, elixir-format
msgid "Price paid"
msgstr "Kaufpreis"
#: lib/cannery_web/components/ammo_group_card.ex:42
#, elixir-autogen, elixir-format
msgid "Price paid:"
msgstr "Kaufpreis:"
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:118
#: lib/cannery_web/live/ammo_type_live/index.ex:67
#: lib/cannery_web/live/ammo_type_live/show.html.heex:51
#, elixir-autogen, elixir-format
msgid "Primer type"
msgstr "Zündertyp"
#: lib/cannery_web/live/home_live.ex:124
#, elixir-autogen, elixir-format
msgid "Public Signups"
msgstr "Öffentliche Registrierung"
#: lib/cannery_web/live/home_live.ex:72
#, elixir-autogen, elixir-format
msgid "Secure:"
msgstr "Sicher:"
#: lib/cannery_web/live/home_live.ex:75
#, elixir-autogen, elixir-format
msgid "Self-host your own instance, or use an instance from someone you trust."
msgstr ""
"Hosten Sie Ihre eigene Instanz oder verwenden Sie eine Instanz, der Sie "
"vertrauen."
#: lib/cannery_web/live/invite_live/index.html.heex:79
#, elixir-autogen, elixir-format
msgid "Set Unlimited"
msgstr "Unbegrenzt setzen"
#: lib/cannery_web/controllers/user_settings_controller.ex:10
#: lib/cannery_web/templates/user_settings/edit.html.heex:3
#, elixir-autogen, elixir-format
msgid "Settings"
msgstr "Einstellungen"
#: lib/cannery_web/live/ammo_group_live/show.ex:41
#, elixir-autogen, elixir-format
msgid "Show Ammo group"
msgstr "Munitionsgruppen anzeigen"
#: lib/cannery_web/live/ammo_type_live/show.ex:46
#, elixir-autogen, elixir-format
msgid "Show Ammo type"
msgstr "Zeige Munitionsarten"
#: lib/cannery_web/live/home_live.ex:82
#, elixir-autogen, elixir-format
msgid "Simple:"
msgstr "Einfach:"
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:47
#, elixir-autogen, elixir-format
msgid "Steel"
msgstr "Stahl"
#: lib/cannery_web/live/ammo_group_live/show.html.heex:98
#, elixir-autogen, elixir-format
msgid "Stored in"
msgstr "Gelagert in"
#: lib/cannery_web/components/topbar.ex:40
#: lib/cannery_web/live/tag_live/index.ex:34
#: lib/cannery_web/live/tag_live/index.html.heex:3
#, elixir-autogen, elixir-format
msgid "Tags"
msgstr "Tags"
#: lib/cannery_web/live/tag_live/index.html.heex:6
#, elixir-autogen, elixir-format
msgid "Tags can be added to your containers to help you organize"
msgstr "Tags können zur besseren Ordnung einem Behälter hinzugefügt werden"
#: lib/cannery_web/live/tag_live/form_component.ex:60
#, elixir-autogen, elixir-format
msgid "Text color"
msgstr "Textfarbe"
#: lib/cannery_web/live/home_live.ex:51
#, elixir-autogen, elixir-format
msgid "The self-hosted firearm tracker website"
msgstr "Die selbst-gehostete Website zur Verwaltung von Schusswaffen"
#: lib/cannery_web/live/ammo_group_live/show.html.heex:103
#, elixir-autogen, elixir-format
msgid "This ammo group is not in a container"
msgstr "Diese Munitionsgruppe ist nicht in einem Behälter"
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:132
#: lib/cannery_web/live/ammo_type_live/index.ex:69
#: lib/cannery_web/live/ammo_type_live/show.html.heex:53
#, elixir-autogen, elixir-format
msgid "Tracer"
msgstr "Leuchtspur"
#: lib/cannery_web/components/move_ammo_group_component.ex:68
#: lib/cannery_web/live/container_live/form_component.html.heex:35
#, elixir-autogen, elixir-format
msgid "Type"
msgstr "Art"
#: lib/cannery_web/components/container_card.ex:37
#: lib/cannery_web/live/container_live/show.html.heex:14
#, elixir-autogen, elixir-format
msgid "Type:"
msgstr "Art:"
#: lib/cannery_web/live/invite_live/index.html.heex:119
#, elixir-autogen, elixir-format
msgid "Users"
msgstr "Benutzer"
#: lib/cannery_web/components/invite_card.ex:22
#, elixir-autogen, elixir-format
msgid "Uses Left:"
msgstr "Verbleibende Nutzung:"
#: lib/cannery_web/live/invite_live/form_component.html.heex:24
#, elixir-autogen, elixir-format
msgid "Uses left"
msgstr "Verbleibende Nutzung"
#: lib/cannery_web/live/home_live.ex:47
#, elixir-autogen, elixir-format
msgid "Welcome to %{name}"
msgstr "Willkommen %{name}"
#: lib/cannery_web/live/home_live.ex:76
#, elixir-autogen, elixir-format
msgid "Your data stays with you, period"
msgstr "Ihre Daten bleiben bei Ihnen, Punkt"
#: lib/cannery_web/live/container_live/show.html.heex:49
#, elixir-autogen, elixir-format
msgid "No tags for this container"
msgstr "Keine Tags für diesen Behälter"
#: lib/cannery_web/components/topbar.ex:64
#: lib/cannery_web/live/ammo_group_live/index.ex:84
#, elixir-autogen, elixir-format
msgid "Range"
msgstr "Schießplatz"
#: lib/cannery_web/live/range_live/index.html.heex:3
#, elixir-autogen, elixir-format
msgid "Range day"
msgstr "Range Day"
#: lib/cannery_web/live/ammo_group_live/show.ex:91
#: lib/cannery_web/live/range_live/index.ex:85
#, elixir-autogen, elixir-format
msgid "Date"
msgstr "Datum"
#: lib/cannery_web/live/range_live/form_component.html.heex:21
#, elixir-autogen, elixir-format
msgid "Shots fired"
msgstr "Schüsse abgegeben"
#: lib/cannery_web/live/range_live/index.html.heex:8
#, elixir-autogen, elixir-format
msgid "No ammo staged"
msgstr "Keine Munition selektiert"
#: lib/cannery_web/live/ammo_group_live/show.html.heex:77
#: lib/cannery_web/live/range_live/index.html.heex:33
#, elixir-autogen, elixir-format
msgid "Stage for range"
msgstr "Für Schießplatz selektieren"
#: lib/cannery_web/live/ammo_group_live/show.html.heex:76
#: lib/cannery_web/live/range_live/index.html.heex:32
#, elixir-autogen, elixir-format
msgid "Unstage from range"
msgstr "Für Schießplatz deselektieren"
#: lib/cannery_web/components/add_shot_group_component.html.heex:3
#: lib/cannery_web/live/ammo_group_live/index.ex:26
#, elixir-autogen, elixir-format
msgid "Record shots"
msgstr "Schüsse dokumentieren"
#: lib/cannery_web/live/ammo_type_live/index.html.heex:3
#, elixir-autogen, elixir-format
msgid "Ammo Types"
msgstr "Munitionsarten"
#: lib/cannery_web/live/ammo_group_live/index.ex:49
#, elixir-autogen, elixir-format
msgid "Ammo groups"
msgstr "Munitionsgruppen"
#: lib/cannery_web/components/add_shot_group_component.html.heex:38
#: lib/cannery_web/live/range_live/form_component.html.heex:36
#, elixir-autogen, elixir-format
msgid "Date (UTC)"
msgstr "Zeit (UTC)"
#: lib/cannery_web/live/ammo_group_live/show.ex:39
#: lib/cannery_web/live/range_live/index.ex:34
#, elixir-autogen, elixir-format
msgid "Edit Shot Records"
msgstr "Schießkladde editieren"
#: lib/cannery_web/live/range_live/index.ex:40
#, elixir-autogen, elixir-format
msgid "New Shot Records"
msgstr "Neue Schießkladde"
#: lib/cannery_web/live/range_live/index.html.heex:48
#, elixir-autogen, elixir-format
msgid "No shots recorded"
msgstr "Keine Schüsse dokumentiert"
#: lib/cannery_web/components/add_shot_group_component.html.heex:21
#, elixir-autogen, elixir-format
msgid "Rounds left"
msgstr "Patronen verbleibend"
#: lib/cannery_web/live/ammo_group_live/show.ex:89
#: lib/cannery_web/live/range_live/index.ex:83
#, elixir-autogen, elixir-format
msgid "Rounds shot"
msgstr "Patronen abgefeuert"
#: lib/cannery_web/live/range_live/index.ex:46
#, elixir-autogen, elixir-format
msgid "Shot Records"
msgstr "Schießkladde"
#: lib/cannery_web/live/ammo_group_live/index.ex:32
#: lib/cannery_web/live/ammo_group_live/show.ex:40
#, elixir-autogen, elixir-format
msgid "Move Ammo group"
msgstr "Munitionsgruppe verschieben"
#: lib/cannery_web/components/move_ammo_group_component.ex:80
#, elixir-autogen, elixir-format
msgid "Move ammo"
msgstr "Munition verschieben"
#: lib/cannery_web/components/move_ammo_group_component.ex:85
#, elixir-autogen, elixir-format
msgid "No other containers"
msgstr "Kein weiterer Behälter"
#: lib/cannery_web/live/range_live/index.html.heex:53
#, elixir-autogen, elixir-format
msgid "Shot log"
msgstr "Schießkladde"
#: lib/cannery_web/components/ammo_group_card.ex:43
#: lib/cannery_web/live/ammo_group_live/index.ex:117
#: lib/cannery_web/live/ammo_group_live/show.html.heex:32
#: lib/cannery_web/live/ammo_group_live/show.html.heex:39
#: lib/cannery_web/live/ammo_type_live/show.html.heex:98
#, elixir-autogen, elixir-format
msgid "$%{amount}"
msgstr "$%{amount}"
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:75
#, elixir-autogen, elixir-format
msgid "Bimetal"
msgstr "Bimetall"
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:72
#: lib/cannery_web/live/ammo_type_live/index.ex:57
#: lib/cannery_web/live/ammo_type_live/show.html.heex:45
#, elixir-autogen, elixir-format
msgid "Jacket type"
msgstr "Patronenhülse"
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:79
#: lib/cannery_web/live/ammo_type_live/index.ex:58
#: lib/cannery_web/live/ammo_type_live/show.html.heex:46
#, elixir-autogen, elixir-format
msgid "Muzzle velocity"
msgstr "Mündungsgeschwindigkeit"
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:93
#: lib/cannery_web/live/ammo_type_live/index.ex:61
#: lib/cannery_web/live/ammo_type_live/show.html.heex:48
#, elixir-autogen, elixir-format
msgid "Powder grains per charge"
msgstr "Pulverkörner pro Ladung"
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:89
#: lib/cannery_web/live/ammo_type_live/index.ex:59
#: lib/cannery_web/live/ammo_type_live/show.html.heex:47
#, elixir-autogen, elixir-format
msgid "Powder type"
msgstr "Pulverart"
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:152
#: lib/cannery_web/live/ammo_type_live/index.ex:74
#: lib/cannery_web/live/ammo_type_live/show.html.heex:58
#, elixir-autogen, elixir-format
msgid "UPC"
msgstr "UPC"
#: lib/cannery_web/templates/user_settings/edit.html.heex:80
#, elixir-autogen, elixir-format
msgid "Confirm new password"
msgstr "Passwort bestätigen"
#: lib/cannery_web/templates/user_settings/edit.html.heex:33
#: lib/cannery_web/templates/user_settings/edit.html.heex:89
#, elixir-autogen, elixir-format
msgid "Current password"
msgstr "Derzeitiges Passwort"
#: lib/cannery_web/templates/user_settings/edit.html.heex:73
#, elixir-autogen, elixir-format
msgid "New password"
msgstr "Neues Passwort"
#: lib/cannery_web/live/ammo_group_live/index.ex:131
#, elixir-autogen, elixir-format
msgid "Stage"
msgstr "Markiert"
#: lib/cannery_web/live/ammo_group_live/index.ex:131
#, elixir-autogen, elixir-format
msgid "Unstage"
msgstr "Demarkiert"
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:125
#: lib/cannery_web/live/ammo_type_live/index.ex:68
#: lib/cannery_web/live/ammo_type_live/show.html.heex:52
#, elixir-autogen, elixir-format
msgid "Firing type"
msgstr "Patronenhülsenform"
#: lib/cannery_web/templates/layout/live.html.heex:50
#, elixir-autogen, elixir-format
msgid "Reconnecting..."
msgstr "Neu verbinden..."
#: lib/cannery_web/templates/layout/live.html.heex:37
#, elixir-autogen, elixir-format
msgid "Loading..."
msgstr "Lädt..."
#: lib/cannery_web/live/container_live/index.ex:29
#: lib/cannery_web/live/container_live/show.ex:97
#, elixir-autogen, elixir-format
msgid "Edit %{name}"
msgstr "%{name} bearbeiten"
#: lib/cannery_web/live/container_live/index.ex:48
#: lib/cannery_web/live/container_live/show.ex:98
#, elixir-autogen, elixir-format
msgid "Edit %{name} tags"
msgstr "Editiere %{name} Tags"
#: lib/cannery_web/components/container_card.ex:50
#, elixir-autogen, elixir-format
msgid "Rounds:"
msgstr "Patronen:"
#: lib/cannery_web/live/container_live/show.ex:96
#, elixir-autogen, elixir-format
msgid "Show %{name}"
msgstr "Zeige %{name}"
#: lib/cannery_web/live/ammo_type_live/show.html.heex:104
#, elixir-autogen, elixir-format
msgid "No cost information"
msgstr "Keine Preisinformationen"
#: lib/cannery_web/live/ammo_group_live/index.ex:83
#, elixir-autogen, elixir-format
msgid "% left"
msgstr "% verbleibend"
#: lib/cannery_web/live/ammo_group_live/show.html.heex:38
#, elixir-autogen, elixir-format
msgid "Current value:"
msgstr "Derzeitiger Wert:"
#: lib/cannery_web/live/ammo_group_live/show.html.heex:31
#, elixir-autogen, elixir-format
msgid "Original cost:"
msgstr "Originalpreis:"
#: lib/cannery_web/live/ammo_group_live/show.html.heex:13
#, elixir-autogen, elixir-format
msgid "Original count:"
msgstr "Ursprüngliche Anzahl:"
#: lib/cannery_web/live/ammo_group_live/show.html.heex:18
#, elixir-autogen, elixir-format
msgid "Percentage left:"
msgstr "Prozent verbleibend:"
#: lib/cannery_web/live/ammo_group_live/show.html.heex:111
#, elixir-autogen, elixir-format
msgid "Rounds used"
msgstr "Patronen verbraucht"
#: lib/cannery_web/live/ammo_type_live/show.html.heex:77
#, elixir-autogen, elixir-format
msgid "Current # of rounds:"
msgstr "Derzeitige # an Patronen:"
#: lib/cannery_web/live/ammo_type_live/index.ex:86
#, elixir-autogen, elixir-format
msgid "Total # of rounds"
msgstr "Summe aller Patronen"
#: lib/cannery_web/live/ammo_type_live/show.html.heex:85
#, elixir-autogen, elixir-format
msgid "Total rounds shot:"
msgstr "Summe abgegebener Schüsse:"
#: lib/cannery_web/controllers/user_confirmation_controller.ex:8
#, elixir-autogen, elixir-format
msgid "Confirm your account"
msgstr "Bestätigen Sie ihr Nutzerkonto"
#: lib/cannery_web/controllers/user_reset_password_controller.ex:9
#, elixir-autogen, elixir-format
msgid "Forgot your password?"
msgstr "Passwort vergessen?"
#: lib/cannery_web/controllers/user_session_controller.ex:8
#, elixir-autogen, elixir-format
msgid "Log in"
msgstr "Einloggen"
#: lib/cannery_web/controllers/user_registration_controller.ex:35
#, elixir-autogen, elixir-format
msgid "Register"
msgstr "Registrieren"
#: lib/cannery_web/controllers/user_reset_password_controller.ex:36
#, elixir-autogen, elixir-format
msgid "Reset your password"
msgstr "Passwort zurücksetzen"
#: lib/cannery_web/live/ammo_group_live/show.ex:38
#: lib/cannery_web/live/range_live/index.ex:28
#, elixir-autogen, elixir-format
msgid "Record Shots"
msgstr "Schüsse dokumentieren"
#: lib/cannery_web/live/ammo_group_live/form_component.html.heex:58
#, elixir-autogen, elixir-format
msgid "Copies"
msgstr "Kopien"
#: lib/cannery_web/live/ammo_type_live/index.ex:34
#, elixir-autogen, elixir-format
msgid "Ammo types"
msgstr "Munitionsart"

View File

@ -0,0 +1,121 @@
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-04-19 19:32+0000\n"
"PO-Revision-Date: 2022-04-19 21:44+0000\n"
"Last-Translator: Kaia Estra <kaia@fedora.email>\n"
"Language-Team: German <https://weblate.bubbletea.dev/projects/cannery/emails/"
"de/>\n"
"Language: de\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 4.11.2\n"
## This file is a PO Template file.
##
## "msgid"s here are often extracted from source code.
## Add new translations manually only if they're dynamic
## translations that can't be statically extracted.
##
## Run "mix gettext.extract" to bring this file up to
## date. Leave "msgstr"s empty as changing them here has no
## effect: edit them in PO (.po) files instead.
#: lib/cannery/accounts/email.ex:30
#, elixir-autogen, elixir-format
msgid "Confirm your %{name} account"
msgstr "Bestätigen Sie ihr %{name} Nutzerkonto"
#: lib/cannery_web/templates/email/confirm_email.html.eex:3
#: lib/cannery_web/templates/email/confirm_email.txt.eex:2
#: lib/cannery_web/templates/email/reset_password.html.eex:3
#: lib/cannery_web/templates/email/reset_password.txt.eex:2
#: lib/cannery_web/templates/email/update_email.html.eex:3
#: lib/cannery_web/templates/email/update_email.txt.eex:2
#, elixir-autogen, elixir-format
msgid "Hi %{email},"
msgstr "Hallo %{email},"
#: lib/cannery_web/templates/email/confirm_email.txt.eex:10
#, elixir-autogen, elixir-format
msgid "If you didn't create an account at %{url}, please ignore this."
msgstr ""
"Falls Sie dieses Nutzerkonto bei %{url} nicht erstellt haben, ignorieren Sie "
"diese Nachricht bitte."
#: lib/cannery_web/templates/email/reset_password.txt.eex:8
#: lib/cannery_web/templates/email/update_email.txt.eex:8
#, elixir-autogen, elixir-format
msgid "If you didn't request this change from %{url}, please ignore this."
msgstr ""
"Falls Sie diese Änderung von %{url} nicht angefordert haben, ignorieren Sie "
"bitte diese Nachricht."
#: lib/cannery/accounts/email.ex:37
#, elixir-autogen, elixir-format
msgid "Reset your %{name} password"
msgstr "Passwort für %{name} zurücksetzen"
#: lib/cannery/accounts/email.ex:44
#, elixir-autogen, elixir-format
msgid "Update your %{name} email"
msgstr "Aktualisieren Sie %{name} Mailadresse"
#: lib/cannery_web/templates/email/confirm_email.html.eex:9
#, elixir-autogen, elixir-format
msgid "Welcome to %{name}!"
msgstr "Willkommen %{name}!"
#: lib/cannery_web/templates/email/confirm_email.txt.eex:4
#, elixir-autogen, elixir-format
msgid "Welcome to %{name}%!"
msgstr "Willkommen %{name}%!"
#: lib/cannery_web/templates/email/update_email.html.eex:8
#: lib/cannery_web/templates/email/update_email.txt.eex:4
#, elixir-autogen, elixir-format
msgid "You can change your email by visiting the URL below:"
msgstr "Sie können Ihre Mailadresse unter folgender URL ändern:"
#: lib/cannery_web/templates/email/confirm_email.html.eex:14
#: lib/cannery_web/templates/email/confirm_email.txt.eex:6
#, elixir-autogen, elixir-format
msgid "You can confirm your account by visiting the URL below:"
msgstr "Sie können Ihr Nutzerkonto unter folgender URL bestätigen:"
#: lib/cannery_web/templates/email/reset_password.html.eex:8
#: lib/cannery_web/templates/email/reset_password.txt.eex:4
#, elixir-autogen, elixir-format
msgid "You can reset your password by visiting the URL below:"
msgstr "Sie können ihr Passwort unter folgender URL zurücksetzen:"
#: lib/cannery_web/templates/email/confirm_email.html.eex:22
#, elixir-autogen, elixir-format
msgid "If you didn't create an account at %{name}, please ignore this."
msgstr ""
"Falls SIe dieses Nutzerkonto unter %{name}, nicht erstellt haben, ignorieren "
"Sie diese Nachricht bitte."
#: lib/cannery_web/templates/email/reset_password.html.eex:16
#: lib/cannery_web/templates/email/update_email.html.eex:16
#, elixir-autogen, elixir-format
msgid "If you didn't request this change from %{name}, please ignore this."
msgstr ""
"Falls Sie die Änderung von %{name} nicht angefragt haben, ignorieren Sie "
"diese Nachricht bitte."
#: lib/cannery_web/templates/layout/email.txt.eex:9
#, elixir-autogen, elixir-format
msgid "This email was sent from %{name} at %{url}, the self-hosted firearm tracker website."
msgstr ""
"Diese Nachricht wurde von %{name} unter %{url} gesandt, einem selbst-"
"gehosteten Schusswaffenmanager."
#: lib/cannery_web/templates/layout/email.html.heex:17
#, elixir-autogen, elixir-format
msgid "This email was sent from %{name}, the self-hosted firearm tracker website."
msgstr ""
"Diese Nachricht wurde von %{name} gesandt, einem selbst-gehosteten "
"Schusswaffenmanager."

View File

@ -0,0 +1,187 @@
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-04-19 19:32+0000\n"
"PO-Revision-Date: 2022-04-19 21:32+0000\n"
"Last-Translator: shibao <shibao@bubbletea.dev>\n"
"Language-Team: German <https://weblate.bubbletea.dev/projects/cannery/errors/"
"de/>\n"
"Language: de\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 4.11.2\n"
## This file is a PO Template file.
##
## "msgid"s here are often extracted from source code.
## Add new translations manually only if they're dynamic
## translations that can't be statically extracted.
##
## Run "mix gettext.extract" to bring this file up to
## date. Leave "msgstr"s empty as changing them here has no
## effect: edit them in PO (.po) files instead.
#: lib/cannery/containers.ex:122
#, elixir-autogen, elixir-format
msgid "Container must be empty before deleting"
msgstr "Behälter muss vor dem Löschen leer sein"
#: lib/cannery_web/live/container_live/index.ex:71
#: lib/cannery_web/live/container_live/show.ex:73
#, elixir-autogen, elixir-format
msgid "Could not delete %{name}: %{error}"
msgstr "Konnte %{name} nicht löschen: %{error}"
#: lib/cannery_web/live/container_live/index.ex:59
#, elixir-autogen, elixir-format
msgid "Could not find that container"
msgstr "Konnte Behälter nicht finden"
#: lib/cannery_web/controllers/user_settings_controller.ex:67
#, elixir-autogen, elixir-format
msgid "Email change link is invalid or it has expired."
msgstr "Mailadressenänderungs-Link ist ungültig oder abgelaufen."
#: lib/cannery_web/templates/error/error.html.heex:8
#, elixir-autogen, elixir-format
msgid "Error"
msgstr "Fehler"
#: lib/cannery_web/templates/error/error.html.heex:29
#, elixir-autogen, elixir-format
msgid "Go back home"
msgstr "Zur Hauptseite zurückkehren"
#: lib/cannery_web/views/error_view.ex:11
#, elixir-autogen, elixir-format
msgid "Internal Server Error"
msgstr "Interner Serverfehler"
#: lib/cannery_web/controllers/user_session_controller.ex:17
#, elixir-autogen, elixir-format
msgid "Invalid email or password"
msgstr "Ungültige Mailadresse oder Passwort"
#: lib/cannery_web/views/error_view.ex:9
#, elixir-autogen, elixir-format
msgid "Not found"
msgstr "Nicht gefunden"
#: lib/cannery_web/templates/user_registration/new.html.heex:16
#: lib/cannery_web/templates/user_reset_password/edit.html.heex:16
#: lib/cannery_web/templates/user_settings/edit.html.heex:22
#: lib/cannery_web/templates/user_settings/edit.html.heex:66
#, elixir-autogen, elixir-format
msgid "Oops, something went wrong! Please check the errors below."
msgstr "Oops, etwas ist schiefgegangen. Bitte beachten Sie den Fehler unten."
#: lib/cannery_web/controllers/user_reset_password_controller.ex:63
#, elixir-autogen, elixir-format
msgid "Reset password link is invalid or it has expired."
msgstr "Link zum Passwort zurücksetzen ist ungültig oder abgelaufen."
#: lib/cannery_web/controllers/user_registration_controller.ex:25
#: lib/cannery_web/controllers/user_registration_controller.ex:56
#, elixir-autogen, elixir-format
msgid "Sorry, public registration is disabled"
msgstr "Entschuldigung, aber öffentliche Registrierung ist deaktiviert"
#: lib/cannery_web/controllers/user_registration_controller.ex:15
#: lib/cannery_web/controllers/user_registration_controller.ex:46
#, elixir-autogen, elixir-format
msgid "Sorry, this invite was not found or expired"
msgstr ""
"Entschuldigung, aber diese Einladung wurde nicht gefunden oder ist abgelaufen"
#: lib/cannery_web/controllers/user_settings_controller.ex:82
#, elixir-autogen, elixir-format
msgid "Unable to delete user"
msgstr "Dieser Nutzer konnte nicht gelöscht werden"
#: lib/cannery_web/views/error_view.ex:10
#, elixir-autogen, elixir-format
msgid "Unauthorized"
msgstr "Unbefugt"
#: lib/cannery_web/controllers/user_confirmation_controller.ex:54
#, elixir-autogen, elixir-format
msgid "User confirmation link is invalid or it has expired."
msgstr "Nutzerkonto Bestätigungslink ist ungültig oder abgelaufen."
#: lib/cannery_web/live/invite_live/index.ex:20
#, elixir-autogen, elixir-format
msgid "You are not authorized to view this page"
msgstr "Sie sind nicht berechtigt, diese Seite aufzurufen"
#: lib/cannery_web/controllers/user_auth.ex:177
#, elixir-autogen, elixir-format
msgid "You are not authorized to view this page."
msgstr "Sie sind nicht berechtigt, diese Seite aufzurufen."
#: lib/cannery/accounts/user.ex:128
#, elixir-autogen, elixir-format
msgid "did not change"
msgstr "hat sich nicht geändert"
#: lib/cannery/accounts/user.ex:149
#, elixir-autogen, elixir-format
msgid "does not match password"
msgstr "Passwort stimmt nicht überein"
#: lib/cannery/accounts/user.ex:186
#, elixir-autogen, elixir-format
msgid "is not valid"
msgstr "ist nicht gültig"
#: lib/cannery/accounts/user.ex:82
#, elixir-autogen, elixir-format
msgid "must have the @ sign and no spaces"
msgstr "Muss ein @ Zeichen und keine Leerzeichen haben"
#: lib/cannery/tags.ex:40
#, elixir-autogen, elixir-format
msgid "Tag not found"
msgstr "Tag nicht gefunden"
#: lib/cannery_web/live/container_live/edit_tags_component.ex:30
#, elixir-autogen, elixir-format
msgid "Tag could not be added"
msgstr "Tag konnte nicht hinzugefügt werden"
#: lib/cannery/activity_log.ex:125
#, elixir-autogen, elixir-format
msgid "Count must be at least 1"
msgstr "Anzahl muss mindestens 1 sein"
#: lib/cannery/activity_log.ex:73
#: lib/cannery/activity_log.ex:120
#, elixir-autogen, elixir-format
msgid "Count must be less than %{count}"
msgstr "Anzahl muss weniger als %{count} betragen"
#: lib/cannery_web/controllers/user_auth.ex:39
#: lib/cannery_web/controllers/user_auth.ex:161
#, elixir-autogen, elixir-format
msgid "You must confirm your account and log in to access this page."
msgstr ""
"Sie müssen ihr Nutzerkonto bestätigen und einloggen, um diese Seite "
"anzuzeigen."
#: lib/cannery_web/live/container_live/edit_tags_component.ex:52
#, elixir-autogen, elixir-format
msgid "Tag could not be removed"
msgstr "Tag konnte nicht gelöscht werden"
#: lib/cannery_web/live/ammo_group_live/form_component.ex:126
#, elixir-autogen, elixir-format
msgid "Could not parse number of copies"
msgstr "Konnte die Anzahl der Kopien nicht verstehen"
#: lib/cannery_web/live/ammo_group_live/form_component.ex:111
#, elixir-autogen, elixir-format
msgid "Invalid number of copies, must be between 1 and %{max}. Was %{multiplier}"
msgstr ""
"Ungültige Nummer an Kopien. Muss zwischen 1 and %{max} liegen. War "
"%{multiplier}"

View File

@ -0,0 +1,281 @@
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-04-19 19:32+0000\n"
"PO-Revision-Date: 2022-04-19 21:32+0000\n"
"Last-Translator: Kaia Estra <kaia@fedora.email>\n"
"Language-Team: German <https://weblate.bubbletea.dev/projects/cannery/"
"prompts/de/>\n"
"Language: de\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 4.11.2\n"
## This file is a PO Template file.
##
## "msgid"s here are often extracted from source code.
## Add new translations manually only if they're dynamic
## translations that can't be statically extracted.
##
## Run "mix gettext.extract" to bring this file up to
## date. Leave "msgstr"s empty as changing them here has no
## effect: edit them in PO (.po) files instead.
#: lib/cannery_web/live/ammo_type_live/form_component.ex:64
#: lib/cannery_web/live/container_live/form_component.ex:65
#: lib/cannery_web/live/invite_live/form_component.ex:59
#: lib/cannery_web/live/tag_live/form_component.ex:101
#, elixir-autogen, elixir-format
msgid "%{name} created successfully"
msgstr "%{name} erfolgreich erstellt"
#: lib/cannery_web/live/ammo_type_live/index.ex:41
#: lib/cannery_web/live/ammo_type_live/show.ex:40
#: lib/cannery_web/live/invite_live/index.ex:55
#: lib/cannery_web/live/invite_live/index.ex:135
#: lib/cannery_web/live/tag_live/index.ex:40
#, elixir-autogen, elixir-format
msgid "%{name} deleted succesfully"
msgstr "%{name} erfolgreich gelöscht"
#: lib/cannery_web/live/invite_live/index.ex:111
#, elixir-autogen, elixir-format
msgid "%{name} disabled succesfully"
msgstr "%{name} erfolgreich deaktiviert"
#: lib/cannery_web/live/invite_live/index.ex:89
#, elixir-autogen, elixir-format
msgid "%{name} enabled succesfully"
msgstr "%{name} erfolgreich aktiviert"
#: lib/cannery_web/live/container_live/index.ex:64
#: lib/cannery_web/live/container_live/show.ex:63
#, elixir-autogen, elixir-format
msgid "%{name} has been deleted"
msgstr "%{name} wurde gelöscht"
#: lib/cannery_web/live/invite_live/index.ex:69
#, elixir-autogen, elixir-format
msgid "%{name} updated succesfully"
msgstr "%{name} erfolgreich aktualisiert"
#: lib/cannery_web/live/ammo_type_live/form_component.ex:46
#: lib/cannery_web/live/container_live/form_component.ex:47
#: lib/cannery_web/live/invite_live/form_component.ex:41
#: lib/cannery_web/live/tag_live/form_component.ex:83
#, elixir-autogen, elixir-format
msgid "%{name} updated successfully"
msgstr "%{name} erfolgreich aktualisiert"
#: lib/cannery_web/controllers/user_settings_controller.ex:28
#, elixir-autogen, elixir-format
msgid "A link to confirm your email change has been sent to the new address."
msgstr "Eine Mail zum Bestätigen ihre Mailadresse wurde Ihnen zugesandt."
#: lib/cannery_web/live/ammo_group_live/index.ex:56
#: lib/cannery_web/live/ammo_group_live/show.ex:52
#, elixir-autogen, elixir-format
msgid "Ammo group deleted succesfully"
msgstr "Munitionsgruppe erfolgreich gelöscht"
#: lib/cannery_web/live/ammo_group_live/form_component.ex:88
#, elixir-autogen, elixir-format
msgid "Ammo group updated successfully"
msgstr "Munitionsgruppe erfolgreich aktualisiert"
#: lib/cannery_web/live/invite_live/index.html.heex:102
#: lib/cannery_web/live/invite_live/index.html.heex:131
#, elixir-autogen, elixir-format
msgid "Are you sure you want to delete %{email}? This action is permanent!"
msgstr ""
"Sind Sie sicher, dass sie %{email} löschen möchten? Dies kann nicht "
"zurückgenommen werden!"
#: lib/cannery_web/live/ammo_type_live/show.html.heex:29
#: lib/cannery_web/live/container_live/index.html.heex:46
#: lib/cannery_web/live/container_live/show.html.heex:37
#: lib/cannery_web/live/tag_live/index.html.heex:38
#, elixir-autogen, elixir-format
msgid "Are you sure you want to delete %{name}?"
msgstr "Sind Sie sicher, dass sie %{name} löschen möchten?"
#: lib/cannery_web/live/invite_live/index.html.heex:49
#, elixir-autogen, elixir-format
msgid "Are you sure you want to delete the invite for %{name}?"
msgstr "Sind Sie sicher, dass sie die Einladung für %{name} löschen möchten?"
#: lib/cannery_web/live/ammo_group_live/index.ex:167
#: lib/cannery_web/live/ammo_group_live/show.html.heex:66
#: lib/cannery_web/live/ammo_type_live/index.ex:130
#, elixir-autogen, elixir-format
msgid "Are you sure you want to delete this ammo?"
msgstr "Sind Sie sicher, dass sie diese Munition löschen möchten?"
#: lib/cannery_web/templates/user_settings/edit.html.heex:112
#, elixir-autogen, elixir-format
msgid "Are you sure you want to delete your account?"
msgstr "Sind Sie sicher, dass sie Ihren Account löschen möchten?"
#: lib/cannery_web/components/topbar.ex:86
#, elixir-autogen, elixir-format
msgid "Are you sure you want to log out?"
msgstr "Wirklich ausloggen?"
#: lib/cannery_web/live/invite_live/index.html.heex:74
#, elixir-autogen, elixir-format
msgid "Are you sure you want to make %{name} unlimited?"
msgstr "Sind Sie sicher, dass sie %{name} auf unbegrenzt setzen möchten?"
#: lib/cannery_web/controllers/user_settings_controller.ex:60
#, elixir-autogen, elixir-format
msgid "Email changed successfully."
msgstr "Mailadresse erfolgreich geändert."
#: lib/cannery_web/controllers/user_confirmation_controller.ex:23
#, elixir-autogen, elixir-format
msgid "If your email is in our system and it has not been confirmed yet, you will receive an email with instructions shortly."
msgstr ""
"Falls Ihre Mailadresse bereits in unserer Datenbank ist und noch nicht "
"bestätigt wurde, erhalten Sie gleich eine Mail mit Anweisungen."
#: lib/cannery_web/controllers/user_reset_password_controller.ex:24
#, elixir-autogen, elixir-format
msgid "If your email is in our system, you will receive instructions to reset your password shortly."
msgstr ""
"Falls Ihre Mailadresse bereits in unserer Datenbank ist, erhalten Sie gleich "
"eine Mail mit Anweisungen zum Ändern ihres Passworts."
#: lib/cannery_web/controllers/user_session_controller.ex:23
#, elixir-autogen, elixir-format
msgid "Logged out successfully."
msgstr "Erfolgreich ausgeloggt."
#: lib/cannery_web/controllers/user_reset_password_controller.ex:46
#, elixir-autogen, elixir-format
msgid "Password reset successfully."
msgstr "Passwort erfolgreich zurückgesetzt."
#: lib/cannery_web/controllers/user_settings_controller.ex:47
#, elixir-autogen, elixir-format
msgid "Password updated successfully."
msgstr "Passwort erfolgreich geändert."
#: lib/cannery_web/controllers/user_registration_controller.ex:74
#, elixir-autogen, elixir-format
msgid "Please check your email to verify your account"
msgstr "Bitte überprüfen Sie ihre Mailbox und bestätigen Sie das Nutzerkonto"
#: lib/cannery_web/live/home_live.ex:103
#, elixir-autogen, elixir-format
msgid "Register to setup %{name}"
msgstr "Registrieren Sie sich, um %{name} zu bearbeiten"
#: lib/cannery_web/components/add_shot_group_component.html.heex:48
#: lib/cannery_web/live/ammo_group_live/form_component.html.heex:74
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:157
#: lib/cannery_web/live/container_live/form_component.html.heex:52
#: lib/cannery_web/live/invite_live/form_component.html.heex:30
#: lib/cannery_web/live/range_live/form_component.html.heex:42
#: lib/cannery_web/live/tag_live/form_component.ex:68
#, elixir-autogen, elixir-format
msgid "Saving..."
msgstr "Speichere..."
#: lib/cannery_web/controllers/user_settings_controller.ex:78
#, elixir-autogen, elixir-format
msgid "Your account has been deleted"
msgstr "Ihr Nutzerkonto wurde gelöscht"
#: lib/cannery_web/live/container_live/edit_tags_component.html.heex:16
#, elixir-autogen, elixir-format
msgid "Are you sure you want to remove the %{tag_name} tag from %{container_name}?"
msgstr ""
"Sind Sie sicher, dass sie %{tag_name} Tag von %{container_name} entfernen "
"wollen?"
#: lib/cannery_web/live/container_live/edit_tags_component.ex:36
#, elixir-autogen, elixir-format
msgid "%{name} added successfully"
msgstr "%{name} erfolgreich hinzugefügt"
#: lib/cannery_web/live/container_live/show.ex:39
#, elixir-autogen, elixir-format
msgid "%{tag_name} has been removed from %{container_name}"
msgstr "%{tag_name} wurde von %{container_name} entfernt"
#: lib/cannery_web/live/container_live/edit_tags_component.html.heex:54
#, elixir-autogen, elixir-format
msgid "Adding..."
msgstr "Füge hinzu..."
#: lib/cannery_web/components/add_shot_group_component.ex:68
#, elixir-autogen, elixir-format
msgid "Shots recorded successfully"
msgstr "Schüsse erfolgreich dokumentiert"
#: lib/cannery_web/live/range_live/index.html.heex:29
#, elixir-autogen, elixir-format
msgid "Are you sure you want to unstage this ammo?"
msgstr "Sind sie sicher, dass Sie diese Munition demarkieren möchten?"
#: lib/cannery_web/live/range_live/index.ex:70
#, elixir-autogen, elixir-format
msgid "Ammo group unstaged succesfully"
msgstr "Munition erfolgreich demarkiert"
#: lib/cannery_web/live/ammo_group_live/show.ex:132
#: lib/cannery_web/live/range_live/index.ex:130
#, elixir-autogen, elixir-format
msgid "Are you sure you want to delete this shot record?"
msgstr "Sind sie sicher, dass sie die Schießkladde löschen möchten?"
#: lib/cannery_web/live/ammo_group_live/show.ex:80
#: lib/cannery_web/live/range_live/index.ex:56
#, elixir-autogen, elixir-format
msgid "Shot records deleted succesfully"
msgstr "Schießkladde erfolgreich gelöscht"
#: lib/cannery_web/live/range_live/form_component.ex:55
#, elixir-autogen, elixir-format
msgid "Shot records updated successfully"
msgstr "Schießkladde erfolgreich aktualisiert"
#: lib/cannery_web/controllers/user_confirmation_controller.ex:38
#, elixir-autogen, elixir-format
msgid "%{email} confirmed successfully."
msgstr "%{email} erfolgreich bestätigt."
#: lib/cannery_web/components/move_ammo_group_component.ex:53
#, elixir-autogen, elixir-format
msgid "Ammo moved to %{name} successfully"
msgstr "Munition erfolgreich zu %{name} verschoben"
#: lib/cannery_web/live/invite_live/index.ex:123
#, elixir-autogen, elixir-format
msgid "Copied to clipboard"
msgstr "Der Zwischenablage hinzugefügt"
#: lib/cannery_web/live/container_live/edit_tags_component.ex:58
#, elixir-autogen, elixir-format
msgid "%{name} removed successfully"
msgstr "%{name} erfolgreich entfernt"
#: lib/cannery_web/live/ammo_group_live/index.html.heex:15
#: lib/cannery_web/live/ammo_group_live/index.html.heex:33
#, elixir-autogen, elixir-format
msgid "You'll need to"
msgstr "Sie müssen"
#: lib/cannery_web/live/ammo_group_live/form_component.html.heex:67
#, elixir-autogen, elixir-format
msgid "Creating..."
msgstr "Erstellen..."
#: lib/cannery_web/live/ammo_group_live/form_component.ex:147
#, elixir-autogen, elixir-format
msgid "Ammo group created successfully"
msgid_plural "Ammo groups created successfully"
msgstr[0] "Munitionsgruppe erfolgreich erstellt"
msgstr[1] "Munitionsgruppen erfolgreich erstellt"

View File

@ -11,12 +11,12 @@ msgid ""
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/home_live.ex:63
#: lib/cannery_web/live/home_live.ex:61
msgid "%{name} lets you easily keep an eye on your ammo levels before and after range day"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/home_live.ex:85
#: lib/cannery_web/live/home_live.ex:83
msgid "Access from any internet-capable device"
msgstr ""
@ -26,25 +26,26 @@ msgid "Admins"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/home_live.ex:99
#: lib/cannery_web/live/home_live.ex:97
msgid "Admins:"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/components/topbar.ex:52
#: lib/cannery_web/components/topbar.ex:50
#: lib/cannery_web/live/ammo_group_live/index.html.heex:3
#: lib/cannery_web/live/range_live/index.html.heex:61
#: lib/cannery_web/live/range_live/index.ex:82
msgid "Ammo"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_group_live/form_component.html.heex:21
#: lib/cannery_web/live/ammo_group_live/index.html.heex:27
#: lib/cannery_web/live/ammo_group_live/index.ex:80
msgid "Ammo type"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_type_live/show.html.heex:94
#: lib/cannery_web/live/ammo_type_live/index.ex:87
#: lib/cannery_web/live/ammo_type_live/show.html.heex:92
msgid "Average Price paid"
msgstr ""
@ -54,75 +55,76 @@ msgid "Background color"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:154
#: lib/cannery_web/live/ammo_type_live/index.ex:67
#: lib/cannery_web/live/ammo_type_live/show.html.heex:55
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:140
#: lib/cannery_web/live/ammo_type_live/index.ex:71
#: lib/cannery_web/live/ammo_type_live/show.html.heex:53
msgid "Blank"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:74
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:68
msgid "Brass"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:46
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:44
#: lib/cannery_web/live/ammo_type_live/index.ex:53
#: lib/cannery_web/live/ammo_type_live/show.html.heex:41
#: lib/cannery_web/live/ammo_type_live/show.html.heex:39
msgid "Bullet core"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:37
#: lib/cannery_web/live/ammo_type_live/index.ex:52
#: lib/cannery_web/live/ammo_type_live/show.html.heex:40
#: lib/cannery_web/live/ammo_type_live/show.html.heex:38
msgid "Bullet type"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:62
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:58
#: lib/cannery_web/live/ammo_type_live/index.ex:55
#: lib/cannery_web/live/ammo_type_live/show.html.heex:43
#: lib/cannery_web/live/ammo_type_live/show.html.heex:41
msgid "Caliber"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:55
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:51
#: lib/cannery_web/live/ammo_type_live/index.ex:54
#: lib/cannery_web/live/ammo_type_live/show.html.heex:42
#: lib/cannery_web/live/ammo_type_live/show.html.heex:40
msgid "Cartridge"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:69
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:65
#: lib/cannery_web/live/ammo_type_live/index.ex:56
#: lib/cannery_web/live/ammo_type_live/show.html.heex:44
#: lib/cannery_web/live/ammo_type_live/show.html.heex:42
msgid "Case material"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/components/move_ammo_group_component.html.heex:22
#: lib/cannery_web/components/move_ammo_group_component.ex:67
#: lib/cannery_web/live/ammo_group_live/form_component.html.heex:48
#: lib/cannery_web/live/ammo_group_live/index.html.heex:42
#: lib/cannery_web/live/ammo_group_live/index.ex:85
msgid "Container"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/components/topbar.ex:46
#: lib/cannery_web/components/topbar.ex:44
#: lib/cannery_web/live/container_live/index.ex:38
#: lib/cannery_web/live/container_live/index.html.heex:3
msgid "Containers"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:158
#: lib/cannery_web/live/ammo_type_live/index.ex:68
#: lib/cannery_web/live/ammo_type_live/show.html.heex:56
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:144
#: lib/cannery_web/live/ammo_type_live/index.ex:72
#: lib/cannery_web/live/ammo_type_live/show.html.heex:54
msgid "Corrosive"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_group_live/form_component.html.heex:27
#: lib/cannery_web/live/ammo_group_live/index.html.heex:30
#: lib/cannery_web/live/ammo_group_live/index.ex:81
msgid "Count"
msgstr ""
@ -150,13 +152,13 @@ msgid "Disable"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/home_live.ex:60
#: lib/cannery_web/live/home_live.ex:58
msgid "Easy to Use:"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_group_live/index.ex:36
#: lib/cannery_web/live/ammo_group_live/show.ex:55
#: lib/cannery_web/live/ammo_group_live/index.ex:38
#: lib/cannery_web/live/ammo_group_live/show.ex:42
msgid "Edit Ammo group"
msgstr ""
@ -187,41 +189,42 @@ msgid "Example bullet type abbreviations"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:42
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:40
msgid "FMJ"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:113
#: lib/cannery_web/live/ammo_type_live/index.ex:61
#: lib/cannery_web/live/ammo_type_live/show.html.heex:49
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:103
#: lib/cannery_web/live/ammo_type_live/index.ex:65
#: lib/cannery_web/live/ammo_type_live/show.html.heex:47
msgid "Grains"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:150
#: lib/cannery_web/live/ammo_type_live/index.ex:66
#: lib/cannery_web/live/ammo_type_live/show.html.heex:54
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:136
#: lib/cannery_web/live/ammo_type_live/index.ex:70
#: lib/cannery_web/live/ammo_type_live/show.html.heex:52
msgid "Incendiary"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/home_live.ex:94
#: lib/cannery_web/live/home_live.ex:92
msgid "Instance Information"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/components/invite_card.ex:27
#: lib/cannery_web/components/invite_card.ex:25
msgid "Invite Disabled"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/home_live.ex:125
#: lib/cannery_web/live/home_live.ex:123
msgid "Invite Only"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/components/topbar.ex:71
#: lib/cannery_web/components/topbar.ex:69
#: lib/cannery_web/live/invite_live/index.ex:43
#: lib/cannery_web/live/invite_live/index.html.heex:3
msgid "Invites"
msgstr ""
@ -232,27 +235,7 @@ msgid "Keep me logged in for 60 days"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_type_live/index.ex:34
msgid "Listing Ammo types"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/container_live/index.ex:38
msgid "Listing Containers"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/invite_live/index.ex:43
msgid "Listing Invites"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/tag_live/index.ex:34
msgid "Listing Tags"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/components/move_ammo_group_component.html.heex:30
#: lib/cannery_web/components/move_ammo_group_component.ex:69
#: lib/cannery_web/live/container_live/form_component.html.heex:42
msgid "Location"
msgstr ""
@ -269,14 +252,14 @@ msgid "Magazine, Clip, Ammo Box, etc"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/components/topbar.ex:58
#: lib/cannery_web/components/topbar.ex:56
msgid "Manage"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:162
#: lib/cannery_web/live/ammo_type_live/index.ex:69
#: lib/cannery_web/live/ammo_type_live/show.html.heex:57
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:148
#: lib/cannery_web/live/ammo_type_live/index.ex:73
#: lib/cannery_web/live/ammo_type_live/show.html.heex:55
msgid "Manufacturer"
msgstr ""
@ -330,12 +313,12 @@ msgid "No Ammo Types"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_type_live/show.html.heex:114
#: lib/cannery_web/live/ammo_type_live/show.html.heex:112
msgid "No ammo for this type"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/container_live/show.html.heex:77
#: lib/cannery_web/live/container_live/show.html.heex:78
msgid "No ammo groups in this container"
msgstr ""
@ -358,9 +341,9 @@ msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/components/add_shot_group_component.html.heex:30
#: lib/cannery_web/live/ammo_group_live/form_component.html.heex:41
#: lib/cannery_web/live/ammo_group_live/show.html.heex:122
#: lib/cannery_web/live/ammo_group_live/show.ex:90
#: lib/cannery_web/live/range_live/form_component.html.heex:29
#: lib/cannery_web/live/range_live/index.html.heex:67
#: lib/cannery_web/live/range_live/index.ex:84
msgid "Notes"
msgstr ""
@ -376,15 +359,15 @@ msgid "On the bookshelf"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:121
#: lib/cannery_web/live/ammo_type_live/index.ex:62
#: lib/cannery_web/live/ammo_type_live/show.html.heex:50
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:111
#: lib/cannery_web/live/ammo_type_live/index.ex:66
#: lib/cannery_web/live/ammo_type_live/show.html.heex:48
msgid "Pressure"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_group_live/form_component.html.heex:34
#: lib/cannery_web/live/ammo_group_live/index.html.heex:33
#: lib/cannery_web/live/ammo_group_live/index.ex:82
msgid "Price paid"
msgstr ""
@ -394,24 +377,24 @@ msgid "Price paid:"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:128
#: lib/cannery_web/live/ammo_type_live/index.ex:63
#: lib/cannery_web/live/ammo_type_live/show.html.heex:51
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:118
#: lib/cannery_web/live/ammo_type_live/index.ex:67
#: lib/cannery_web/live/ammo_type_live/show.html.heex:49
msgid "Primer type"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/home_live.ex:124
#: lib/cannery_web/live/home_live.ex:122
msgid "Public Signups"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/home_live.ex:72
#: lib/cannery_web/live/home_live.ex:70
msgid "Secure:"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/home_live.ex:75
#: lib/cannery_web/live/home_live.ex:73
msgid "Self-host your own instance, or use an instance from someone you trust."
msgstr ""
@ -421,12 +404,13 @@ msgid "Set Unlimited"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/controllers/user_settings_controller.ex:10
#: lib/cannery_web/templates/user_settings/edit.html.heex:3
msgid "Settings"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_group_live/show.ex:54
#: lib/cannery_web/live/ammo_group_live/show.ex:41
msgid "Show Ammo group"
msgstr ""
@ -436,12 +420,12 @@ msgid "Show Ammo type"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/home_live.ex:82
#: lib/cannery_web/live/home_live.ex:80
msgid "Simple:"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:51
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:47
msgid "Steel"
msgstr ""
@ -451,7 +435,8 @@ msgid "Stored in"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/components/topbar.ex:40
#: lib/cannery_web/components/topbar.ex:38
#: lib/cannery_web/live/tag_live/index.ex:34
#: lib/cannery_web/live/tag_live/index.html.heex:3
msgid "Tags"
msgstr ""
@ -467,7 +452,7 @@ msgid "Text color"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/home_live.ex:51
#: lib/cannery_web/live/home_live.ex:49
msgid "The self-hosted firearm tracker website"
msgstr ""
@ -477,14 +462,14 @@ msgid "This ammo group is not in a container"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:146
#: lib/cannery_web/live/ammo_type_live/index.ex:65
#: lib/cannery_web/live/ammo_type_live/show.html.heex:53
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:132
#: lib/cannery_web/live/ammo_type_live/index.ex:69
#: lib/cannery_web/live/ammo_type_live/show.html.heex:51
msgid "Tracer"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/components/move_ammo_group_component.html.heex:26
#: lib/cannery_web/components/move_ammo_group_component.ex:68
#: lib/cannery_web/live/container_live/form_component.html.heex:35
msgid "Type"
msgstr ""
@ -501,7 +486,7 @@ msgid "Users"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/components/invite_card.ex:22
#: lib/cannery_web/components/invite_card.ex:20
msgid "Uses Left:"
msgstr ""
@ -511,12 +496,12 @@ msgid "Uses left"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/home_live.ex:47
#: lib/cannery_web/live/home_live.ex:45
msgid "Welcome to %{name}"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/home_live.ex:76
#: lib/cannery_web/live/home_live.ex:74
msgid "Your data stays with you, period"
msgstr ""
@ -526,8 +511,8 @@ msgid "No tags for this container"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/components/topbar.ex:64
#: lib/cannery_web/live/ammo_group_live/index.html.heex:39
#: lib/cannery_web/components/topbar.ex:62
#: lib/cannery_web/live/ammo_group_live/index.ex:84
msgid "Range"
msgstr ""
@ -537,8 +522,8 @@ msgid "Range day"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_group_live/show.html.heex:125
#: lib/cannery_web/live/range_live/index.html.heex:70
#: lib/cannery_web/live/ammo_group_live/show.ex:91
#: lib/cannery_web/live/range_live/index.ex:85
msgid "Date"
msgstr ""
@ -564,15 +549,9 @@ msgstr ""
msgid "Unstage from range"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_group_live/show.ex:52
msgid "Add Shot group"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/components/add_shot_group_component.html.heex:3
#: lib/cannery_web/live/ammo_group_live/index.ex:24
#: lib/cannery_web/live/range_live/index.ex:28
#: lib/cannery_web/live/ammo_group_live/index.ex:26
msgid "Record shots"
msgstr ""
@ -582,7 +561,7 @@ msgid "Ammo Types"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_group_live/index.ex:47
#: lib/cannery_web/live/ammo_group_live/index.ex:49
msgid "Ammo groups"
msgstr ""
@ -593,6 +572,7 @@ msgid "Date (UTC)"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_group_live/show.ex:39
#: lib/cannery_web/live/range_live/index.ex:34
msgid "Edit Shot Records"
msgstr ""
@ -613,8 +593,8 @@ msgid "Rounds left"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_group_live/show.html.heex:119
#: lib/cannery_web/live/range_live/index.html.heex:64
#: lib/cannery_web/live/ammo_group_live/show.ex:89
#: lib/cannery_web/live/range_live/index.ex:83
msgid "Rounds shot"
msgstr ""
@ -624,18 +604,18 @@ msgid "Shot Records"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_group_live/index.ex:30
#: lib/cannery_web/live/ammo_group_live/show.ex:53
#: lib/cannery_web/live/ammo_group_live/index.ex:32
#: lib/cannery_web/live/ammo_group_live/show.ex:40
msgid "Move Ammo group"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/components/move_ammo_group_component.html.heex:3
#: lib/cannery_web/components/move_ammo_group_component.ex:80
msgid "Move ammo"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/components/move_ammo_group_component.html.heex:8
#: lib/cannery_web/components/move_ammo_group_component.ex:85
msgid "No other containers"
msgstr ""
@ -646,50 +626,51 @@ msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/components/ammo_group_card.ex:43
#: lib/cannery_web/live/ammo_group_live/index.html.heex:64
#: lib/cannery_web/live/ammo_group_live/index.ex:117
#: lib/cannery_web/live/ammo_group_live/show.html.heex:32
#: lib/cannery_web/live/ammo_group_live/show.html.heex:39
#: lib/cannery_web/live/ammo_type_live/show.html.heex:98
#: lib/cannery_web/live/ammo_type_live/index.ex:114
#: lib/cannery_web/live/ammo_type_live/show.html.heex:96
msgid "$%{amount}"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:83
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:75
msgid "Bimetal"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:78
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:72
#: lib/cannery_web/live/ammo_type_live/index.ex:57
#: lib/cannery_web/live/ammo_type_live/show.html.heex:45
#: lib/cannery_web/live/ammo_type_live/show.html.heex:43
msgid "Jacket type"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:87
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:79
#: lib/cannery_web/live/ammo_type_live/index.ex:58
#: lib/cannery_web/live/ammo_type_live/show.html.heex:46
#: lib/cannery_web/live/ammo_type_live/show.html.heex:44
msgid "Muzzle velocity"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:103
#: lib/cannery_web/live/ammo_type_live/index.ex:60
#: lib/cannery_web/live/ammo_type_live/show.html.heex:48
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:93
#: lib/cannery_web/live/ammo_type_live/index.ex:61
#: lib/cannery_web/live/ammo_type_live/show.html.heex:46
msgid "Powder grains per charge"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:97
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:89
#: lib/cannery_web/live/ammo_type_live/index.ex:59
#: lib/cannery_web/live/ammo_type_live/show.html.heex:47
#: lib/cannery_web/live/ammo_type_live/show.html.heex:45
msgid "Powder type"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:168
#: lib/cannery_web/live/ammo_type_live/index.ex:70
#: lib/cannery_web/live/ammo_type_live/show.html.heex:58
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:152
#: lib/cannery_web/live/ammo_type_live/index.ex:74
#: lib/cannery_web/live/ammo_type_live/show.html.heex:56
msgid "UPC"
msgstr ""
@ -710,19 +691,19 @@ msgid "New password"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_group_live/index.html.heex:82
#: lib/cannery_web/live/ammo_group_live/index.ex:131
msgid "Stage"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_group_live/index.html.heex:82
#: lib/cannery_web/live/ammo_group_live/index.ex:131
msgid "Unstage"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:137
#: lib/cannery_web/live/ammo_type_live/index.ex:64
#: lib/cannery_web/live/ammo_type_live/show.html.heex:52
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:125
#: lib/cannery_web/live/ammo_type_live/index.ex:68
#: lib/cannery_web/live/ammo_type_live/show.html.heex:50
msgid "Firing type"
msgstr ""
@ -759,12 +740,13 @@ msgid "Show %{name}"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_type_live/show.html.heex:104
#: lib/cannery_web/live/ammo_type_live/index.ex:113
#: lib/cannery_web/live/ammo_type_live/show.html.heex:102
msgid "No cost information"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_group_live/index.html.heex:36
#: lib/cannery_web/live/ammo_group_live/index.ex:83
msgid "% left"
msgstr ""
@ -794,16 +776,57 @@ msgid "Rounds used"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_type_live/show.html.heex:77
#: lib/cannery_web/live/ammo_type_live/show.html.heex:75
msgid "Current # of rounds:"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_type_live/index.html.heex:32
#: lib/cannery_web/live/ammo_type_live/index.ex:86
msgid "Total # of rounds"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_type_live/show.html.heex:85
#: lib/cannery_web/live/ammo_type_live/show.html.heex:83
msgid "Total rounds shot:"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/controllers/user_confirmation_controller.ex:8
msgid "Confirm your account"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/controllers/user_reset_password_controller.ex:9
msgid "Forgot your password?"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/controllers/user_session_controller.ex:8
msgid "Log in"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/controllers/user_registration_controller.ex:35
msgid "Register"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/controllers/user_reset_password_controller.ex:36
msgid "Reset your password"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_group_live/show.ex:38
#: lib/cannery_web/live/range_live/index.ex:28
msgid "Record Shots"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_group_live/form_component.html.heex:58
msgid "Copies"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_type_live/index.ex:34
msgid "Ammo types"
msgstr ""

View File

@ -91,6 +91,6 @@ msgid "This email was sent from %{name} at %{url}, the self-hosted firearm track
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/templates/layout/email.html.heex:17
#: lib/cannery_web/templates/layout/email.html.heex:13
msgid "This email was sent from %{name}, the self-hosted firearm tracker website."
msgstr ""

View File

@ -12,12 +12,12 @@ msgstr ""
"Plural-Forms: nplurals=2\n"
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_group_live/index.ex:42
#: lib/cannery_web/live/ammo_group_live/index.ex:44
msgid "Add Ammo"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_group_live/index.html.heex:12
#: lib/cannery_web/live/ammo_group_live/index.html.heex:24
msgid "Add your first box!"
msgstr ""
@ -82,7 +82,7 @@ msgid "Make your first tag!"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_group_live/index.html.heex:17
#: lib/cannery_web/live/ammo_group_live/index.html.heex:42
msgid "New Ammo group"
msgstr ""
@ -125,9 +125,9 @@ msgid "Reset password"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/components/add_shot_group_component.html.heex:42
#: lib/cannery_web/live/ammo_group_live/form_component.html.heex:54
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:172
#: lib/cannery_web/components/add_shot_group_component.html.heex:46
#: lib/cannery_web/live/ammo_group_live/form_component.html.heex:73
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:156
#: lib/cannery_web/live/container_live/form_component.html.heex:50
#: lib/cannery_web/live/invite_live/form_component.html.heex:28
#: lib/cannery_web/live/range_live/form_component.html.heex:40
@ -161,7 +161,7 @@ msgid "Why not get some ready to shoot?"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_group_live/index.html.heex:85
#: lib/cannery_web/live/ammo_group_live/index.ex:133
#: lib/cannery_web/live/ammo_group_live/show.html.heex:86
#: lib/cannery_web/live/range_live/index.html.heex:36
msgid "Record shots"
@ -173,7 +173,7 @@ msgid "Ammo Details"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/components/move_ammo_group_component.html.heex:12
#: lib/cannery_web/components/move_ammo_group_component.ex:89
msgid "Add another container!"
msgstr ""
@ -183,7 +183,7 @@ msgid "Move containers"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/components/move_ammo_group_component.html.heex:60
#: lib/cannery_web/components/move_ammo_group_component.ex:127
msgid "Select"
msgstr ""
@ -191,3 +191,14 @@ msgstr ""
#: lib/cannery_web/live/invite_live/index.html.heex:33
msgid "Copy to clipboard"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_group_live/index.html.heex:18
#: lib/cannery_web/live/ammo_group_live/index.html.heex:36
msgid "add a container first"
msgstr ""
#, elixir-autogen, elixir-format, fuzzy
#: lib/cannery_web/live/ammo_group_live/form_component.html.heex:66
msgid "Create"
msgstr ""

View File

@ -34,13 +34,13 @@ msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/components/topbar.ex:52
#: lib/cannery_web/live/ammo_group_live/index.html.heex:3
#: lib/cannery_web/live/range_live/index.html.heex:61
#: lib/cannery_web/live/range_live/index.ex:82
msgid "Ammo"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_group_live/form_component.html.heex:21
#: lib/cannery_web/live/ammo_group_live/index.html.heex:27
#: lib/cannery_web/live/ammo_group_live/index.ex:80
msgid "Ammo type"
msgstr ""
@ -55,19 +55,19 @@ msgid "Background color"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:154
#: lib/cannery_web/live/ammo_type_live/index.ex:67
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:140
#: lib/cannery_web/live/ammo_type_live/index.ex:71
#: lib/cannery_web/live/ammo_type_live/show.html.heex:55
msgid "Blank"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:74
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:68
msgid "Brass"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:46
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:44
#: lib/cannery_web/live/ammo_type_live/index.ex:53
#: lib/cannery_web/live/ammo_type_live/show.html.heex:41
msgid "Bullet core"
@ -81,49 +81,50 @@ msgid "Bullet type"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:62
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:58
#: lib/cannery_web/live/ammo_type_live/index.ex:55
#: lib/cannery_web/live/ammo_type_live/show.html.heex:43
msgid "Caliber"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:55
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:51
#: lib/cannery_web/live/ammo_type_live/index.ex:54
#: lib/cannery_web/live/ammo_type_live/show.html.heex:42
msgid "Cartridge"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:69
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:65
#: lib/cannery_web/live/ammo_type_live/index.ex:56
#: lib/cannery_web/live/ammo_type_live/show.html.heex:44
msgid "Case material"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/components/move_ammo_group_component.html.heex:22
#: lib/cannery_web/components/move_ammo_group_component.ex:67
#: lib/cannery_web/live/ammo_group_live/form_component.html.heex:48
#: lib/cannery_web/live/ammo_group_live/index.html.heex:42
#: lib/cannery_web/live/ammo_group_live/index.ex:85
msgid "Container"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/components/topbar.ex:46
#: lib/cannery_web/live/container_live/index.ex:38
#: lib/cannery_web/live/container_live/index.html.heex:3
msgid "Containers"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:158
#: lib/cannery_web/live/ammo_type_live/index.ex:68
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:144
#: lib/cannery_web/live/ammo_type_live/index.ex:72
#: lib/cannery_web/live/ammo_type_live/show.html.heex:56
msgid "Corrosive"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_group_live/form_component.html.heex:27
#: lib/cannery_web/live/ammo_group_live/index.html.heex:30
#: lib/cannery_web/live/ammo_group_live/index.ex:81
msgid "Count"
msgstr ""
@ -156,8 +157,8 @@ msgid "Easy to Use:"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_group_live/index.ex:36
#: lib/cannery_web/live/ammo_group_live/show.ex:55
#: lib/cannery_web/live/ammo_group_live/index.ex:38
#: lib/cannery_web/live/ammo_group_live/show.ex:42
msgid "Edit Ammo group"
msgstr ""
@ -188,20 +189,20 @@ msgid "Example bullet type abbreviations"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:42
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:40
msgid "FMJ"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:113
#: lib/cannery_web/live/ammo_type_live/index.ex:61
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:103
#: lib/cannery_web/live/ammo_type_live/index.ex:65
#: lib/cannery_web/live/ammo_type_live/show.html.heex:49
msgid "Grains"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:150
#: lib/cannery_web/live/ammo_type_live/index.ex:66
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:136
#: lib/cannery_web/live/ammo_type_live/index.ex:70
#: lib/cannery_web/live/ammo_type_live/show.html.heex:54
msgid "Incendiary"
msgstr ""
@ -223,6 +224,7 @@ msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/components/topbar.ex:71
#: lib/cannery_web/live/invite_live/index.ex:43
#: lib/cannery_web/live/invite_live/index.html.heex:3
msgid "Invites"
msgstr ""
@ -233,27 +235,7 @@ msgid "Keep me logged in for 60 days"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_type_live/index.ex:34
msgid "Listing Ammo types"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/container_live/index.ex:38
msgid "Listing Containers"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/invite_live/index.ex:43
msgid "Listing Invites"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/tag_live/index.ex:34
msgid "Listing Tags"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/components/move_ammo_group_component.html.heex:30
#: lib/cannery_web/components/move_ammo_group_component.ex:69
#: lib/cannery_web/live/container_live/form_component.html.heex:42
msgid "Location"
msgstr ""
@ -275,8 +257,8 @@ msgid "Manage"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:162
#: lib/cannery_web/live/ammo_type_live/index.ex:69
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:148
#: lib/cannery_web/live/ammo_type_live/index.ex:73
#: lib/cannery_web/live/ammo_type_live/show.html.heex:57
msgid "Manufacturer"
msgstr ""
@ -336,7 +318,7 @@ msgid "No ammo for this type"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/container_live/show.html.heex:77
#: lib/cannery_web/live/container_live/show.html.heex:78
msgid "No ammo groups in this container"
msgstr ""
@ -359,9 +341,9 @@ msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/components/add_shot_group_component.html.heex:30
#: lib/cannery_web/live/ammo_group_live/form_component.html.heex:41
#: lib/cannery_web/live/ammo_group_live/show.html.heex:122
#: lib/cannery_web/live/ammo_group_live/show.ex:90
#: lib/cannery_web/live/range_live/form_component.html.heex:29
#: lib/cannery_web/live/range_live/index.html.heex:67
#: lib/cannery_web/live/range_live/index.ex:84
msgid "Notes"
msgstr ""
@ -377,15 +359,15 @@ msgid "On the bookshelf"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:121
#: lib/cannery_web/live/ammo_type_live/index.ex:62
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:111
#: lib/cannery_web/live/ammo_type_live/index.ex:66
#: lib/cannery_web/live/ammo_type_live/show.html.heex:50
msgid "Pressure"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_group_live/form_component.html.heex:34
#: lib/cannery_web/live/ammo_group_live/index.html.heex:33
#: lib/cannery_web/live/ammo_group_live/index.ex:82
msgid "Price paid"
msgstr ""
@ -395,8 +377,8 @@ msgid "Price paid:"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:128
#: lib/cannery_web/live/ammo_type_live/index.ex:63
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:118
#: lib/cannery_web/live/ammo_type_live/index.ex:67
#: lib/cannery_web/live/ammo_type_live/show.html.heex:51
msgid "Primer type"
msgstr ""
@ -422,12 +404,13 @@ msgid "Set Unlimited"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/controllers/user_settings_controller.ex:10
#: lib/cannery_web/templates/user_settings/edit.html.heex:3
msgid "Settings"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_group_live/show.ex:54
#: lib/cannery_web/live/ammo_group_live/show.ex:41
msgid "Show Ammo group"
msgstr ""
@ -442,7 +425,7 @@ msgid "Simple:"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:51
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:47
msgid "Steel"
msgstr ""
@ -453,6 +436,7 @@ msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/components/topbar.ex:40
#: lib/cannery_web/live/tag_live/index.ex:34
#: lib/cannery_web/live/tag_live/index.html.heex:3
msgid "Tags"
msgstr ""
@ -478,14 +462,14 @@ msgid "This ammo group is not in a container"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:146
#: lib/cannery_web/live/ammo_type_live/index.ex:65
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:132
#: lib/cannery_web/live/ammo_type_live/index.ex:69
#: lib/cannery_web/live/ammo_type_live/show.html.heex:53
msgid "Tracer"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/components/move_ammo_group_component.html.heex:26
#: lib/cannery_web/components/move_ammo_group_component.ex:68
#: lib/cannery_web/live/container_live/form_component.html.heex:35
msgid "Type"
msgstr ""
@ -528,7 +512,7 @@ msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/components/topbar.ex:64
#: lib/cannery_web/live/ammo_group_live/index.html.heex:39
#: lib/cannery_web/live/ammo_group_live/index.ex:84
msgid "Range"
msgstr ""
@ -538,8 +522,8 @@ msgid "Range day"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_group_live/show.html.heex:125
#: lib/cannery_web/live/range_live/index.html.heex:70
#: lib/cannery_web/live/ammo_group_live/show.ex:91
#: lib/cannery_web/live/range_live/index.ex:85
msgid "Date"
msgstr ""
@ -565,15 +549,9 @@ msgstr ""
msgid "Unstage from range"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_group_live/show.ex:52
msgid "Add Shot group"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/components/add_shot_group_component.html.heex:3
#: lib/cannery_web/live/ammo_group_live/index.ex:24
#: lib/cannery_web/live/range_live/index.ex:28
#: lib/cannery_web/live/ammo_group_live/index.ex:26
msgid "Record shots"
msgstr ""
@ -583,7 +561,7 @@ msgid "Ammo Types"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_group_live/index.ex:47
#: lib/cannery_web/live/ammo_group_live/index.ex:49
msgid "Ammo groups"
msgstr ""
@ -594,6 +572,7 @@ msgid "Date (UTC)"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_group_live/show.ex:39
#: lib/cannery_web/live/range_live/index.ex:34
msgid "Edit Shot Records"
msgstr ""
@ -614,8 +593,8 @@ msgid "Rounds left"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_group_live/show.html.heex:119
#: lib/cannery_web/live/range_live/index.html.heex:64
#: lib/cannery_web/live/ammo_group_live/show.ex:89
#: lib/cannery_web/live/range_live/index.ex:83
msgid "Rounds shot"
msgstr ""
@ -625,18 +604,18 @@ msgid "Shot Records"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_group_live/index.ex:30
#: lib/cannery_web/live/ammo_group_live/show.ex:53
#: lib/cannery_web/live/ammo_group_live/index.ex:32
#: lib/cannery_web/live/ammo_group_live/show.ex:40
msgid "Move Ammo group"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/components/move_ammo_group_component.html.heex:3
#: lib/cannery_web/components/move_ammo_group_component.ex:80
msgid "Move ammo"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/components/move_ammo_group_component.html.heex:8
#: lib/cannery_web/components/move_ammo_group_component.ex:85
msgid "No other containers"
msgstr ""
@ -647,7 +626,7 @@ msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/components/ammo_group_card.ex:43
#: lib/cannery_web/live/ammo_group_live/index.html.heex:64
#: lib/cannery_web/live/ammo_group_live/index.ex:117
#: lib/cannery_web/live/ammo_group_live/show.html.heex:32
#: lib/cannery_web/live/ammo_group_live/show.html.heex:39
#: lib/cannery_web/live/ammo_type_live/show.html.heex:98
@ -655,41 +634,41 @@ msgid "$%{amount}"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:83
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:75
msgid "Bimetal"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:78
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:72
#: lib/cannery_web/live/ammo_type_live/index.ex:57
#: lib/cannery_web/live/ammo_type_live/show.html.heex:45
msgid "Jacket type"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:87
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:79
#: lib/cannery_web/live/ammo_type_live/index.ex:58
#: lib/cannery_web/live/ammo_type_live/show.html.heex:46
msgid "Muzzle velocity"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:103
#: lib/cannery_web/live/ammo_type_live/index.ex:60
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:93
#: lib/cannery_web/live/ammo_type_live/index.ex:61
#: lib/cannery_web/live/ammo_type_live/show.html.heex:48
msgid "Powder grains per charge"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:97
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:89
#: lib/cannery_web/live/ammo_type_live/index.ex:59
#: lib/cannery_web/live/ammo_type_live/show.html.heex:47
msgid "Powder type"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:168
#: lib/cannery_web/live/ammo_type_live/index.ex:70
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:152
#: lib/cannery_web/live/ammo_type_live/index.ex:74
#: lib/cannery_web/live/ammo_type_live/show.html.heex:58
msgid "UPC"
msgstr ""
@ -711,18 +690,18 @@ msgid "New password"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_group_live/index.html.heex:82
#: lib/cannery_web/live/ammo_group_live/index.ex:130
msgid "Stage"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_group_live/index.html.heex:82
#: lib/cannery_web/live/ammo_group_live/index.ex:130
msgid "Unstage"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:137
#: lib/cannery_web/live/ammo_type_live/index.ex:64
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:125
#: lib/cannery_web/live/ammo_type_live/index.ex:68
#: lib/cannery_web/live/ammo_type_live/show.html.heex:52
msgid "Firing type"
msgstr ""
@ -765,7 +744,7 @@ msgid "No cost information"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_group_live/index.html.heex:36
#: lib/cannery_web/live/ammo_group_live/index.ex:83
msgid "% left"
msgstr ""
@ -800,7 +779,7 @@ msgid "Current # of rounds:"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_type_live/index.html.heex:32
#: lib/cannery_web/live/ammo_type_live/index.ex:86
msgid "Total # of rounds"
msgstr ""
@ -808,3 +787,44 @@ msgstr ""
#: lib/cannery_web/live/ammo_type_live/show.html.heex:85
msgid "Total rounds shot:"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/controllers/user_confirmation_controller.ex:8
msgid "Confirm your account"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/controllers/user_reset_password_controller.ex:9
msgid "Forgot your password?"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/controllers/user_session_controller.ex:8
msgid "Log in"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/controllers/user_registration_controller.ex:35
msgid "Register"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/controllers/user_reset_password_controller.ex:36
msgid "Reset your password"
msgstr ""
#, elixir-autogen, elixir-format, fuzzy
#: lib/cannery_web/live/ammo_group_live/show.ex:38
#: lib/cannery_web/live/range_live/index.ex:28
msgid "Record Shots"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_group_live/form_component.html.heex:58
msgid "Copies"
msgstr ""
#, elixir-autogen, elixir-format, fuzzy
#: lib/cannery_web/live/ammo_type_live/index.ex:34
msgid "Ammo types"
msgstr ""

View File

@ -65,19 +65,19 @@ msgid "Oops, something went wrong! Please check the errors below."
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/controllers/user_reset_password_controller.ex:60
#: lib/cannery_web/controllers/user_reset_password_controller.ex:63
msgid "Reset password link is invalid or it has expired."
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/controllers/user_registration_controller.ex:25
#: lib/cannery_web/controllers/user_registration_controller.ex:53
#: lib/cannery_web/controllers/user_registration_controller.ex:56
msgid "Sorry, public registration is disabled"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/controllers/user_registration_controller.ex:15
#: lib/cannery_web/controllers/user_registration_controller.ex:43
#: lib/cannery_web/controllers/user_registration_controller.ex:46
msgid "Sorry, this invite was not found or expired"
msgstr ""
@ -92,7 +92,7 @@ msgid "Unauthorized"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/controllers/user_confirmation_controller.ex:53
#: lib/cannery_web/controllers/user_confirmation_controller.ex:54
msgid "User confirmation link is invalid or it has expired."
msgstr ""
@ -158,3 +158,13 @@ msgstr ""
#: lib/cannery_web/live/container_live/edit_tags_component.ex:52
msgid "Tag could not be removed"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_group_live/form_component.ex:113
msgid "Could not parse number of copies"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_group_live/form_component.ex:98
msgid "Invalid number of copies, must be between 1 and %{max}. Was %{multiplier}"
msgstr ""

View File

@ -63,18 +63,13 @@ msgid "A link to confirm your email change has been sent to the new address."
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_group_live/form_component.ex:87
msgid "Ammo group created successfully"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_group_live/index.ex:54
#: lib/cannery_web/live/ammo_group_live/show.ex:34
#: lib/cannery_web/live/ammo_group_live/index.ex:56
#: lib/cannery_web/live/ammo_group_live/show.ex:52
msgid "Ammo group deleted succesfully"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_group_live/form_component.ex:69
#: lib/cannery_web/live/ammo_group_live/form_component.ex:75
msgid "Ammo group updated successfully"
msgstr ""
@ -98,9 +93,9 @@ msgid "Are you sure you want to delete the invite for %{name}?"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_group_live/index.html.heex:120
#: lib/cannery_web/live/ammo_group_live/index.ex:165
#: lib/cannery_web/live/ammo_group_live/show.html.heex:66
#: lib/cannery_web/live/ammo_type_live/index.html.heex:75
#: lib/cannery_web/live/ammo_type_live/index.ex:130
msgid "Are you sure you want to delete this ammo?"
msgstr ""
@ -125,7 +120,7 @@ msgid "Email changed successfully."
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/controllers/user_confirmation_controller.ex:22
#: lib/cannery_web/controllers/user_confirmation_controller.ex:23
msgid "If your email is in our system and it has not been confirmed yet, you will receive an email with instructions shortly."
msgstr ""
@ -140,7 +135,7 @@ msgid "Logged out successfully."
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/controllers/user_reset_password_controller.ex:43
#: lib/cannery_web/controllers/user_reset_password_controller.ex:46
msgid "Password reset successfully."
msgstr ""
@ -150,7 +145,7 @@ msgid "Password updated successfully."
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/controllers/user_registration_controller.ex:71
#: lib/cannery_web/controllers/user_registration_controller.ex:74
msgid "Please check your email to verify your account"
msgstr ""
@ -160,9 +155,9 @@ msgid "Register to setup %{name}"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/components/add_shot_group_component.html.heex:44
#: lib/cannery_web/live/ammo_group_live/form_component.html.heex:55
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:173
#: lib/cannery_web/components/add_shot_group_component.html.heex:48
#: lib/cannery_web/live/ammo_group_live/form_component.html.heex:74
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:157
#: lib/cannery_web/live/container_live/form_component.html.heex:52
#: lib/cannery_web/live/invite_live/form_component.html.heex:30
#: lib/cannery_web/live/range_live/form_component.html.heex:42
@ -211,11 +206,13 @@ msgid "Ammo group unstaged succesfully"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/range_live/index.html.heex:108
#: lib/cannery_web/live/ammo_group_live/show.ex:132
#: lib/cannery_web/live/range_live/index.ex:130
msgid "Are you sure you want to delete this shot record?"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_group_live/show.ex:80
#: lib/cannery_web/live/range_live/index.ex:56
msgid "Shot records deleted succesfully"
msgstr ""
@ -226,12 +223,12 @@ msgid "Shot records updated successfully"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/controllers/user_confirmation_controller.ex:37
#: lib/cannery_web/controllers/user_confirmation_controller.ex:38
msgid "%{email} confirmed successfully."
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/components/move_ammo_group_component.ex:47
#: lib/cannery_web/components/move_ammo_group_component.ex:53
msgid "Ammo moved to %{name} successfully"
msgstr ""
@ -244,3 +241,21 @@ msgstr ""
#: lib/cannery_web/live/container_live/edit_tags_component.ex:58
msgid "%{name} removed successfully"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_group_live/index.html.heex:15
#: lib/cannery_web/live/ammo_group_live/index.html.heex:33
msgid "You'll need to"
msgstr ""
#, elixir-autogen, elixir-format, fuzzy
#: lib/cannery_web/live/ammo_group_live/form_component.html.heex:67
msgid "Creating..."
msgstr ""
#, elixir-autogen, elixir-format, fuzzy
#: lib/cannery_web/live/ammo_group_live/form_component.ex:134
msgid "Ammo group created successfully"
msgid_plural "Ammo groups created successfully"
msgstr[0] ""
msgstr[1] ""

View File

@ -37,7 +37,7 @@ msgid "Error"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/templates/error/error.html.heex:29
#: lib/cannery_web/templates/error/error.html.heex:28
msgid "Go back home"
msgstr ""
@ -65,19 +65,19 @@ msgid "Oops, something went wrong! Please check the errors below."
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/controllers/user_reset_password_controller.ex:60
#: lib/cannery_web/controllers/user_reset_password_controller.ex:63
msgid "Reset password link is invalid or it has expired."
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/controllers/user_registration_controller.ex:25
#: lib/cannery_web/controllers/user_registration_controller.ex:53
#: lib/cannery_web/controllers/user_registration_controller.ex:56
msgid "Sorry, public registration is disabled"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/controllers/user_registration_controller.ex:15
#: lib/cannery_web/controllers/user_registration_controller.ex:43
#: lib/cannery_web/controllers/user_registration_controller.ex:46
msgid "Sorry, this invite was not found or expired"
msgstr ""
@ -92,7 +92,7 @@ msgid "Unauthorized"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/controllers/user_confirmation_controller.ex:53
#: lib/cannery_web/controllers/user_confirmation_controller.ex:54
msgid "User confirmation link is invalid or it has expired."
msgstr ""
@ -157,3 +157,13 @@ msgstr ""
#: lib/cannery_web/live/container_live/edit_tags_component.ex:52
msgid "Tag could not be removed"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_group_live/form_component.ex:126
msgid "Could not parse number of copies"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_group_live/form_component.ex:111
msgid "Invalid number of copies, must be between 1 and %{max}. Was %{multiplier}"
msgstr ""

View File

@ -62,18 +62,13 @@ msgid "A link to confirm your email change has been sent to the new address."
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_group_live/form_component.ex:87
msgid "Ammo group created successfully"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_group_live/index.ex:54
#: lib/cannery_web/live/ammo_group_live/show.ex:34
#: lib/cannery_web/live/ammo_group_live/index.ex:56
#: lib/cannery_web/live/ammo_group_live/show.ex:52
msgid "Ammo group deleted succesfully"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_group_live/form_component.ex:69
#: lib/cannery_web/live/ammo_group_live/form_component.ex:88
msgid "Ammo group updated successfully"
msgstr ""
@ -84,7 +79,7 @@ msgid "Are you sure you want to delete %{email}? This action is permanent!"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_type_live/show.html.heex:29
#: lib/cannery_web/live/ammo_type_live/show.html.heex:27
#: lib/cannery_web/live/container_live/index.html.heex:46
#: lib/cannery_web/live/container_live/show.html.heex:37
#: lib/cannery_web/live/tag_live/index.html.heex:38
@ -97,9 +92,9 @@ msgid "Are you sure you want to delete the invite for %{name}?"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_group_live/index.html.heex:120
#: lib/cannery_web/live/ammo_group_live/index.ex:167
#: lib/cannery_web/live/ammo_group_live/show.html.heex:66
#: lib/cannery_web/live/ammo_type_live/index.html.heex:75
#: lib/cannery_web/live/ammo_type_live/index.ex:140
msgid "Are you sure you want to delete this ammo?"
msgstr ""
@ -109,7 +104,7 @@ msgid "Are you sure you want to delete your account?"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/components/topbar.ex:86
#: lib/cannery_web/components/topbar.ex:84
msgid "Are you sure you want to log out?"
msgstr ""
@ -124,7 +119,7 @@ msgid "Email changed successfully."
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/controllers/user_confirmation_controller.ex:22
#: lib/cannery_web/controllers/user_confirmation_controller.ex:23
msgid "If your email is in our system and it has not been confirmed yet, you will receive an email with instructions shortly."
msgstr ""
@ -139,7 +134,7 @@ msgid "Logged out successfully."
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/controllers/user_reset_password_controller.ex:43
#: lib/cannery_web/controllers/user_reset_password_controller.ex:46
msgid "Password reset successfully."
msgstr ""
@ -149,19 +144,19 @@ msgid "Password updated successfully."
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/controllers/user_registration_controller.ex:71
#: lib/cannery_web/controllers/user_registration_controller.ex:74
msgid "Please check your email to verify your account"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/home_live.ex:103
#: lib/cannery_web/live/home_live.ex:101
msgid "Register to setup %{name}"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/components/add_shot_group_component.html.heex:44
#: lib/cannery_web/live/ammo_group_live/form_component.html.heex:55
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:173
#: lib/cannery_web/components/add_shot_group_component.html.heex:48
#: lib/cannery_web/live/ammo_group_live/form_component.html.heex:74
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:157
#: lib/cannery_web/live/container_live/form_component.html.heex:52
#: lib/cannery_web/live/invite_live/form_component.html.heex:30
#: lib/cannery_web/live/range_live/form_component.html.heex:42
@ -210,11 +205,13 @@ msgid "Ammo group unstaged succesfully"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/range_live/index.html.heex:108
#: lib/cannery_web/live/ammo_group_live/show.ex:132
#: lib/cannery_web/live/range_live/index.ex:130
msgid "Are you sure you want to delete this shot record?"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_group_live/show.ex:80
#: lib/cannery_web/live/range_live/index.ex:56
msgid "Shot records deleted succesfully"
msgstr ""
@ -225,12 +222,12 @@ msgid "Shot records updated successfully"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/controllers/user_confirmation_controller.ex:37
#: lib/cannery_web/controllers/user_confirmation_controller.ex:38
msgid "%{email} confirmed successfully."
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/components/move_ammo_group_component.ex:47
#: lib/cannery_web/components/move_ammo_group_component.ex:53
msgid "Ammo moved to %{name} successfully"
msgstr ""
@ -243,3 +240,21 @@ msgstr ""
#: lib/cannery_web/live/container_live/edit_tags_component.ex:58
msgid "%{name} removed successfully"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_group_live/index.html.heex:15
#: lib/cannery_web/live/ammo_group_live/index.html.heex:33
msgid "You'll need to"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_group_live/form_component.html.heex:67
msgid "Creating..."
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_group_live/form_component.ex:147
msgid "Ammo group created successfully"
msgid_plural "Ammo groups created successfully"
msgstr[0] ""
msgstr[1] ""

10
priv/i18n/de.tbx Normal file
View File

@ -0,0 +1,10 @@
<?xml version="1.0"?>
<!DOCTYPE martif PUBLIC "ISO 12200:1999A//DTD MARTIF core (DXFcdV04)//EN" "TBXcdv04.dtd">
<martif type="TBX">
<martifHeader>
<fileDesc>
<sourceDesc><p>Translate Toolkit</p></sourceDesc>
</fileDesc>
</martifHeader>
<text><body></body></text>
</martif>

View File

@ -304,9 +304,9 @@ defmodule Cannery.AccountsTest do
end
test "deletes all tokens for the given user", %{user: user} do
_ = Accounts.generate_user_session_token(user)
_token = Accounts.generate_user_session_token(user)
{:ok, _} =
{:ok, _user} =
Accounts.update_user_password(user, valid_user_password(), %{
"password" => "new valid password"
})
@ -501,8 +501,8 @@ defmodule Cannery.AccountsTest do
end
test "deletes all tokens for the given user", %{user: user} do
_ = Accounts.generate_user_session_token(user)
{:ok, _} = Accounts.reset_user_password(user, %{"password" => "new valid password"})
_token = Accounts.generate_user_session_token(user)
{:ok, _user} = Accounts.reset_user_password(user, %{"password" => "new valid password"})
refute Repo.get_by(UserToken, user_id: user.id)
end
end

View File

@ -20,8 +20,8 @@ defmodule Cannery.ActivityLogTest do
container = container_fixture(current_user)
ammo_type = ammo_type_fixture(current_user)
%{id: ammo_group_id} =
ammo_group = ammo_group_fixture(%{"count" => 25}, ammo_type, container, current_user)
{1, [%{id: ammo_group_id} = ammo_group]} =
ammo_group_fixture(%{"count" => 25}, ammo_type, container, current_user)
shot_group =
%{"count" => 5, "date" => ~N[2022-02-13 03:17:00], "notes" => "some notes"}

View File

@ -108,7 +108,7 @@ defmodule Cannery.AmmoTest do
current_user = user_fixture()
ammo_type = ammo_type_fixture(current_user)
container = container_fixture(current_user)
ammo_group = ammo_group_fixture(ammo_type, container, current_user)
{1, [ammo_group]} = ammo_group_fixture(ammo_type, container, current_user)
[
ammo_type: ammo_type,
@ -129,28 +129,28 @@ defmodule Cannery.AmmoTest do
ammo_group |> Repo.preload(:shot_groups)
end
test "create_ammo_group/1 with valid data creates a ammo_group",
test "create_ammo_groups/3 with valid data creates a ammo_group",
%{
ammo_type: ammo_type,
container: container,
current_user: current_user
} do
assert {:ok, %AmmoGroup{} = ammo_group} =
assert {:ok, {1, [%AmmoGroup{} = ammo_group]}} =
@valid_attrs
|> Map.merge(%{"ammo_type_id" => ammo_type.id, "container_id" => container.id})
|> Ammo.create_ammo_group(current_user)
|> Ammo.create_ammo_groups(1, current_user)
assert ammo_group.count == 42
assert ammo_group.notes == "some notes"
assert ammo_group.price_paid == 120.5
end
test "create_ammo_group/1 with invalid data returns error changeset",
test "create_ammo_groups/3 with invalid data returns error changeset",
%{ammo_type: ammo_type, container: container, current_user: current_user} do
assert {:error, %Changeset{}} =
@invalid_attrs
|> Map.merge(%{"ammo_type_id" => ammo_type.id, "container_id" => container.id})
|> Ammo.create_ammo_group(current_user)
|> Ammo.create_ammo_groups(1, current_user)
end
test "update_ammo_group/2 with valid data updates the ammo_group",

View File

@ -116,7 +116,7 @@ defmodule CanneryWeb.UserAuthTest do
end
test "does not authenticate if data is missing", %{conn: conn, current_user: current_user} do
_ = Accounts.generate_user_session_token(current_user)
_token = Accounts.generate_user_session_token(current_user)
conn = UserAuth.fetch_current_user(conn, [])
refute get_session(conn, :user_token)
refute conn.assigns.current_user

View File

@ -5,8 +5,7 @@ defmodule CanneryWeb.UserConfirmationControllerTest do
use CanneryWeb.ConnCase, async: true
import CanneryWeb.Gettext
alias Cannery.Accounts
alias Cannery.Repo
alias Cannery.{Accounts, Repo}
@moduletag :user_confirmation_controller_test

View File

@ -6,18 +6,26 @@ defmodule CanneryWeb.AmmoGroupLiveTest do
use CanneryWeb.ConnCase
import Phoenix.LiveViewTest
import CanneryWeb.Gettext
alias Cannery.Repo
alias Cannery.{Ammo, Repo}
@moduletag :ammo_group_live_test
@shot_group_create_attrs %{"ammo_left" => 5, "notes" => "some notes"}
@create_attrs %{count: 42, notes: "some notes", price_paid: 120.5}
@update_attrs %{count: 43, notes: "some updated notes", price_paid: 456.7}
@shot_group_update_attrs %{"count" => 5, "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
# @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)
%{ammo_group: ammo_group_fixture(ammo_type, container, current_user)}
{1, [ammo_group]} = ammo_group_fixture(ammo_type, container, current_user)
shot_group =
%{"count" => 5, "date" => ~N[2022-02-13 03:17:00], "notes" => "some notes"}
|> shot_group_fixture(current_user, ammo_group)
%{ammo_group: ammo_group, shot_group: shot_group}
end
describe "Index" do
@ -31,7 +39,7 @@ defmodule CanneryWeb.AmmoGroupLiveTest do
assert html =~ ammo_group.ammo_type.name
end
test "saves new ammo_group", %{conn: conn} do
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", "New Ammo group")) |> render_click() =~
@ -43,7 +51,7 @@ defmodule CanneryWeb.AmmoGroupLiveTest do
# |> form("#ammo_group-form", ammo_group: @invalid_attrs)
# |> render_change() =~ dgettext("errors", "can't be blank")
{:ok, _, html} =
{:ok, _view, html} =
index_live
|> form("#ammo_group-form", ammo_group: @create_attrs)
|> render_submit()
@ -53,6 +61,68 @@ defmodule CanneryWeb.AmmoGroupLiveTest do
assert html =~ "42"
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", "New Ammo group")) |> render_click() =~
gettext("New Ammo group")
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 groups created successfully")
assert Ammo.list_ammo_groups(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", "New Ammo group")) |> render_click() =~
gettext("New Ammo group")
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 "saves new shot_group", %{conn: conn, ammo_group: ammo_group} do
{:ok, index_live, _html} = live(conn, Routes.ammo_group_index_path(conn, :index))
@ -65,7 +135,7 @@ defmodule CanneryWeb.AmmoGroupLiveTest do
# |> form("#shot_group-form", shot_group: @invalid_attrs)
# |> render_change() =~ dgettext("errors", "is invalid")
{:ok, _, html} =
{:ok, _view, html} =
index_live
|> form("#shot-group-form", shot_group: @shot_group_create_attrs)
|> render_submit()
@ -88,7 +158,7 @@ defmodule CanneryWeb.AmmoGroupLiveTest do
# |> form("#ammo_group-form", ammo_group: @invalid_attrs)
# |> render_change() =~ dgettext("errors", "can't be blank")
{:ok, _, html} =
{:ok, _view, html} =
index_live
|> form("#ammo_group-form", ammo_group: @update_attrs)
|> render_submit()
@ -134,7 +204,7 @@ defmodule CanneryWeb.AmmoGroupLiveTest do
# |> form("#ammo_group-form", ammo_group: @invalid_attrs)
# |> render_change() =~ dgettext("errors", "can't be blank")
{:ok, _, html} =
{:ok, _view, html} =
show_live
|> form("#ammo_group-form", ammo_group: @update_attrs)
|> render_submit()
@ -156,7 +226,7 @@ defmodule CanneryWeb.AmmoGroupLiveTest do
# |> form("#shot_group-form", shot_group: @invalid_attrs)
# |> render_change() =~ dgettext("errors", "is invalid")
{:ok, _, html} =
{:ok, _view, html} =
index_live
|> form("#shot-group-form", shot_group: @shot_group_create_attrs)
|> render_submit()
@ -164,5 +234,40 @@ defmodule CanneryWeb.AmmoGroupLiveTest do
assert html =~ dgettext("prompts", "Shots recorded successfully")
end
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("[data-qa=\"edit-#{shot_group.id}\"]") |> 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("[data-qa=\"delete-#{shot_group.id}\"]") |> render_click()
refute has_element?(index_live, "#shot_group-#{shot_group.id}")
end
end
end

View File

@ -62,7 +62,7 @@ defmodule CanneryWeb.AmmoTypeLiveTest do
# |> form("#ammo_type-form", ammo_type: @invalid_attrs)
# |> render_change() =~ dgettext("errors", "can't be blank")
{:ok, _, html} =
{:ok, _view, html} =
index_live
|> form("#ammo_type-form", ammo_type: @create_attrs)
|> render_submit()
@ -86,7 +86,7 @@ defmodule CanneryWeb.AmmoTypeLiveTest do
# |> form("#ammo_type-form", ammo_type: @invalid_attrs)
# |> render_change() =~ dgettext("errors", "can't be blank")
{:ok, _, html} =
{:ok, _view, html} =
index_live
|> form("#ammo_type-form", ammo_type: @update_attrs)
|> render_submit()
@ -128,7 +128,7 @@ defmodule CanneryWeb.AmmoTypeLiveTest do
# |> form("#ammo_type-form", ammo_type: @invalid_attrs)
# |> render_change() =~ dgettext("errors", "can't be blank")
{:ok, _, html} =
{:ok, _view, html} =
show_live
|> form("#ammo_type-form", ammo_type: @update_attrs)
|> render_submit()

View File

@ -52,7 +52,7 @@ defmodule CanneryWeb.ContainerLiveTest do
# |> form("#container-form", container: @invalid_attrs)
# |> render_change() =~ dgettext("errors", "can't be blank")
{:ok, _, html} =
{:ok, _view, html} =
index_live
|> form("#container-form", container: @create_attrs)
|> render_submit()
@ -78,7 +78,7 @@ defmodule CanneryWeb.ContainerLiveTest do
# |> form("#container-form", container: @invalid_attrs)
# |> render_change() =~ dgettext("errors", "can't be blank")
{:ok, _, html} =
{:ok, _view, html} =
index_live
|> form("#container-form", container: @update_attrs)
|> render_submit()
@ -123,7 +123,7 @@ defmodule CanneryWeb.ContainerLiveTest do
# |> form("#container-form", container: @invalid_attrs)
# |> render_change() =~ dgettext("errors", "can't be blank")
{:ok, _, html} =
{:ok, _view, html} =
show_live
|> form("#container-form", container: @update_attrs)
|> render_submit()

View File

@ -40,7 +40,7 @@ defmodule CanneryWeb.InviteLiveTest do
# |> form("#invite-form", invite: @invalid_attrs)
# |> render_change() =~ dgettext("errors", "can't be blank")
{:ok, _, html} =
{:ok, _view, html} =
index_live
|> form("#invite-form", invite: @create_attrs)
|> render_submit()
@ -63,7 +63,7 @@ defmodule CanneryWeb.InviteLiveTest do
# |> form("#invite-form", invite: @invalid_attrs)
# |> render_change() =~ dgettext("errors", "can't be blank")
{:ok, _, html} =
{:ok, _view, html} =
index_live
|> form("#invite-form", invite: @update_attrs)
|> render_submit()

View File

@ -16,7 +16,9 @@ defmodule CanneryWeb.RangeLiveTest do
defp create_shot_group(%{current_user: current_user}) do
container = container_fixture(%{"staged" => true}, current_user)
ammo_type = ammo_type_fixture(current_user)
ammo_group = ammo_group_fixture(%{"staged" => true}, ammo_type, container, current_user)
{1, [ammo_group]} =
ammo_group_fixture(%{"staged" => true}, ammo_type, container, current_user)
shot_group =
%{"count" => 5, "date" => ~N[2022-02-13 03:17:00], "notes" => "some notes"}
@ -47,7 +49,7 @@ defmodule CanneryWeb.RangeLiveTest do
# |> form("#shot_group-form", shot_group: @invalid_attrs)
# |> render_change() =~ dgettext("errors", "is invalid")
{:ok, _, html} =
{:ok, _view, html} =
index_live
|> form("#shot-group-form", shot_group: @create_attrs)
|> render_submit()
@ -69,7 +71,7 @@ defmodule CanneryWeb.RangeLiveTest do
# |> form("#shot_group-form", shot_group: @invalid_attrs)
# |> render_change() =~ dgettext("errors", "is invalid")
{:ok, _, html} =
{:ok, _view, html} =
index_live
|> form("#shot-group-form", shot_group: @update_attrs)
|> render_submit()

View File

@ -53,7 +53,7 @@ defmodule CanneryWeb.TagLiveTest do
# |> form("#tag-form", tag: @invalid_attrs)
# |> render_change() =~ dgettext("errors", "can't be blank")
{:ok, _, html} =
{:ok, _view, html} =
index_live
|> form("#tag-form", tag: @create_attrs)
|> render_submit()
@ -75,7 +75,7 @@ defmodule CanneryWeb.TagLiveTest do
# |> form("#tag-form", tag: @invalid_attrs)
# |> render_change() =~ dgettext("errors", "can't be blank")
{:ok, _, html} =
{:ok, _view, html} =
index_live
|> form("#tag-form", tag: @update_attrs)
|> render_submit()

View File

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

View File

@ -25,6 +25,7 @@ defmodule CanneryWeb.ConnCase do
# Import conveniences for testing with connections
import Plug.Conn
import Phoenix.ConnTest
# credo:disable-for-next-line Credo.Check.Consistency.MultiAliasImportRequireUse
import Cannery.Fixtures
import CanneryWeb.ConnCase

View File

@ -22,10 +22,8 @@ defmodule Cannery.DataCase do
alias Cannery.Repo
import Ecto
import Ecto.Changeset
import Ecto.Query
import Cannery.DataCase
import Cannery.Fixtures
import Ecto.{Changeset, Query}
import Cannery.{DataCase, Fixtures}
end
end
@ -45,7 +43,7 @@ defmodule Cannery.DataCase do
"""
def errors_on(changeset) do
Ecto.Changeset.traverse_errors(changeset, fn {message, opts} ->
Regex.replace(~r"%{(\w+)}", message, fn _, key ->
Regex.replace(~r"%{(\w+)}", message, fn _content, key ->
opts |> Keyword.get(String.to_existing_atom(key), key) |> to_string()
end)
end)

View File

@ -111,10 +111,20 @@ defmodule Cannery.Fixtures do
@doc """
Generate a AmmoGroup
"""
@spec ammo_group_fixture(AmmoType.t(), Container.t(), User.t()) :: AmmoGroup.t()
@spec ammo_group_fixture(attrs :: map(), AmmoType.t(), Container.t(), User.t()) :: AmmoGroup.t()
@spec ammo_group_fixture(AmmoType.t(), Container.t(), User.t()) ::
{count :: non_neg_integer(), [AmmoGroup.t()]}
@spec ammo_group_fixture(attrs :: map(), AmmoType.t(), Container.t(), User.t()) ::
{count :: non_neg_integer(), [AmmoGroup.t()]}
@spec ammo_group_fixture(
attrs :: map(),
multiplier :: non_neg_integer(),
AmmoType.t(),
Container.t(),
User.t()
) :: {count :: non_neg_integer(), [AmmoGroup.t()]}
def ammo_group_fixture(
attrs \\ %{},
multiplier \\ 1,
%AmmoType{id: ammo_type_id},
%Container{id: container_id},
%User{} = user
@ -125,7 +135,7 @@ defmodule Cannery.Fixtures do
"container_id" => container_id,
"count" => 20
})
|> Ammo.create_ammo_group(user)
|> Ammo.create_ammo_groups(multiplier, user)
|> unwrap_ok_tuple()
end