();
+ const emailColumn = columnHelper.accessor('email', {
+ header: 'Email',
+ cell: ({ getValue }) => {getValue()}
,
+ });
+
+ const createdAtColumn = columnHelper.accessor('createdAt', {
+ header: 'Created At',
+ cell: ({ getValue }) => {
+ return {formatDateTime(getValue())}
;
},
- {
- accessorKey: 'expiresAt',
- header: 'Expires At',
- cell: ({ row }) => {
- return (
-
-
- {formatDateTime(row.getValue('expiresAt')?.toDate())}
-
-
- );
- },
+ });
+
+ const expiresAtColumn = columnHelper.accessor('expiresAt', {
+ header: 'Expires At',
+ cell: ({ getValue }) => {
+ return {formatDateTime(getValue())}
;
},
- {
- id: 'actions',
- cell: ({ row }) => {
- return (
-
-
-
-
- );
- },
+ });
+
+ const roleColumn = columnHelper.accessor('role', {
+ header: 'Role',
+ cell: ({ getValue }) => (
+
+ {getAccountRoleString(getValue())}
+
+ ),
+ });
+
+ const actionsColumn = columnHelper.display({
+ id: 'actions',
+ cell: ({ row, table }) => {
+ return (
+
+
+
+ table.options.meta?.invitesTable?.onDeleted(row.original.id)
+ }
+ inviteId={row.original.id}
+ />
+
+ );
},
- ];
+ });
+
+ if (isRbacEnabled) {
+ return [
+ emailColumn,
+ createdAtColumn,
+ expiresAtColumn,
+ roleColumn,
+ actionsColumn,
+ ];
+ }
+
+ return [emailColumn, createdAtColumn, expiresAtColumn, actionsColumn];
+}
+
+function useGetColumns(): ColumnDef[] {
+ const { data: config } = useGetSystemAppConfig();
+ const isRbacEnabled = config?.isRbacEnabled ?? false;
+ return useMemo(() => {
+ return getColumns(isRbacEnabled);
+ }, [isRbacEnabled]);
}
interface Props {
accountId: string;
}
-export function InvitesTable(props: Props) {
+export function InvitesTable(props: Props): React.ReactElement {
const { accountId } = props;
- const { data, isLoading, refetch } = useQuery(
+ const { data, isLoading, refetch, isFetching } = useQuery(
getTeamAccountInvites,
{ accountId: accountId },
{ enabled: !!accountId }
);
+ const invites = data?.invites || [];
+ const invitesRows = useMemo(() => {
+ return invites.map((invite): MemberInviteRow => {
+ return {
+ id: invite.id,
+ email: invite.email,
+ createdAt: invite.createdAt?.toDate() ?? new Date(),
+ expiresAt: invite.expiresAt?.toDate() ?? new Date(),
+ token: invite.token,
+ role: invite.role,
+ };
+ });
+ }, [isFetching, invites]);
+
+ const columns = useGetColumns();
+
if (isLoading) {
return ;
}
- return refetch()} />;
+ return (
+ refetch()}
+ />
+ );
+}
+
+declare module '@tanstack/react-table' {
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
+ interface TableMeta {
+ invitesTable?: {
+ onDeleted(id: string): void;
+ };
+ }
}
interface DataTableProps {
- data: AccountInvite[];
+ data: MemberInviteRow[];
+ columns: ColumnDef[];
onDeleted(id: string): void;
}
function DataTable(props: DataTableProps): React.ReactElement {
- const { data, onDeleted } = props;
- const [sorting, setSorting] = React.useState([]);
- const [columnFilters, setColumnFilters] = React.useState(
- []
- );
- const [columnVisibility, setColumnVisibility] =
- React.useState({});
- const [rowSelection, setRowSelection] = React.useState({});
-
- const columns = React.useMemo(() => getColumns({ onDeleted }), []);
+ const { data, columns, onDeleted } = props;
+ const [sorting, setSorting] = useState([]);
+ const [columnFilters, setColumnFilters] = useState([]);
+ const [columnVisibility, setColumnVisibility] = useState({});
+ const [rowSelection, setRowSelection] = useState({});
const table = useReactTable({
data,
@@ -148,6 +201,11 @@ function DataTable(props: DataTableProps): React.ReactElement {
columnVisibility,
rowSelection,
},
+ meta: {
+ invitesTable: {
+ onDeleted,
+ },
+ },
});
return (
diff --git a/frontend/apps/web/app/(mgmt)/[account]/settings/members/components/InviteUserForm.tsx b/frontend/apps/web/app/(mgmt)/[account]/settings/members/components/InviteUserForm.tsx
index 66eccb1e59..ecf684f561 100644
--- a/frontend/apps/web/app/(mgmt)/[account]/settings/members/components/InviteUserForm.tsx
+++ b/frontend/apps/web/app/(mgmt)/[account]/settings/members/components/InviteUserForm.tsx
@@ -15,8 +15,10 @@ import {
import {
Form,
FormControl,
+ FormDescription,
FormField,
FormItem,
+ FormLabel,
FormMessage,
} from '@/components/ui/form';
import { Input } from '@/components/ui/input';
@@ -25,12 +27,14 @@ import { getErrorMessage } from '@/util/util';
import { InviteMembersForm } from '@/yup-validations/invite-members';
import { useMutation } from '@connectrpc/connect-query';
import { yupResolver } from '@hookform/resolvers/yup';
+import { AccountRole } from '@neosync/sdk';
import { inviteUserToTeamAccount } from '@neosync/sdk/connectquery';
import { DialogClose } from '@radix-ui/react-dialog';
import { PlusIcon } from '@radix-ui/react-icons';
import { ReactElement, useState } from 'react';
import { useForm } from 'react-hook-form';
import { toast } from 'sonner';
+import SelectAccountRole from './SelectAccountRole';
interface Props {
accountId: string;
@@ -38,6 +42,8 @@ interface Props {
}
export default function InviteUserForm(props: Props): ReactElement {
const { accountId, onInvited } = props;
+ const { data: systemAppData } = useGetSystemAppConfig();
+ const isRbacEnabled = systemAppData?.isRbacEnabled ?? false;
const [showNewInviteDialog, setShowNewinviteDialog] = useState(false);
const [newInviteToken, setNewInviteToken] = useState('');
const [openInviteCreated, setOpenInviteCreated] = useState(false);
@@ -46,6 +52,7 @@ export default function InviteUserForm(props: Props): ReactElement {
resolver: yupResolver(InviteMembersForm),
defaultValues: {
email: '',
+ role: AccountRole.JOB_VIEWER,
},
});
const { mutateAsync } = useMutation(inviteUserToTeamAccount);
@@ -55,6 +62,7 @@ export default function InviteUserForm(props: Props): ReactElement {
const invite = await mutateAsync({
accountId: accountId,
email: values.email,
+ role: values.role,
});
setShowNewinviteDialog(false);
if (invite?.invite?.token) {
@@ -89,16 +97,20 @@ export default function InviteUserForm(props: Props): ReactElement {
Add new member
- Invite members with their email.
+ Invite a new member to your account.