forked from shibao/cannery
		
	add search to ammo groups index
This commit is contained in:
		@@ -421,36 +421,86 @@ defmodule Cannery.Ammo do
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  @doc """
 | 
			
		||||
  Returns the list of ammo_groups for a user.
 | 
			
		||||
  Returns the list of ammo_groups.
 | 
			
		||||
 | 
			
		||||
  ## Examples
 | 
			
		||||
 | 
			
		||||
      iex> list_ammo_groups(%User{id: 123})
 | 
			
		||||
      [%AmmoGroup{}, ...]
 | 
			
		||||
 | 
			
		||||
      iex> list_ammo_groups("cool", true, %User{id: 123})
 | 
			
		||||
      [%AmmoGroup{notes: "My cool ammo group"}, ...]
 | 
			
		||||
 | 
			
		||||
  """
 | 
			
		||||
  @spec list_ammo_groups(User.t()) :: [AmmoGroup.t()]
 | 
			
		||||
  @spec list_ammo_groups(User.t(), include_empty :: boolean()) :: [AmmoGroup.t()]
 | 
			
		||||
  def list_ammo_groups(user, include_empty \\ false)
 | 
			
		||||
 | 
			
		||||
  def list_ammo_groups(%User{id: user_id}, true = _include_empty) do
 | 
			
		||||
    Repo.all(
 | 
			
		||||
      from ag in AmmoGroup,
 | 
			
		||||
        left_join: sg in assoc(ag, :shot_groups),
 | 
			
		||||
        where: ag.user_id == ^user_id,
 | 
			
		||||
        preload: [shot_groups: sg],
 | 
			
		||||
        order_by: ag.id
 | 
			
		||||
  @spec list_ammo_groups(search :: nil | String.t(), User.t()) :: [AmmoGroup.t()]
 | 
			
		||||
  @spec list_ammo_groups(search :: nil | String.t(), include_empty :: boolean(), User.t()) ::
 | 
			
		||||
          [AmmoGroup.t()]
 | 
			
		||||
  def list_ammo_groups(search \\ nil, include_empty \\ false, %{id: user_id}) do
 | 
			
		||||
    from(
 | 
			
		||||
      ag in AmmoGroup,
 | 
			
		||||
      as: :ag,
 | 
			
		||||
      left_join: sg in assoc(ag, :shot_groups),
 | 
			
		||||
      as: :sg,
 | 
			
		||||
      join: at in assoc(ag, :ammo_type),
 | 
			
		||||
      as: :at,
 | 
			
		||||
      join: c in assoc(ag, :container),
 | 
			
		||||
      as: :c,
 | 
			
		||||
      left_join: t in assoc(c, :tags),
 | 
			
		||||
      as: :t,
 | 
			
		||||
      where: ag.user_id == ^user_id,
 | 
			
		||||
      preload: [shot_groups: sg, ammo_type: at, container: {c, tags: t}],
 | 
			
		||||
      order_by: ag.id
 | 
			
		||||
    )
 | 
			
		||||
    |> list_ammo_groups_include_empty(include_empty)
 | 
			
		||||
    |> list_ammo_groups_search(search)
 | 
			
		||||
    |> Repo.all()
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def list_ammo_groups(%User{id: user_id}, false = _include_empty) do
 | 
			
		||||
    Repo.all(
 | 
			
		||||
      from ag in AmmoGroup,
 | 
			
		||||
        left_join: sg in assoc(ag, :shot_groups),
 | 
			
		||||
        where: ag.user_id == ^user_id,
 | 
			
		||||
        where: not (ag.count == 0),
 | 
			
		||||
        preload: [shot_groups: sg],
 | 
			
		||||
        order_by: ag.id
 | 
			
		||||
  defp list_ammo_groups_include_empty(query, true), do: query
 | 
			
		||||
 | 
			
		||||
  defp list_ammo_groups_include_empty(query, false) do
 | 
			
		||||
    query |> where([ag], not (ag.count == 0))
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  defp list_ammo_groups_search(query, nil), do: query
 | 
			
		||||
  defp list_ammo_groups_search(query, ""), do: query
 | 
			
		||||
 | 
			
		||||
  defp list_ammo_groups_search(query, search) do
 | 
			
		||||
    trimmed_search = String.trim(search)
 | 
			
		||||
 | 
			
		||||
    query
 | 
			
		||||
    |> where(
 | 
			
		||||
      [ag: ag, at: at, c: c, t: t],
 | 
			
		||||
      fragment(
 | 
			
		||||
        "? @@ websearch_to_tsquery('english', ?)",
 | 
			
		||||
        ag.search,
 | 
			
		||||
        ^trimmed_search
 | 
			
		||||
      ) or
 | 
			
		||||
        fragment(
 | 
			
		||||
          "? @@ websearch_to_tsquery('english', ?)",
 | 
			
		||||
          at.search,
 | 
			
		||||
          ^trimmed_search
 | 
			
		||||
        ) or
 | 
			
		||||
        fragment(
 | 
			
		||||
          "? @@ websearch_to_tsquery('english', ?)",
 | 
			
		||||
          c.search,
 | 
			
		||||
          ^trimmed_search
 | 
			
		||||
        ) or
 | 
			
		||||
        fragment(
 | 
			
		||||
          "? @@ websearch_to_tsquery('english', ?)",
 | 
			
		||||
          t.search,
 | 
			
		||||
          ^trimmed_search
 | 
			
		||||
        )
 | 
			
		||||
    )
 | 
			
		||||
    |> order_by(
 | 
			
		||||
      [ag: ag],
 | 
			
		||||
      desc:
 | 
			
		||||
        fragment(
 | 
			
		||||
          "ts_rank_cd(?, websearch_to_tsquery('english', ?), 4)",
 | 
			
		||||
          ag.search,
 | 
			
		||||
          ^trimmed_search
 | 
			
		||||
        )
 | 
			
		||||
    )
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -23,7 +23,7 @@ defmodule CanneryWeb.ExportController do
 | 
			
		||||
      end)
 | 
			
		||||
 | 
			
		||||
    ammo_groups =
 | 
			
		||||
      Ammo.list_ammo_groups(current_user, true)
 | 
			
		||||
      Ammo.list_ammo_groups(nil, true, current_user)
 | 
			
		||||
      |> Enum.map(fn ammo_group ->
 | 
			
		||||
        cpr = ammo_group |> Ammo.get_cpr()
 | 
			
		||||
        used_count = ammo_group |> Ammo.get_used_count()
 | 
			
		||||
 
 | 
			
		||||
@@ -4,12 +4,15 @@ defmodule CanneryWeb.AmmoGroupLive.Index do
 | 
			
		||||
  """
 | 
			
		||||
 | 
			
		||||
  use CanneryWeb, :live_view
 | 
			
		||||
  alias Cannery.{Ammo, Ammo.AmmoGroup, Containers, Repo}
 | 
			
		||||
  alias CanneryWeb.Endpoint
 | 
			
		||||
  alias Cannery.{Ammo, Ammo.AmmoGroup, Containers}
 | 
			
		||||
 | 
			
		||||
  @impl true
 | 
			
		||||
  def mount(%{"search" => search}, _session, socket) do
 | 
			
		||||
    {:ok, socket |> assign(show_used: false, search: search) |> display_ammo_groups()}
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def mount(_params, _session, socket) do
 | 
			
		||||
    {:ok, socket |> assign(show_used: false)}
 | 
			
		||||
    {:ok, socket |> assign(show_used: false, search: nil) |> display_ammo_groups()}
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  @impl true
 | 
			
		||||
@@ -23,38 +26,60 @@ defmodule CanneryWeb.AmmoGroupLive.Index do
 | 
			
		||||
         %{"id" => id}
 | 
			
		||||
       ) do
 | 
			
		||||
    socket
 | 
			
		||||
    |> assign(:page_title, gettext("Record shots"))
 | 
			
		||||
    |> assign(:ammo_group, Ammo.get_ammo_group!(id, current_user))
 | 
			
		||||
    |> assign(
 | 
			
		||||
      page_title: gettext("Record shots"),
 | 
			
		||||
      ammo_group: Ammo.get_ammo_group!(id, current_user)
 | 
			
		||||
    )
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  defp apply_action(%{assigns: %{current_user: current_user}} = socket, :move, %{"id" => id}) do
 | 
			
		||||
    socket
 | 
			
		||||
    |> assign(:page_title, gettext("Move ammo"))
 | 
			
		||||
    |> assign(:ammo_group, Ammo.get_ammo_group!(id, current_user))
 | 
			
		||||
    |> assign(
 | 
			
		||||
      page_title: gettext("Move ammo"),
 | 
			
		||||
      ammo_group: Ammo.get_ammo_group!(id, current_user)
 | 
			
		||||
    )
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  defp apply_action(%{assigns: %{current_user: current_user}} = socket, :edit, %{"id" => id}) do
 | 
			
		||||
    socket
 | 
			
		||||
    |> assign(:page_title, gettext("Edit ammo"))
 | 
			
		||||
    |> assign(:ammo_group, Ammo.get_ammo_group!(id, current_user))
 | 
			
		||||
    |> assign(
 | 
			
		||||
      page_title: gettext("Edit ammo"),
 | 
			
		||||
      ammo_group: Ammo.get_ammo_group!(id, current_user)
 | 
			
		||||
    )
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  defp apply_action(%{assigns: %{current_user: current_user}} = socket, :clone, %{"id" => id}) do
 | 
			
		||||
    socket
 | 
			
		||||
    |> assign(:page_title, dgettext("actions", "Add Ammo"))
 | 
			
		||||
    |> assign(:ammo_group, %{Ammo.get_ammo_group!(id, current_user) | id: nil})
 | 
			
		||||
    |> assign(
 | 
			
		||||
      page_title: dgettext("actions", "Add Ammo"),
 | 
			
		||||
      ammo_group: %{Ammo.get_ammo_group!(id, current_user) | id: nil}
 | 
			
		||||
    )
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  defp apply_action(socket, :new, _params) do
 | 
			
		||||
    socket
 | 
			
		||||
    |> assign(:page_title, dgettext("actions", "Add Ammo"))
 | 
			
		||||
    |> assign(:ammo_group, %AmmoGroup{})
 | 
			
		||||
    |> assign(
 | 
			
		||||
      page_title: dgettext("actions", "Add Ammo"),
 | 
			
		||||
      ammo_group: %AmmoGroup{}
 | 
			
		||||
    )
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  defp apply_action(socket, :index, _params) do
 | 
			
		||||
    socket
 | 
			
		||||
    |> assign(:page_title, gettext("Ammo"))
 | 
			
		||||
    |> assign(:ammo_group, nil)
 | 
			
		||||
    |> assign(
 | 
			
		||||
      page_title: gettext("Ammo"),
 | 
			
		||||
      search: nil,
 | 
			
		||||
      ammo_group: nil
 | 
			
		||||
    )
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  defp apply_action(socket, :search, %{"search" => search}) do
 | 
			
		||||
    socket
 | 
			
		||||
    |> assign(
 | 
			
		||||
      page_title: gettext("Ammo"),
 | 
			
		||||
      search: search,
 | 
			
		||||
      ammo_group: nil
 | 
			
		||||
    )
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  @impl true
 | 
			
		||||
@@ -85,13 +110,22 @@ defmodule CanneryWeb.AmmoGroupLive.Index do
 | 
			
		||||
    {:noreply, socket |> assign(:show_used, !show_used) |> display_ammo_groups()}
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  defp display_ammo_groups(
 | 
			
		||||
         %{assigns: %{current_user: current_user, show_used: show_used}} = socket
 | 
			
		||||
       ) do
 | 
			
		||||
    ammo_groups =
 | 
			
		||||
      Ammo.list_ammo_groups(current_user, show_used)
 | 
			
		||||
      |> Repo.preload([:ammo_type, :container], force: true)
 | 
			
		||||
  @impl true
 | 
			
		||||
  def handle_event("search", %{"search" => %{"search_term" => ""}}, socket) do
 | 
			
		||||
    {:noreply, socket |> push_patch(to: Routes.ammo_group_index_path(Endpoint, :index))}
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def handle_event("search", %{"search" => %{"search_term" => search_term}}, socket) do
 | 
			
		||||
    socket =
 | 
			
		||||
      socket |> push_patch(to: Routes.ammo_group_index_path(Endpoint, :search, search_term))
 | 
			
		||||
 | 
			
		||||
    {:noreply, socket}
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  defp display_ammo_groups(
 | 
			
		||||
         %{assigns: %{search: search, current_user: current_user, show_used: show_used}} = socket
 | 
			
		||||
       ) do
 | 
			
		||||
    ammo_groups = Ammo.list_ammo_groups(search, show_used, current_user)
 | 
			
		||||
    ammo_types_count = Ammo.get_ammo_types_count!(current_user)
 | 
			
		||||
    containers_count = Containers.get_containers_count!(current_user)
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -3,7 +3,7 @@
 | 
			
		||||
    <%= gettext("Ammo") %>
 | 
			
		||||
  </h1>
 | 
			
		||||
 | 
			
		||||
  <%= if @ammo_groups |> Enum.empty?() do %>
 | 
			
		||||
  <%= if @ammo_groups |> Enum.empty?() and @search |> is_nil() do %>
 | 
			
		||||
    <h2 class="title text-xl text-primary-600">
 | 
			
		||||
      <%= gettext("No Ammo") %>
 | 
			
		||||
      <%= display_emoji("😔") %>
 | 
			
		||||
@@ -31,7 +31,7 @@
 | 
			
		||||
          <%= dgettext("actions", "add an ammo type first") %>
 | 
			
		||||
        </.link>
 | 
			
		||||
      </div>
 | 
			
		||||
    <% @ammo_groups |> Enum.empty?() -> %>
 | 
			
		||||
    <% @ammo_groups |> Enum.empty?() and @search |> is_nil() -> %>
 | 
			
		||||
      <.link patch={Routes.ammo_group_index_path(Endpoint, :new)} class="btn btn-primary">
 | 
			
		||||
        <%= dgettext("actions", "Add your first box!") %>
 | 
			
		||||
      </.link>
 | 
			
		||||
@@ -41,15 +41,36 @@
 | 
			
		||||
      </.link>
 | 
			
		||||
  <% end %>
 | 
			
		||||
 | 
			
		||||
  <%= unless @ammo_groups |> Enum.empty?() do %>
 | 
			
		||||
    <div class="flex flex-col space-y-4 justify-center items-center">
 | 
			
		||||
      <.toggle_button action="toggle_show_used" value={@show_used}>
 | 
			
		||||
        <span class="title text-lg text-primary-600">
 | 
			
		||||
          <%= gettext("Show used") %>
 | 
			
		||||
        </span>
 | 
			
		||||
      </.toggle_button>
 | 
			
		||||
    </div>
 | 
			
		||||
  <div class="w-full flex flex-col sm:flex-row justify-center items-center space-y-4 sm:space-y-0 sm:space-x-4 max-w-xl">
 | 
			
		||||
    <.form
 | 
			
		||||
      :let={f}
 | 
			
		||||
      for={:search}
 | 
			
		||||
      phx-change="search"
 | 
			
		||||
      phx-submit="search"
 | 
			
		||||
      class="grow self-stretch flex flex-col items-stretch"
 | 
			
		||||
      data-qa="ammo_group_search"
 | 
			
		||||
    >
 | 
			
		||||
      <%= text_input(f, :search_term,
 | 
			
		||||
        class: "input input-primary",
 | 
			
		||||
        value: @search,
 | 
			
		||||
        phx_debounce: 300,
 | 
			
		||||
        placeholder: gettext("Search ammo")
 | 
			
		||||
      ) %>
 | 
			
		||||
    </.form>
 | 
			
		||||
 | 
			
		||||
    <.toggle_button action="toggle_show_used" value={@show_used}>
 | 
			
		||||
      <span class="title text-lg text-primary-600">
 | 
			
		||||
        <%= gettext("Show used") %>
 | 
			
		||||
      </span>
 | 
			
		||||
    </.toggle_button>
 | 
			
		||||
  </div>
 | 
			
		||||
 | 
			
		||||
  <%= if @ammo_groups |> Enum.empty?() do %>
 | 
			
		||||
    <h2 class="title text-xl text-primary-600">
 | 
			
		||||
      <%= gettext("No Ammo") %>
 | 
			
		||||
      <%= display_emoji("😔") %>
 | 
			
		||||
    </h2>
 | 
			
		||||
  <% else %>
 | 
			
		||||
    <.live_component
 | 
			
		||||
      module={CanneryWeb.Components.AmmoGroupTableComponent}
 | 
			
		||||
      id="ammo-group-index-table"
 | 
			
		||||
 
 | 
			
		||||
@@ -90,16 +90,17 @@ defmodule CanneryWeb.Router do
 | 
			
		||||
 | 
			
		||||
    live "/ammo", AmmoGroupLive.Index, :index
 | 
			
		||||
    live "/ammo/new", AmmoGroupLive.Index, :new
 | 
			
		||||
    live "/ammo/:id/edit", AmmoGroupLive.Index, :edit
 | 
			
		||||
    live "/ammo/:id/clone", AmmoGroupLive.Index, :clone
 | 
			
		||||
    live "/ammo/:id/add_shot_group", AmmoGroupLive.Index, :add_shot_group
 | 
			
		||||
    live "/ammo/:id/move", AmmoGroupLive.Index, :move
 | 
			
		||||
    live "/ammo/edit/:id", AmmoGroupLive.Index, :edit
 | 
			
		||||
    live "/ammo/clone/:id", AmmoGroupLive.Index, :clone
 | 
			
		||||
    live "/ammo/add_shot_group/:id", AmmoGroupLive.Index, :add_shot_group
 | 
			
		||||
    live "/ammo/move/:id", AmmoGroupLive.Index, :move
 | 
			
		||||
    live "/ammo/search/:search", AmmoGroupLive.Index, :search
 | 
			
		||||
 | 
			
		||||
    live "/ammo/:id/show", AmmoGroupLive.Show, :show
 | 
			
		||||
    live "/ammo/:id/show/edit", AmmoGroupLive.Show, :edit
 | 
			
		||||
    live "/ammo/:id/show/add_shot_group", AmmoGroupLive.Show, :add_shot_group
 | 
			
		||||
    live "/ammo/:id/show/move", AmmoGroupLive.Show, :move
 | 
			
		||||
    live "/ammo/:id/show/:shot_group_id/edit", AmmoGroupLive.Show, :edit_shot_group
 | 
			
		||||
    live "/ammo/show/:id", AmmoGroupLive.Show, :show
 | 
			
		||||
    live "/ammo/show/edit/:id", AmmoGroupLive.Show, :edit
 | 
			
		||||
    live "/ammo/show/add_shot_group/:id", AmmoGroupLive.Show, :add_shot_group
 | 
			
		||||
    live "/ammo/show/move/:id", AmmoGroupLive.Show, :move
 | 
			
		||||
    live "/ammo/show/:id/edit/:shot_group_id", AmmoGroupLive.Show, :edit_shot_group
 | 
			
		||||
 | 
			
		||||
    live "/range", RangeLive.Index, :index
 | 
			
		||||
    live "/range/:id/edit", RangeLive.Index, :edit
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user