"use client"; import { ActionButton } from "@/components/ui/action-button"; import { ButtonWithTooltip } from "@/components/ui/button"; import LoadingSpinner from "@/components/ui/spinner"; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "@/components/ui/table"; import { toast } from "@/components/ui/use-toast"; import { api } from "@/lib/trpc"; import { formatDistanceToNow } from "date-fns"; import { Mail, MailX, UserPlus } from "lucide-react"; import ActionConfirmingDialog from "../ui/action-confirming-dialog"; import CreateInviteDialog from "./CreateInviteDialog"; export default function InvitesList() { const invalidateInvitesList = api.useUtils().invites.list.invalidate; const { data: invites, isLoading } = api.invites.list.useQuery(); const { mutateAsync: revokeInvite, isPending: isRevokePending } = api.invites.revoke.useMutation({ onSuccess: () => { toast({ description: "Invite revoked successfully", }); invalidateInvitesList(); }, onError: (e) => { toast({ variant: "destructive", description: `Failed to revoke invite: ${e.message}`, }); }, }); const { mutateAsync: resendInvite, isPending: isResendPending } = api.invites.resend.useMutation({ onSuccess: () => { toast({ description: "Invite resent successfully", }); invalidateInvitesList(); }, onError: (e) => { toast({ variant: "destructive", description: `Failed to resend invite: ${e.message}`, }); }, }); if (isLoading) { return ; } const activeInvites = invites?.invites?.filter( (invite) => new Date(invite.expiresAt) > new Date(), ) || []; const expiredInvites = invites?.invites?.filter( (invite) => new Date(invite.expiresAt) <= new Date(), ) || []; const getStatusBadge = ( invite: NonNullable["invites"][0], ) => { if (new Date(invite.expiresAt) <= new Date()) { return ( Expired ); } return ( Active ); }; const InviteTable = ({ invites: inviteList, title, }: { invites: NonNullable["invites"]; title: string; }) => (

{title} ({inviteList.length})

{inviteList.length === 0 ? (

No {title.toLowerCase()} invites

) : ( Email Invited By Created Expires Status Actions {inviteList.map((invite) => ( {invite.email} {invite.invitedBy.name} {formatDistanceToNow(new Date(invite.createdAt), { addSuffix: true, })} {formatDistanceToNow(new Date(invite.expiresAt), { addSuffix: true, })} {getStatusBadge(invite)} {new Date(invite.expiresAt) > new Date() && ( <> resendInvite({ inviteId: invite.id })} disabled={isResendPending} > ( { await revokeInvite({ inviteId: invite.id }); setDialogOpen(false); }} > Revoke )} > )} ))}
)}
); return (
User Invitations
); }