From e9db5acc859500df1c3041e71d5789118587108d Mon Sep 17 00:00:00 2001 From: Timur Ercan Date: Fri, 3 Feb 2023 18:07:43 +0100 Subject: [PATCH] add recipient ui --- .../api/documents/[id]/recipients/index.ts | 18 +++- apps/web/pages/documents.tsx | 42 ++++++++-- apps/web/pages/documents/[id]/recipients.tsx | 84 +++++++++++++------ packages/prisma/schema.prisma | 3 +- 4 files changed, 110 insertions(+), 37 deletions(-) diff --git a/apps/web/pages/api/documents/[id]/recipients/index.ts b/apps/web/pages/api/documents/[id]/recipients/index.ts index a99d69175..439211106 100644 --- a/apps/web/pages/api/documents/[id]/recipients/index.ts +++ b/apps/web/pages/api/documents/[id]/recipients/index.ts @@ -21,6 +21,10 @@ async function postHandler(req: NextApiRequest, res: NextApiResponse) { return; } + if (!body.email) { + res.status(400).send("Missing parameter email."); + } + const document: PrismaDocument = await getDocument(+documentId, req, res); // todo encapsulate entity ownerships checks @@ -28,15 +32,23 @@ async function postHandler(req: NextApiRequest, res: NextApiResponse) { return res.status(401).send("User does not have access to this document."); } - await prisma.recipient.create({ - data: { + const upsert = await prisma.recipient.upsert({ + where: { + email: body.email, + }, + update: { + email: body.email, + name: body.name, + }, + create: { documentId: +documentId, email: body.email, + name: body.name, token: short.generate().toString(), }, }); - return res.status(201).end(); + return res.status(200).end(); } export default defaultHandler({ diff --git a/apps/web/pages/documents.tsx b/apps/web/pages/documents.tsx index fdddbf4da..8ff1fd1b0 100644 --- a/apps/web/pages/documents.tsx +++ b/apps/web/pages/documents.tsx @@ -8,6 +8,7 @@ import { EnvelopeIcon, EyeIcon, PlusIcon, + SunIcon, TrashIcon, } from "@heroicons/react/24/outline"; import Link from "next/link"; @@ -135,28 +136,51 @@ const DocumentsPage: NextPageWithLayout = (props: any) => { {document.Recipient.map((item: any) => (
+ {item.sendStatus === "NOT_SENT" ? ( + + {item.name + ? item.name + " <" + item.email + ">" + : item.email} + + ) : ( + "" + )} {item.sendStatus === "SENT" && - item.readStatus !== "OPENED" && - item.signingStatus !== "SIGNED" ? ( + item.readStatus !== "OPENED" ? ( - {item.email} + + {item.name + ? item.name + " <" + item.email + ">" + : item.email} + ) : ( "" )} - {item.sendStatus === "SENT" && - item.readStatus === "OPENED" ? ( + {item.readStatus === "OPENED" && + item.signingStatus === "NOT_SIGNED" ? ( {" "} - {item.email} + + {item.name + ? item.name + " <" + item.email + ">" + : item.email} + ) : ( "" )} - {item.sendStatus === "SENT" && - item.readStatus === "OPENED" && - item.signingStatus === "SIGNED" ? ( + {item.signingStatus === "SIGNED" ? ( {" "} {item.email} diff --git a/apps/web/pages/documents/[id]/recipients.tsx b/apps/web/pages/documents/[id]/recipients.tsx index b18cd4388..f11868fd7 100644 --- a/apps/web/pages/documents/[id]/recipients.tsx +++ b/apps/web/pages/documents/[id]/recipients.tsx @@ -14,6 +14,7 @@ import { getUserFromToken } from "@documenso/lib/server"; import { getDocument } from "@documenso/lib/query"; import { Document as PrismaDocument } from "@prisma/client"; import { Breadcrumb, Button, IconButton } from "@documenso/ui"; +import toast from "react-hot-toast"; const RecipientsPage: NextPageWithLayout = (props: any) => { const title: string = @@ -91,7 +92,34 @@ const RecipientsPage: NextPageWithLayout = (props: any) => { htmlFor="name" className="block text-xs font-medium text-gray-900" > - Name + Email + + { + const updatedSigners = [...signers]; + updatedSigners[index].email = e.target.value; + setSigners(updatedSigners); + }} + onBlur={() => { + item.documentId = props.document.id; + upsertRecipient(item); + }} + onKeyDown={(event: any) => { + if (event.key === "Enter") upsertRecipient(item); + }} + className="block w-full border-0 p-0 text-gray-900 placeholder-gray-500 sm:text-sm outline-none bg-inherit" + placeholder="john.dorian@loremipsum.com" + /> +
+
+ { updatedSigners[index].name = e.target.value; setSigners(updatedSigners); }} - id="name" + onBlur={() => { + item.documentId = props.document.id; + upsertRecipient(item); + }} + onKeyDown={(event: any) => { + if (event.key === "Enter") upsertRecipient(item); + }} className="block w-full border-0 p-0 text-gray-900 placeholder-gray-500 sm:text-sm outline-none bg-inherit" placeholder="John Dorian" />
-
- - { - const updatedSigners = [...signers]; - updatedSigners[index].email = e.target.value; - setSigners(updatedSigners); - }} - id="name" - className="block w-full border-0 p-0 text-gray-900 placeholder-gray-500 sm:text-sm outline-none bg-inherit" - placeholder="john.dorian@loremipsum.com" - /> -
{ console.log("click"); // todo save to api }} - // className="group-hover:text-neon-dark" + className="group-hover:text-neon-dark" >
@@ -167,6 +180,29 @@ const RecipientsPage: NextPageWithLayout = (props: any) => { ); }; +async function upsertRecipient(recipient: any) { + toast.promise( + fetch("/api/documents/" + recipient.documentId + "/recipients", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify(recipient), + }), + { + loading: "Saving...", + success: "Saved.", + error: "Could not save :/", + }, + { + id: "saving", + style: { + minWidth: "200px", + }, + } + ); +} + RecipientsPage.getLayout = function getLayout(page: ReactElement) { return {page}; }; diff --git a/packages/prisma/schema.prisma b/packages/prisma/schema.prisma index 19936e176..1fa60c27a 100644 --- a/packages/prisma/schema.prisma +++ b/packages/prisma/schema.prisma @@ -20,7 +20,8 @@ model Document { model Recipient { id Int @id @default(autoincrement()) documentId Int - email String @db.VarChar(255) + email String @unique @db.VarChar(255) + name String @default("") @db.VarChar(255) token String readStatus ReadStatus @default(NOT_OPENED) signingStatus SigningStatus @default(NOT_SIGNED)