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 027d845b2..484d5d31d 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 { DocumentData, Field, Recipient, User } from '@documenso/prisma/client'; +import { DocumentData, DocumentStatus, 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'; @@ -14,6 +14,8 @@ import { AddSignersFormPartial } from '@documenso/ui/primitives/document-flow/ad import { TAddSignersFormSchema } from '@documenso/ui/primitives/document-flow/add-signers.types'; import { AddSubjectFormPartial } from '@documenso/ui/primitives/document-flow/add-subject'; import { TAddSubjectFormSchema } from '@documenso/ui/primitives/document-flow/add-subject.types'; +import { AddTitleFormPartial } from '@documenso/ui/primitives/document-flow/add-title'; +import { TAddTitleFormSchema } from '@documenso/ui/primitives/document-flow/add-title.types'; import { DocumentFlowFormContainer, DocumentFlowFormContainerHeader, @@ -25,6 +27,7 @@ import { useToast } from '@documenso/ui/primitives/use-toast'; import { addFields } from '~/components/forms/edit-document/add-fields.action'; import { addSigners } from '~/components/forms/edit-document/add-signers.action'; import { completeDocument } from '~/components/forms/edit-document/add-subject.action'; +import { addTitle } from '~/components/forms/edit-document/add-title.action'; export type EditDocumentFormProps = { className?: string; @@ -35,7 +38,7 @@ export type EditDocumentFormProps = { documentData: DocumentData; }; -type EditDocumentStep = 'signers' | 'fields' | 'subject'; +type EditDocumentStep = 'title' | 'signers' | 'fields' | 'subject'; export const EditDocumentForm = ({ className, @@ -48,30 +51,60 @@ export const EditDocumentForm = ({ const { toast } = useToast(); const router = useRouter(); - const [step, setStep] = useState('signers'); + const [step, setStep] = useState( + document.status === DocumentStatus.DRAFT ? 'title' : 'signers', + ); const documentFlow: Record = { + title: { + title: 'Add Title', + description: 'Add the title to the document.', + stepIndex: 1, + }, signers: { title: 'Add Signers', description: 'Add the people who will sign the document.', - stepIndex: 1, + stepIndex: 2, + onBackStep: () => document.status === DocumentStatus.DRAFT && setStep('title'), }, fields: { title: 'Add Fields', description: 'Add all relevant fields for each recipient.', - stepIndex: 2, + stepIndex: 3, onBackStep: () => setStep('signers'), }, subject: { title: 'Add Subject', description: 'Add the subject and message you wish to send to signers.', - stepIndex: 3, + stepIndex: 4, onBackStep: () => setStep('fields'), }, }; const currentDocumentFlow = documentFlow[step]; + const onAddTitleFormSubmit = async (data: TAddTitleFormSchema) => { + try { + // Custom invocation server action + await addTitle({ + documentId: document.id, + title: data.title, + }); + + router.refresh(); + + setStep('signers'); + } catch (err) { + console.error(err); + + toast({ + title: 'Error', + description: 'An error occurred while updating title.', + variant: 'destructive', + }); + } + }; + const onAddSignersFormSubmit = async (data: TAddSignersFormSchema) => { try { // Custom invocation server action @@ -164,10 +197,23 @@ export const EditDocumentForm = ({ description={currentDocumentFlow.description} /> + {step === 'title' && ( + + )} + {step === 'signers' && ( { + 'use server'; + + const { user } = await getRequiredServerComponentSession(); + + await updateTitle({ + documentId, + userId: user.id, + title: title, + }); +}; diff --git a/packages/lib/server-only/document/update-title.ts b/packages/lib/server-only/document/update-title.ts new file mode 100644 index 000000000..ba086b9cb --- /dev/null +++ b/packages/lib/server-only/document/update-title.ts @@ -0,0 +1,21 @@ +'use server'; + +import { prisma } from '@documenso/prisma'; + +export type UpdateTitleOptions = { + userId: number; + documentId: number; + title: string; +}; + +export const updateTitle = async ({ userId, documentId, title }: UpdateTitleOptions) => { + return await prisma.document.update({ + where: { + id: documentId, + userId, + }, + data: { + title, + }, + }); +}; diff --git a/packages/trpc/server/document-router/router.ts b/packages/trpc/server/document-router/router.ts index bd92312da..924d3a9bd 100644 --- a/packages/trpc/server/document-router/router.ts +++ b/packages/trpc/server/document-router/router.ts @@ -8,6 +8,7 @@ import { getDocumentById } from '@documenso/lib/server-only/document/get-documen import { getDocumentAndSenderByToken } from '@documenso/lib/server-only/document/get-document-by-token'; import { resendDocument } from '@documenso/lib/server-only/document/resend-document'; import { sendDocument } from '@documenso/lib/server-only/document/send-document'; +import { updateTitle } from '@documenso/lib/server-only/document/update-title'; import { setFieldsForDocument } from '@documenso/lib/server-only/field/set-fields-for-document'; import { setRecipientsForDocument } from '@documenso/lib/server-only/recipient/set-recipients-for-document'; @@ -21,6 +22,7 @@ import { ZSendDocumentMutationSchema, ZSetFieldsForDocumentMutationSchema, ZSetRecipientsForDocumentMutationSchema, + ZSetTitleForDocumentMutationSchema, } from './schema'; export const documentRouter = router({ @@ -113,6 +115,20 @@ export const documentRouter = router({ } }), + setTitleForDocument: authenticatedProcedure + .input(ZSetTitleForDocumentMutationSchema) + .mutation(async ({ input, ctx }) => { + const { documentId, title } = input; + + const userId = ctx.user.id; + + return await updateTitle({ + title, + userId, + documentId, + }); + }), + setRecipientsForDocument: authenticatedProcedure .input(ZSetRecipientsForDocumentMutationSchema) .mutation(async ({ input, ctx }) => { diff --git a/packages/trpc/server/document-router/schema.ts b/packages/trpc/server/document-router/schema.ts index b9bea71c3..cc010046e 100644 --- a/packages/trpc/server/document-router/schema.ts +++ b/packages/trpc/server/document-router/schema.ts @@ -21,6 +21,13 @@ export const ZCreateDocumentMutationSchema = z.object({ export type TCreateDocumentMutationSchema = z.infer; +export const ZSetTitleForDocumentMutationSchema = z.object({ + documentId: z.number(), + title: z.string().min(1), +}); + +export type TSetTitleForDocumentMutationSchema = z.infer; + export const ZSetRecipientsForDocumentMutationSchema = z.object({ documentId: z.number(), recipients: z.array( diff --git a/packages/ui/primitives/document-flow/add-signers.tsx b/packages/ui/primitives/document-flow/add-signers.tsx index 14d728f0a..b623b0d4e 100644 --- a/packages/ui/primitives/document-flow/add-signers.tsx +++ b/packages/ui/primitives/document-flow/add-signers.tsx @@ -9,7 +9,8 @@ import { Controller, useFieldArray, useForm } from 'react-hook-form'; import { useLimits } from '@documenso/ee/server-only/limits/provider/client'; import { nanoid } from '@documenso/lib/universal/id'; -import { Field, Recipient, SendStatus } from '@documenso/prisma/client'; +import { DocumentStatus, Field, Recipient, SendStatus } from '@documenso/prisma/client'; +import { DocumentWithData } from '@documenso/prisma/types/document-with-data'; import { Button } from '@documenso/ui/primitives/button'; import { FormErrorMessage } from '@documenso/ui/primitives/form/form-error-message'; import { Input } from '@documenso/ui/primitives/input'; @@ -29,6 +30,7 @@ export type AddSignersFormProps = { documentFlow: DocumentFlowStep; recipients: Recipient[]; fields: Field[]; + document: DocumentWithData; numberOfSteps: number; onSubmit: (_data: TAddSignersFormSchema) => void; }; @@ -37,6 +39,7 @@ export const AddSignersFormPartial = ({ documentFlow, numberOfSteps, recipients, + document, fields: _fields, onSubmit, }: AddSignersFormProps) => { @@ -223,6 +226,7 @@ export const AddSignersFormPartial = ({ /> void; +}; + +export const AddTitleFormPartial = ({ + documentFlow, + recipients: _recipients, + fields: _fields, + document, + numberOfSteps, + onSubmit, +}: AddTitleFormProps) => { + const { + register, + handleSubmit, + formState: { errors, isSubmitting }, + } = useForm({ + defaultValues: { + title: document.title, + }, + }); + + const onFormSubmit = handleSubmit(onSubmit); + + return ( + <> + +
+
+
+ + + + + +
+
+
+
+ + + + + void onFormSubmit()} + /> + + + ); +}; diff --git a/packages/ui/primitives/document-flow/add-title.types.ts b/packages/ui/primitives/document-flow/add-title.types.ts new file mode 100644 index 000000000..aaa8c17e4 --- /dev/null +++ b/packages/ui/primitives/document-flow/add-title.types.ts @@ -0,0 +1,7 @@ +import { z } from 'zod'; + +export const ZAddTitleFormSchema = z.object({ + title: z.string().min(1), +}); + +export type TAddTitleFormSchema = z.infer; diff --git a/packages/ui/primitives/document-flow/types.ts b/packages/ui/primitives/document-flow/types.ts index 2c24f8c96..c9244ad05 100644 --- a/packages/ui/primitives/document-flow/types.ts +++ b/packages/ui/primitives/document-flow/types.ts @@ -3,6 +3,8 @@ import { z } from 'zod'; import { FieldType } from '@documenso/prisma/client'; export const ZDocumentFlowFormSchema = z.object({ + title: z.string().min(1), + signers: z .array( z.object({ @@ -52,6 +54,6 @@ export interface DocumentFlowStep { title: string; description: string; stepIndex: number; - onBackStep?: () => void; - onNextStep?: () => void; + onBackStep?: () => unknown; + onNextStep?: () => unknown; }