From d74aca2aa67b793ef4bb04cfff2e6989362bf60c Mon Sep 17 00:00:00 2001 From: Catalin Pit <25515812+catalinpit@users.noreply.github.com> Date: Tue, 20 Aug 2024 14:19:16 +0300 Subject: [PATCH] feat: save subject and message on blur --- .../trpc/server/document-router/router.ts | 27 +++++ .../trpc/server/document-router/schema.ts | 6 + .../primitives/document-flow/add-subject.tsx | 108 +++++++++++++++++- 3 files changed, 139 insertions(+), 2 deletions(-) diff --git a/packages/trpc/server/document-router/router.ts b/packages/trpc/server/document-router/router.ts index 049035f89..5bfbfb01c 100644 --- a/packages/trpc/server/document-router/router.ts +++ b/packages/trpc/server/document-router/router.ts @@ -38,6 +38,7 @@ import { ZResendDocumentMutationSchema, ZSearchDocumentsMutationSchema, ZSendDocumentMutationSchema, + ZSetDocumentEmailSettingsMutationSchema, ZSetPasswordForDocumentMutationSchema, ZSetSettingsForDocumentMutationSchema, ZSetTitleForDocumentMutationSchema, @@ -275,6 +276,32 @@ export const documentRouter = router({ } }), + setDocumentEmailSettings: authenticatedProcedure + .input(ZSetDocumentEmailSettingsMutationSchema) + .mutation(async ({ input, ctx }) => { + try { + const { documentId, subject, message } = input; + + const userId = ctx.user.id; + + return await upsertDocumentMeta({ + documentId, + userId, + subject, + message, + requestMetadata: extractNextApiRequestMetadata(ctx.req), + }); + } catch (err) { + console.error(err); + + throw new TRPCError({ + code: 'BAD_REQUEST', + message: + 'We were unable to update the email settings for this document. Please try again later.', + }); + } + }), + setPasswordForDocument: authenticatedProcedure .input(ZSetPasswordForDocumentMutationSchema) .mutation(async ({ input, ctx }) => { diff --git a/packages/trpc/server/document-router/schema.ts b/packages/trpc/server/document-router/schema.ts index 31e049173..06b1ce774 100644 --- a/packages/trpc/server/document-router/schema.ts +++ b/packages/trpc/server/document-router/schema.ts @@ -139,6 +139,12 @@ export const ZSendDocumentMutationSchema = z.object({ }), }); +export const ZSetDocumentEmailSettingsMutationSchema = z.object({ + documentId: z.number(), + subject: z.string().optional(), + message: z.string().optional(), +}); + export const ZSetPasswordForDocumentMutationSchema = z.object({ documentId: z.number(), password: z.string(), diff --git a/packages/ui/primitives/document-flow/add-subject.tsx b/packages/ui/primitives/document-flow/add-subject.tsx index bef5fbf5c..946e3f794 100644 --- a/packages/ui/primitives/document-flow/add-subject.tsx +++ b/packages/ui/primitives/document-flow/add-subject.tsx @@ -1,13 +1,21 @@ 'use client'; +import { useState } from 'react'; + +import { useRouter } from 'next/navigation'; + import { zodResolver } from '@hookform/resolvers/zod'; import { useForm } from 'react-hook-form'; +import { DO_NOT_INVALIDATE_QUERY_ON_MUTATION } from '@documenso/lib/constants/trpc'; import type { Field, Recipient } from '@documenso/prisma/client'; import { DocumentStatus } from '@documenso/prisma/client'; import type { DocumentWithData } from '@documenso/prisma/types/document-with-data'; +import { trpc } from '@documenso/trpc/react'; import { DocumentSendEmailMessageHelper } from '@documenso/ui/components/document/document-send-email-message-helper'; +import { useToast } from '@documenso/ui/primitives/use-toast'; +import { Button } from '../button'; import { FormErrorMessage } from '../form/form-error-message'; import { Input } from '../input'; import { Label } from '../label'; @@ -44,6 +52,7 @@ export const AddSubjectFormPartial = ({ const { register, handleSubmit, + setValue, formState: { errors, isSubmitting }, } = useForm({ defaultValues: { @@ -55,6 +64,87 @@ export const AddSubjectFormPartial = ({ resolver: zodResolver(ZAddSubjectFormSchema), }); + const [oldEmailData, setOldEmailData] = useState<{ subject: string; message: string } | null>( + () => + document.documentMeta + ? { + subject: document.documentMeta.subject ?? '', + message: document.documentMeta.message ?? '', + } + : null, + ); + + const { toast } = useToast(); + const router = useRouter(); + const utils = trpc.useUtils(); + + const { mutateAsync: setEmailSettingsForDocument } = + trpc.document.setDocumentEmailSettings.useMutation({ + ...DO_NOT_INVALIDATE_QUERY_ON_MUTATION, + onSuccess: () => { + const data = utils.document.getDocumentWithDetailsById.getData({ + id: document.id, + }); + + setOldEmailData({ + subject: data?.documentMeta?.subject ?? '', + message: data?.documentMeta?.message ?? '', + }); + }, + }); + + const handleOnBlur = async (field: 'subject' | 'message', value: string) => { + try { + await setEmailSettingsForDocument({ + documentId: document.id, + [field]: value, + }); + + router.refresh(); + + toast({ + title: 'Email settings updated', + description: `The email settings for the document have been updated.`, + }); + } catch (e) { + console.error(e); + + toast({ + title: 'Error', + description: 'An error occurred while updating the email settings.', + }); + } + }; + + const handleUndoButton = async () => { + try { + if (oldEmailData) { + await setEmailSettingsForDocument({ + documentId: document.id, + subject: oldEmailData.subject, + message: oldEmailData.message, + }); + + setValue('meta.subject', oldEmailData.subject); + setValue('meta.message', oldEmailData.message); + + setOldEmailData(null); + router.refresh(); + + toast({ + title: 'Changes reverted', + description: 'The latest change has been reverted to the original value.', + }); + } + } catch (e) { + console.error(e); + toast({ + title: 'Error', + description: 'An error occurred while undoing the latest change.', + }); + } + }; + const onFormSubmit = handleSubmit(onSubmit); const { currentStep, totalSteps, previousStep } = useStep(); @@ -64,6 +154,7 @@ export const AddSubjectFormPartial = ({ title={documentFlow.title} description={documentFlow.description} /> +
{isDocumentPdfLoaded && @@ -81,7 +172,11 @@ export const AddSubjectFormPartial = ({ id="subject" className="bg-background mt-2" disabled={isSubmitting} - {...register('meta.subject')} + {...register('meta.subject', { + onBlur: (event) => { + void handleOnBlur('subject', event.target.value); + }, + })} /> @@ -96,7 +191,11 @@ export const AddSubjectFormPartial = ({ id="message" className="bg-background mt-2 h-32 resize-none" disabled={isSubmitting} - {...register('meta.message')} + {...register('meta.message', { + onBlur: (event) => { + void handleOnBlur('message', event.target.value); + }, + })} />
+ {/* Hide the button after 5 seconds */} + {oldEmailData && ( + + )} +