diff --git a/apps/web/src/app/(dashboard)/documents/data-table-action-button.tsx b/apps/web/src/app/(dashboard)/documents/data-table-action-button.tsx index 54a8f6184..51f3f7c58 100644 --- a/apps/web/src/app/(dashboard)/documents/data-table-action-button.tsx +++ b/apps/web/src/app/(dashboard)/documents/data-table-action-button.tsx @@ -6,13 +6,12 @@ import { Download, Edit, Pencil } from 'lucide-react'; import { useSession } from 'next-auth/react'; import { match } from 'ts-pattern'; -import { getFile } from '@documenso/lib/universal/upload/get-file'; +import { downloadFile } from '@documenso/lib/client-only/download-pdf'; import type { Document, Recipient, User } from '@documenso/prisma/client'; import { DocumentStatus, SigningStatus } from '@documenso/prisma/client'; import type { DocumentWithData } from '@documenso/prisma/types/document-with-data'; import { trpc as trpcClient } from '@documenso/trpc/client'; import { Button } from '@documenso/ui/primitives/button'; -import { useToast } from '@documenso/ui/primitives/use-toast'; export type DataTableActionButtonProps = { row: Document & { @@ -23,7 +22,6 @@ export type DataTableActionButtonProps = { export const DataTableActionButton = ({ row }: DataTableActionButtonProps) => { const { data: session } = useSession(); - const { toast } = useToast(); if (!session) { return null; @@ -39,47 +37,25 @@ export const DataTableActionButton = ({ row }: DataTableActionButtonProps) => { const isSigned = recipient?.signingStatus === SigningStatus.SIGNED; const onDownloadClick = async () => { - try { - let document: DocumentWithData | null = null; + let document: DocumentWithData | null = null; - if (!recipient) { - document = await trpcClient.document.getDocumentById.query({ - id: row.id, - }); - } else { - document = await trpcClient.document.getDocumentByToken.query({ - token: recipient.token, - }); - } - - const documentData = document?.documentData; - - if (!documentData) { - return; - } - - const documentBytes = await getFile(documentData); - - const blob = new Blob([documentBytes], { - type: 'application/pdf', + if (!recipient) { + document = await trpcClient.document.getDocumentById.query({ + id: row.id, }); - - const link = window.document.createElement('a'); - const baseTitle = row.title.includes('.pdf') ? row.title.split('.pdf')[0] : row.title; - - link.href = window.URL.createObjectURL(blob); - link.download = baseTitle ? `${baseTitle}_signed.pdf` : 'document.pdf'; - - link.click(); - - window.URL.revokeObjectURL(link.href); - } catch (error) { - toast({ - title: 'Something went wrong', - description: 'An error occurred while trying to download file.', - variant: 'destructive', + } else { + document = await trpcClient.document.getDocumentByToken.query({ + token: recipient.token, }); } + + const documentData = document?.documentData; + + if (!documentData) { + return; + } + + await downloadFile({ documentData, fileName: row.title }); }; return match({ diff --git a/apps/web/src/app/(dashboard)/documents/data-table-action-dropdown.tsx b/apps/web/src/app/(dashboard)/documents/data-table-action-dropdown.tsx index 9c3532f88..e9a713d62 100644 --- a/apps/web/src/app/(dashboard)/documents/data-table-action-dropdown.tsx +++ b/apps/web/src/app/(dashboard)/documents/data-table-action-dropdown.tsx @@ -17,7 +17,7 @@ import { } from 'lucide-react'; import { useSession } from 'next-auth/react'; -import { getFile } from '@documenso/lib/universal/upload/get-file'; +import { downloadFile } from '@documenso/lib/client-only/download-pdf'; import type { Document, Recipient, User } from '@documenso/prisma/client'; import { DocumentStatus } from '@documenso/prisma/client'; import type { DocumentWithData } from '@documenso/prisma/types/document-with-data'; @@ -81,21 +81,7 @@ export const DataTableActionDropdown = ({ row }: DataTableActionDropdownProps) = return; } - const documentBytes = await getFile(documentData); - - const blob = new Blob([documentBytes], { - type: 'application/pdf', - }); - - const link = window.document.createElement('a'); - const baseTitle = row.title.includes('.pdf') ? row.title.split('.pdf')[0] : row.title; - - link.href = window.URL.createObjectURL(blob); - link.download = baseTitle ? `${baseTitle}_signed.pdf` : 'document.pdf'; - - link.click(); - - window.URL.revokeObjectURL(link.href); + await downloadFile({ documentData, fileName: row.title }); }; const nonSignedRecipients = row.Recipient.filter((item) => item.signingStatus !== 'SIGNED'); diff --git a/packages/lib/client-only/download-pdf.ts b/packages/lib/client-only/download-pdf.ts new file mode 100644 index 000000000..af304f983 --- /dev/null +++ b/packages/lib/client-only/download-pdf.ts @@ -0,0 +1,37 @@ +import type { DocumentData } from '@documenso/prisma/client'; +import { toast } from '@documenso/ui/primitives/use-toast'; + +import { getFile } from '../universal/upload/get-file'; + +type DownloadPDFProps = { + documentData: DocumentData; + fileName?: string; +}; + +export const downloadFile = async ({ documentData, fileName }: DownloadPDFProps) => { + try { + const bytes = await getFile(documentData); + + const blob = new Blob([bytes], { + type: 'application/pdf', + }); + + const link = window.document.createElement('a'); + const baseTitle = fileName?.includes('.pdf') ? fileName.split('.pdf')[0] : fileName; + + link.href = window.URL.createObjectURL(blob); + link.download = baseTitle ? `${baseTitle}_signed.pdf` : 'document.pdf'; + + link.click(); + + window.URL.revokeObjectURL(link.href); + } catch (err) { + console.error(err); + + toast({ + title: 'Something went wrong', + description: 'An error occurred while downloading your document.', + variant: 'destructive', + }); + } +}; diff --git a/packages/prisma/types/document-with-data.ts b/packages/prisma/types/document-with-data.ts index d8dd8a888..461d13e6c 100644 --- a/packages/prisma/types/document-with-data.ts +++ b/packages/prisma/types/document-with-data.ts @@ -1,4 +1,4 @@ -import { Document, DocumentData, DocumentMeta } from '@documenso/prisma/client'; +import type { Document, DocumentData, DocumentMeta } from '@documenso/prisma/client'; export type DocumentWithData = Document & { documentData?: DocumentData | null; diff --git a/packages/ui/components/document/document-download-button.tsx b/packages/ui/components/document/document-download-button.tsx index a2a35e490..9471611ff 100644 --- a/packages/ui/components/document/document-download-button.tsx +++ b/packages/ui/components/document/document-download-button.tsx @@ -5,11 +5,10 @@ import { useState } from 'react'; import { Download } from 'lucide-react'; -import { getFile } from '@documenso/lib/universal/upload/get-file'; +import { downloadFile } from '@documenso/lib/client-only/download-pdf'; import type { DocumentData } from '@documenso/prisma/client'; import { Button } from '../../primitives/button'; -import { useToast } from '../../primitives/use-toast'; export type DownloadButtonProps = HTMLAttributes & { disabled?: boolean; @@ -24,44 +23,18 @@ export const DocumentDownloadButton = ({ disabled, ...props }: DownloadButtonProps) => { - const { toast } = useToast(); - const [isLoading, setIsLoading] = useState(false); const onDownloadClick = async () => { - try { - setIsLoading(true); + setIsLoading(true); - if (!documentData) { - return; - } - - const bytes = await getFile(documentData); - - const blob = new Blob([bytes], { - type: 'application/pdf', - }); - - const link = window.document.createElement('a'); - const baseTitle = fileName?.includes('.pdf') ? fileName.split('.pdf')[0] : fileName; - - link.href = window.URL.createObjectURL(blob); - link.download = baseTitle ? `${baseTitle}_signed.pdf` : 'document.pdf'; - - link.click(); - - window.URL.revokeObjectURL(link.href); - } catch (err) { - console.error(err); - - toast({ - title: 'Error', - description: 'An error occurred while downloading your document.', - variant: 'destructive', - }); - } finally { - setIsLoading(false); + if (!documentData) { + return; } + + await downloadFile({ documentData, fileName }).then(() => { + setIsLoading(false); + }); }; return ( diff --git a/packages/ui/primitives/use-toast.ts b/packages/ui/primitives/use-toast.ts index 6524baf30..27f96aa29 100644 --- a/packages/ui/primitives/use-toast.ts +++ b/packages/ui/primitives/use-toast.ts @@ -1,7 +1,8 @@ // Inspired by react-hot-toast library import * as React from 'react'; -import { ToastActionElement, type ToastProps } from './toast'; +import type { ToastActionElement } from './toast'; +import { type ToastProps } from './toast'; const TOAST_LIMIT = 1; const TOAST_REMOVE_DELAY = 1000000;