diff --git a/assets/js/socket.js b/assets/js/socket.js
index 09929abc..8a673927 100644
--- a/assets/js/socket.js
+++ b/assets/js/socket.js
@@ -45,7 +45,7 @@ let socket = new Socket("/socket", {params: {token: window.userToken}})
// # max_age: 1209600 is equivalent to two weeks in seconds
// case Phoenix.Token.verify(socket, "user socket", token, max_age: 1209600) do
// {:ok, user_id} ->
-// {:ok, assign(socket, :user, user_id)}
+// {:ok, socket |> assign(:user, user_id)}
// {:error, reason} ->
// :error
// end
diff --git a/lib/cannery/ammo.ex b/lib/cannery/ammo.ex
new file mode 100644
index 00000000..52ebae09
--- /dev/null
+++ b/lib/cannery/ammo.ex
@@ -0,0 +1,200 @@
+defmodule Cannery.Ammo do
+ @moduledoc """
+ The Ammo context.
+ """
+
+ import Ecto.Query, warn: false
+ alias Cannery.Repo
+
+ alias Cannery.Ammo.AmmoType
+
+ @doc """
+ Returns the list of ammo_types.
+
+ ## Examples
+
+ iex> list_ammo_types()
+ [%AmmoType{}, ...]
+
+ """
+ def list_ammo_types do
+ Repo.all(AmmoType)
+ end
+
+ @doc """
+ Gets a single ammo_type.
+
+ Raises `Ecto.NoResultsError` if the Ammo type does not exist.
+
+ ## Examples
+
+ iex> get_ammo_type!(123)
+ %AmmoType{}
+
+ iex> get_ammo_type!(456)
+ ** (Ecto.NoResultsError)
+
+ """
+ def get_ammo_type!(id), do: Repo.get!(AmmoType, id)
+
+ @doc """
+ Creates a ammo_type.
+
+ ## Examples
+
+ iex> create_ammo_type(%{field: value})
+ {:ok, %AmmoType{}}
+
+ iex> create_ammo_type(%{field: bad_value})
+ {:error, %Ecto.Changeset{}}
+
+ """
+ def create_ammo_type(attrs \\ %{}) do
+ %AmmoType{}
+ |> AmmoType.changeset(attrs)
+ |> Repo.insert()
+ end
+
+ @doc """
+ Updates a ammo_type.
+
+ ## Examples
+
+ iex> update_ammo_type(ammo_type, %{field: new_value})
+ {:ok, %AmmoType{}}
+
+ iex> update_ammo_type(ammo_type, %{field: bad_value})
+ {:error, %Ecto.Changeset{}}
+
+ """
+ def update_ammo_type(%AmmoType{} = ammo_type, attrs) do
+ ammo_type
+ |> AmmoType.changeset(attrs)
+ |> Repo.update()
+ end
+
+ @doc """
+ Deletes a ammo_type.
+
+ ## Examples
+
+ iex> delete_ammo_type(ammo_type)
+ {:ok, %AmmoType{}}
+
+ iex> delete_ammo_type(ammo_type)
+ {:error, %Ecto.Changeset{}}
+
+ """
+ def delete_ammo_type(%AmmoType{} = ammo_type) do
+ Repo.delete(ammo_type)
+ end
+
+ @doc """
+ Returns an `%Ecto.Changeset{}` for tracking ammo_type changes.
+
+ ## Examples
+
+ iex> change_ammo_type(ammo_type)
+ %Ecto.Changeset{data: %AmmoType{}}
+
+ """
+ def change_ammo_type(%AmmoType{} = ammo_type, attrs \\ %{}) do
+ AmmoType.changeset(ammo_type, attrs)
+ end
+
+ alias Cannery.Ammo.AmmoGroup
+
+ @doc """
+ Returns the list of ammo_groups.
+
+ ## Examples
+
+ iex> list_ammo_groups()
+ [%AmmoGroup{}, ...]
+
+ """
+ def list_ammo_groups do
+ Repo.all(AmmoGroup)
+ end
+
+ @doc """
+ Gets a single ammo_group.
+
+ Raises `Ecto.NoResultsError` if the Ammo group does not exist.
+
+ ## Examples
+
+ iex> get_ammo_group!(123)
+ %AmmoGroup{}
+
+ iex> get_ammo_group!(456)
+ ** (Ecto.NoResultsError)
+
+ """
+ def get_ammo_group!(id), do: Repo.get!(AmmoGroup, id)
+
+ @doc """
+ Creates a ammo_group.
+
+ ## Examples
+
+ iex> create_ammo_group(%{field: value})
+ {:ok, %AmmoGroup{}}
+
+ iex> create_ammo_group(%{field: bad_value})
+ {:error, %Ecto.Changeset{}}
+
+ """
+ def create_ammo_group(attrs \\ %{}) do
+ %AmmoGroup{}
+ |> AmmoGroup.changeset(attrs)
+ |> Repo.insert()
+ end
+
+ @doc """
+ Updates a ammo_group.
+
+ ## Examples
+
+ iex> update_ammo_group(ammo_group, %{field: new_value})
+ {:ok, %AmmoGroup{}}
+
+ iex> update_ammo_group(ammo_group, %{field: bad_value})
+ {:error, %Ecto.Changeset{}}
+
+ """
+ def update_ammo_group(%AmmoGroup{} = ammo_group, attrs) do
+ ammo_group
+ |> AmmoGroup.changeset(attrs)
+ |> Repo.update()
+ end
+
+ @doc """
+ Deletes a ammo_group.
+
+ ## Examples
+
+ iex> delete_ammo_group(ammo_group)
+ {:ok, %AmmoGroup{}}
+
+ iex> delete_ammo_group(ammo_group)
+ {:error, %Ecto.Changeset{}}
+
+ """
+ def delete_ammo_group(%AmmoGroup{} = ammo_group) do
+ Repo.delete(ammo_group)
+ end
+
+ @doc """
+ Returns an `%Ecto.Changeset{}` for tracking ammo_group changes.
+
+ ## Examples
+
+ iex> change_ammo_group(ammo_group)
+ %Ecto.Changeset{data: %AmmoGroup{}}
+
+ """
+ def change_ammo_group(%AmmoGroup{} = ammo_group, attrs \\ %{}) do
+ AmmoGroup.changeset(ammo_group, attrs)
+ end
+end
diff --git a/lib/cannery/ammo/ammo_group.ex b/lib/cannery/ammo/ammo_group.ex
new file mode 100644
index 00000000..1a163462
--- /dev/null
+++ b/lib/cannery/ammo/ammo_group.ex
@@ -0,0 +1,25 @@
+defmodule Cannery.Ammo.AmmoGroup do
+ use Ecto.Schema
+ import Ecto.Changeset
+
+ @primary_key {:id, :binary_id, autogenerate: true}
+ @foreign_key_type :binary_id
+ schema "ammo_groups" do
+ field :count, :integer
+ field :notes, :string
+ field :price_paid, :float
+ field :tag_id, :binary_id
+ field :ammo_type_id, :binary_id
+ field :container_id, :binary_id
+ field :user_id, :binary_id
+
+ timestamps()
+ end
+
+ @doc false
+ def changeset(ammo_group, attrs) do
+ ammo_group
+ |> cast(attrs, [:count, :price_paid, :notes])
+ |> validate_required([:count, :price_paid, :notes])
+ end
+end
diff --git a/lib/cannery/ammo/ammo_type.ex b/lib/cannery/ammo/ammo_type.ex
new file mode 100644
index 00000000..e2c4ebbc
--- /dev/null
+++ b/lib/cannery/ammo/ammo_type.ex
@@ -0,0 +1,24 @@
+defmodule Cannery.Ammo.AmmoType do
+ use Ecto.Schema
+ import Ecto.Changeset
+
+ @primary_key {:id, :binary_id, autogenerate: true}
+ @foreign_key_type :binary_id
+ schema "ammo_types" do
+ field :bullet_type, :string
+ field :case_material, :string
+ field :desc, :string
+ field :manufacturer, :string
+ field :name, :string
+ field :weight, :float
+
+ timestamps()
+ end
+
+ @doc false
+ def changeset(ammo_type, attrs) do
+ ammo_type
+ |> cast(attrs, [:name, :desc, :case_material, :bullet_type, :weight, :manufacturer])
+ |> validate_required([:name, :desc, :case_material, :bullet_type, :weight, :manufacturer])
+ end
+end
diff --git a/lib/cannery/containers.ex b/lib/cannery/containers.ex
new file mode 100644
index 00000000..e47bf10b
--- /dev/null
+++ b/lib/cannery/containers.ex
@@ -0,0 +1,104 @@
+defmodule Cannery.Containers do
+ @moduledoc """
+ The Containers context.
+ """
+
+ import Ecto.Query, warn: false
+ alias Cannery.Repo
+
+ alias Cannery.Containers.Container
+
+ @doc """
+ Returns the list of containers.
+
+ ## Examples
+
+ iex> list_containers()
+ [%Container{}, ...]
+
+ """
+ def list_containers do
+ Repo.all(Container)
+ end
+
+ @doc """
+ Gets a single container.
+
+ Raises `Ecto.NoResultsError` if the Container does not exist.
+
+ ## Examples
+
+ iex> get_container!(123)
+ %Container{}
+
+ iex> get_container!(456)
+ ** (Ecto.NoResultsError)
+
+ """
+ def get_container!(id), do: Repo.get!(Container, id)
+
+ @doc """
+ Creates a container.
+
+ ## Examples
+
+ iex> create_container(%{field: value})
+ {:ok, %Container{}}
+
+ iex> create_container(%{field: bad_value})
+ {:error, %Ecto.Changeset{}}
+
+ """
+ def create_container(attrs \\ %{}) do
+ %Container{}
+ |> Container.changeset(attrs)
+ |> Repo.insert()
+ end
+
+ @doc """
+ Updates a container.
+
+ ## Examples
+
+ iex> update_container(container, %{field: new_value})
+ {:ok, %Container{}}
+
+ iex> update_container(container, %{field: bad_value})
+ {:error, %Ecto.Changeset{}}
+
+ """
+ def update_container(%Container{} = container, attrs) do
+ container
+ |> Container.changeset(attrs)
+ |> Repo.update()
+ end
+
+ @doc """
+ Deletes a container.
+
+ ## Examples
+
+ iex> delete_container(container)
+ {:ok, %Container{}}
+
+ iex> delete_container(container)
+ {:error, %Ecto.Changeset{}}
+
+ """
+ def delete_container(%Container{} = container) do
+ Repo.delete(container)
+ end
+
+ @doc """
+ Returns an `%Ecto.Changeset{}` for tracking container changes.
+
+ ## Examples
+
+ iex> change_container(container)
+ %Ecto.Changeset{data: %Container{}}
+
+ """
+ def change_container(%Container{} = container, attrs \\ %{}) do
+ Container.changeset(container, attrs)
+ end
+end
diff --git a/lib/cannery/containers/container.ex b/lib/cannery/containers/container.ex
new file mode 100644
index 00000000..eb9b4a83
--- /dev/null
+++ b/lib/cannery/containers/container.ex
@@ -0,0 +1,23 @@
+defmodule Cannery.Containers.Container do
+ use Ecto.Schema
+ import Ecto.Changeset
+
+ @primary_key {:id, :binary_id, autogenerate: true}
+ @foreign_key_type :binary_id
+ schema "containers" do
+ field :desc, :string
+ field :location, :string
+ field :name, :string
+ field :type, :string
+ field :user_id, :binary_id
+
+ timestamps()
+ end
+
+ @doc false
+ def changeset(container, attrs) do
+ container
+ |> cast(attrs, [:name, :desc, :type, :location])
+ |> validate_required([:name, :desc, :type, :location])
+ end
+end
diff --git a/lib/cannery/tags.ex b/lib/cannery/tags.ex
new file mode 100644
index 00000000..4a74f06a
--- /dev/null
+++ b/lib/cannery/tags.ex
@@ -0,0 +1,104 @@
+defmodule Cannery.Tags do
+ @moduledoc """
+ The Tags context.
+ """
+
+ import Ecto.Query, warn: false
+ alias Cannery.Repo
+
+ alias Cannery.Tags.Tag
+
+ @doc """
+ Returns the list of tags.
+
+ ## Examples
+
+ iex> list_tags()
+ [%Tag{}, ...]
+
+ """
+ def list_tags do
+ Repo.all(Tag)
+ end
+
+ @doc """
+ Gets a single tag.
+
+ Raises `Ecto.NoResultsError` if the Tag does not exist.
+
+ ## Examples
+
+ iex> get_tag!(123)
+ %Tag{}
+
+ iex> get_tag!(456)
+ ** (Ecto.NoResultsError)
+
+ """
+ def get_tag!(id), do: Repo.get!(Tag, id)
+
+ @doc """
+ Creates a tag.
+
+ ## Examples
+
+ iex> create_tag(%{field: value})
+ {:ok, %Tag{}}
+
+ iex> create_tag(%{field: bad_value})
+ {:error, %Ecto.Changeset{}}
+
+ """
+ def create_tag(attrs \\ %{}) do
+ %Tag{}
+ |> Tag.changeset(attrs)
+ |> Repo.insert()
+ end
+
+ @doc """
+ Updates a tag.
+
+ ## Examples
+
+ iex> update_tag(tag, %{field: new_value})
+ {:ok, %Tag{}}
+
+ iex> update_tag(tag, %{field: bad_value})
+ {:error, %Ecto.Changeset{}}
+
+ """
+ def update_tag(%Tag{} = tag, attrs) do
+ tag
+ |> Tag.changeset(attrs)
+ |> Repo.update()
+ end
+
+ @doc """
+ Deletes a tag.
+
+ ## Examples
+
+ iex> delete_tag(tag)
+ {:ok, %Tag{}}
+
+ iex> delete_tag(tag)
+ {:error, %Ecto.Changeset{}}
+
+ """
+ def delete_tag(%Tag{} = tag) do
+ Repo.delete(tag)
+ end
+
+ @doc """
+ Returns an `%Ecto.Changeset{}` for tracking tag changes.
+
+ ## Examples
+
+ iex> change_tag(tag)
+ %Ecto.Changeset{data: %Tag{}}
+
+ """
+ def change_tag(%Tag{} = tag, attrs \\ %{}) do
+ Tag.changeset(tag, attrs)
+ end
+end
diff --git a/lib/cannery/tags/tag.ex b/lib/cannery/tags/tag.ex
new file mode 100644
index 00000000..66e5865e
--- /dev/null
+++ b/lib/cannery/tags/tag.ex
@@ -0,0 +1,22 @@
+defmodule Cannery.Tags.Tag do
+ use Ecto.Schema
+ import Ecto.Changeset
+
+ @primary_key {:id, :binary_id, autogenerate: true}
+ @foreign_key_type :binary_id
+ schema "tags" do
+ field :"bg-color", :string
+ field :name, :string
+ field :"text-color", :string
+ field :user_id, :binary_id
+
+ timestamps()
+ end
+
+ @doc false
+ def changeset(tag, attrs) do
+ tag
+ |> cast(attrs, [:name, :"bg-color", :"text-color"])
+ |> validate_required([:name, :"bg-color", :"text-color"])
+ end
+end
diff --git a/lib/cannery_web.ex b/lib/cannery_web.ex
index 44917f8f..b37dcabe 100644
--- a/lib/cannery_web.ex
+++ b/lib/cannery_web.ex
@@ -46,7 +46,7 @@ defmodule CanneryWeb do
quote do
use Phoenix.LiveView,
layout: {CanneryWeb.LayoutView, "live.html"}
-
+
unquote(view_helpers())
end
end
@@ -83,6 +83,7 @@ defmodule CanneryWeb do
# Import LiveView helpers (live_render, live_component, live_patch, etc)
import Phoenix.LiveView.Helpers
+ import CanneryWeb.LiveHelpers
# Import basic rendering functionality (render, render_layout, etc)
import Phoenix.View
diff --git a/lib/cannery_web/channels/user_socket.ex b/lib/cannery_web/channels/user_socket.ex
index 778a0233..985278d2 100644
--- a/lib/cannery_web/channels/user_socket.ex
+++ b/lib/cannery_web/channels/user_socket.ex
@@ -9,7 +9,7 @@ defmodule CanneryWeb.UserSocket do
# verification, you can put default assigns into
# the socket that will be set for all channels, ie
#
- # {:ok, assign(socket, :user_id, verified_user_id)}
+ # {:ok, socket |> assign(:user_id, verified_user_id)}
#
# To deny connection, return `:error`.
#
diff --git a/lib/cannery_web/gettext.ex b/lib/cannery_web/gettext.ex
index 062b92b1..7fb3580c 100644
--- a/lib/cannery_web/gettext.ex
+++ b/lib/cannery_web/gettext.ex
@@ -20,5 +20,5 @@ defmodule CanneryWeb.Gettext do
See the [Gettext Docs](https://hexdocs.pm/gettext) for detailed usage.
"""
- use Gettext, otp_app: :cannery
+ # use Gettext, otp_app: :cannery
end
diff --git a/lib/cannery_web/live/ammo_group_live/form_component.ex b/lib/cannery_web/live/ammo_group_live/form_component.ex
new file mode 100644
index 00000000..b01aa0ff
--- /dev/null
+++ b/lib/cannery_web/live/ammo_group_live/form_component.ex
@@ -0,0 +1,55 @@
+defmodule CanneryWeb.AmmoGroupLive.FormComponent do
+ use CanneryWeb, :live_component
+
+ alias Cannery.Ammo
+
+ @impl true
+ def update(%{ammo_group: ammo_group} = assigns, socket) do
+ changeset = Ammo.change_ammo_group(ammo_group)
+
+ {:ok,
+ socket
+ |> assign(assigns)
+ |> assign(:changeset, changeset)}
+ end
+
+ @impl true
+ def handle_event("validate", %{"ammo_group" => ammo_group_params}, socket) do
+ changeset =
+ socket.assigns.ammo_group
+ |> Ammo.change_ammo_group(ammo_group_params)
+ |> Map.put(:action, :validate)
+
+ {:noreply, socket |> assign(:changeset, changeset)}
+ end
+
+ def handle_event("save", %{"ammo_group" => ammo_group_params}, socket) do
+ save_ammo_group(socket, socket.assigns.action, ammo_group_params)
+ end
+
+ defp save_ammo_group(socket, :edit, ammo_group_params) do
+ case Ammo.update_ammo_group(socket.assigns.ammo_group, ammo_group_params) do
+ {:ok, _ammo_group} ->
+ {:noreply,
+ socket
+ |> put_flash(:info, "Ammo group updated successfully")
+ |> push_redirect(to: socket.assigns.return_to)}
+
+ {:error, %Ecto.Changeset{} = changeset} ->
+ {:noreply, socket |> assign(:changeset, changeset)}
+ end
+ end
+
+ defp save_ammo_group(socket, :new, ammo_group_params) do
+ case Ammo.create_ammo_group(ammo_group_params) do
+ {:ok, _ammo_group} ->
+ {:noreply,
+ socket
+ |> put_flash(:info, "Ammo group created successfully")
+ |> push_redirect(to: socket.assigns.return_to)}
+
+ {:error, %Ecto.Changeset{} = changeset} ->
+ {:noreply, socket |> assign(changeset: changeset)}
+ end
+ end
+end
diff --git a/lib/cannery_web/live/ammo_group_live/form_component.html.leex b/lib/cannery_web/live/ammo_group_live/form_component.html.leex
new file mode 100644
index 00000000..63106942
--- /dev/null
+++ b/lib/cannery_web/live/ammo_group_live/form_component.html.leex
@@ -0,0 +1,22 @@
+
<%= @title %>
+
+<%= f = form_for @changeset, "#",
+ id: "ammo_group-form",
+ phx_target: @myself,
+ phx_change: "validate",
+ phx_submit: "save" %>
+
+ <%= label f, :count %>
+ <%= number_input f, :count %>
+ <%= error_tag f, :count %>
+
+ <%= label f, :price_paid %>
+ <%= number_input f, :price_paid, step: "any" %>
+ <%= error_tag f, :price_paid %>
+
+ <%= label f, :notes %>
+ <%= textarea f, :notes %>
+ <%= error_tag f, :notes %>
+
+ <%= submit "Save", phx_disable_with: "Saving..." %>
+
diff --git a/lib/cannery_web/live/ammo_group_live/index.ex b/lib/cannery_web/live/ammo_group_live/index.ex
new file mode 100644
index 00000000..2f0913da
--- /dev/null
+++ b/lib/cannery_web/live/ammo_group_live/index.ex
@@ -0,0 +1,46 @@
+defmodule CanneryWeb.AmmoGroupLive.Index do
+ use CanneryWeb, :live_view
+
+ alias Cannery.Ammo
+ alias Cannery.Ammo.AmmoGroup
+
+ @impl true
+ def mount(_params, _session, socket) do
+ {:ok, socket |> assign(:ammo_groups, list_ammo_groups())}
+ end
+
+ @impl true
+ def handle_params(params, _url, socket) do
+ {:noreply, apply_action(socket, socket.assigns.live_action, params)}
+ end
+
+ defp apply_action(socket, :edit, %{"id" => id}) do
+ socket
+ |> assign(:page_title, "Edit Ammo group")
+ |> assign(:ammo_group, Ammo.get_ammo_group!(id))
+ end
+
+ defp apply_action(socket, :new, _params) do
+ socket
+ |> assign(:page_title, "New Ammo group")
+ |> assign(:ammo_group, %AmmoGroup{})
+ end
+
+ defp apply_action(socket, :index, _params) do
+ socket
+ |> assign(:page_title, "Listing Ammo groups")
+ |> assign(:ammo_group, nil)
+ end
+
+ @impl true
+ def handle_event("delete", %{"id" => id}, socket) do
+ ammo_group = Ammo.get_ammo_group!(id)
+ {:ok, _} = Ammo.delete_ammo_group(ammo_group)
+
+ {:noreply, socket |> assign(:ammo_groups, list_ammo_groups())}
+ end
+
+ defp list_ammo_groups do
+ Ammo.list_ammo_groups()
+ end
+end
diff --git a/lib/cannery_web/live/ammo_group_live/index.html.leex b/lib/cannery_web/live/ammo_group_live/index.html.leex
new file mode 100644
index 00000000..e1eb5559
--- /dev/null
+++ b/lib/cannery_web/live/ammo_group_live/index.html.leex
@@ -0,0 +1,39 @@
+Listing Ammo groups
+
+<%= if @live_action in [:new, :edit] do %>
+ <%= live_modal CanneryWeb.AmmoGroupLive.FormComponent,
+ id: @ammo_group.id || :new,
+ title: @page_title,
+ action: @live_action,
+ ammo_group: @ammo_group,
+ return_to: Routes.ammo_group_index_path(@socket, :index) %>
+<% end %>
+
+
+
+
+ Count |
+ Price paid |
+ Notes |
+
+ |
+
+
+
+ <%= for ammo_group <- @ammo_groups do %>
+
+ <%= ammo_group.count %> |
+ <%= ammo_group.price_paid %> |
+ <%= ammo_group.notes %> |
+
+
+ <%= live_redirect "Show", to: Routes.ammo_group_show_path(@socket, :show, ammo_group) %>
+ <%= live_patch "Edit", to: Routes.ammo_group_index_path(@socket, :edit, ammo_group) %>
+ <%= link "Delete", to: "#", phx_click: "delete", phx_value_id: ammo_group.id, data: [confirm: "Are you sure?"] %>
+ |
+
+ <% end %>
+
+
+
+<%= live_patch "New Ammo group", to: Routes.ammo_group_index_path(@socket, :new) %>
diff --git a/lib/cannery_web/live/ammo_group_live/show.ex b/lib/cannery_web/live/ammo_group_live/show.ex
new file mode 100644
index 00000000..101d1b20
--- /dev/null
+++ b/lib/cannery_web/live/ammo_group_live/show.ex
@@ -0,0 +1,21 @@
+defmodule CanneryWeb.AmmoGroupLive.Show do
+ use CanneryWeb, :live_view
+
+ alias Cannery.Ammo
+
+ @impl true
+ def mount(_params, _session, socket) do
+ {:ok, socket}
+ end
+
+ @impl true
+ def handle_params(%{"id" => id}, _, socket) do
+ {:noreply,
+ socket
+ |> assign(:page_title, page_title(socket.assigns.live_action))
+ |> assign(:ammo_group, Ammo.get_ammo_group!(id))}
+ end
+
+ defp page_title(:show), do: "Show Ammo group"
+ defp page_title(:edit), do: "Edit Ammo group"
+end
diff --git a/lib/cannery_web/live/ammo_group_live/show.html.leex b/lib/cannery_web/live/ammo_group_live/show.html.leex
new file mode 100644
index 00000000..67a00f80
--- /dev/null
+++ b/lib/cannery_web/live/ammo_group_live/show.html.leex
@@ -0,0 +1,32 @@
+Show Ammo group
+
+<%= if @live_action in [:edit] do %>
+ <%= live_modal CanneryWeb.AmmoGroupLive.FormComponent,
+ id: @ammo_group.id,
+ title: @page_title,
+ action: @live_action,
+ ammo_group: @ammo_group,
+ return_to: Routes.ammo_group_show_path(@socket, :show, @ammo_group) %>
+<% end %>
+
+
+
+ -
+ Count:
+ <%= @ammo_group.count %>
+
+
+ -
+ Price paid:
+ <%= @ammo_group.price_paid %>
+
+
+ -
+ Notes:
+ <%= @ammo_group.notes %>
+
+
+
+
+<%= live_patch "Edit", to: Routes.ammo_group_show_path(@socket, :edit, @ammo_group), class: "button" %>
+<%= live_redirect "Back", to: Routes.ammo_group_index_path(@socket, :index) %>
diff --git a/lib/cannery_web/live/ammo_type_live/form_component.ex b/lib/cannery_web/live/ammo_type_live/form_component.ex
new file mode 100644
index 00000000..3095b423
--- /dev/null
+++ b/lib/cannery_web/live/ammo_type_live/form_component.ex
@@ -0,0 +1,55 @@
+defmodule CanneryWeb.AmmoTypeLive.FormComponent do
+ use CanneryWeb, :live_component
+
+ alias Cannery.Ammo
+
+ @impl true
+ def update(%{ammo_type: ammo_type} = assigns, socket) do
+ changeset = Ammo.change_ammo_type(ammo_type)
+
+ {:ok,
+ socket
+ |> assign(assigns)
+ |> assign(:changeset, changeset)}
+ end
+
+ @impl true
+ def handle_event("validate", %{"ammo_type" => ammo_type_params}, socket) do
+ changeset =
+ socket.assigns.ammo_type
+ |> Ammo.change_ammo_type(ammo_type_params)
+ |> Map.put(:action, :validate)
+
+ {:noreply, socket |> assign(:changeset, changeset)}
+ end
+
+ def handle_event("save", %{"ammo_type" => ammo_type_params}, socket) do
+ save_ammo_type(socket, socket.assigns.action, ammo_type_params)
+ end
+
+ defp save_ammo_type(socket, :edit, ammo_type_params) do
+ case Ammo.update_ammo_type(socket.assigns.ammo_type, ammo_type_params) do
+ {:ok, _ammo_type} ->
+ {:noreply,
+ socket
+ |> put_flash(:info, "Ammo type updated successfully")
+ |> push_redirect(to: socket.assigns.return_to)}
+
+ {:error, %Ecto.Changeset{} = changeset} ->
+ {:noreply, socket |> assign(:changeset, changeset)}
+ end
+ end
+
+ defp save_ammo_type(socket, :new, ammo_type_params) do
+ case Ammo.create_ammo_type(ammo_type_params) do
+ {:ok, _ammo_type} ->
+ {:noreply,
+ socket
+ |> put_flash(:info, "Ammo type created successfully")
+ |> push_redirect(to: socket.assigns.return_to)}
+
+ {:error, %Ecto.Changeset{} = changeset} ->
+ {:noreply, socket |> assign(changeset: changeset)}
+ end
+ end
+end
diff --git a/lib/cannery_web/live/ammo_type_live/form_component.html.leex b/lib/cannery_web/live/ammo_type_live/form_component.html.leex
new file mode 100644
index 00000000..48e74564
--- /dev/null
+++ b/lib/cannery_web/live/ammo_type_live/form_component.html.leex
@@ -0,0 +1,34 @@
+<%= @title %>
+
+<%= f = form_for @changeset, "#",
+ id: "ammo_type-form",
+ phx_target: @myself,
+ phx_change: "validate",
+ phx_submit: "save" %>
+
+ <%= label f, :name %>
+ <%= text_input f, :name %>
+ <%= error_tag f, :name %>
+
+ <%= label f, :desc %>
+ <%= text_input f, :desc %>
+ <%= error_tag f, :desc %>
+
+ <%= label f, :case_material %>
+ <%= text_input f, :case_material %>
+ <%= error_tag f, :case_material %>
+
+ <%= label f, :bullet_type %>
+ <%= text_input f, :bullet_type %>
+ <%= error_tag f, :bullet_type %>
+
+ <%= label f, :weight %>
+ <%= number_input f, :weight, step: "any" %>
+ <%= error_tag f, :weight %>
+
+ <%= label f, :manufacturer %>
+ <%= text_input f, :manufacturer %>
+ <%= error_tag f, :manufacturer %>
+
+ <%= submit "Save", phx_disable_with: "Saving..." %>
+
diff --git a/lib/cannery_web/live/ammo_type_live/index.ex b/lib/cannery_web/live/ammo_type_live/index.ex
new file mode 100644
index 00000000..7da84b36
--- /dev/null
+++ b/lib/cannery_web/live/ammo_type_live/index.ex
@@ -0,0 +1,46 @@
+defmodule CanneryWeb.AmmoTypeLive.Index do
+ use CanneryWeb, :live_view
+
+ alias Cannery.Ammo
+ alias Cannery.Ammo.AmmoType
+
+ @impl true
+ def mount(_params, _session, socket) do
+ {:ok, socket |> assign(:ammo_types, list_ammo_types())}
+ end
+
+ @impl true
+ def handle_params(params, _url, socket) do
+ {:noreply, apply_action(socket, socket.assigns.live_action, params)}
+ end
+
+ defp apply_action(socket, :edit, %{"id" => id}) do
+ socket
+ |> assign(:page_title, "Edit Ammo type")
+ |> assign(:ammo_type, Ammo.get_ammo_type!(id))
+ end
+
+ defp apply_action(socket, :new, _params) do
+ socket
+ |> assign(:page_title, "New Ammo type")
+ |> assign(:ammo_type, %AmmoType{})
+ end
+
+ defp apply_action(socket, :index, _params) do
+ socket
+ |> assign(:page_title, "Listing Ammo types")
+ |> assign(:ammo_type, nil)
+ end
+
+ @impl true
+ def handle_event("delete", %{"id" => id}, socket) do
+ ammo_type = Ammo.get_ammo_type!(id)
+ {:ok, _} = Ammo.delete_ammo_type(ammo_type)
+
+ {:noreply, socket |> assign(:ammo_types, list_ammo_types())}
+ end
+
+ defp list_ammo_types do
+ Ammo.list_ammo_types()
+ end
+end
diff --git a/lib/cannery_web/live/ammo_type_live/index.html.leex b/lib/cannery_web/live/ammo_type_live/index.html.leex
new file mode 100644
index 00000000..9abe40ed
--- /dev/null
+++ b/lib/cannery_web/live/ammo_type_live/index.html.leex
@@ -0,0 +1,45 @@
+Listing Ammo types
+
+<%= if @live_action in [:new, :edit] do %>
+ <%= live_modal CanneryWeb.AmmoTypeLive.FormComponent,
+ id: @ammo_type.id || :new,
+ title: @page_title,
+ action: @live_action,
+ ammo_type: @ammo_type,
+ return_to: Routes.ammo_type_index_path(@socket, :index) %>
+<% end %>
+
+
+
+
+ Name |
+ Desc |
+ Case material |
+ Bullet type |
+ Weight |
+ Manufacturer |
+
+ |
+
+
+
+ <%= for ammo_type <- @ammo_types do %>
+
+ <%= ammo_type.name %> |
+ <%= ammo_type.desc %> |
+ <%= ammo_type.case_material %> |
+ <%= ammo_type.bullet_type %> |
+ <%= ammo_type.weight %> |
+ <%= ammo_type.manufacturer %> |
+
+
+ <%= live_redirect "Show", to: Routes.ammo_type_show_path(@socket, :show, ammo_type) %>
+ <%= live_patch "Edit", to: Routes.ammo_type_index_path(@socket, :edit, ammo_type) %>
+ <%= link "Delete", to: "#", phx_click: "delete", phx_value_id: ammo_type.id, data: [confirm: "Are you sure?"] %>
+ |
+
+ <% end %>
+
+
+
+<%= live_patch "New Ammo type", to: Routes.ammo_type_index_path(@socket, :new) %>
diff --git a/lib/cannery_web/live/ammo_type_live/show.ex b/lib/cannery_web/live/ammo_type_live/show.ex
new file mode 100644
index 00000000..3997efa0
--- /dev/null
+++ b/lib/cannery_web/live/ammo_type_live/show.ex
@@ -0,0 +1,21 @@
+defmodule CanneryWeb.AmmoTypeLive.Show do
+ use CanneryWeb, :live_view
+
+ alias Cannery.Ammo
+
+ @impl true
+ def mount(_params, _session, socket) do
+ {:ok, socket}
+ end
+
+ @impl true
+ def handle_params(%{"id" => id}, _, socket) do
+ {:noreply,
+ socket
+ |> assign(:page_title, page_title(socket.assigns.live_action))
+ |> assign(:ammo_type, Ammo.get_ammo_type!(id))}
+ end
+
+ defp page_title(:show), do: "Show Ammo type"
+ defp page_title(:edit), do: "Edit Ammo type"
+end
diff --git a/lib/cannery_web/live/ammo_type_live/show.html.leex b/lib/cannery_web/live/ammo_type_live/show.html.leex
new file mode 100644
index 00000000..93e323c7
--- /dev/null
+++ b/lib/cannery_web/live/ammo_type_live/show.html.leex
@@ -0,0 +1,47 @@
+Show Ammo type
+
+<%= if @live_action in [:edit] do %>
+ <%= live_modal CanneryWeb.AmmoTypeLive.FormComponent,
+ id: @ammo_type.id,
+ title: @page_title,
+ action: @live_action,
+ ammo_type: @ammo_type,
+ return_to: Routes.ammo_type_show_path(@socket, :show, @ammo_type) %>
+<% end %>
+
+
+
+ -
+ Name:
+ <%= @ammo_type.name %>
+
+
+ -
+ Desc:
+ <%= @ammo_type.desc %>
+
+
+ -
+ Case material:
+ <%= @ammo_type.case_material %>
+
+
+ -
+ Bullet type:
+ <%= @ammo_type.bullet_type %>
+
+
+ -
+ Weight:
+ <%= @ammo_type.weight %>
+
+
+ -
+ Manufacturer:
+ <%= @ammo_type.manufacturer %>
+
+
+
+
+<%= live_patch "Edit", to: Routes.ammo_type_show_path(@socket, :edit, @ammo_type), class: "button" %>
+<%= live_redirect "Back", to: Routes.ammo_type_index_path(@socket, :index) %>
diff --git a/lib/cannery_web/live/component/topbar.ex b/lib/cannery_web/live/component/topbar.ex
index 2e5f474c..9309abaa 100644
--- a/lib/cannery_web/live/component/topbar.ex
+++ b/lib/cannery_web/live/component/topbar.ex
@@ -1,12 +1,12 @@
defmodule CanneryWeb.Live.Component.Topbar do
use CanneryWeb, :live_component
-
+
alias CanneryWeb.{PageLive}
-
+
def mount(socket) do
{:ok, socket |> assign(results: [], title_content: nil)}
end
-
+
def update(assigns, socket) do
{:ok, socket |> assign(assigns)}
end
@@ -41,7 +41,7 @@ defmodule CanneryWeb.Live.Component.Topbar do
<%# user settings %>
- <%= if assigns |> Map.has_key?(:current_user) do %>
+ <%= if @current_user do %>
<%= @current_user.email %>
@@ -89,4 +89,4 @@ defmodule CanneryWeb.Live.Component.Topbar do
"""
end
-end
\ No newline at end of file
+end
diff --git a/lib/cannery_web/live/container_live/form_component.ex b/lib/cannery_web/live/container_live/form_component.ex
new file mode 100644
index 00000000..063b12eb
--- /dev/null
+++ b/lib/cannery_web/live/container_live/form_component.ex
@@ -0,0 +1,55 @@
+defmodule CanneryWeb.ContainerLive.FormComponent do
+ use CanneryWeb, :live_component
+
+ alias Cannery.Containers
+
+ @impl true
+ def update(%{container: container} = assigns, socket) do
+ changeset = Containers.change_container(container)
+
+ {:ok,
+ socket
+ |> assign(assigns)
+ |> assign(:changeset, changeset)}
+ end
+
+ @impl true
+ def handle_event("validate", %{"container" => container_params}, socket) do
+ changeset =
+ socket.assigns.container
+ |> Containers.change_container(container_params)
+ |> Map.put(:action, :validate)
+
+ {:noreply, socket |> assign(:changeset, changeset)}
+ end
+
+ def handle_event("save", %{"container" => container_params}, socket) do
+ save_container(socket, socket.assigns.action, container_params)
+ end
+
+ defp save_container(socket, :edit, container_params) do
+ case Containers.update_container(socket.assigns.container, container_params) do
+ {:ok, _container} ->
+ {:noreply,
+ socket
+ |> put_flash(:info, "Container updated successfully")
+ |> push_redirect(to: socket.assigns.return_to)}
+
+ {:error, %Ecto.Changeset{} = changeset} ->
+ {:noreply, socket |> assign(:changeset, changeset)}
+ end
+ end
+
+ defp save_container(socket, :new, container_params) do
+ case Containers.create_container(container_params) do
+ {:ok, _container} ->
+ {:noreply,
+ socket
+ |> put_flash(:info, "Container created successfully")
+ |> push_redirect(to: socket.assigns.return_to)}
+
+ {:error, %Ecto.Changeset{} = changeset} ->
+ {:noreply, socket |> assign(changeset: changeset)}
+ end
+ end
+end
diff --git a/lib/cannery_web/live/container_live/form_component.html.leex b/lib/cannery_web/live/container_live/form_component.html.leex
new file mode 100644
index 00000000..a86848f6
--- /dev/null
+++ b/lib/cannery_web/live/container_live/form_component.html.leex
@@ -0,0 +1,26 @@
+<%= @title %>
+
+<%= f = form_for @changeset, "#",
+ id: "container-form",
+ phx_target: @myself,
+ phx_change: "validate",
+ phx_submit: "save" %>
+
+ <%= label f, :name %>
+ <%= text_input f, :name %>
+ <%= error_tag f, :name %>
+
+ <%= label f, :desc %>
+ <%= text_input f, :desc %>
+ <%= error_tag f, :desc %>
+
+ <%= label f, :type %>
+ <%= text_input f, :type %>
+ <%= error_tag f, :type %>
+
+ <%= label f, :location %>
+ <%= text_input f, :location %>
+ <%= error_tag f, :location %>
+
+ <%= submit "Save", phx_disable_with: "Saving..." %>
+
diff --git a/lib/cannery_web/live/container_live/index.ex b/lib/cannery_web/live/container_live/index.ex
new file mode 100644
index 00000000..1d85f387
--- /dev/null
+++ b/lib/cannery_web/live/container_live/index.ex
@@ -0,0 +1,46 @@
+defmodule CanneryWeb.ContainerLive.Index do
+ use CanneryWeb, :live_view
+
+ alias Cannery.Containers
+ alias Cannery.Containers.Container
+
+ @impl true
+ def mount(_params, _session, socket) do
+ {:ok, socket |> assign(:containers, list_containers())}
+ end
+
+ @impl true
+ def handle_params(params, _url, socket) do
+ {:noreply, apply_action(socket, socket.assigns.live_action, params)}
+ end
+
+ defp apply_action(socket, :edit, %{"id" => id}) do
+ socket
+ |> assign(:page_title, "Edit Container")
+ |> assign(:container, Containers.get_container!(id))
+ end
+
+ defp apply_action(socket, :new, _params) do
+ socket
+ |> assign(:page_title, "New Container")
+ |> assign(:container, %Container{})
+ end
+
+ defp apply_action(socket, :index, _params) do
+ socket
+ |> assign(:page_title, "Listing Containers")
+ |> assign(:container, nil)
+ end
+
+ @impl true
+ def handle_event("delete", %{"id" => id}, socket) do
+ container = Containers.get_container!(id)
+ {:ok, _} = Containers.delete_container(container)
+
+ {:noreply, socket |> assign(:containers, list_containers())}
+ end
+
+ defp list_containers do
+ Containers.list_containers()
+ end
+end
diff --git a/lib/cannery_web/live/container_live/index.html.leex b/lib/cannery_web/live/container_live/index.html.leex
new file mode 100644
index 00000000..9fc2d627
--- /dev/null
+++ b/lib/cannery_web/live/container_live/index.html.leex
@@ -0,0 +1,41 @@
+Listing Containers
+
+<%= if @live_action in [:new, :edit] do %>
+ <%= live_modal CanneryWeb.ContainerLive.FormComponent,
+ id: @container.id || :new,
+ title: @page_title,
+ action: @live_action,
+ container: @container,
+ return_to: Routes.container_index_path(@socket, :index) %>
+<% end %>
+
+
+
+
+ Name |
+ Desc |
+ Type |
+ Location |
+
+ |
+
+
+
+ <%= for container <- @containers do %>
+
+ <%= container.name %> |
+ <%= container.desc %> |
+ <%= container.type %> |
+ <%= container.location %> |
+
+
+ <%= live_redirect "Show", to: Routes.container_show_path(@socket, :show, container) %>
+ <%= live_patch "Edit", to: Routes.container_index_path(@socket, :edit, container) %>
+ <%= link "Delete", to: "#", phx_click: "delete", phx_value_id: container.id, data: [confirm: "Are you sure?"] %>
+ |
+
+ <% end %>
+
+
+
+<%= live_patch "New Container", to: Routes.container_index_path(@socket, :new) %>
diff --git a/lib/cannery_web/live/container_live/show.ex b/lib/cannery_web/live/container_live/show.ex
new file mode 100644
index 00000000..ab271aa2
--- /dev/null
+++ b/lib/cannery_web/live/container_live/show.ex
@@ -0,0 +1,21 @@
+defmodule CanneryWeb.ContainerLive.Show do
+ use CanneryWeb, :live_view
+
+ alias Cannery.Containers
+
+ @impl true
+ def mount(_params, _session, socket) do
+ {:ok, socket}
+ end
+
+ @impl true
+ def handle_params(%{"id" => id}, _, socket) do
+ {:noreply,
+ socket
+ |> assign(:page_title, page_title(socket.assigns.live_action))
+ |> assign(:container, Containers.get_container!(id))}
+ end
+
+ defp page_title(:show), do: "Show Container"
+ defp page_title(:edit), do: "Edit Container"
+end
diff --git a/lib/cannery_web/live/container_live/show.html.leex b/lib/cannery_web/live/container_live/show.html.leex
new file mode 100644
index 00000000..2d39aa90
--- /dev/null
+++ b/lib/cannery_web/live/container_live/show.html.leex
@@ -0,0 +1,37 @@
+Show Container
+
+<%= if @live_action in [:edit] do %>
+ <%= live_modal CanneryWeb.ContainerLive.FormComponent,
+ id: @container.id,
+ title: @page_title,
+ action: @live_action,
+ container: @container,
+ return_to: Routes.container_show_path(@socket, :show, @container) %>
+<% end %>
+
+
+
+ -
+ Name:
+ <%= @container.name %>
+
+
+ -
+ Desc:
+ <%= @container.desc %>
+
+
+ -
+ Type:
+ <%= @container.type %>
+
+
+ -
+ Location:
+ <%= @container.location %>
+
+
+
+
+<%= live_patch "Edit", to: Routes.container_show_path(@socket, :edit, @container), class: "button" %>
+<%= live_redirect "Back", to: Routes.container_index_path(@socket, :index) %>
diff --git a/lib/cannery_web/live/live_helpers.ex b/lib/cannery_web/live/live_helpers.ex
new file mode 100644
index 00000000..c9487a8e
--- /dev/null
+++ b/lib/cannery_web/live/live_helpers.ex
@@ -0,0 +1,36 @@
+defmodule CanneryWeb.LiveHelpers do
+ import Phoenix.LiveView.Helpers
+ import Phoenix.LiveView, only: [assign_new: 3]
+ alias Cannery.{Accounts}
+
+ @doc """
+ Renders a component inside the `CanneryWeb.ModalComponent` component.
+
+ The rendered modal receives a `:return_to` option to properly update
+ the URL when the modal is closed.
+
+ ## Examples
+
+ <%= live_modal CanneryWeb.TagLive.FormComponent,
+ id: @tag.id || :new,
+ action: @live_action,
+ tag: @tag,
+ return_to: Routes.tag_index_path(@socket, :index) %>
+ """
+ def live_modal(component, opts) do
+ path = Keyword.fetch!(opts, :return_to)
+ modal_opts = [id: :modal, return_to: path, component: component, opts: opts]
+ live_component(CanneryWeb.ModalComponent, modal_opts)
+ end
+
+ def assign_defaults(socket, %{"user_token" => user_token} = _session) do
+ socket
+ |> assign_new(:current_user, fn ->
+ Accounts.get_user_by_session_token(user_token)
+ end)
+ end
+
+ def assign_defaults(socket, _session) do
+ socket
+ end
+end
diff --git a/lib/cannery_web/live/modal_component.ex b/lib/cannery_web/live/modal_component.ex
new file mode 100644
index 00000000..019129da
--- /dev/null
+++ b/lib/cannery_web/live/modal_component.ex
@@ -0,0 +1,26 @@
+defmodule CanneryWeb.ModalComponent do
+ use CanneryWeb, :live_component
+
+ @impl true
+ def render(assigns) do
+ ~L"""
+
+
+
+ <%= live_patch raw("×"), to: @return_to, class: "phx-modal-close" %>
+ <%= live_component @socket, @component, @opts %>
+
+
+ """
+ end
+
+ @impl true
+ def handle_event("close", _, socket) do
+ {:noreply, push_patch(socket, to: socket.assigns.return_to)}
+ end
+end
diff --git a/lib/cannery_web/live/page_live.ex b/lib/cannery_web/live/page_live.ex
index a479dd40..e21cfcb4 100644
--- a/lib/cannery_web/live/page_live.ex
+++ b/lib/cannery_web/live/page_live.ex
@@ -2,13 +2,13 @@ defmodule CanneryWeb.PageLive do
use CanneryWeb, :live_view
@impl true
- def mount(_params, _session, socket) do
- {:ok, assign(socket, query: "", results: %{})}
+ def mount(_params, session, socket) do
+ {:ok, socket |> assign_defaults(session) |> assign(query: "", results: %{})}
end
@impl true
def handle_event("suggest", %{"q" => query}, socket) do
- {:noreply, assign(socket, results: search(query), query: query)}
+ {:noreply, socket |> assign(results: search(query), query: query)}
end
@impl true
diff --git a/lib/cannery_web/live/tag_live/form_component.ex b/lib/cannery_web/live/tag_live/form_component.ex
new file mode 100644
index 00000000..60e88791
--- /dev/null
+++ b/lib/cannery_web/live/tag_live/form_component.ex
@@ -0,0 +1,55 @@
+defmodule CanneryWeb.TagLive.FormComponent do
+ use CanneryWeb, :live_component
+
+ alias Cannery.Tags
+
+ @impl true
+ def update(%{tag: tag} = assigns, socket) do
+ changeset = Tags.change_tag(tag)
+
+ {:ok,
+ socket
+ |> assign(assigns)
+ |> assign(:changeset, changeset)}
+ end
+
+ @impl true
+ def handle_event("validate", %{"tag" => tag_params}, socket) do
+ changeset =
+ socket.assigns.tag
+ |> Tags.change_tag(tag_params)
+ |> Map.put(:action, :validate)
+
+ {:noreply, socket |> assign(:changeset, changeset)}
+ end
+
+ def handle_event("save", %{"tag" => tag_params}, socket) do
+ save_tag(socket, socket.assigns.action, tag_params)
+ end
+
+ defp save_tag(socket, :edit, tag_params) do
+ case Tags.update_tag(socket.assigns.tag, tag_params) do
+ {:ok, _tag} ->
+ {:noreply,
+ socket
+ |> put_flash(:info, "Tag updated successfully")
+ |> push_redirect(to: socket.assigns.return_to)}
+
+ {:error, %Ecto.Changeset{} = changeset} ->
+ {:noreply, socket |> assign(:changeset, changeset)}
+ end
+ end
+
+ defp save_tag(socket, :new, tag_params) do
+ case Tags.create_tag(tag_params) do
+ {:ok, _tag} ->
+ {:noreply,
+ socket
+ |> put_flash(:info, "Tag created successfully")
+ |> push_redirect(to: socket.assigns.return_to)}
+
+ {:error, %Ecto.Changeset{} = changeset} ->
+ {:noreply, socket |> assign(changeset: changeset)}
+ end
+ end
+end
diff --git a/lib/cannery_web/live/tag_live/form_component.html.leex b/lib/cannery_web/live/tag_live/form_component.html.leex
new file mode 100644
index 00000000..d9329407
--- /dev/null
+++ b/lib/cannery_web/live/tag_live/form_component.html.leex
@@ -0,0 +1,22 @@
+<%= @title %>
+
+<%= f = form_for @changeset, "#",
+ id: "tag-form",
+ phx_target: @myself,
+ phx_change: "validate",
+ phx_submit: "save" %>
+
+ <%= label f, :name %>
+ <%= text_input f, :name %>
+ <%= error_tag f, :name %>
+
+ <%= label f, :"bg-color" %>
+ <%= text_input f, :"bg-color" %>
+ <%= error_tag f, :"bg-color" %>
+
+ <%= label f, :"text-color" %>
+ <%= text_input f, :"text-color" %>
+ <%= error_tag f, :"text-color" %>
+
+ <%= submit "Save", phx_disable_with: "Saving..." %>
+
diff --git a/lib/cannery_web/live/tag_live/index.ex b/lib/cannery_web/live/tag_live/index.ex
new file mode 100644
index 00000000..119aef32
--- /dev/null
+++ b/lib/cannery_web/live/tag_live/index.ex
@@ -0,0 +1,46 @@
+defmodule CanneryWeb.TagLive.Index do
+ use CanneryWeb, :live_view
+
+ alias Cannery.Tags
+ alias Cannery.Tags.Tag
+
+ @impl true
+ def mount(_params, _session, socket) do
+ {:ok, socket |> assign(:tags, list_tags())}
+ end
+
+ @impl true
+ def handle_params(params, _url, socket) do
+ {:noreply, apply_action(socket, socket.assigns.live_action, params)}
+ end
+
+ defp apply_action(socket, :edit, %{"id" => id}) do
+ socket
+ |> assign(:page_title, "Edit Tag")
+ |> assign(:tag, Tags.get_tag!(id))
+ end
+
+ defp apply_action(socket, :new, _params) do
+ socket
+ |> assign(:page_title, "New Tag")
+ |> assign(:tag, %Tag{})
+ end
+
+ defp apply_action(socket, :index, _params) do
+ socket
+ |> assign(:page_title, "Listing Tags")
+ |> assign(:tag, nil)
+ end
+
+ @impl true
+ def handle_event("delete", %{"id" => id}, socket) do
+ tag = Tags.get_tag!(id)
+ {:ok, _} = Tags.delete_tag(tag)
+
+ {:noreply, socket |> assign(:tags, list_tags())}
+ end
+
+ defp list_tags do
+ Tags.list_tags()
+ end
+end
diff --git a/lib/cannery_web/live/tag_live/index.html.leex b/lib/cannery_web/live/tag_live/index.html.leex
new file mode 100644
index 00000000..4a57721f
--- /dev/null
+++ b/lib/cannery_web/live/tag_live/index.html.leex
@@ -0,0 +1,39 @@
+Listing Tags
+
+<%= if @live_action in [:new, :edit] do %>
+ <%= live_modal CanneryWeb.TagLive.FormComponent,
+ id: @tag.id || :new,
+ title: @page_title,
+ action: @live_action,
+ tag: @tag,
+ return_to: Routes.tag_index_path(@socket, :index) %>
+<% end %>
+
+
+
+
+ Name |
+ Bg-color |
+ Text-color |
+
+ |
+
+
+
+ <%= for tag <- @tags do %>
+
+ <%= tag.name %> |
+ <%= tag.bg_color %> |
+ <%= tag.text_color %> |
+
+
+ <%= live_redirect "Show", to: Routes.tag_show_path(@socket, :show, tag) %>
+ <%= live_patch "Edit", to: Routes.tag_index_path(@socket, :edit, tag) %>
+ <%= link "Delete", to: "#", phx_click: "delete", phx_value_id: tag.id, data: [confirm: "Are you sure?"] %>
+ |
+
+ <% end %>
+
+
+
+<%= live_patch "New Tag", to: Routes.tag_index_path(@socket, :new) %>
diff --git a/lib/cannery_web/live/tag_live/show.ex b/lib/cannery_web/live/tag_live/show.ex
new file mode 100644
index 00000000..1aed2b2b
--- /dev/null
+++ b/lib/cannery_web/live/tag_live/show.ex
@@ -0,0 +1,21 @@
+defmodule CanneryWeb.TagLive.Show do
+ use CanneryWeb, :live_view
+
+ alias Cannery.Tags
+
+ @impl true
+ def mount(_params, _session, socket) do
+ {:ok, socket}
+ end
+
+ @impl true
+ def handle_params(%{"id" => id}, _, socket) do
+ {:noreply,
+ socket
+ |> assign(:page_title, page_title(socket.assigns.live_action))
+ |> assign(:tag, Tags.get_tag!(id))}
+ end
+
+ defp page_title(:show), do: "Show Tag"
+ defp page_title(:edit), do: "Edit Tag"
+end
diff --git a/lib/cannery_web/live/tag_live/show.html.leex b/lib/cannery_web/live/tag_live/show.html.leex
new file mode 100644
index 00000000..9201b57c
--- /dev/null
+++ b/lib/cannery_web/live/tag_live/show.html.leex
@@ -0,0 +1,32 @@
+Show Tag
+
+<%= if @live_action in [:edit] do %>
+ <%= live_modal CanneryWeb.TagLive.FormComponent,
+ id: @tag.id,
+ title: @page_title,
+ action: @live_action,
+ tag: @tag,
+ return_to: Routes.tag_show_path(@socket, :show, @tag) %>
+<% end %>
+
+
+
+ -
+ Name:
+ <%= @tag.name %>
+
+
+ -
+ Bg-color:
+ <%= @tag.bg_color %>
+
+
+ -
+ Text-color:
+ <%= @tag.text_color %>
+
+
+
+
+<%= live_patch "Edit", to: Routes.tag_show_path(@socket, :edit, @tag), class: "button" %>
+<%= live_redirect "Back", to: Routes.tag_index_path(@socket, :index) %>
diff --git a/lib/cannery_web/router.ex b/lib/cannery_web/router.ex
index a912ec8b..05570f38 100644
--- a/lib/cannery_web/router.ex
+++ b/lib/cannery_web/router.ex
@@ -60,6 +60,34 @@ defmodule CanneryWeb.Router do
get "/users/settings", UserSettingsController, :edit
put "/users/settings", UserSettingsController, :update
get "/users/settings/confirm_email/:token", UserSettingsController, :confirm_email
+
+ live "/tags", TagLive.Index, :index
+ live "/tags/new", TagLive.Index, :new
+ live "/tags/:id/edit", TagLive.Index, :edit
+
+ live "/tags/:id", TagLive.Show, :show
+ live "/tags/:id/show/edit", TagLive.Show, :edit
+
+ live "/ammo_types", AmmoTypeLive.Index, :index
+ live "/ammo_types/new", AmmoTypeLive.Index, :new
+ live "/ammo_types/:id/edit", AmmoTypeLive.Index, :edit
+
+ live "/ammo_types/:id", AmmoTypeLive.Show, :show
+ live "/ammo_types/:id/show/edit", AmmoTypeLive.Show, :edit
+
+ live "/containers", ContainerLive.Index, :index
+ live "/containers/new", ContainerLive.Index, :new
+ live "/containers/:id/edit", ContainerLive.Index, :edit
+
+ live "/containers/:id", ContainerLive.Show, :show
+ live "/containers/:id/show/edit", ContainerLive.Show, :edit
+
+ live "/ammo_groups", AmmoGroupLive.Index, :index
+ live "/ammo_groups/new", AmmoGroupLive.Index, :new
+ live "/ammo_groups/:id/edit", AmmoGroupLive.Index, :edit
+
+ live "/ammo_groups/:id", AmmoGroupLive.Show, :show
+ live "/ammo_groups/:id/show/edit", AmmoGroupLive.Show, :edit
end
scope "/", CanneryWeb do
diff --git a/lib/cannery_web/templates/layout/live.html.leex b/lib/cannery_web/templates/layout/live.html.leex
index f35519fb..c886d893 100644
--- a/lib/cannery_web/templates/layout/live.html.leex
+++ b/lib/cannery_web/templates/layout/live.html.leex
@@ -1,5 +1,5 @@
- <%= live_component CanneryWeb.Live.Component.Topbar %>
+ <%= live_component CanneryWeb.Live.Component.Topbar, current_user: assigns[:current_user] %>
<%= @inner_content %>
diff --git a/priv/repo/migrations/20210903015442_create_tags.exs b/priv/repo/migrations/20210903015442_create_tags.exs
new file mode 100644
index 00000000..c1c1bc59
--- /dev/null
+++ b/priv/repo/migrations/20210903015442_create_tags.exs
@@ -0,0 +1,17 @@
+defmodule Cannery.Repo.Migrations.CreateTags do
+ use Ecto.Migration
+
+ def change do
+ create table(:tags, primary_key: false) do
+ add :id, :binary_id, primary_key: true
+ add :name, :string
+ add :"bg-color", :string
+ add :"text-color", :string
+ add :user_id, references(:users, on_delete: :nothing, type: :binary_id)
+
+ timestamps()
+ end
+
+ create index(:tags, [:user_id])
+ end
+end
diff --git a/priv/repo/migrations/20210903015537_create_ammo_types.exs b/priv/repo/migrations/20210903015537_create_ammo_types.exs
new file mode 100644
index 00000000..22388412
--- /dev/null
+++ b/priv/repo/migrations/20210903015537_create_ammo_types.exs
@@ -0,0 +1,18 @@
+defmodule Cannery.Repo.Migrations.CreateAmmoTypes do
+ use Ecto.Migration
+
+ def change do
+ create table(:ammo_types, primary_key: false) do
+ add :id, :binary_id, primary_key: true
+ add :name, :string
+ add :desc, :string
+ add :case_material, :string
+ add :bullet_type, :string
+ add :weight, :float
+ add :manufacturer, :string
+
+ timestamps()
+ end
+
+ end
+end
diff --git a/priv/repo/migrations/20210903015553_create_containers.exs b/priv/repo/migrations/20210903015553_create_containers.exs
new file mode 100644
index 00000000..7193df13
--- /dev/null
+++ b/priv/repo/migrations/20210903015553_create_containers.exs
@@ -0,0 +1,18 @@
+defmodule Cannery.Repo.Migrations.CreateContainers do
+ use Ecto.Migration
+
+ def change do
+ create table(:containers, primary_key: false) do
+ add :id, :binary_id, primary_key: true
+ add :name, :string
+ add :desc, :string
+ add :type, :string
+ add :location, :string
+ add :user_id, references(:users, on_delete: :nothing, type: :binary_id)
+
+ timestamps()
+ end
+
+ create index(:containers, [:user_id])
+ end
+end
diff --git a/priv/repo/migrations/20210903015611_create_ammo_groups.exs b/priv/repo/migrations/20210903015611_create_ammo_groups.exs
new file mode 100644
index 00000000..40924f56
--- /dev/null
+++ b/priv/repo/migrations/20210903015611_create_ammo_groups.exs
@@ -0,0 +1,23 @@
+defmodule Cannery.Repo.Migrations.CreateAmmoGroups do
+ use Ecto.Migration
+
+ def change do
+ create table(:ammo_groups, primary_key: false) do
+ add :id, :binary_id, primary_key: true
+ add :count, :integer
+ add :price_paid, :float
+ add :notes, :text
+ add :tag_id, references(:tags, on_delete: :nothing, type: :binary_id)
+ add :ammo_type_id, references(:ammo_types, on_delete: :nothing, type: :binary_id)
+ add :container_id, references(:containers, on_delete: :nothing, type: :binary_id)
+ add :user_id, references(:users, on_delete: :nothing, type: :binary_id)
+
+ timestamps()
+ end
+
+ create index(:ammo_groups, [:tag_id])
+ create index(:ammo_groups, [:ammo_type_id])
+ create index(:ammo_groups, [:container_id])
+ create index(:ammo_groups, [:user_id])
+ end
+end
diff --git a/test/cannery/ammo_test.exs b/test/cannery/ammo_test.exs
new file mode 100644
index 00000000..d9f07981
--- /dev/null
+++ b/test/cannery/ammo_test.exs
@@ -0,0 +1,137 @@
+defmodule Cannery.AmmoTest do
+ use Cannery.DataCase
+
+ alias Cannery.Ammo
+
+ describe "ammo_types" do
+ alias Cannery.Ammo.AmmoType
+
+ @valid_attrs %{bullet_type: "some bullet_type", case_material: "some case_material", desc: "some desc", manufacturer: "some manufacturer", name: "some name", weight: 120.5}
+ @update_attrs %{bullet_type: "some updated bullet_type", case_material: "some updated case_material", desc: "some updated desc", manufacturer: "some updated manufacturer", name: "some updated name", weight: 456.7}
+ @invalid_attrs %{bullet_type: nil, case_material: nil, desc: nil, manufacturer: nil, name: nil, weight: nil}
+
+ def ammo_type_fixture(attrs \\ %{}) do
+ {:ok, ammo_type} =
+ attrs
+ |> Enum.into(@valid_attrs)
+ |> Ammo.create_ammo_type()
+
+ ammo_type
+ end
+
+ test "list_ammo_types/0 returns all ammo_types" do
+ ammo_type = ammo_type_fixture()
+ assert Ammo.list_ammo_types() == [ammo_type]
+ end
+
+ test "get_ammo_type!/1 returns the ammo_type with given id" do
+ ammo_type = ammo_type_fixture()
+ assert Ammo.get_ammo_type!(ammo_type.id) == ammo_type
+ end
+
+ test "create_ammo_type/1 with valid data creates a ammo_type" do
+ assert {:ok, %AmmoType{} = ammo_type} = Ammo.create_ammo_type(@valid_attrs)
+ assert ammo_type.bullet_type == "some bullet_type"
+ assert ammo_type.case_material == "some case_material"
+ assert ammo_type.desc == "some desc"
+ assert ammo_type.manufacturer == "some manufacturer"
+ assert ammo_type.name == "some name"
+ assert ammo_type.weight == 120.5
+ end
+
+ test "create_ammo_type/1 with invalid data returns error changeset" do
+ assert {:error, %Ecto.Changeset{}} = Ammo.create_ammo_type(@invalid_attrs)
+ end
+
+ test "update_ammo_type/2 with valid data updates the ammo_type" do
+ ammo_type = ammo_type_fixture()
+ assert {:ok, %AmmoType{} = ammo_type} = Ammo.update_ammo_type(ammo_type, @update_attrs)
+ assert ammo_type.bullet_type == "some updated bullet_type"
+ assert ammo_type.case_material == "some updated case_material"
+ assert ammo_type.desc == "some updated desc"
+ assert ammo_type.manufacturer == "some updated manufacturer"
+ assert ammo_type.name == "some updated name"
+ assert ammo_type.weight == 456.7
+ end
+
+ test "update_ammo_type/2 with invalid data returns error changeset" do
+ ammo_type = ammo_type_fixture()
+ assert {:error, %Ecto.Changeset{}} = Ammo.update_ammo_type(ammo_type, @invalid_attrs)
+ assert ammo_type == Ammo.get_ammo_type!(ammo_type.id)
+ end
+
+ test "delete_ammo_type/1 deletes the ammo_type" do
+ ammo_type = ammo_type_fixture()
+ assert {:ok, %AmmoType{}} = Ammo.delete_ammo_type(ammo_type)
+ assert_raise Ecto.NoResultsError, fn -> Ammo.get_ammo_type!(ammo_type.id) end
+ end
+
+ test "change_ammo_type/1 returns a ammo_type changeset" do
+ ammo_type = ammo_type_fixture()
+ assert %Ecto.Changeset{} = Ammo.change_ammo_type(ammo_type)
+ end
+ end
+
+ describe "ammo_groups" do
+ alias Cannery.Ammo.AmmoGroup
+
+ @valid_attrs %{count: 42, notes: "some notes", price_paid: 120.5}
+ @update_attrs %{count: 43, notes: "some updated notes", price_paid: 456.7}
+ @invalid_attrs %{count: nil, notes: nil, price_paid: nil}
+
+ def ammo_group_fixture(attrs \\ %{}) do
+ {:ok, ammo_group} =
+ attrs
+ |> Enum.into(@valid_attrs)
+ |> Ammo.create_ammo_group()
+
+ ammo_group
+ end
+
+ test "list_ammo_groups/0 returns all ammo_groups" do
+ ammo_group = ammo_group_fixture()
+ assert Ammo.list_ammo_groups() == [ammo_group]
+ end
+
+ test "get_ammo_group!/1 returns the ammo_group with given id" do
+ ammo_group = ammo_group_fixture()
+ assert Ammo.get_ammo_group!(ammo_group.id) == ammo_group
+ end
+
+ test "create_ammo_group/1 with valid data creates a ammo_group" do
+ assert {:ok, %AmmoGroup{} = ammo_group} = Ammo.create_ammo_group(@valid_attrs)
+ 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" do
+ assert {:error, %Ecto.Changeset{}} = Ammo.create_ammo_group(@invalid_attrs)
+ end
+
+ test "update_ammo_group/2 with valid data updates the ammo_group" do
+ ammo_group = ammo_group_fixture()
+ assert {:ok, %AmmoGroup{} = ammo_group} = Ammo.update_ammo_group(ammo_group, @update_attrs)
+ assert ammo_group.count == 43
+ assert ammo_group.notes == "some updated notes"
+ assert ammo_group.price_paid == 456.7
+ end
+
+ test "update_ammo_group/2 with invalid data returns error changeset" do
+ ammo_group = ammo_group_fixture()
+ assert {:error, %Ecto.Changeset{}} = Ammo.update_ammo_group(ammo_group, @invalid_attrs)
+ assert ammo_group == Ammo.get_ammo_group!(ammo_group.id)
+ end
+
+ test "delete_ammo_group/1 deletes the ammo_group" do
+ ammo_group = ammo_group_fixture()
+ assert {:ok, %AmmoGroup{}} = Ammo.delete_ammo_group(ammo_group)
+ assert_raise Ecto.NoResultsError, fn -> Ammo.get_ammo_group!(ammo_group.id) end
+ end
+
+ test "change_ammo_group/1 returns a ammo_group changeset" do
+ ammo_group = ammo_group_fixture()
+ assert %Ecto.Changeset{} = Ammo.change_ammo_group(ammo_group)
+ end
+ end
+end
diff --git a/test/cannery/containers_test.exs b/test/cannery/containers_test.exs
new file mode 100644
index 00000000..e8e6c74d
--- /dev/null
+++ b/test/cannery/containers_test.exs
@@ -0,0 +1,70 @@
+defmodule Cannery.ContainersTest do
+ use Cannery.DataCase
+
+ alias Cannery.Containers
+
+ describe "containers" do
+ alias Cannery.Containers.Container
+
+ @valid_attrs %{desc: "some desc", location: "some location", name: "some name", type: "some type"}
+ @update_attrs %{desc: "some updated desc", location: "some updated location", name: "some updated name", type: "some updated type"}
+ @invalid_attrs %{desc: nil, location: nil, name: nil, type: nil}
+
+ def container_fixture(attrs \\ %{}) do
+ {:ok, container} =
+ attrs
+ |> Enum.into(@valid_attrs)
+ |> Containers.create_container()
+
+ container
+ end
+
+ test "list_containers/0 returns all containers" do
+ container = container_fixture()
+ assert Containers.list_containers() == [container]
+ end
+
+ test "get_container!/1 returns the container with given id" do
+ container = container_fixture()
+ assert Containers.get_container!(container.id) == container
+ end
+
+ test "create_container/1 with valid data creates a container" do
+ assert {:ok, %Container{} = container} = Containers.create_container(@valid_attrs)
+ assert container.desc == "some desc"
+ assert container.location == "some location"
+ assert container.name == "some name"
+ assert container.type == "some type"
+ end
+
+ test "create_container/1 with invalid data returns error changeset" do
+ assert {:error, %Ecto.Changeset{}} = Containers.create_container(@invalid_attrs)
+ end
+
+ test "update_container/2 with valid data updates the container" do
+ container = container_fixture()
+ assert {:ok, %Container{} = container} = Containers.update_container(container, @update_attrs)
+ assert container.desc == "some updated desc"
+ assert container.location == "some updated location"
+ assert container.name == "some updated name"
+ assert container.type == "some updated type"
+ end
+
+ test "update_container/2 with invalid data returns error changeset" do
+ container = container_fixture()
+ assert {:error, %Ecto.Changeset{}} = Containers.update_container(container, @invalid_attrs)
+ assert container == Containers.get_container!(container.id)
+ end
+
+ test "delete_container/1 deletes the container" do
+ container = container_fixture()
+ assert {:ok, %Container{}} = Containers.delete_container(container)
+ assert_raise Ecto.NoResultsError, fn -> Containers.get_container!(container.id) end
+ end
+
+ test "change_container/1 returns a container changeset" do
+ container = container_fixture()
+ assert %Ecto.Changeset{} = Containers.change_container(container)
+ end
+ end
+end
diff --git a/test/cannery/tags_test.exs b/test/cannery/tags_test.exs
new file mode 100644
index 00000000..fca21f1b
--- /dev/null
+++ b/test/cannery/tags_test.exs
@@ -0,0 +1,68 @@
+defmodule Cannery.TagsTest do
+ use Cannery.DataCase
+
+ alias Cannery.Tags
+
+ describe "tags" do
+ alias Cannery.Tags.Tag
+
+ @valid_attrs %{"bg-color": "some bg-color", name: "some name", "text-color": "some text-color"}
+ @update_attrs %{"bg-color": "some updated bg-color", name: "some updated name", "text-color": "some updated text-color"}
+ @invalid_attrs %{"bg-color": nil, name: nil, "text-color": nil}
+
+ def tag_fixture(attrs \\ %{}) do
+ {:ok, tag} =
+ attrs
+ |> Enum.into(@valid_attrs)
+ |> Tags.create_tag()
+
+ tag
+ end
+
+ test "list_tags/0 returns all tags" do
+ tag = tag_fixture()
+ assert Tags.list_tags() == [tag]
+ end
+
+ test "get_tag!/1 returns the tag with given id" do
+ tag = tag_fixture()
+ assert Tags.get_tag!(tag.id) == tag
+ end
+
+ test "create_tag/1 with valid data creates a tag" do
+ assert {:ok, %Tag{} = tag} = Tags.create_tag(@valid_attrs)
+ assert tag.bg-color == "some bg-color"
+ assert tag.name == "some name"
+ assert tag.text-color == "some text-color"
+ end
+
+ test "create_tag/1 with invalid data returns error changeset" do
+ assert {:error, %Ecto.Changeset{}} = Tags.create_tag(@invalid_attrs)
+ end
+
+ test "update_tag/2 with valid data updates the tag" do
+ tag = tag_fixture()
+ assert {:ok, %Tag{} = tag} = Tags.update_tag(tag, @update_attrs)
+ assert tag.bg-color == "some updated bg-color"
+ assert tag.name == "some updated name"
+ assert tag.text-color == "some updated text-color"
+ end
+
+ test "update_tag/2 with invalid data returns error changeset" do
+ tag = tag_fixture()
+ assert {:error, %Ecto.Changeset{}} = Tags.update_tag(tag, @invalid_attrs)
+ assert tag == Tags.get_tag!(tag.id)
+ end
+
+ test "delete_tag/1 deletes the tag" do
+ tag = tag_fixture()
+ assert {:ok, %Tag{}} = Tags.delete_tag(tag)
+ assert_raise Ecto.NoResultsError, fn -> Tags.get_tag!(tag.id) end
+ end
+
+ test "change_tag/1 returns a tag changeset" do
+ tag = tag_fixture()
+ assert %Ecto.Changeset{} = Tags.change_tag(tag)
+ end
+ end
+end
diff --git a/test/cannery_web/live/ammo_group_live_test.exs b/test/cannery_web/live/ammo_group_live_test.exs
new file mode 100644
index 00000000..ae6c5281
--- /dev/null
+++ b/test/cannery_web/live/ammo_group_live_test.exs
@@ -0,0 +1,116 @@
+defmodule CanneryWeb.AmmoGroupLiveTest do
+ use CanneryWeb.ConnCase
+
+ import Phoenix.LiveViewTest
+
+ alias Cannery.Ammo
+
+ @create_attrs %{count: 42, notes: "some notes", price_paid: 120.5}
+ @update_attrs %{count: 43, notes: "some updated notes", price_paid: 456.7}
+ @invalid_attrs %{count: nil, notes: nil, price_paid: nil}
+
+ defp fixture(:ammo_group) do
+ {:ok, ammo_group} = Ammo.create_ammo_group(@create_attrs)
+ ammo_group
+ end
+
+ defp create_ammo_group(_) do
+ ammo_group = fixture(:ammo_group)
+ %{ammo_group: ammo_group}
+ end
+
+ describe "Index" do
+ setup [:create_ammo_group]
+
+ test "lists all ammo_groups", %{conn: conn, ammo_group: ammo_group} do
+ {:ok, _index_live, html} = live(conn, Routes.ammo_group_index_path(conn, :index))
+
+ assert html =~ "Listing Ammo groups"
+ assert html =~ ammo_group.notes
+ end
+
+ test "saves new ammo_group", %{conn: conn} do
+ {:ok, index_live, _html} = live(conn, Routes.ammo_group_index_path(conn, :index))
+
+ assert index_live |> element("a", "New Ammo group") |> render_click() =~
+ "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() =~ "can't be blank"
+
+ {:ok, _, html} =
+ index_live
+ |> form("#ammo_group-form", ammo_group: @create_attrs)
+ |> render_submit()
+ |> follow_redirect(conn, Routes.ammo_group_index_path(conn, :index))
+
+ assert html =~ "Ammo group created successfully"
+ assert html =~ "some notes"
+ end
+
+ test "updates ammo_group in listing", %{conn: conn, ammo_group: ammo_group} do
+ {:ok, index_live, _html} = live(conn, Routes.ammo_group_index_path(conn, :index))
+
+ assert index_live |> element("#ammo_group-#{ammo_group.id} a", "Edit") |> render_click() =~
+ "Edit Ammo group"
+
+ assert_patch(index_live, Routes.ammo_group_index_path(conn, :edit, ammo_group))
+
+ assert index_live
+ |> form("#ammo_group-form", ammo_group: @invalid_attrs)
+ |> render_change() =~ "can't be blank"
+
+ {:ok, _, html} =
+ index_live
+ |> form("#ammo_group-form", ammo_group: @update_attrs)
+ |> render_submit()
+ |> follow_redirect(conn, Routes.ammo_group_index_path(conn, :index))
+
+ assert html =~ "Ammo group updated successfully"
+ assert html =~ "some updated notes"
+ end
+
+ test "deletes ammo_group in listing", %{conn: conn, ammo_group: ammo_group} do
+ {:ok, index_live, _html} = live(conn, Routes.ammo_group_index_path(conn, :index))
+
+ assert index_live |> element("#ammo_group-#{ammo_group.id} a", "Delete") |> render_click()
+ refute has_element?(index_live, "#ammo_group-#{ammo_group.id}")
+ end
+ end
+
+ describe "Show" do
+ setup [:create_ammo_group]
+
+ test "displays ammo_group", %{conn: conn, ammo_group: ammo_group} do
+ {:ok, _show_live, html} = live(conn, Routes.ammo_group_show_path(conn, :show, ammo_group))
+
+ assert html =~ "Show Ammo group"
+ assert html =~ ammo_group.notes
+ end
+
+ test "updates ammo_group within modal", %{conn: conn, ammo_group: ammo_group} do
+ {:ok, show_live, _html} = live(conn, Routes.ammo_group_show_path(conn, :show, ammo_group))
+
+ assert show_live |> element("a", "Edit") |> render_click() =~
+ "Edit Ammo group"
+
+ assert_patch(show_live, Routes.ammo_group_show_path(conn, :edit, ammo_group))
+
+ assert show_live
+ |> form("#ammo_group-form", ammo_group: @invalid_attrs)
+ |> render_change() =~ "can't be blank"
+
+ {:ok, _, html} =
+ show_live
+ |> form("#ammo_group-form", ammo_group: @update_attrs)
+ |> render_submit()
+ |> follow_redirect(conn, Routes.ammo_group_show_path(conn, :show, ammo_group))
+
+ assert html =~ "Ammo group updated successfully"
+ assert html =~ "some updated notes"
+ end
+ end
+end
diff --git a/test/cannery_web/live/ammo_type_live_test.exs b/test/cannery_web/live/ammo_type_live_test.exs
new file mode 100644
index 00000000..14b4eb06
--- /dev/null
+++ b/test/cannery_web/live/ammo_type_live_test.exs
@@ -0,0 +1,116 @@
+defmodule CanneryWeb.AmmoTypeLiveTest do
+ use CanneryWeb.ConnCase
+
+ import Phoenix.LiveViewTest
+
+ alias Cannery.Ammo
+
+ @create_attrs %{bullet_type: "some bullet_type", case_material: "some case_material", desc: "some desc", manufacturer: "some manufacturer", name: "some name", weight: 120.5}
+ @update_attrs %{bullet_type: "some updated bullet_type", case_material: "some updated case_material", desc: "some updated desc", manufacturer: "some updated manufacturer", name: "some updated name", weight: 456.7}
+ @invalid_attrs %{bullet_type: nil, case_material: nil, desc: nil, manufacturer: nil, name: nil, weight: nil}
+
+ defp fixture(:ammo_type) do
+ {:ok, ammo_type} = Ammo.create_ammo_type(@create_attrs)
+ ammo_type
+ end
+
+ defp create_ammo_type(_) do
+ ammo_type = fixture(:ammo_type)
+ %{ammo_type: ammo_type}
+ end
+
+ describe "Index" do
+ setup [:create_ammo_type]
+
+ test "lists all ammo_types", %{conn: conn, ammo_type: ammo_type} do
+ {:ok, _index_live, html} = live(conn, Routes.ammo_type_index_path(conn, :index))
+
+ assert html =~ "Listing Ammo types"
+ assert html =~ ammo_type.bullet_type
+ end
+
+ test "saves new ammo_type", %{conn: conn} do
+ {:ok, index_live, _html} = live(conn, Routes.ammo_type_index_path(conn, :index))
+
+ assert index_live |> element("a", "New Ammo type") |> render_click() =~
+ "New Ammo type"
+
+ assert_patch(index_live, Routes.ammo_type_index_path(conn, :new))
+
+ assert index_live
+ |> form("#ammo_type-form", ammo_type: @invalid_attrs)
+ |> render_change() =~ "can't be blank"
+
+ {:ok, _, html} =
+ index_live
+ |> form("#ammo_type-form", ammo_type: @create_attrs)
+ |> render_submit()
+ |> follow_redirect(conn, Routes.ammo_type_index_path(conn, :index))
+
+ assert html =~ "Ammo type created successfully"
+ assert html =~ "some bullet_type"
+ end
+
+ test "updates ammo_type in listing", %{conn: conn, ammo_type: ammo_type} do
+ {:ok, index_live, _html} = live(conn, Routes.ammo_type_index_path(conn, :index))
+
+ assert index_live |> element("#ammo_type-#{ammo_type.id} a", "Edit") |> render_click() =~
+ "Edit Ammo type"
+
+ assert_patch(index_live, Routes.ammo_type_index_path(conn, :edit, ammo_type))
+
+ assert index_live
+ |> form("#ammo_type-form", ammo_type: @invalid_attrs)
+ |> render_change() =~ "can't be blank"
+
+ {:ok, _, html} =
+ index_live
+ |> form("#ammo_type-form", ammo_type: @update_attrs)
+ |> render_submit()
+ |> follow_redirect(conn, Routes.ammo_type_index_path(conn, :index))
+
+ assert html =~ "Ammo type updated successfully"
+ assert html =~ "some updated bullet_type"
+ end
+
+ test "deletes ammo_type in listing", %{conn: conn, ammo_type: ammo_type} do
+ {:ok, index_live, _html} = live(conn, Routes.ammo_type_index_path(conn, :index))
+
+ assert index_live |> element("#ammo_type-#{ammo_type.id} a", "Delete") |> render_click()
+ refute has_element?(index_live, "#ammo_type-#{ammo_type.id}")
+ end
+ end
+
+ describe "Show" do
+ setup [:create_ammo_type]
+
+ test "displays ammo_type", %{conn: conn, ammo_type: ammo_type} do
+ {:ok, _show_live, html} = live(conn, Routes.ammo_type_show_path(conn, :show, ammo_type))
+
+ assert html =~ "Show Ammo type"
+ assert html =~ ammo_type.bullet_type
+ end
+
+ test "updates ammo_type within modal", %{conn: conn, ammo_type: ammo_type} do
+ {:ok, show_live, _html} = live(conn, Routes.ammo_type_show_path(conn, :show, ammo_type))
+
+ assert show_live |> element("a", "Edit") |> render_click() =~
+ "Edit Ammo type"
+
+ assert_patch(show_live, Routes.ammo_type_show_path(conn, :edit, ammo_type))
+
+ assert show_live
+ |> form("#ammo_type-form", ammo_type: @invalid_attrs)
+ |> render_change() =~ "can't be blank"
+
+ {:ok, _, html} =
+ show_live
+ |> form("#ammo_type-form", ammo_type: @update_attrs)
+ |> render_submit()
+ |> follow_redirect(conn, Routes.ammo_type_show_path(conn, :show, ammo_type))
+
+ assert html =~ "Ammo type updated successfully"
+ assert html =~ "some updated bullet_type"
+ end
+ end
+end
diff --git a/test/cannery_web/live/container_live_test.exs b/test/cannery_web/live/container_live_test.exs
new file mode 100644
index 00000000..75e2ac0a
--- /dev/null
+++ b/test/cannery_web/live/container_live_test.exs
@@ -0,0 +1,116 @@
+defmodule CanneryWeb.ContainerLiveTest do
+ use CanneryWeb.ConnCase
+
+ import Phoenix.LiveViewTest
+
+ alias Cannery.Containers
+
+ @create_attrs %{desc: "some desc", location: "some location", name: "some name", type: "some type"}
+ @update_attrs %{desc: "some updated desc", location: "some updated location", name: "some updated name", type: "some updated type"}
+ @invalid_attrs %{desc: nil, location: nil, name: nil, type: nil}
+
+ defp fixture(:container) do
+ {:ok, container} = Containers.create_container(@create_attrs)
+ container
+ end
+
+ defp create_container(_) do
+ container = fixture(:container)
+ %{container: container}
+ end
+
+ describe "Index" do
+ setup [:create_container]
+
+ test "lists all containers", %{conn: conn, container: container} do
+ {:ok, _index_live, html} = live(conn, Routes.container_index_path(conn, :index))
+
+ assert html =~ "Listing Containers"
+ assert html =~ container.desc
+ end
+
+ test "saves new container", %{conn: conn} do
+ {:ok, index_live, _html} = live(conn, Routes.container_index_path(conn, :index))
+
+ assert index_live |> element("a", "New Container") |> render_click() =~
+ "New Container"
+
+ assert_patch(index_live, Routes.container_index_path(conn, :new))
+
+ assert index_live
+ |> form("#container-form", container: @invalid_attrs)
+ |> render_change() =~ "can't be blank"
+
+ {:ok, _, html} =
+ index_live
+ |> form("#container-form", container: @create_attrs)
+ |> render_submit()
+ |> follow_redirect(conn, Routes.container_index_path(conn, :index))
+
+ assert html =~ "Container created successfully"
+ assert html =~ "some desc"
+ end
+
+ test "updates container in listing", %{conn: conn, container: container} do
+ {:ok, index_live, _html} = live(conn, Routes.container_index_path(conn, :index))
+
+ assert index_live |> element("#container-#{container.id} a", "Edit") |> render_click() =~
+ "Edit Container"
+
+ assert_patch(index_live, Routes.container_index_path(conn, :edit, container))
+
+ assert index_live
+ |> form("#container-form", container: @invalid_attrs)
+ |> render_change() =~ "can't be blank"
+
+ {:ok, _, html} =
+ index_live
+ |> form("#container-form", container: @update_attrs)
+ |> render_submit()
+ |> follow_redirect(conn, Routes.container_index_path(conn, :index))
+
+ assert html =~ "Container updated successfully"
+ assert html =~ "some updated desc"
+ end
+
+ test "deletes container in listing", %{conn: conn, container: container} do
+ {:ok, index_live, _html} = live(conn, Routes.container_index_path(conn, :index))
+
+ assert index_live |> element("#container-#{container.id} a", "Delete") |> render_click()
+ refute has_element?(index_live, "#container-#{container.id}")
+ end
+ end
+
+ describe "Show" do
+ setup [:create_container]
+
+ test "displays container", %{conn: conn, container: container} do
+ {:ok, _show_live, html} = live(conn, Routes.container_show_path(conn, :show, container))
+
+ assert html =~ "Show Container"
+ assert html =~ container.desc
+ end
+
+ test "updates container within modal", %{conn: conn, container: container} do
+ {:ok, show_live, _html} = live(conn, Routes.container_show_path(conn, :show, container))
+
+ assert show_live |> element("a", "Edit") |> render_click() =~
+ "Edit Container"
+
+ assert_patch(show_live, Routes.container_show_path(conn, :edit, container))
+
+ assert show_live
+ |> form("#container-form", container: @invalid_attrs)
+ |> render_change() =~ "can't be blank"
+
+ {:ok, _, html} =
+ show_live
+ |> form("#container-form", container: @update_attrs)
+ |> render_submit()
+ |> follow_redirect(conn, Routes.container_show_path(conn, :show, container))
+
+ assert html =~ "Container updated successfully"
+ assert html =~ "some updated desc"
+ end
+ end
+end
diff --git a/test/cannery_web/live/tag_live_test.exs b/test/cannery_web/live/tag_live_test.exs
new file mode 100644
index 00000000..73245577
--- /dev/null
+++ b/test/cannery_web/live/tag_live_test.exs
@@ -0,0 +1,116 @@
+defmodule CanneryWeb.TagLiveTest do
+ use CanneryWeb.ConnCase
+
+ import Phoenix.LiveViewTest
+
+ alias Cannery.Tags
+
+ @create_attrs %{"bg-color": "some bg-color", name: "some name", "text-color": "some text-color"}
+ @update_attrs %{"bg-color": "some updated bg-color", name: "some updated name", "text-color": "some updated text-color"}
+ @invalid_attrs %{"bg-color": nil, name: nil, "text-color": nil}
+
+ defp fixture(:tag) do
+ {:ok, tag} = Tags.create_tag(@create_attrs)
+ tag
+ end
+
+ defp create_tag(_) do
+ tag = fixture(:tag)
+ %{tag: tag}
+ end
+
+ describe "Index" do
+ setup [:create_tag]
+
+ test "lists all tags", %{conn: conn, tag: tag} do
+ {:ok, _index_live, html} = live(conn, Routes.tag_index_path(conn, :index))
+
+ assert html =~ "Listing Tags"
+ assert html =~ tag.bg-color
+ end
+
+ test "saves new tag", %{conn: conn} do
+ {:ok, index_live, _html} = live(conn, Routes.tag_index_path(conn, :index))
+
+ assert index_live |> element("a", "New Tag") |> render_click() =~
+ "New Tag"
+
+ assert_patch(index_live, Routes.tag_index_path(conn, :new))
+
+ assert index_live
+ |> form("#tag-form", tag: @invalid_attrs)
+ |> render_change() =~ "can't be blank"
+
+ {:ok, _, html} =
+ index_live
+ |> form("#tag-form", tag: @create_attrs)
+ |> render_submit()
+ |> follow_redirect(conn, Routes.tag_index_path(conn, :index))
+
+ assert html =~ "Tag created successfully"
+ assert html =~ "some bg-color"
+ end
+
+ test "updates tag in listing", %{conn: conn, tag: tag} do
+ {:ok, index_live, _html} = live(conn, Routes.tag_index_path(conn, :index))
+
+ assert index_live |> element("#tag-#{tag.id} a", "Edit") |> render_click() =~
+ "Edit Tag"
+
+ assert_patch(index_live, Routes.tag_index_path(conn, :edit, tag))
+
+ assert index_live
+ |> form("#tag-form", tag: @invalid_attrs)
+ |> render_change() =~ "can't be blank"
+
+ {:ok, _, html} =
+ index_live
+ |> form("#tag-form", tag: @update_attrs)
+ |> render_submit()
+ |> follow_redirect(conn, Routes.tag_index_path(conn, :index))
+
+ assert html =~ "Tag updated successfully"
+ assert html =~ "some updated bg-color"
+ end
+
+ test "deletes tag in listing", %{conn: conn, tag: tag} do
+ {:ok, index_live, _html} = live(conn, Routes.tag_index_path(conn, :index))
+
+ assert index_live |> element("#tag-#{tag.id} a", "Delete") |> render_click()
+ refute has_element?(index_live, "#tag-#{tag.id}")
+ end
+ end
+
+ describe "Show" do
+ setup [:create_tag]
+
+ test "displays tag", %{conn: conn, tag: tag} do
+ {:ok, _show_live, html} = live(conn, Routes.tag_show_path(conn, :show, tag))
+
+ assert html =~ "Show Tag"
+ assert html =~ tag.bg-color
+ end
+
+ test "updates tag within modal", %{conn: conn, tag: tag} do
+ {:ok, show_live, _html} = live(conn, Routes.tag_show_path(conn, :show, tag))
+
+ assert show_live |> element("a", "Edit") |> render_click() =~
+ "Edit Tag"
+
+ assert_patch(show_live, Routes.tag_show_path(conn, :edit, tag))
+
+ assert show_live
+ |> form("#tag-form", tag: @invalid_attrs)
+ |> render_change() =~ "can't be blank"
+
+ {:ok, _, html} =
+ show_live
+ |> form("#tag-form", tag: @update_attrs)
+ |> render_submit()
+ |> follow_redirect(conn, Routes.tag_show_path(conn, :show, tag))
+
+ assert html =~ "Tag updated successfully"
+ assert html =~ "some updated bg-color"
+ end
+ end
+end