feat: add groups to member overview

This commit is contained in:
Simon 2026-02-13 09:28:16 +01:00
parent 82e908a7e4
commit dce4b2cf33
Signed by: simon
GPG key ID: 40E7A58C4AA1EDB2
6 changed files with 459 additions and 13 deletions

View file

@ -0,0 +1,97 @@
defmodule MvWeb.MemberLive.IndexGroupsDisplayTest do
@moduledoc """
Tests for displaying groups in the member overview.
Tests cover:
- Group badges are displayed for members in groups
- Multiple badges for members in multiple groups
- No badge for members without groups
- Badge shows group name correctly
"""
use MvWeb.ConnCase, async: false
import Phoenix.LiveViewTest
require Ash.Query
alias Mv.Membership.{Group, MemberGroup}
setup do
system_actor = Mv.Helpers.SystemActor.get_system_actor()
{:ok, member1} =
Mv.Membership.create_member(
%{first_name: "Alice", last_name: "Anderson", email: "alice@example.com"},
actor: system_actor
)
{:ok, member2} =
Mv.Membership.create_member(
%{first_name: "Bob", last_name: "Brown", email: "bob@example.com"},
actor: system_actor
)
{:ok, member3} =
Mv.Membership.create_member(
%{first_name: "Charlie", last_name: "Clark", email: "charlie@example.com"},
actor: system_actor
)
{:ok, group1} =
Group
|> Ash.Changeset.for_create(:create, %{name: "Board Members"})
|> Ash.create(actor: system_actor)
{:ok, group2} =
Group
|> Ash.Changeset.for_create(:create, %{name: "Active Members"})
|> Ash.create(actor: system_actor)
{:ok, _mg1} =
MemberGroup
|> Ash.Changeset.for_create(:create, %{member_id: member1.id, group_id: group1.id})
|> Ash.create(actor: system_actor)
{:ok, _mg2} =
MemberGroup
|> Ash.Changeset.for_create(:create, %{member_id: member1.id, group_id: group2.id})
|> Ash.create(actor: system_actor)
{:ok, _mg3} =
MemberGroup
|> Ash.Changeset.for_create(:create, %{member_id: member2.id, group_id: group1.id})
|> Ash.create(actor: system_actor)
%{member1: member1, member2: member2, member3: member3, group1: group1, group2: group2}
end
test "displays group badges for members in groups", %{conn: conn, group1: group1, group2: group2} do
conn = conn_with_oidc_user(conn)
{:ok, _view, html} = live(conn, "/members")
assert html =~ group1.name
assert html =~ group2.name
end
test "displays multiple badges for member in multiple groups", %{
conn: conn,
member1: member1,
group1: group1,
group2: group2
} do
conn = conn_with_oidc_user(conn)
{:ok, _view, html} = live(conn, "/members")
assert html =~ member1.first_name
assert html =~ group1.name
assert html =~ group2.name
end
test "shows placeholder for members without groups", %{conn: conn, member3: member3} do
conn = conn_with_oidc_user(conn)
{:ok, _view, html} = live(conn, "/members")
assert html =~ member3.first_name
end
test "displays group name correctly in badge", %{conn: conn, group1: group1} do
conn = conn_with_oidc_user(conn)
{:ok, _view, html} = live(conn, "/members")
assert html =~ group1.name
end
end

View file

