mirror of
https://github.com/documenso/documenso.git
synced 2025-11-23 21:21:37 +10:00
feat: universal upload
Implementation of a universal upload allowing for multiple storage backends starting with `database` and `s3`. Allows clients to put and retrieve files from either client or server using a blend of client and server actions.
This commit is contained in:
@ -32,6 +32,7 @@ export type EditDocumentFormProps = {
|
||||
document: DocumentWithData;
|
||||
recipients: Recipient[];
|
||||
fields: Field[];
|
||||
dataUrl: string;
|
||||
};
|
||||
|
||||
type EditDocumentStep = 'signers' | 'fields' | 'subject';
|
||||
@ -42,16 +43,13 @@ export const EditDocumentForm = ({
|
||||
recipients,
|
||||
fields,
|
||||
user: _user,
|
||||
dataUrl,
|
||||
}: EditDocumentFormProps) => {
|
||||
const { toast } = useToast();
|
||||
const router = useRouter();
|
||||
|
||||
const { documentData } = document;
|
||||
|
||||
const [step, setStep] = useState<EditDocumentStep>('signers');
|
||||
|
||||
const documentUrl = `data:application/pdf;base64,${documentData?.data}`;
|
||||
|
||||
const documentFlow: Record<EditDocumentStep, DocumentFlowStep> = {
|
||||
signers: {
|
||||
title: 'Add Signers',
|
||||
@ -154,11 +152,11 @@ export const EditDocumentForm = ({
|
||||
return (
|
||||
<div className={cn('grid w-full grid-cols-12 gap-8', className)}>
|
||||
<Card
|
||||
className="col-span-12 rounded-xl before:rounded-xl lg:col-span-6 xl:col-span-7"
|
||||
className="relative col-span-12 rounded-xl before:rounded-xl lg:col-span-6 xl:col-span-7"
|
||||
gradient
|
||||
>
|
||||
<CardContent className="p-2">
|
||||
<LazyPDFViewer document={documentUrl} />
|
||||
<LazyPDFViewer document={dataUrl} />
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
|
||||
@ -1,20 +0,0 @@
|
||||
'use client';
|
||||
|
||||
import { Card, CardContent } from '@documenso/ui/primitives/card';
|
||||
import { LazyPDFViewer } from '@documenso/ui/primitives/lazy-pdf-viewer';
|
||||
import { PDFViewerProps } from '@documenso/ui/primitives/pdf-viewer';
|
||||
|
||||
export type LoadablePDFCard = PDFViewerProps & {
|
||||
className?: string;
|
||||
pdfClassName?: string;
|
||||
};
|
||||
|
||||
export const LoadablePDFCard = ({ className, pdfClassName, ...props }: LoadablePDFCard) => {
|
||||
return (
|
||||
<Card className={className} gradient {...props}>
|
||||
<CardContent className="p-2">
|
||||
<LazyPDFViewer className={pdfClassName} {...props} />
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
@ -7,6 +7,7 @@ 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';
|
||||
|
||||
@ -42,6 +43,12 @@ 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}`);
|
||||
|
||||
console.log({ documentDataUrl: documentDataUrl.slice(0, 40) });
|
||||
|
||||
const [recipients, fields] = await Promise.all([
|
||||
await getRecipientsForDocument({
|
||||
documentId,
|
||||
@ -88,12 +95,13 @@ export default async function DocumentPage({ params }: DocumentPageProps) {
|
||||
user={session}
|
||||
recipients={recipients}
|
||||
fields={fields}
|
||||
dataUrl={documentDataUrl}
|
||||
/>
|
||||
)}
|
||||
|
||||
{document.status === InternalDocumentStatus.COMPLETED && (
|
||||
<div className="mx-auto mt-12 max-w-2xl">
|
||||
<LazyPDFViewer document={`data:application/pdf;base64,${documentData.data}`} />
|
||||
<LazyPDFViewer document={documentDataUrl} />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@ -1,29 +1,45 @@
|
||||
'use client';
|
||||
|
||||
import { useState } from 'react';
|
||||
|
||||
import { useRouter } from 'next/navigation';
|
||||
|
||||
import { Loader } from 'lucide-react';
|
||||
|
||||
import { createDocumentData } from '@documenso/lib/server-only/document-data/create-document-data';
|
||||
import { putFile } from '@documenso/lib/universal/upload/put-file';
|
||||
import { trpc } from '@documenso/trpc/react';
|
||||
import { cn } from '@documenso/ui/lib/utils';
|
||||
import { DocumentDropzone } from '@documenso/ui/primitives/document-dropzone';
|
||||
import { useToast } from '@documenso/ui/primitives/use-toast';
|
||||
|
||||
import { useCreateDocument } from '~/api/document/create/fetcher';
|
||||
|
||||
export type UploadDocumentProps = {
|
||||
className?: string;
|
||||
};
|
||||
|
||||
export const UploadDocument = ({ className }: UploadDocumentProps) => {
|
||||
const { toast } = useToast();
|
||||
const router = useRouter();
|
||||
|
||||
const { isLoading, mutateAsync: createDocument } = useCreateDocument();
|
||||
const { toast } = useToast();
|
||||
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
||||
const { mutateAsync: createDocument } = trpc.document.createDocument.useMutation();
|
||||
|
||||
const onFileDrop = async (file: File) => {
|
||||
try {
|
||||
setIsLoading(true);
|
||||
|
||||
const { type, data } = await putFile(file);
|
||||
|
||||
const { id: documentDataId } = await createDocumentData({
|
||||
type,
|
||||
data,
|
||||
});
|
||||
|
||||
const { id } = await createDocument({
|
||||
file: file,
|
||||
title: file.name,
|
||||
documentDataId,
|
||||
});
|
||||
|
||||
toast({
|
||||
@ -41,6 +57,8 @@ export const UploadDocument = ({ className }: UploadDocumentProps) => {
|
||||
description: 'An error occurred while uploading your document.',
|
||||
variant: 'destructive',
|
||||
});
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user