From 5a3dd547b80f29700beebd777d86afd473f47761 Mon Sep 17 00:00:00 2001 From: Timur Ercan Date: Fri, 17 Feb 2023 13:37:28 +0100 Subject: [PATCH] =?UTF-8?q?=F0=9F=9A=A7=20signign=20workflow?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/web/components/editor/pdf-signer.tsx | 53 ++++++++++++++++- .../components/editor/signature-dialog.tsx | 11 +++- apps/web/pages/api/documents/[id]/sign.ts | 58 +++++++++++-------- apps/web/pages/documents/[id]/signed.tsx | 46 +++++++++++++++ 4 files changed, 141 insertions(+), 27 deletions(-) create mode 100644 apps/web/pages/documents/[id]/signed.tsx diff --git a/apps/web/components/editor/pdf-signer.tsx b/apps/web/components/editor/pdf-signer.tsx index 801d01956..73559e6ba 100644 --- a/apps/web/components/editor/pdf-signer.tsx +++ b/apps/web/components/editor/pdf-signer.tsx @@ -6,6 +6,7 @@ import SignatureDialog from "./signature-dialog"; import { useState } from "react"; import { Button } from "@documenso/ui"; import { CheckBadgeIcon } from "@heroicons/react/24/outline"; +import toast from "react-hot-toast"; const PDFViewer = dynamic(() => import("./pdf-viewer"), { ssr: false, @@ -14,17 +15,61 @@ const PDFViewer = dynamic(() => import("./pdf-viewer"), { export default function PDFSigner(props: any) { const router = useRouter(); const [open, setOpen] = useState(false); - const [fields, setFields] = useState(props.fields); + const [signatures, setSignatures] = useState([]); + const [dialogField, setDialogField] = useState(); function onClick(item: any) { if (item.type === "SIGNATURE") { + setDialogField(item); setOpen(true); } } + function onDialogClose(dialogResult: any) { + console.log(dialogResult); + console.log(dialogField); + setSignatures( + signatures.concat({ + fieldId: dialogField.id, + type: dialogResult.type, + name: dialogResult.name, + signatureImage: null, + }) + ); + setOpen(false); + setDialogField(null); + } + + function sign() { + const body = { documentId: props.document.id, signatures: signatures }; + toast.promise( + fetch( + `/api/documents/${props.document.id}/sign?token=${router.query.token}`, + { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify(body), + } + ).then(() => { + router.push( + `/documents/${props.document.id}/signed?token=${router.query.token}` + ); + }), + { + loading: "Signing...", + success: `"${props.document.title}" signed successfully.`, + error: "Could not sign :/", + } + ); + + // goto signing done page + } + return ( <> - +
@@ -36,9 +81,13 @@ export default function PDFSigner(props: any) { document.

diff --git a/apps/web/components/editor/signature-dialog.tsx b/apps/web/components/editor/signature-dialog.tsx index dddb1149d..ca6872095 100644 --- a/apps/web/components/editor/signature-dialog.tsx +++ b/apps/web/components/editor/signature-dialog.tsx @@ -105,7 +105,16 @@ export default function SignatureDialog(props: any) { > Cancel -
diff --git a/apps/web/pages/api/documents/[id]/sign.ts b/apps/web/pages/api/documents/[id]/sign.ts index 644fdc950..b3f76c210 100644 --- a/apps/web/pages/api/documents/[id]/sign.ts +++ b/apps/web/pages/api/documents/[id]/sign.ts @@ -14,8 +14,7 @@ async function postHandler(req: NextApiRequest, res: NextApiResponse) { const { token: recipientToken } = req.query; if (!recipientToken) { - res.status(401).send("Missing recipient token."); - return; + return res.status(401).send("Missing recipient token."); } const recipient = await prisma.recipient.findFirstOrThrow({ @@ -23,36 +22,18 @@ async function postHandler(req: NextApiRequest, res: NextApiResponse) { }); if (!recipient) { - res.status(401).send("Recipient not found."); - return; + return res.status(401).send("Recipient not found."); } const document: PrismaDocument = await getDocument( recipient.documentId, - res, - req + req, + res ); if (!document) res.status(404).end(`No document found.`); - // todo sign stuff - - const unsignedRecipients = await prisma.recipient.findMany({ - where: { - signingStatus: SigningStatus.NOT_SIGNED, - }, - }); - - if (unsignedRecipients.length === 0) { - await prisma.document.update({ - where: { - id: recipient.documentId, - }, - data: { - status: DocumentStatus.COMPLETED, - }, - }); - } + // save signature to db for later use await prisma.recipient.update({ where: { @@ -63,6 +44,35 @@ async function postHandler(req: NextApiRequest, res: NextApiResponse) { }, }); + const unsignedRecipients = await prisma.recipient.findMany({ + where: { + documentId: recipient.documentId, + signingStatus: SigningStatus.NOT_SIGNED, + }, + }); + + await prisma.document.update({ + where: { + id: recipient.documentId, + }, + data: { + status: DocumentStatus.COMPLETED, + }, + }); + + if (unsignedRecipients.length === 0) { + // if everybody signed insert images and create signature + await prisma.document.update({ + where: { + id: recipient.documentId, + }, + data: { + status: DocumentStatus.COMPLETED, + }, + }); + // send notifications + } + return res.status(200).end(); } diff --git a/apps/web/pages/documents/[id]/signed.tsx b/apps/web/pages/documents/[id]/signed.tsx new file mode 100644 index 000000000..95183cd9f --- /dev/null +++ b/apps/web/pages/documents/[id]/signed.tsx @@ -0,0 +1,46 @@ +import prisma from "@documenso/prisma"; +import Head from "next/head"; +import { NextPageWithLayout } from "../../_app"; +import { ReadStatus } from "@prisma/client"; + +const SignPage: NextPageWithLayout = (props: any) => { + return ( + <> + + Sign | Documenso + + You signed,thanks for playing. + + ); +}; + +export async function getServerSideProps(context: any) { + const recipientToken: string = context.query["token"]; + + const recipient = await prisma.recipient.findFirstOrThrow({ + where: { + token: recipientToken, + }, + include: { + Document: true, + }, + }); + + const fields = await prisma.field.findMany({ + where: { + documentId: recipient.Document.id, + }, + include: { + Recipient: true, + }, + }); + + return { + props: { + document: recipient.Document, + fields: fields, + }, + }; +} + +export default SignPage;