diff --git a/frontend/src/pages/organization/AccessManagementPage/components/OrgMembersTab/components/OrgMembersSection/OrgMembersTable.tsx b/frontend/src/pages/organization/AccessManagementPage/components/OrgMembersTab/components/OrgMembersSection/OrgMembersTable.tsx index e0350741e..1ad9cfdd1 100644 --- a/frontend/src/pages/organization/AccessManagementPage/components/OrgMembersTab/components/OrgMembersSection/OrgMembersTable.tsx +++ b/frontend/src/pages/organization/AccessManagementPage/components/OrgMembersTab/components/OrgMembersSection/OrgMembersTable.tsx @@ -1,8 +1,11 @@ -import { useCallback, useMemo } from "react"; +import { useCallback, useMemo, useState } from "react"; import { faArrowDown, faArrowUp, + faCheckCircle, + faChevronRight, faEllipsis, + faFilter, faMagnifyingGlass, faSearch, faUsers @@ -19,7 +22,11 @@ import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, + DropdownMenuLabel, DropdownMenuTrigger, + DropdownSubMenu, + DropdownSubMenuContent, + DropdownSubMenuTrigger, EmptyState, IconButton, Input, @@ -75,6 +82,10 @@ enum OrgMembersOrderBy { Email = "email" } +type Filter = { + roles: string[]; +}; + export const OrgMembersTable = ({ handlePopUpOpen, setCompleteInviteLinks }: Props) => { const navigate = useNavigate(); const { subscription } = useSubscription(); @@ -184,17 +195,29 @@ export const OrgMembersTable = ({ handlePopUpOpen, setCompleteInviteLinks }: Pro setUserTablePreference("orgMembersTable", PreferenceKey.PerPage, newPerPage); }; + const [filter, setFilter] = useState({ + roles: [] + }); + const filteredUsers = useMemo( () => members - ?.filter( - ({ user: u, inviteEmail }) => + ?.filter(({ user: u, inviteEmail, role, roleId }) => { + if ( + filter.roles.length && + !filter.roles.includes(role === "custom" ? findRoleFromId(roleId)!.slug : role) + ) { + return false; + } + + return ( u?.firstName?.toLowerCase().includes(search.toLowerCase()) || u?.lastName?.toLowerCase().includes(search.toLowerCase()) || u?.username?.toLowerCase().includes(search.toLowerCase()) || u?.email?.toLowerCase().includes(search.toLowerCase()) || inviteEmail?.toLowerCase().includes(search.toLowerCase()) - ) + ); + }) .sort((a, b) => { const [memberOne, memberTwo] = orderDirection === OrderByDirection.ASC ? [a, b] : [b, a]; @@ -217,7 +240,7 @@ export const OrgMembersTable = ({ handlePopUpOpen, setCompleteInviteLinks }: Pro return valueOne.toLowerCase().localeCompare(valueTwo.toLowerCase()); }), - [members, search, orderDirection, orderBy] + [members, search, orderDirection, orderBy, filter] ); const handleSort = (column: OrgMembersOrderBy) => { @@ -236,14 +259,81 @@ export const OrgMembersTable = ({ handlePopUpOpen, setCompleteInviteLinks }: Pro setPage }); + const handleRoleToggle = useCallback( + (roleSlug: string) => + setFilter((state) => { + const currentRoles = state.roles || []; + + if (currentRoles.includes(roleSlug)) { + return { ...state, roles: currentRoles.filter((role) => role !== roleSlug) }; + } + return { ...state, roles: [...currentRoles, roleSlug] }; + }), + [] + ); + + const isTableFiltered = Boolean(filter.roles.length); + return (
- setSearch(e.target.value)} - leftIcon={} - placeholder="Search members..." - /> +
+ + + + + + + + Filter By + + } + > + Roles + + + + Apply Roles to Filter Users + + {roles?.map(({ id, slug, name }) => ( + { + evt.preventDefault(); + handleRoleToggle(slug); + }} + key={id} + icon={filter.roles.includes(slug) && } + iconPos="right" + > +
+
+ {name} +
+ + ))} + + + + + setSearch(e.target.value)} + leftIcon={} + placeholder="Search members..." + /> +