add search to range index

This commit is contained in:
2022-12-03 21:27:39 -05:00
parent 3ea4b77b67
commit 45da547f62
20 changed files with 342 additions and 110 deletions

View File

@ -15,10 +15,50 @@ defmodule Cannery.ActivityLog do
iex> list_shot_groups(%User{id: 123})
[%ShotGroup{}, ...]
iex> list_shot_groups("cool", %User{id: 123})
[%ShotGroup{notes: "My cool shot group"}, ...]
"""
@spec list_shot_groups(User.t()) :: [ShotGroup.t()]
def list_shot_groups(%User{id: user_id}) do
Repo.all(from(sg in ShotGroup, where: sg.user_id == ^user_id))
@spec list_shot_groups(search :: nil | String.t(), User.t()) :: [ShotGroup.t()]
def list_shot_groups(search \\ nil, user)
def list_shot_groups(search, %{id: user_id}) when search |> is_nil() or search == "",
do: Repo.all(from sg in ShotGroup, where: sg.user_id == ^user_id)
def list_shot_groups(search, %{id: user_id}) when search |> is_binary() do
trimmed_search = String.trim(search)
Repo.all(
from sg in ShotGroup,
left_join: ag in assoc(sg, :ammo_group),
left_join: at in assoc(ag, :ammo_type),
where: sg.user_id == ^user_id,
where:
fragment(
"? @@ websearch_to_tsquery('english', ?)",
sg.search,
^trimmed_search
) or
fragment(
"? @@ websearch_to_tsquery('english', ?)",
ag.search,
^trimmed_search
) or
fragment(
"? @@ websearch_to_tsquery('english', ?)",
at.search,
^trimmed_search
),
order_by: {
:desc,
fragment(
"ts_rank_cd(?, websearch_to_tsquery('english', ?), 4)",
sg.search,
^trimmed_search
)
}
)
end
@doc """

View File

@ -10,7 +10,13 @@ defmodule CanneryWeb.RangeLive.Index do
alias Phoenix.LiveView.Socket
@impl true
def mount(_params, _session, socket), do: {:ok, socket |> display_shot_groups()}
def mount(%{"search" => search}, _session, socket) do
{:ok, socket |> assign(search: search) |> display_shot_groups()}
end
def mount(_params, _session, socket) do
{:ok, socket |> assign(search: nil) |> display_shot_groups()}
end
@impl true
def handle_params(params, _url, %{assigns: %{live_action: live_action}} = socket) do
@ -23,26 +29,46 @@ defmodule CanneryWeb.RangeLive.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, :edit, %{"id" => id}) do
socket
|> assign(:page_title, gettext("Edit Shot Records"))
|> assign(:shot_group, ActivityLog.get_shot_group!(id, current_user))
|> assign(
page_title: gettext("Edit Shot Records"),
shot_group: ActivityLog.get_shot_group!(id, current_user)
)
end
defp apply_action(socket, :new, _params) do
socket
|> assign(:page_title, gettext("New Shot Records"))
|> assign(:shot_group, %ShotGroup{})
|> assign(
page_title: gettext("New Shot Records"),
shot_group: %ShotGroup{}
)
end
defp apply_action(socket, :index, _params) do
socket
|> assign(:page_title, gettext("Shot Records"))
|> assign(:shot_group, nil)
|> assign(
page_title: gettext("Shot Records"),
search: nil,
shot_group: nil
)
|> display_shot_groups()
end
defp apply_action(socket, :search, %{"search" => search}) do
socket
|> assign(
page_title: gettext("Shot Records"),
search: search,
shot_group: nil
)
|> display_shot_groups()
end
@impl true
@ -55,6 +81,7 @@ defmodule CanneryWeb.RangeLive.Index do
{:noreply, socket |> put_flash(:info, prompt) |> display_shot_groups()}
end
@impl true
def handle_event(
"toggle_staged",
%{"ammo_group_id" => ammo_group_id},
@ -69,10 +96,20 @@ defmodule CanneryWeb.RangeLive.Index do
{:noreply, socket |> put_flash(:info, prompt) |> display_shot_groups()}
end
@impl true
def handle_event("search", %{"search" => %{"search_term" => ""}}, socket) do
{:noreply, socket |> push_patch(to: Routes.range_index_path(Endpoint, :index))}
end
def handle_event("search", %{"search" => %{"search_term" => search_term}}, socket) do
{:noreply, socket |> push_patch(to: Routes.range_index_path(Endpoint, :search, search_term))}
end
@spec display_shot_groups(Socket.t()) :: Socket.t()
defp display_shot_groups(%{assigns: %{current_user: current_user}} = socket) do
defp display_shot_groups(%{assigns: %{search: search, current_user: current_user}} = socket) do
shot_groups =
ActivityLog.list_shot_groups(current_user) |> Repo.preload(ammo_group: :ammo_type)
ActivityLog.list_shot_groups(search, current_user)
|> Repo.preload(ammo_group: :ammo_type)
ammo_groups = Ammo.list_staged_ammo_groups(current_user)
@ -114,7 +151,7 @@ defmodule CanneryWeb.RangeLive.Index do
label: gettext("Rounds shot: %{count}", count: sum)
}
end)
|> Enum.sort_by(fn %{date: date} -> date end)
|> Enum.sort_by(fn %{date: date} -> date end, Date)
end
@spec get_row_data_for_shot_group(ShotGroup.t(), [map()]) :: map()

View File

@ -43,7 +43,7 @@
<hr class="hr" />
<%= if @shot_groups |> Enum.empty?() do %>
<%= if @shot_groups |> Enum.empty?() and @search |> is_nil() do %>
<h1 class="title text-xl text-primary-600">
<%= gettext("No shots recorded") %>
<%= display_emoji("😔") %>
@ -67,14 +67,39 @@
<%= dgettext("errors", "Your browser does not support the canvas element.") %>
</canvas>
<.live_component
module={CanneryWeb.Components.TableComponent}
id="shot_groups_index_table"
columns={@columns}
rows={@rows}
initial_key={:date}
initial_sort_mode={:desc}
/>
<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="shot_group_search"
>
<%= text_input(f, :search_term,
class: "input input-primary",
value: @search,
phx_debounce: 300,
placeholder: gettext("Search shot records")
) %>
</.form>
</div>
<%= if @shot_groups |> Enum.empty?() do %>
<h1 class="title text-xl text-primary-600">
<%= gettext("No shots recorded") %>
<%= display_emoji("😔") %>
</h1>
<% else %>
<.live_component
module={CanneryWeb.Components.TableComponent}
id="shot_groups_index_table"
columns={@columns}
rows={@rows}
initial_key={:date}
initial_sort_mode={:desc}
/>
<% end %>
<% end %>
</div>

View File

@ -103,8 +103,9 @@ defmodule CanneryWeb.Router do
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
live "/range/:id/add_shot_group", RangeLive.Index, :add_shot_group
live "/range/edit/:id", RangeLive.Index, :edit
live "/range/add_shot_group/:id", RangeLive.Index, :add_shot_group
live "/range/search/:search", RangeLive.Index, :search
end
scope "/", CanneryWeb do