@ -0,0 +1,113 @@
defmodule MvWeb.MemberLive.IndexGroupsFilterTest do
@moduledoc """
Tests for filtering members by group in the member overview.
"""
use MvWeb.ConnCase, async: false
import Phoenix.LiveViewTest
require Ash.Query
alias Mv.Membership.{Group, MemberGroup}
setup do
system_actor = Mv.Helpers.SystemActor.get_system_actor()
{:ok, member1} =
Mv.Membership.create_member(
%{first_name: "Alice", last_name: "Anderson", email: "alice@example.com"},
actor: system_actor
)
{:ok, member2} =
Mv.Membership.create_member(
%{first_name: "Bob", last_name: "Brown", email: "bob@example.com"},
actor: system_actor
)
{:ok, member3} =
Mv.Membership.create_member(
%{first_name: "Charlie", last_name: "Clark", email: "charlie@example.com"},
actor: system_actor
)
{:ok, group1} =
Group
|> Ash.Changeset.for_create(:create, %{name: "Board Members"})
|> Ash.create(actor: system_actor)
{:ok, group2} =
Group
|> Ash.Changeset.for_create(:create, %{name: "Active Members"})
|> Ash.create(actor: system_actor)
{:ok, _mg1} =
MemberGroup
|> Ash.Changeset.for_create(:create, %{member_id: member1.id, group_id: group1.id})
|> Ash.create(actor: system_actor)
{:ok, _mg2} =
MemberGroup
|> Ash.Changeset.for_create(:create, %{member_id: member2.id, group_id: group2.id})
|> Ash.create(actor: system_actor)
%{member1: member1, member2: member2, member3: member3, group1: group1, group2: group2}
end
test "filter 'All groups' shows all members", %{conn: conn, member1: m1, member2: m2, member3: m3} do
conn = conn_with_oidc_user(conn)
{:ok, _view, html} = live(conn, "/members")
assert html =~ m1.first_name
assert html =~ m2.first_name
assert html =~ m3.first_name
end
test "filter by specific group shows only members in that group", %{
conn: conn,
member1: m1,
member2: m2,
member3: m3,
group1: group1
} do
conn = conn_with_oidc_user(conn)
{:ok, view, _html} = live(conn, "/members")
view
|> element("#group-filter-form")
|> render_change(%{"group_filter" => group1.id})
html = render(view)
assert html =~ m1.first_name
refute html =~ m2.first_name
refute html =~ m3.first_name
end
test "filter persists in URL parameters", %{conn: conn, group1: group1, member1: m1} do
conn = conn_with_oidc_user(conn)
{:ok, view, _html} = live(conn, "/members")
view
|> element("#group-filter-form")
|> render_change(%{"group_filter" => group1.id})
# Verify filter is applied
html = render(view)
assert html =~ m1.first_name
# Verify visiting with group_filter in URL shows same filtered list
{:ok, _view2, html2} = live(conn, "/members?group_filter=#{group1.id}")
assert html2 =~ m1.first_name
end
test "filter is restored from URL on load", %{
conn: conn,
member1: m1,
member2: m2,
member3: m3,
group1: group1
} do
conn = conn_with_oidc_user(conn)
{:ok, _view, html} = live(conn, "/members?group_filter=#{group1.id}")
assert html =~ m1.first_name
refute html =~ m2.first_name
refute html =~ m3.first_name
end
end

View file

@ -0,0 +1,69 @@
defmodule MvWeb.MemberLive.IndexGroupsSortingTest do
@moduledoc """
Tests for sorting by groups in the member overview.
"""
use MvWeb.ConnCase, async: false
import Phoenix.LiveViewTest
require Ash.Query
alias Mv.Membership.{Group, MemberGroup}
setup do
system_actor = Mv.Helpers.SystemActor.get_system_actor()
{:ok, member1} =
Mv.Membership.create_member(
%{first_name: "Alice", last_name: "Anderson", email: "alice@example.com"},
actor: system_actor
)
{:ok, member2} =
Mv.Membership.create_member(
%{first_name: "Bob", last_name: "Brown", email: "bob@example.com"},
actor: system_actor
)
{:ok, member4} =
Mv.Membership.create_member(
%{first_name: "David", last_name: "Davis", email: "david@example.com"},
actor: system_actor
)
{:ok, group_a} =
Group
|> Ash.Changeset.for_create(:create, %{name: "A Group"})
|> Ash.create(actor: system_actor)
{:ok, group_b} =
Group
|> Ash.Changeset.for_create(:create, %{name: "B Group"})
|> Ash.create(actor: system_actor)
{:ok, _mg1} =
MemberGroup
|> Ash.Changeset.for_create(:create, %{member_id: member1.id, group_id: group_a.id})
|> Ash.create(actor: system_actor)
{:ok, _mg2} =
MemberGroup
|> Ash.Changeset.for_create(:create, %{member_id: member2.id, group_id: group_b.id})
|> Ash.create(actor: system_actor)
%{member1: member1, member2: member2, member4: member4, group_a: group_a, group_b: group_b}
end
test "sorts by group name ascending", %{conn: conn, group_a: group_a} do
conn = conn_with_oidc_user(conn)
{:ok, view, _html} = live(conn, "/members")
view
|> element("[data-testid='groups']")
|> render_click()
# Sort was applied: button shows ascending state and group names still visible
assert has_element?(view, "[data-testid='groups']")
html = render(view)
assert html =~ group_a.name
end
end