import { useState } from 'react'; import { msg } from '@lingui/core/macro'; import { useLingui } from '@lingui/react'; import { Trans } from '@lingui/react/macro'; import { Cloud, FileText, Loader, X } from 'lucide-react'; import { useDropzone } from 'react-dropzone'; import { useFormContext } from 'react-hook-form'; import { APP_DOCUMENT_UPLOAD_SIZE_LIMIT } from '@documenso/lib/constants/app'; import { cn } from '@documenso/ui/lib/utils'; import { Button } from '@documenso/ui/primitives/button'; import { FormControl, FormField, FormItem, FormLabel, FormMessage, } from '@documenso/ui/primitives/form/form'; import { useToast } from '@documenso/ui/primitives/use-toast'; import { useConfigureDocument } from './configure-document-context'; import type { TConfigureEmbedFormSchema } from './configure-document-view.types'; export interface ConfigureDocumentUploadProps { isSubmitting?: boolean; } export const ConfigureDocumentUpload = ({ isSubmitting = false }: ConfigureDocumentUploadProps) => { const { _ } = useLingui(); const { toast } = useToast(); const { isPersisted } = useConfigureDocument(); const form = useFormContext(); const [isLoading, setIsLoading] = useState(false); // Watch the documentData field from the form const documentData = form.watch('documentData'); const onFileDrop = async (acceptedFiles: File[]) => { try { const file = acceptedFiles[0]; if (!file) { return; } setIsLoading(true); // Convert file to UInt8Array const arrayBuffer = await file.arrayBuffer(); const uint8Array = new Uint8Array(arrayBuffer); // Store file metadata and UInt8Array in form data form.setValue('documentData', { name: file.name, type: file.type, size: file.size, data: uint8Array, // Store as UInt8Array }); // Auto-populate title if it's empty const currentTitle = form.getValues('title'); if (!currentTitle) { // Get filename without extension const fileNameWithoutExtension = file.name.replace(/\.[^/.]+$/, ''); form.setValue('title', fileNameWithoutExtension); } } catch (error) { console.error('Error uploading file', error); toast({ title: _(msg`Error uploading file`), description: _(msg`There was an error uploading your file. Please try again.`), variant: 'destructive', duration: 5000, }); } finally { setIsLoading(false); } }; const onDropRejected = () => { toast({ title: _(msg`Your document failed to upload.`), description: _(msg`File cannot be larger than ${APP_DOCUMENT_UPLOAD_SIZE_LIMIT}MB`), duration: 5000, variant: 'destructive', }); }; const onRemoveFile = () => { if (isPersisted) { toast({ title: _(msg`Cannot remove document`), description: _(msg`The document is already saved and cannot be changed.`), duration: 5000, variant: 'destructive', }); return; } form.unregister('documentData'); }; const formatFileSize = (bytes: number) => { if (bytes === 0) return '0 Bytes'; const sizes = ['Bytes', 'KB', 'MB', 'GB']; const i = Math.floor(Math.log(bytes) / Math.log(1024)); return `${parseFloat((bytes / Math.pow(1024, i)).toFixed(2))} ${sizes[i]}`; }; const { getRootProps, getInputProps, isDragActive } = useDropzone({ accept: { 'application/pdf': ['.pdf'], }, maxSize: APP_DOCUMENT_UPLOAD_SIZE_LIMIT * 1024 * 1024, multiple: false, disabled: isSubmitting || isLoading || isPersisted, onDrop: (files) => { void onFileDrop(files); }, onDropRejected, }); return (
( Upload Document
{!documentData ? (

{isDragActive ? ( Drop your document here ) : isPersisted ? ( Document is already uploaded ) : ( Drag and drop or click to upload )}

{isPersisted ? ( This document cannot be changed ) : ( .PDF documents accepted (max {APP_DOCUMENT_UPLOAD_SIZE_LIMIT}MB) )}

{isLoading && (
)}
) : (
{documentData.name}
{formatFileSize(documentData.size)}
{!isPersisted && ( )}
)}
)} />
); };