diff --git a/h/static/scripts/group-forms/components/EditGroupMembersForm.tsx b/h/static/scripts/group-forms/components/EditGroupMembersForm.tsx index 77365eab095..dc18f171b96 100644 --- a/h/static/scripts/group-forms/components/EditGroupMembersForm.tsx +++ b/h/static/scripts/group-forms/components/EditGroupMembersForm.tsx @@ -1,5 +1,5 @@ -import { DataTable, Scroll } from '@hypothesis/frontend-shared'; -import { useEffect, useState } from 'preact/hooks'; +import { DataTable, Input, Scroll } from '@hypothesis/frontend-shared'; +import { useEffect, useMemo, useState } from 'preact/hooks'; import { routes } from '../routes'; import type { Group } from '../config'; @@ -56,6 +56,8 @@ export default function EditGroupMembersForm({ }, ]; + const [filter, setFilter] = useState(''); + const renderRow = (user: MemberRow, field: keyof MemberRow) => { switch (field) { case 'username': @@ -76,11 +78,46 @@ export default function EditGroupMembersForm({ const memberText = pluralize(members?.length ?? 0, 'member', 'members'); + const filteredMembers = useMemo(() => { + if (!filter || !members) { + return members; + } + + const normalizedFilter = filter.toLowerCase(); + + // nb. We can get away with lower-casing name and filter to do + // case-insensitive search because of the character set restrictions on + // usernames. This would be incorrect for Unicode text. + return members.filter(m => + m.username.toLowerCase().includes(normalizedFilter), + ); + }, [filter, members]); + + let emptyMessage; + if (members !== null && members.length > 0 && filter) { + emptyMessage = ( +