onDocumentLoaded(d)}
externalLinkTarget="_blank"
@@ -74,9 +132,13 @@ export const PDFViewer = ({ className, document, ...props }: PDFViewerProps) =>
.map((_, i) => (
-
+
onDocumentPageClick(e, i + 1)}
+ />
))}
diff --git a/apps/web/src/components/forms/edit-document.tsx b/apps/web/src/components/forms/edit-document.tsx
new file mode 100644
index 000000000..d89892de4
--- /dev/null
+++ b/apps/web/src/components/forms/edit-document.tsx
@@ -0,0 +1,131 @@
+'use client';
+
+import { useState } from 'react';
+
+import dynamic from 'next/dynamic';
+
+import { zodResolver } from '@hookform/resolvers/zod';
+import { Loader } from 'lucide-react';
+import { useForm } from 'react-hook-form';
+
+import { Document, User } from '@documenso/prisma/client';
+import { cn } from '@documenso/ui/lib/utils';
+import { Button } from '@documenso/ui/primitives/button';
+import { Card, CardContent } from '@documenso/ui/primitives/card';
+
+import { AddFieldsFormPartial } from './edit-document/add-fields';
+import { AddSignersFormPartial } from './edit-document/add-signers';
+import { TEditDocumentFormSchema, ZEditDocumentFormSchema } from './edit-document/types';
+
+const PDFViewer = dynamic(async () => import('~/components/(dashboard)/pdf-viewer/pdf-viewer'), {
+ ssr: false,
+ loading: () => (
+
+
+
+
Loading document...
+
+ ),
+});
+
+const MAX_STEP = 2;
+
+export type EditDocumentFormProps = {
+ className?: string;
+ user: User;
+ document: Document;
+};
+
+export const EditDocumentForm = ({ className, document, user: _user }: EditDocumentFormProps) => {
+ const documentUrl = `data:application/pdf;base64,${document.document}`;
+
+ const [step, setStep] = useState(0);
+
+ const {
+ control,
+ // handleSubmit,
+ watch,
+ formState: { errors, isSubmitting, isValid },
+ } = useForm
({
+ mode: 'onBlur',
+ defaultValues: {
+ signers: [
+ {
+ name: '',
+ email: '',
+ },
+ ],
+ },
+ resolver: zodResolver(ZEditDocumentFormSchema),
+ });
+
+ const canGoBack = step > 0;
+ const canGoNext = isValid && step < MAX_STEP;
+
+ const onGoBackClick = () => setStep((prev) => Math.max(0, prev - 1));
+ const onGoNextClick = () => setStep((prev) => Math.min(MAX_STEP, prev + 1));
+
+ return (
+
+
+
+
+
+
+
+
+
+ {step === 0 && (
+
+ )}
+
+ {step === 1 && (
+
+ )}
+
+
+
+ Add Signers ({step + 1}/{MAX_STEP + 1})
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
diff --git a/apps/web/src/components/forms/edit-document/add-fields.tsx b/apps/web/src/components/forms/edit-document/add-fields.tsx
new file mode 100644
index 000000000..4a5e495f8
--- /dev/null
+++ b/apps/web/src/components/forms/edit-document/add-fields.tsx
@@ -0,0 +1,163 @@
+'use client';
+
+import { useState } from 'react';
+
+import { Caveat } from 'next/font/google';
+
+import { Check, ChevronsUpDown } from 'lucide-react';
+import { Control, FieldErrors, UseFormWatch } from 'react-hook-form';
+
+import { cn } from '@documenso/ui/lib/utils';
+import { Button } from '@documenso/ui/primitives/button';
+import { Card, CardContent } from '@documenso/ui/primitives/card';
+import {
+ Command,
+ CommandEmpty,
+ CommandGroup,
+ CommandInput,
+ CommandItem,
+} from '@documenso/ui/primitives/command';
+import { Popover, PopoverContent, PopoverTrigger } from '@documenso/ui/primitives/popover';
+
+import { TEditDocumentFormSchema } from './types';
+
+const fontCaveat = Caveat({
+ weight: ['500'],
+ subsets: ['latin'],
+ display: 'swap',
+ variable: '--font-caveat',
+});
+
+export type AddFieldsFormProps = {
+ className?: string;
+ control: Control;
+ watch: UseFormWatch;
+ errors: FieldErrors;
+ isSubmitting: boolean;
+};
+
+export const AddFieldsFormPartial = ({
+ className,
+ control: _control,
+ watch,
+ errors: _errors,
+ isSubmitting: _isSubmitting,
+}: AddFieldsFormProps) => {
+ const signers = watch('signers');
+
+ const [selectedSigner, setSelectedSigner] = useState(() => signers[0]);
+
+ return (
+
+
Edit Document
+
+
Add all relevant fields for each recipient.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {signers.map((signer, index) => (
+ setSelectedSigner(signer)}>
+
+ {signer.name && (
+
+ {signer.name} ({signer.email})
+
+ )}
+
+ {!signer.name && {signer.email}}
+
+ ))}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
diff --git a/apps/web/src/components/forms/edit-document/add-signers.tsx b/apps/web/src/components/forms/edit-document/add-signers.tsx
new file mode 100644
index 000000000..2f0f1c6ec
--- /dev/null
+++ b/apps/web/src/components/forms/edit-document/add-signers.tsx
@@ -0,0 +1,125 @@
+'use client';
+
+import { AnimatePresence, motion } from 'framer-motion';
+import { Plus, Trash } from 'lucide-react';
+import { Control, Controller, FieldErrors, useFieldArray } from 'react-hook-form';
+
+import { cn } from '@documenso/ui/lib/utils';
+import { Button } from '@documenso/ui/primitives/button';
+import { Input } from '@documenso/ui/primitives/input';
+import { Label } from '@documenso/ui/primitives/label';
+
+import { FormErrorMessage } from '~/components/form/form-error-message';
+
+import { TEditDocumentFormSchema } from './types';
+
+export type AddSignersFormProps = {
+ className?: string;
+ control: Control;
+ errors: FieldErrors;
+ isSubmitting: boolean;
+};
+
+export const AddSignersFormPartial = ({
+ className,
+ control,
+ errors,
+ isSubmitting,
+}: AddSignersFormProps) => {
+ const {
+ append,
+ fields: signers,
+ remove,
+ } = useFieldArray({
+ control,
+ name: 'signers',
+ });
+
+ return (
+
+
Add Signers
+
+
Add the people who will sign the document.
+
+
+
+
+
+
+ {signers.map((field, index) => (
+
+
+
+
+ (
+
+ )}
+ />
+
+
+
+
+
+ (
+
+ )}
+ />
+
+
+
+
+
+
+
+
+
+
+
+ ))}
+
+
+
+
+
+
+
+
+ );
+};
diff --git a/apps/web/src/components/forms/edit-document/types.ts b/apps/web/src/components/forms/edit-document/types.ts
new file mode 100644
index 000000000..7ca551f48
--- /dev/null
+++ b/apps/web/src/components/forms/edit-document/types.ts
@@ -0,0 +1,13 @@
+import { z } from 'zod';
+
+export const ZEditDocumentFormSchema = z.object({
+ signers: z.array(
+ z.object({
+ id: z.number().optional(),
+ email: z.string().min(1).email(),
+ name: z.string(),
+ }),
+ ),
+});
+
+export type TEditDocumentFormSchema = z.infer;