diff --git a/apps/marketing/src/app/(marketing)/singleplayer/client.tsx b/apps/marketing/src/app/(marketing)/singleplayer/client.tsx
index 4780200c0..747b77a15 100644
--- a/apps/marketing/src/app/(marketing)/singleplayer/client.tsx
+++ b/apps/marketing/src/app/(marketing)/singleplayer/client.tsx
@@ -8,7 +8,7 @@ import { useRouter } from 'next/navigation';
import { useAnalytics } from '@documenso/lib/client-only/hooks/use-analytics';
import { base64 } from '@documenso/lib/universal/base64';
import { putFile } from '@documenso/lib/universal/upload/put-file';
-import { Field, Prisma, Recipient } from '@documenso/prisma/client';
+import { DocumentDataType, Field, Prisma, Recipient } from '@documenso/prisma/client';
import { Card, CardContent } from '@documenso/ui/primitives/card';
import { DocumentDropzone } from '@documenso/ui/primitives/document-dropzone';
import { AddFieldsFormPartial } from '@documenso/ui/primitives/document-flow/add-fields';
@@ -199,7 +199,14 @@ export const SinglePlayerClient = () => {
{uploadedFile ? (
-
+
) : (
diff --git a/apps/web/src/app/(dashboard)/documents/[id]/edit-document.tsx b/apps/web/src/app/(dashboard)/documents/[id]/edit-document.tsx
index 7c30dc411..7684c9b64 100644
--- a/apps/web/src/app/(dashboard)/documents/[id]/edit-document.tsx
+++ b/apps/web/src/app/(dashboard)/documents/[id]/edit-document.tsx
@@ -4,7 +4,7 @@ import { useState } from 'react';
import { useRouter } from 'next/navigation';
-import { Field, Recipient, User } from '@documenso/prisma/client';
+import { DocumentData, Field, Recipient, User } from '@documenso/prisma/client';
import { DocumentWithData } from '@documenso/prisma/types/document-with-data';
import { cn } from '@documenso/ui/lib/utils';
import { Card, CardContent } from '@documenso/ui/primitives/card';
@@ -32,7 +32,7 @@ export type EditDocumentFormProps = {
document: DocumentWithData;
recipients: Recipient[];
fields: Field[];
- dataUrl: string;
+ documentData: DocumentData;
};
type EditDocumentStep = 'signers' | 'fields' | 'subject';
@@ -43,7 +43,7 @@ export const EditDocumentForm = ({
recipients,
fields,
user: _user,
- dataUrl,
+ documentData,
}: EditDocumentFormProps) => {
const { toast } = useToast();
const router = useRouter();
@@ -153,7 +153,7 @@ export const EditDocumentForm = ({
gradient
>
-
+
diff --git a/apps/web/src/app/(dashboard)/documents/[id]/page.tsx b/apps/web/src/app/(dashboard)/documents/[id]/page.tsx
index d44ac2800..85e30012c 100644
--- a/apps/web/src/app/(dashboard)/documents/[id]/page.tsx
+++ b/apps/web/src/app/(dashboard)/documents/[id]/page.tsx
@@ -7,7 +7,6 @@ import { getRequiredServerComponentSession } from '@documenso/lib/next-auth/get-
import { getDocumentById } from '@documenso/lib/server-only/document/get-document-by-id';
import { getFieldsForDocument } from '@documenso/lib/server-only/field/get-fields-for-document';
import { getRecipientsForDocument } from '@documenso/lib/server-only/recipient/get-recipients-for-document';
-import { getFile } from '@documenso/lib/universal/upload/get-file';
import { DocumentStatus as InternalDocumentStatus } from '@documenso/prisma/client';
import { LazyPDFViewer } from '@documenso/ui/primitives/lazy-pdf-viewer';
@@ -43,10 +42,6 @@ export default async function DocumentPage({ params }: DocumentPageProps) {
const { documentData } = document;
- const documentDataUrl = await getFile(documentData)
- .then((buffer) => Buffer.from(buffer).toString('base64'))
- .then((data) => `data:application/pdf;base64,${data}`);
-
const [recipients, fields] = await Promise.all([
await getRecipientsForDocument({
documentId,
@@ -90,13 +85,13 @@ export default async function DocumentPage({ params }: DocumentPageProps) {
user={user}
recipients={recipients}
fields={fields}
- dataUrl={documentDataUrl}
+ documentData={documentData}
/>
)}
{document.status === InternalDocumentStatus.COMPLETED && (
-
+
)}
diff --git a/apps/web/src/app/(signing)/sign/[token]/page.tsx b/apps/web/src/app/(signing)/sign/[token]/page.tsx
index 40a650afd..3841a2da6 100644
--- a/apps/web/src/app/(signing)/sign/[token]/page.tsx
+++ b/apps/web/src/app/(signing)/sign/[token]/page.tsx
@@ -8,7 +8,6 @@ import { getDocumentAndSenderByToken } from '@documenso/lib/server-only/document
import { viewedDocument } from '@documenso/lib/server-only/document/viewed-document';
import { getFieldsForToken } from '@documenso/lib/server-only/field/get-fields-for-token';
import { getRecipientByToken } from '@documenso/lib/server-only/recipient/get-recipient-by-token';
-import { getFile } from '@documenso/lib/universal/upload/get-file';
import { DocumentStatus, FieldType, SigningStatus } from '@documenso/prisma/client';
import { Card, CardContent } from '@documenso/ui/primitives/card';
import { ElementVisible } from '@documenso/ui/primitives/element-visible';
@@ -47,10 +46,6 @@ export default async function SigningPage({ params: { token } }: SigningPageProp
const { documentData } = document;
- const documentDataUrl = await getFile(documentData)
- .then((buffer) => Buffer.from(buffer).toString('base64'))
- .then((data) => `data:application/pdf;base64,${data}`);
-
const { user } = await getServerComponentSession();
if (
@@ -79,7 +74,7 @@ export default async function SigningPage({ params: { token } }: SigningPageProp
gradient
>
-
+
diff --git a/packages/ui/components/document/document-dialog.tsx b/packages/ui/components/document/document-dialog.tsx
index b76d54eeb..e90147806 100644
--- a/packages/ui/components/document/document-dialog.tsx
+++ b/packages/ui/components/document/document-dialog.tsx
@@ -5,8 +5,9 @@ import { useState } from 'react';
import * as DialogPrimitive from '@radix-ui/react-dialog';
import { X } from 'lucide-react';
-import { cn } from '@documenso/ui/lib/utils';
+import { DocumentDataType } from '@documenso/prisma/client';
+import { cn } from '../../lib/utils';
import { Dialog, DialogOverlay, DialogPortal } from '../../primitives/dialog';
import { LazyPDFViewerNoLoader } from '../../primitives/lazy-pdf-viewer';
@@ -40,7 +41,12 @@ export default function DocumentDialog({ document, ...props }: DocumentDialogPro
>
e.stopPropagation()}
onDocumentLoad={onDocumentLoad}
/>
diff --git a/packages/ui/primitives/pdf-viewer.tsx b/packages/ui/primitives/pdf-viewer.tsx
index 008e81f82..fb7b0d51a 100644
--- a/packages/ui/primitives/pdf-viewer.tsx
+++ b/packages/ui/primitives/pdf-viewer.tsx
@@ -9,8 +9,12 @@ import 'react-pdf/dist/esm/Page/AnnotationLayer.css';
import 'react-pdf/dist/esm/Page/TextLayer.css';
import { PDF_VIEWER_PAGE_SELECTOR } from '@documenso/lib/constants/pdf-viewer';
+import { getFile } from '@documenso/lib/universal/upload/get-file';
+import { DocumentData } from '@documenso/prisma/client';
import { cn } from '@documenso/ui/lib/utils';
+import { useToast } from './use-toast';
+
export type LoadedPDFDocument = PDFDocumentProxy;
/**
@@ -28,9 +32,17 @@ export type OnPDFViewerPageClick = (_event: {
pageY: number;
}) => void | Promise;
+const PDFLoader = () => (
+ <>
+
+
+ Loading document...
+ >
+);
+
export type PDFViewerProps = {
className?: string;
- document: string;
+ documentData: DocumentData;
onDocumentLoad?: (_doc: LoadedPDFDocument) => void;
onPageClick?: OnPDFViewerPageClick;
[key: string]: unknown;
@@ -38,13 +50,18 @@ export type PDFViewerProps = {
export const PDFViewer = ({
className,
- document,
+ documentData,
onDocumentLoad,
onPageClick,
...props
}: PDFViewerProps) => {
+ const { toast } = useToast();
+
const $el = useRef(null);
+ const [isDocumentBytesLoading, setIsDocumentBytesLoading] = useState(false);
+ const [documentBytes, setDocumentBytes] = useState(null);
+
const [width, setWidth] = useState(0);
const [numPages, setNumPages] = useState(0);
const [pdfError, setPdfError] = useState(false);
@@ -110,63 +127,89 @@ export const PDFViewer = ({
}
}, []);
+ useEffect(() => {
+ const fetchDocumentBytes = async () => {
+ try {
+ setIsDocumentBytesLoading(true);
+
+ const bytes = await getFile(documentData);
+
+ setDocumentBytes(bytes);
+
+ setIsDocumentBytesLoading(false);
+ } catch (err) {
+ console.error(err);
+
+ toast({
+ title: 'Error',
+ description: 'An error occurred while loading the document.',
+ variant: 'destructive',
+ });
+ }
+ };
+
+ void fetchDocumentBytes();
+ }, [documentData, toast]);
+
return (
-
onDocumentLoaded(d)}
- // Uploading a invalid document causes an error which doesn't appear to be handled by the `error` prop.
- // Therefore we add some additional custom error handling.
- onSourceError={() => {
- setPdfError(true);
- }}
- externalLinkTarget="_blank"
- loading={
-
- {pdfError ? (
+ {isDocumentBytesLoading ? (
+
+ ) : (
+
onDocumentLoaded(d)}
+ // Uploading a invalid document causes an error which doesn't appear to be handled by the `error` prop.
+ // Therefore we add some additional custom error handling.
+ onSourceError={() => {
+ setPdfError(true);
+ }}
+ externalLinkTarget="_blank"
+ loading={
+
+ {pdfError ? (
+
+
Something went wrong while loading the document.
+
Please try again or contact our support.
+
+ ) : (
+
+ )}
+
+ }
+ error={
+
Something went wrong while loading the document.
Please try again or contact our support.
- ) : (
- <>
-
-
-
Loading document...
- >
- )}
-
- }
- error={
-
-
-
Something went wrong while loading the document.
-
Please try again or contact our support.
-
- }
- >
- {Array(numPages)
- .fill(null)
- .map((_, i) => (
-
-
''}
- onClick={(e) => onDocumentPageClick(e, i + 1)}
- />
-
- ))}
-
+ }
+ >
+ {Array(numPages)
+ .fill(null)
+ .map((_, i) => (
+
+
''}
+ onClick={(e) => onDocumentPageClick(e, i + 1)}
+ />
+
+ ))}
+
+ )}
);
};