feat: improvement org member list (#13859)
* fix: sticky action bar and align checkbox * feat: make teams filterable and clickable, total members * fix: update members count --------- Co-authored-by: sean-brydon <55134778+sean-brydon@users.noreply.github.com> Co-authored-by: Udit Takkar <53316345+Udit-takkar@users.noreply.github.com>
This commit is contained in:
co-authored by
sean-brydon
Udit Takkar
parent
e39bf37f91
commit
01ac2e640a
@@ -110,6 +110,7 @@ function reducer(state: State, action: Action): State {
|
||||
export function UserListTable() {
|
||||
const { data: session } = useSession();
|
||||
const { data: currentMembership } = trpc.viewer.organizations.listCurrent.useQuery();
|
||||
const { data: teams } = trpc.viewer.organizations.getTeams.useQuery();
|
||||
const tableContainerRef = useRef<HTMLDivElement>(null);
|
||||
const [state, dispatch] = useReducer(reducer, initialState);
|
||||
const { t } = useLocale();
|
||||
@@ -126,6 +127,7 @@ export function UserListTable() {
|
||||
}
|
||||
);
|
||||
|
||||
const totalDBRowCount = data?.pages?.[0]?.meta?.totalRowCount ?? 0;
|
||||
const adminOrOwner = currentMembership?.user.role === "ADMIN" || currentMembership?.user.role === "OWNER";
|
||||
const domain = orgBranding?.fullDomain ?? WEBAPP_URL;
|
||||
|
||||
@@ -160,7 +162,7 @@ export function UserListTable() {
|
||||
{
|
||||
id: "member",
|
||||
accessorFn: (data) => data.email,
|
||||
header: "Member",
|
||||
header: `Member (${totalDBRowCount})`,
|
||||
cell: ({ row }) => {
|
||||
const { username, email } = row.original;
|
||||
return (
|
||||
@@ -210,8 +212,9 @@ export function UserListTable() {
|
||||
},
|
||||
{
|
||||
id: "teams",
|
||||
accessorFn: (data) => data.teams.map((team) => team.name),
|
||||
header: "Teams",
|
||||
cell: ({ row }) => {
|
||||
cell: ({ row, table }) => {
|
||||
const { teams, accepted, email, username } = row.original;
|
||||
// TODO: Implement click to filter
|
||||
return (
|
||||
@@ -226,13 +229,22 @@ export function UserListTable() {
|
||||
</Badge>
|
||||
)}
|
||||
{teams.map((team) => (
|
||||
<Badge key={team.id} variant="gray">
|
||||
<Badge
|
||||
key={team.id}
|
||||
variant="gray"
|
||||
onClick={() => {
|
||||
table.getColumn("teams")?.setFilterValue([team.name]);
|
||||
}}>
|
||||
{team.name}
|
||||
</Badge>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
},
|
||||
filterFn: (rows, _, filterValue: string[]) => {
|
||||
const teamNames = rows.original.teams.map((team) => team.name);
|
||||
return filterValue.some((value: string) => teamNames.includes(value));
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "actions",
|
||||
@@ -262,11 +274,10 @@ export function UserListTable() {
|
||||
];
|
||||
|
||||
return cols;
|
||||
}, [session?.user.id, adminOrOwner, dispatch, domain]);
|
||||
}, [session?.user.id, adminOrOwner, dispatch, domain, totalDBRowCount]);
|
||||
|
||||
//we must flatten the array of arrays from the useInfiniteQuery hook
|
||||
const flatData = useMemo(() => data?.pages?.flatMap((page) => page.rows) ?? [], [data]) as User[];
|
||||
const totalDBRowCount = data?.pages?.[0]?.meta?.totalRowCount ?? 0;
|
||||
const totalFetched = flatData.length;
|
||||
|
||||
//called on scroll and possibly on mount to fetch more data as the user scrolls and reaches bottom of table
|
||||
@@ -342,6 +353,11 @@ export function UserListTable() {
|
||||
{ label: "Member", value: "MEMBER" },
|
||||
],
|
||||
},
|
||||
{
|
||||
tableAccessor: "teams",
|
||||
title: "Teams",
|
||||
options: teams ? teams.map((team) => ({ label: team.name, value: team.name })) : [],
|
||||
},
|
||||
]}
|
||||
/>
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { isOrganisationAdmin } from "@calcom/lib/server/queries/organisations";
|
||||
import { prisma } from "@calcom/prisma";
|
||||
|
||||
import { TRPCError } from "@trpc/server";
|
||||
@@ -16,10 +15,6 @@ export async function getTeamsHandler({ ctx }: GetTeamsHandler) {
|
||||
|
||||
if (!currentUser.organizationId) throw new TRPCError({ code: "UNAUTHORIZED" });
|
||||
|
||||
// check if user is admin of organization
|
||||
if (!(await isOrganisationAdmin(currentUser?.id, currentUser.organizationId)))
|
||||
throw new TRPCError({ code: "UNAUTHORIZED" });
|
||||
|
||||
const allOrgTeams = await prisma.team.findMany({
|
||||
where: {
|
||||
parentId: currentUser.organizationId,
|
||||
|
||||
@@ -19,7 +19,7 @@ const TableHeader = React.forwardRef<HTMLTableSectionElement, React.HTMLAttribut
|
||||
({ className, ...props }, ref) => (
|
||||
<thead
|
||||
ref={ref}
|
||||
className={classNames("[&_tr]:bg-subtle md:sticky md:top-[4.25rem] md:z-10 [&_tr]:border-b", className)}
|
||||
className={classNames("[&_tr]:bg-subtle md:z-10 [&_tr]:border-b", className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
@@ -59,7 +59,7 @@ const TableHead = React.forwardRef<HTMLTableCellElement, React.ThHTMLAttributes<
|
||||
<th
|
||||
ref={ref}
|
||||
className={classNames(
|
||||
"text-default h-12 px-4 text-left align-middle font-medium [&:has([role=checkbox])]:pr-0",
|
||||
"text-default h-12 px-2 text-left align-middle font-medium [&:has([role=checkbox])]:pr-0",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
|
||||
Reference in New Issue
Block a user