This commit is contained in:
parent
e4671e816b
commit
900f322422
11 changed files with 161 additions and 80 deletions
|
|
@ -15,6 +15,8 @@ defmodule MvWeb.GroupLive.Show do
|
|||
"""
|
||||
use MvWeb, :live_view
|
||||
|
||||
require Logger
|
||||
|
||||
import MvWeb.LiveHelpers, only: [current_actor: 1]
|
||||
import MvWeb.Authorization
|
||||
|
||||
|
|
@ -162,7 +164,7 @@ defmodule MvWeb.GroupLive.Show do
|
|||
phx-hook="ComboBox"
|
||||
phx-focus="show_member_dropdown"
|
||||
phx-debounce="300"
|
||||
phx-window-keydown="member_dropdown_keydown"
|
||||
phx-keydown="member_dropdown_keydown"
|
||||
phx-mounted={JS.focus()}
|
||||
value={@member_search_query}
|
||||
placeholder={
|
||||
|
|
@ -231,6 +233,14 @@ defmodule MvWeb.GroupLive.Show do
|
|||
>
|
||||
<.icon name="hero-plus" class="size-5" />
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="btn join-item"
|
||||
phx-click="hide_add_member_input"
|
||||
aria-label={gettext("Cancel")}
|
||||
>
|
||||
{gettext("Cancel")}
|
||||
</button>
|
||||
</div>
|
||||
<% else %>
|
||||
<.button
|
||||
|
|
@ -439,12 +449,7 @@ defmodule MvWeb.GroupLive.Show do
|
|||
|
||||
@impl true
|
||||
def handle_event("show_member_dropdown", _params, socket) do
|
||||
# Reload group to ensure we have the latest members list before filtering
|
||||
actor = current_actor(socket)
|
||||
group = socket.assigns.group
|
||||
socket = reload_group(socket, group.slug, actor)
|
||||
|
||||
# Load available members with empty query when input is focused
|
||||
# Use existing group.members for filtering; reload only on add/remove
|
||||
socket =
|
||||
socket
|
||||
|> load_available_members("")
|
||||
|
|
@ -454,6 +459,19 @@ defmodule MvWeb.GroupLive.Show do
|
|||
{:noreply, socket}
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_event("hide_add_member_input", _params, socket) do
|
||||
{:noreply,
|
||||
socket
|
||||
|> assign(:show_add_member_input, false)
|
||||
|> assign(:member_search_query, "")
|
||||
|> assign(:available_members, [])
|
||||
|> assign(:selected_member_ids, [])
|
||||
|> assign(:selected_members, [])
|
||||
|> assign(:show_member_dropdown, false)
|
||||
|> assign(:focused_member_index, nil)}
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_event("hide_member_dropdown", _params, socket) do
|
||||
{:noreply, assign(socket, show_member_dropdown: false, focused_member_index: nil)}
|
||||
|
|
@ -514,11 +532,7 @@ defmodule MvWeb.GroupLive.Show do
|
|||
|
||||
@impl true
|
||||
def handle_event("search_members", %{"member_search" => query}, socket) do
|
||||
# Reload group to ensure we have the latest members list before filtering
|
||||
actor = current_actor(socket)
|
||||
group = socket.assigns.group
|
||||
socket = reload_group(socket, group.slug, actor)
|
||||
|
||||
# Use existing group.members for filtering; reload only on add/remove
|
||||
socket =
|
||||
socket
|
||||
|> assign(:member_search_query, query)
|
||||
|
|
@ -574,7 +588,8 @@ defmodule MvWeb.GroupLive.Show do
|
|||
|
||||
# Server-side authorization check
|
||||
if can?(actor, :update, group) do
|
||||
perform_add_members(socket, group, socket.assigns.selected_member_ids, actor)
|
||||
member_ids = Enum.uniq(socket.assigns.selected_member_ids)
|
||||
perform_add_members(socket, group, member_ids, actor)
|
||||
else
|
||||
{:noreply,
|
||||
socket
|
||||
|
|
@ -648,23 +663,29 @@ defmodule MvWeb.GroupLive.Show do
|
|||
defp load_available_members(socket, query) do
|
||||
require Ash.Query
|
||||
|
||||
current_member_ids = group_member_ids_set(socket.assigns.group)
|
||||
base_query = available_members_base_query(query)
|
||||
limited_query = Ash.Query.limit(base_query, 10)
|
||||
|
||||
# Fetch more than 10, then exclude already-in-group and take 10 (avoids empty dropdown when first N are all in group)
|
||||
fetch_limit = 50
|
||||
limited_query = Ash.Query.limit(base_query, fetch_limit)
|
||||
actor = current_actor(socket)
|
||||
|
||||
case Ash.read(limited_query, actor: actor, domain: Mv.Membership) do
|
||||
{:ok, members} ->
|
||||
current_member_ids = group_member_ids_set(socket.assigns.group)
|
||||
available =
|
||||
members
|
||||
|> Enum.reject(fn m -> MapSet.member?(current_member_ids, m.id) end)
|
||||
|> Enum.take(10)
|
||||
|
||||
filtered_members =
|
||||
Enum.reject(members, fn member ->
|
||||
MapSet.member?(current_member_ids, member.id)
|
||||
end)
|
||||
assign(socket, available_members: available)
|
||||
|
||||
assign(socket, available_members: filtered_members)
|
||||
{:error, error} ->
|
||||
Logger.warning("Failed to load available members for group: #{inspect(error)}")
|
||||
|
||||
{:error, _} ->
|
||||
assign(socket, available_members: [])
|
||||
socket
|
||||
|> put_flash(:error, gettext("Could not load member search. Please try again."))
|
||||
|> assign(:available_members, [])
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -681,18 +702,8 @@ defmodule MvWeb.GroupLive.Show do
|
|||
end
|
||||
|
||||
defp group_member_ids_set(group) do
|
||||
cond do
|
||||
is_list(group.members) and group.members != [] ->
|
||||
group.members
|
||||
|> Enum.map(& &1.id)
|
||||
|> MapSet.new()
|
||||
|
||||
is_list(group.members) ->
|
||||
MapSet.new()
|
||||
|
||||
true ->
|
||||
MapSet.new()
|
||||
end
|
||||
members = group.members || []
|
||||
members |> Enum.map(& &1.id) |> MapSet.new()
|
||||
end
|
||||
|
||||
defp perform_add_members(socket, group, member_ids, actor) when is_list(member_ids) do
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue