From 02f1264eeafccff16616390a8eb7df3d353ffc96 Mon Sep 17 00:00:00 2001 From: Catalin Pit Date: Mon, 15 Dec 2025 03:17:13 +0200 Subject: [PATCH] feat: unlink documents from deleted organization (#2006) --- .../components/dialogs/team-delete-dialog.tsx | 57 ++++++++++++++- .../server-only/envelope/orphan-envelopes.ts | 52 ++++++++++++++ .../envelope/transfer-team-envelopes.ts | 20 ++++++ packages/lib/server-only/user/delete-user.ts | 72 ++++++++++++++----- .../user/service-accounts/deleted-account.ts | 14 ++++ .../delete-organisation.ts | 17 +++++ .../trpc/server/team-router/delete-team.ts | 33 ++++++++- .../server/team-router/delete-team.types.ts | 1 + 8 files changed, 245 insertions(+), 21 deletions(-) create mode 100644 packages/lib/server-only/envelope/orphan-envelopes.ts create mode 100644 packages/lib/server-only/envelope/transfer-team-envelopes.ts diff --git a/apps/remix/app/components/dialogs/team-delete-dialog.tsx b/apps/remix/app/components/dialogs/team-delete-dialog.tsx index 670ba1a2a..ac735e1ff 100644 --- a/apps/remix/app/components/dialogs/team-delete-dialog.tsx +++ b/apps/remix/app/components/dialogs/team-delete-dialog.tsx @@ -8,6 +8,7 @@ import { useForm } from 'react-hook-form'; import { useNavigate } from 'react-router'; import { z } from 'zod'; +import { useCurrentOrganisation } from '@documenso/lib/client-only/providers/organisation'; import { useSession } from '@documenso/lib/client-only/providers/session'; import { AppError } from '@documenso/lib/errors/app-error'; import { trpc } from '@documenso/trpc/react'; @@ -30,6 +31,13 @@ import { FormMessage, } from '@documenso/ui/primitives/form/form'; import { Input } from '@documenso/ui/primitives/input'; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from '@documenso/ui/primitives/select'; import type { Toast } from '@documenso/ui/primitives/use-toast'; import { useToast } from '@documenso/ui/primitives/use-toast'; @@ -53,26 +61,34 @@ export const TeamDeleteDialog = ({ const { toast } = useToast(); const { refreshSession } = useSession(); + const currentOrganisation = useCurrentOrganisation(); + const deleteMessage = _(msg`delete ${teamName}`); + const filteredTeams = currentOrganisation.teams.filter((team) => team.id !== teamId); + const ZDeleteTeamFormSchema = z.object({ teamName: z.literal(deleteMessage, { errorMap: () => ({ message: _(msg`You must enter '${deleteMessage}' to proceed`) }), }), + transferTeamId: z.string().optional(), }); const form = useForm({ resolver: zodResolver(ZDeleteTeamFormSchema), defaultValues: { teamName: '', + transferTeamId: undefined, }, }); const { mutateAsync: deleteTeam } = trpc.team.delete.useMutation(); - const onFormSubmit = async () => { + const onFormSubmit = async (data: z.infer) => { try { - await deleteTeam({ teamId }); + const transferTeamId = data.transferTeamId ? parseInt(data.transferTeamId, 10) : undefined; + + await deleteTeam({ teamId, transferTeamId: transferTeamId || undefined }); await refreshSession(); @@ -168,6 +184,43 @@ export const TeamDeleteDialog = ({ )} /> + {filteredTeams.length > 0 && ( + ( + + + Transfer documents to a different team + + + + + + + + )} + /> + )} +