mirror of
https://github.com/documenso/documenso.git
synced 2025-11-23 21:21:37 +10:00
feat: add teams (#848)
## Description Add support for teams which will allow users to collaborate on documents. Teams features allows users to: - Create, manage and transfer teams - Manage team members - Manage team emails - Manage a shared team inbox and documents These changes do NOT include the following, which are planned for a future release: - Team templates - Team API - Search menu integration ## Testing Performed - Added E2E tests for general team management - Added E2E tests to validate document counts ## Checklist - [X] I have tested these changes locally and they work as expected. - [X] I have added/updated tests that prove the effectiveness of these changes. - [ ] I have updated the documentation to reflect these changes, if applicable. - [X] I have followed the project's coding style guidelines.
This commit is contained in:
@ -0,0 +1,143 @@
|
||||
'use client';
|
||||
|
||||
import { useRouter } from 'next/navigation';
|
||||
|
||||
import { Edit, Loader, Mail, MoreHorizontal, X } from 'lucide-react';
|
||||
|
||||
import type { getTeamByUrl } from '@documenso/lib/server-only/team/get-team';
|
||||
import { trpc } from '@documenso/trpc/react';
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuTrigger,
|
||||
} from '@documenso/ui/primitives/dropdown-menu';
|
||||
import { useToast } from '@documenso/ui/primitives/use-toast';
|
||||
|
||||
import { UpdateTeamEmailDialog } from '~/components/(teams)/dialogs/update-team-email-dialog';
|
||||
|
||||
export type TeamsSettingsPageProps = {
|
||||
team: Awaited<ReturnType<typeof getTeamByUrl>>;
|
||||
};
|
||||
|
||||
export const TeamEmailDropdown = ({ team }: TeamsSettingsPageProps) => {
|
||||
const router = useRouter();
|
||||
|
||||
const { toast } = useToast();
|
||||
|
||||
const { mutateAsync: resendEmailVerification, isLoading: isResendingEmailVerification } =
|
||||
trpc.team.resendTeamEmailVerification.useMutation({
|
||||
onSuccess: () => {
|
||||
toast({
|
||||
title: 'Success',
|
||||
description: 'Email verification has been resent',
|
||||
duration: 5000,
|
||||
});
|
||||
},
|
||||
onError: () => {
|
||||
toast({
|
||||
title: 'Something went wrong',
|
||||
variant: 'destructive',
|
||||
duration: 10000,
|
||||
description: 'Unable to resend verification at this time. Please try again.',
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
const { mutateAsync: deleteTeamEmail, isLoading: isDeletingTeamEmail } =
|
||||
trpc.team.deleteTeamEmail.useMutation({
|
||||
onSuccess: () => {
|
||||
toast({
|
||||
title: 'Success',
|
||||
description: 'Team email has been removed',
|
||||
duration: 5000,
|
||||
});
|
||||
},
|
||||
onError: () => {
|
||||
toast({
|
||||
title: 'Something went wrong',
|
||||
variant: 'destructive',
|
||||
duration: 10000,
|
||||
description: 'Unable to remove team email at this time. Please try again.',
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
const { mutateAsync: deleteTeamEmailVerification, isLoading: isDeletingTeamEmailVerification } =
|
||||
trpc.team.deleteTeamEmailVerification.useMutation({
|
||||
onSuccess: () => {
|
||||
toast({
|
||||
title: 'Success',
|
||||
description: 'Email verification has been removed',
|
||||
duration: 5000,
|
||||
});
|
||||
},
|
||||
onError: () => {
|
||||
toast({
|
||||
title: 'Something went wrong',
|
||||
variant: 'destructive',
|
||||
duration: 10000,
|
||||
description: 'Unable to remove email verification at this time. Please try again.',
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
const onRemove = async () => {
|
||||
if (team.teamEmail) {
|
||||
await deleteTeamEmail({ teamId: team.id });
|
||||
}
|
||||
|
||||
if (team.emailVerification) {
|
||||
await deleteTeamEmailVerification({ teamId: team.id });
|
||||
}
|
||||
|
||||
router.refresh();
|
||||
};
|
||||
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger>
|
||||
<MoreHorizontal className="text-muted-foreground h-5 w-5" />
|
||||
</DropdownMenuTrigger>
|
||||
|
||||
<DropdownMenuContent className="w-52" align="start" forceMount>
|
||||
{!team.teamEmail && team.emailVerification && (
|
||||
<DropdownMenuItem
|
||||
disabled={isResendingEmailVerification}
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
void resendEmailVerification({ teamId: team.id });
|
||||
}}
|
||||
>
|
||||
{isResendingEmailVerification ? (
|
||||
<Loader className="mr-2 h-4 w-4 animate-spin" />
|
||||
) : (
|
||||
<Mail className="mr-2 h-4 w-4" />
|
||||
)}
|
||||
Resend verification
|
||||
</DropdownMenuItem>
|
||||
)}
|
||||
|
||||
{team.teamEmail && (
|
||||
<UpdateTeamEmailDialog
|
||||
teamEmail={team.teamEmail}
|
||||
trigger={
|
||||
<DropdownMenuItem onSelect={(e) => e.preventDefault()}>
|
||||
<Edit className="mr-2 h-4 w-4" />
|
||||
Edit
|
||||
</DropdownMenuItem>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
|
||||
<DropdownMenuItem
|
||||
disabled={isDeletingTeamEmail || isDeletingTeamEmailVerification}
|
||||
onClick={async () => onRemove()}
|
||||
>
|
||||
<X className="mr-2 h-4 w-4" />
|
||||
Remove
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user