import { useLimits } from '@documenso/ee/server-only/limits/provider/client'; import { useAnalytics } from '@documenso/lib/client-only/hooks/use-analytics'; import { useCurrentOrganisation } from '@documenso/lib/client-only/providers/organisation'; import { useSession } from '@documenso/lib/client-only/providers/session'; import { DEFAULT_DOCUMENT_TIME_ZONE, TIME_ZONES } from '@documenso/lib/constants/time-zones'; import { AppError } from '@documenso/lib/errors/app-error'; import { formatDocumentsPath, formatTemplatesPath } from '@documenso/lib/utils/teams'; import { trpc } from '@documenso/trpc/react'; import type { TCreateDocumentPayloadSchema } from '@documenso/trpc/server/document-router/create-document.types'; import type { TCreateTemplatePayloadSchema } from '@documenso/trpc/server/template-router/schema'; import { buildDropzoneRejectionDescription } from '@documenso/ui/lib/handle-dropzone-rejection'; import { cn } from '@documenso/ui/lib/utils'; import { DocumentUploadButton as DocumentUploadButtonPrimitive } from '@documenso/ui/primitives/document-upload-button'; import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@documenso/ui/primitives/tooltip'; import { useToast } from '@documenso/ui/primitives/use-toast'; import { msg } from '@lingui/core/macro'; import { useLingui } from '@lingui/react'; import { Trans } from '@lingui/react/macro'; import { EnvelopeType } from '@prisma/client'; import { useMemo, useState } from 'react'; import type { FileRejection } from 'react-dropzone'; import { useNavigate, useParams } from 'react-router'; import { useCurrentTeam } from '~/providers/team'; import { getUploadErrorMessage } from '~/utils/toast-error-messages'; export type DocumentUploadButtonLegacyProps = { className?: string; type: EnvelopeType; }; export const DocumentUploadButtonLegacy = ({ className, type }: DocumentUploadButtonLegacyProps) => { const { _ } = useLingui(); const { toast } = useToast(); const { user } = useSession(); const { folderId } = useParams(); const team = useCurrentTeam(); const navigate = useNavigate(); const analytics = useAnalytics(); const organisation = useCurrentOrganisation(); const userTimezone = TIME_ZONES.find((timezone) => timezone === Intl.DateTimeFormat().resolvedOptions().timeZone) ?? DEFAULT_DOCUMENT_TIME_ZONE; const { quota, remaining, refreshLimits } = useLimits(); const [isLoading, setIsLoading] = useState(false); const { mutateAsync: createDocument } = trpc.document.create.useMutation(); const { mutateAsync: createTemplate } = trpc.template.createTemplate.useMutation(); const disabledMessage = useMemo(() => { if (!user.emailVerified) { return msg`Verify your email to upload documents.`; } // No errors for templates. if (type === EnvelopeType.TEMPLATE) { return; } if (organisation.subscription && remaining.documents === 0) { return msg`Document upload disabled due to unpaid invoices`; } if (remaining.documents === 0) { return msg`You have reached your document limit.`; } // eslint-disable-next-line react-hooks/exhaustive-deps }, [remaining.documents, user.emailVerified, team, type]); const onFileDrop = async (file: File) => { try { setIsLoading(true); const payload = { title: file.name, folderId: folderId ?? undefined, meta: { timezone: userTimezone, }, } satisfies TCreateDocumentPayloadSchema | TCreateTemplatePayloadSchema; const formData = new FormData(); formData.append('payload', JSON.stringify(payload)); formData.append('file', file); // Handle legacy document creation. if (type === EnvelopeType.DOCUMENT) { const { envelopeId: id } = await createDocument(formData); void refreshLimits(); await navigate(`${formatDocumentsPath(team.url)}/${id}/edit`); toast({ title: _(msg`Document uploaded`), description: _(msg`Your document has been uploaded successfully.`), duration: 5000, }); analytics.capture('App: Document Uploaded', { userId: user.id, documentId: id, timestamp: new Date().toISOString(), }); } // Handle legacy template creation. if (type === EnvelopeType.TEMPLATE) { const { envelopeId: id } = await createTemplate(formData); await navigate(`${formatTemplatesPath(team.url)}/${id}/edit`); toast({ title: _(msg`Template document uploaded`), description: _( msg`Your document has been uploaded successfully. You will be redirected to the template page.`, ), duration: 5000, }); } } catch (err) { const error = AppError.parseError(err); console.error(err); const errorMessage = getUploadErrorMessage(error.code); toast({ title: _(errorMessage.title), description: _(errorMessage.description), variant: 'destructive', duration: 7500, }); } finally { setIsLoading(false); } }; const onFileDropRejected = (fileRejections: FileRejection[]) => { toast({ title: _(msg`Your document failed to upload.`), description: _(buildDropzoneRejectionDescription(fileRejections)), duration: 5000, variant: 'destructive', }); }; return (
onFileDrop(files[0])} onDropRejected={onFileDropRejected} type={type} internalVersion="1" />
{team?.id === undefined && type === EnvelopeType.DOCUMENT && remaining.documents > 0 && Number.isFinite(remaining.documents) && (

{remaining.documents} of {quota.documents} documents remaining this month.

)}
); };