"use client"; import { keepPreviousData } from "@tanstack/react-query"; import { getCoreRowModel, getSortedRowModel, useReactTable, type ColumnDef } from "@tanstack/react-table"; import { useMemo, useReducer, useState } from "react"; import { DataTableProvider } from "~/data-table/DataTableProvider"; import { useColumnFilters } from "~/data-table/hooks/useColumnFilters"; import { useDataTable } from "~/data-table/hooks/useDataTable"; import { DataTableWrapper, DataTableToolbar, DataTableFilters, DataTableSegment, DataTableSelectionBar, } from "~/data-table/components"; import { useSegments } from "~/data-table/hooks/useSegments"; import { getUserAvatarUrl } from "@calcom/lib/getAvatarUrl"; import { useLocale } from "@calcom/lib/hooks/useLocale"; import { trpc } from "@calcom/trpc/react"; import { Avatar } from "@calcom/ui/components/avatar"; import { Badge } from "@calcom/ui/components/badge"; import { Checkbox } from "@calcom/ui/components/form"; import { SkeletonText } from "@calcom/ui/components/skeleton"; import { DeleteBulkUsers } from "./BulkActions/DeleteBulkUsers"; import { DeleteMemberModal } from "./DeleteMemberModal"; import type { UserTableState, UserTableAction, PlatformManagedUserTableUser } from "./types"; const initialState: UserTableState = { changeMemberRole: { showModal: false, }, deleteMember: { showModal: false, }, impersonateMember: { showModal: false, }, inviteMember: { showModal: false, }, editSheet: { showModal: false, }, }; const initalColumnVisibility = { select: true, member: true, role: true, teams: true, actions: true, }; type PlatformManagedUsersTableProps = { oAuthClientId: string; }; export function PlatformManagedUsersTable(props: PlatformManagedUsersTableProps) { return ( ); } function UserListTableContent({ oAuthClientId }: PlatformManagedUsersTableProps) { const { t } = useLocale(); const [state, dispatch] = useReducer(reducer, initialState); const [rowSelection, setRowSelection] = useState({}); const columnFilters = useColumnFilters(); const { pageIndex, pageSize, searchTerm } = useDataTable(); const limit = pageSize; const offset = pageIndex * pageSize; const { data, isPending } = trpc.viewer.organizations.listMembers.useQuery( { limit, offset, searchTerm, filters: columnFilters, oAuthClientId, }, { placeholderData: keepPreviousData, enabled: !!oAuthClientId, } ); const totalRowCount = data?.meta?.totalRowCount ?? 0; //we must flatten the array of arrays from the useInfiniteQuery hook const flatData = useMemo(() => data?.rows ?? [], [data]) as PlatformManagedUserTableUser[]; const columns = useMemo(() => { const cols: ColumnDef[] = [ // Disabling select for this PR: Will work on actions etc in a follow up { id: "select", enableHiding: false, enableSorting: false, enableResizing: false, size: 30, header: ({ table }) => ( table.toggleAllPageRowsSelected(!!value)} aria-label="Select all" /> ), cell: ({ row }) => ( row.toggleSelected(!!value)} aria-label="Select row" className="translate-y-[2px]" /> ), }, { id: "member", accessorFn: (data) => data.email, enableHiding: false, size: 200, header: () => { return t("managed_users"); }, cell: ({ row }) => { if (isPending) { return ; } const { username, email, avatarUrl } = row.original; return (
{username || "No username"}
{email}
); }, }, { id: "role", accessorFn: (data) => data.role, header: t("role"), size: 100, cell: ({ row, table }) => { if (isPending) { return ; } const { role, username } = row.original; return ( { table.getColumn("role")?.setFilterValue([role]); }}> {role} ); }, }, { id: "teams", accessorFn: (data) => data.teams.map((team) => team.name), header: t("teams"), size: 140, cell: ({ row, table }) => { if (isPending) { return ; } const { teams, accepted, email, username } = row.original; // TODO: Implement click to filter return (
{accepted ? null : ( { table.getColumn("role")?.setFilterValue(["PENDING"]); }}> Pending )} {teams.map((team) => ( { table.getColumn("teams")?.setFilterValue([team.name]); }}> {team.name} ))}
); }, }, ]; return cols; }, [isPending]); const table = useReactTable({ data: flatData, columns, enableRowSelection: true, debugTable: true, manualPagination: true, initialState: { columnVisibility: initalColumnVisibility, columnPinning: { left: ["select", "member"], }, }, defaultColumn: { size: 150, }, state: { columnFilters, rowSelection, }, getCoreRowModel: getCoreRowModel(), getSortedRowModel: getSortedRowModel(), onRowSelectionChange: setRowSelection, getRowId: (row) => `${row.id}`, }); function reducer(state: UserTableState, action: UserTableAction): UserTableState { switch (action.type) { case "SET_CHANGE_MEMBER_ROLE_ID": return { ...state, changeMemberRole: action.payload }; case "SET_DELETE_ID": return { ...state, deleteMember: action.payload }; case "SET_IMPERSONATE_ID": return { ...state, impersonateMember: action.payload }; case "INVITE_MEMBER": return { ...state, inviteMember: action.payload }; case "EDIT_USER_SHEET": return { ...state, editSheet: action.payload }; case "CLOSE_MODAL": return { ...state, changeMemberRole: { showModal: false }, deleteMember: { showModal: false }, impersonateMember: { showModal: false }, inviteMember: { showModal: false }, editSheet: { showModal: false }, }; default: return state; } } const numberOfSelectedRows = useMemo(() => table.getSelectedRowModel().rows.length, [table]); return ( <> testId="managed-user-list-data-table" table={table} isPending={isPending} totalRowCount={data?.meta?.totalRowCount} paginationMode="standard" ToolbarLeft={ <> } ToolbarRight={ <> }> {numberOfSelectedRows > 0 && (

{t("number_selected", { count: numberOfSelectedRows })}

row.original)} onRemove={() => table.toggleAllPageRowsSelected(false)} />
)} {state.deleteMember.showModal && } ); }