import { AppError, AppErrorCode } from '@documenso/lib/errors/app-error'; import { trpc } from '@documenso/trpc/react'; import { Button } from '@documenso/ui/primitives/button'; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from '@documenso/ui/primitives/dialog'; import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from '@documenso/ui/primitives/form/form'; import { Input } from '@documenso/ui/primitives/input'; import { useToast } from '@documenso/ui/primitives/use-toast'; import { zodResolver } from '@hookform/resolvers/zod'; import { Plural, Trans, useLingui } from '@lingui/react/macro'; import { EnvelopeType } from '@prisma/client'; import type * as DialogPrimitive from '@radix-ui/react-dialog'; import { FolderIcon, HomeIcon, Loader2, Search } from 'lucide-react'; import { useEffect, useState } from 'react'; import { useForm } from 'react-hook-form'; import { match } from 'ts-pattern'; import { z } from 'zod'; export type EnvelopesBulkMoveDialogProps = { envelopeIds: string[]; envelopeType: EnvelopeType; open: boolean; onOpenChange: (open: boolean) => void; currentFolderId?: string; onSuccess?: () => void; } & Omit; const ZBulkMoveFormSchema = z.object({ folderId: z.string().nullable(), }); type TBulkMoveFormSchema = z.infer; export const EnvelopesBulkMoveDialog = ({ envelopeIds, envelopeType, open, onOpenChange, currentFolderId, onSuccess, ...props }: EnvelopesBulkMoveDialogProps) => { const { t } = useLingui(); const { toast } = useToast(); const [searchTerm, setSearchTerm] = useState(''); const form = useForm({ resolver: zodResolver(ZBulkMoveFormSchema), defaultValues: { folderId: currentFolderId ?? null, }, }); const isDocument = envelopeType === EnvelopeType.DOCUMENT; const { data: folders, isLoading: isFoldersLoading } = trpc.folder.findFoldersInternal.useQuery( { parentId: currentFolderId, type: envelopeType, }, { enabled: open, }, ); const { mutateAsync: bulkMoveEnvelopes } = trpc.envelope.bulk.move.useMutation(); const trpcUtils = trpc.useUtils(); useEffect(() => { if (open) { setSearchTerm(''); form.reset({ folderId: currentFolderId, }); } }, [open, currentFolderId]); const onSubmit = async (data: TBulkMoveFormSchema) => { try { await bulkMoveEnvelopes({ envelopeIds, folderId: data.folderId, envelopeType, }); // Invalidate the appropriate query based on envelope type. if (isDocument) { await trpcUtils.document.findDocumentsInternal.invalidate(); } else { await trpcUtils.template.findTemplates.invalidate(); } toast({ description: t`Selected items have been moved.`, }); onSuccess?.(); onOpenChange(false); } catch (err) { const error = AppError.parseError(err); const errorMessage = match(error.code) .with(AppErrorCode.NOT_FOUND, () => t`The folder you are trying to move the items to does not exist.`) .with(AppErrorCode.UNAUTHORIZED, () => t`You are not allowed to move these items.`) .with(AppErrorCode.INVALID_BODY, () => t`All items must be of the same type.`) .otherwise(() => t`An error occurred while moving the items.`); toast({ description: errorMessage, variant: 'destructive', }); } }; const filteredFolders = folders?.data.filter((folder) => folder.name.toLowerCase().includes(searchTerm.toLowerCase()), ); return ( {isDocument ? Move Documents to Folder : Move Templates to Folder} {isDocument ? ( ) : ( )}
setSearchTerm(e.target.value)} className="pl-8" />
( Folder
{isFoldersLoading ? (
) : ( <> {filteredFolders?.map((folder) => ( ))} {searchTerm && filteredFolders?.length === 0 && (
No folders found
)} )}
)} />
); };