mirror of
https://github.com/documenso/documenso.git
synced 2025-11-13 08:13:56 +10:00
♻️ 🧹 upsert reciient, deleteRecipient, send
This commit is contained in:
@ -25,7 +25,7 @@ async function getHandler(req: NextApiRequest, res: NextApiResponse) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo encapsulate entity ownerships checks
|
// todo entity ownerships checks
|
||||||
|
|
||||||
const fields = await prisma.field.findMany({
|
const fields = await prisma.field.findMany({
|
||||||
where: { documentId: +documentId },
|
where: { documentId: +documentId },
|
||||||
@ -57,7 +57,7 @@ async function postHandler(req: NextApiRequest, res: NextApiResponse) {
|
|||||||
|
|
||||||
const document: PrismaDocument = await getDocument(+documentId, req, res);
|
const document: PrismaDocument = await getDocument(+documentId, req, res);
|
||||||
|
|
||||||
// todo encapsulate entity ownerships checks
|
// todo entity ownerships checks
|
||||||
if (document.userId !== user.id) {
|
if (document.userId !== user.id) {
|
||||||
return res.status(401).send("User does not have access to this document.");
|
return res.status(401).send("User does not have access to this document.");
|
||||||
}
|
}
|
||||||
|
|||||||
@ -23,7 +23,7 @@ async function postHandler(req: NextApiRequest, res: NextApiResponse) {
|
|||||||
|
|
||||||
const document: PrismaDocument = await getDocument(+documentId, req, res);
|
const document: PrismaDocument = await getDocument(+documentId, req, res);
|
||||||
|
|
||||||
// todo encapsulate entity ownerships checks
|
// todo entity ownerships checks
|
||||||
if (document.userId !== user.id) {
|
if (document.userId !== user.id) {
|
||||||
return res.status(401).send("User does not have access to this document.");
|
return res.status(401).send("User does not have access to this document.");
|
||||||
}
|
}
|
||||||
|
|||||||
@ -351,7 +351,6 @@ const DocumentsPage: NextPageWithLayout = (props: any) => {
|
|||||||
const removedItem: any =
|
const removedItem: any =
|
||||||
documentsWithoutIndex.splice(index, 1);
|
documentsWithoutIndex.splice(index, 1);
|
||||||
setDocuments(documentsWithoutIndex);
|
setDocuments(documentsWithoutIndex);
|
||||||
// todo encapsulate
|
|
||||||
deleteDocument(document.id)
|
deleteDocument(document.id)
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
documentsWithoutIndex.splice(
|
documentsWithoutIndex.splice(
|
||||||
|
|||||||
@ -17,8 +17,12 @@ import { getUserFromToken } from "@documenso/lib/server";
|
|||||||
import { getDocument } from "@documenso/lib/query";
|
import { getDocument } from "@documenso/lib/query";
|
||||||
import { Document as PrismaDocument } from "@prisma/client";
|
import { Document as PrismaDocument } from "@prisma/client";
|
||||||
import { Breadcrumb, Button, IconButton } from "@documenso/ui";
|
import { Breadcrumb, Button, IconButton } from "@documenso/ui";
|
||||||
import toast from "react-hot-toast";
|
|
||||||
import { Dialog, Transition } from "@headlessui/react";
|
import { Dialog, Transition } from "@headlessui/react";
|
||||||
|
import {
|
||||||
|
createOrUpdateRecipient,
|
||||||
|
deleteRecipient,
|
||||||
|
sendSigningRequests,
|
||||||
|
} from "@documenso/lib/api";
|
||||||
|
|
||||||
const RecipientsPage: NextPageWithLayout = (props: any) => {
|
const RecipientsPage: NextPageWithLayout = (props: any) => {
|
||||||
const title: string =
|
const title: string =
|
||||||
@ -138,10 +142,11 @@ const RecipientsPage: NextPageWithLayout = (props: any) => {
|
|||||||
}}
|
}}
|
||||||
onBlur={() => {
|
onBlur={() => {
|
||||||
item.documentId = props.document.id;
|
item.documentId = props.document.id;
|
||||||
upsertRecipient(item);
|
createOrUpdateRecipient(item);
|
||||||
}}
|
}}
|
||||||
onKeyDown={(event: any) => {
|
onKeyDown={(event: any) => {
|
||||||
if (event.key === "Enter") upsertRecipient(item);
|
if (event.key === "Enter")
|
||||||
|
createOrUpdateRecipient(item);
|
||||||
}}
|
}}
|
||||||
className="block w-full border-0 p-0 text-gray-900 placeholder-gray-500 sm:text-sm outline-none bg-inherit"
|
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"
|
placeholder="john.dorian@loremipsum.com"
|
||||||
@ -171,10 +176,11 @@ const RecipientsPage: NextPageWithLayout = (props: any) => {
|
|||||||
}}
|
}}
|
||||||
onBlur={() => {
|
onBlur={() => {
|
||||||
item.documentId = props.document.id;
|
item.documentId = props.document.id;
|
||||||
upsertRecipient(item);
|
createOrUpdateRecipient(item);
|
||||||
}}
|
}}
|
||||||
onKeyDown={(event: any) => {
|
onKeyDown={(event: any) => {
|
||||||
if (event.key === "Enter") upsertRecipient(item);
|
if (event.key === "Enter")
|
||||||
|
createOrUpdateRecipient(item);
|
||||||
}}
|
}}
|
||||||
className="block w-full border-0 p-0 text-gray-900 placeholder-gray-500 sm:text-sm outline-none bg-inherit"
|
className="block w-full border-0 p-0 text-gray-900 placeholder-gray-500 sm:text-sm outline-none bg-inherit"
|
||||||
placeholder="John Dorian"
|
placeholder="John Dorian"
|
||||||
@ -250,7 +256,9 @@ const RecipientsPage: NextPageWithLayout = (props: any) => {
|
|||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (confirm("Resend this signing request?")) {
|
if (confirm("Resend this signing request?")) {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
send(props.document, [item.id]).finally(() => {
|
sendSigningRequests(props.document, [
|
||||||
|
item.id,
|
||||||
|
]).finally(() => {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -270,7 +278,7 @@ const RecipientsPage: NextPageWithLayout = (props: any) => {
|
|||||||
1
|
1
|
||||||
);
|
);
|
||||||
setSigners(signersWithoutIndex);
|
setSigners(signersWithoutIndex);
|
||||||
deleteRecipient(item).catch((err) => {
|
deleteRecipient(item)?.catch((err) => {
|
||||||
setSigners(signersWithoutIndex.concat(removedItem));
|
setSigners(signersWithoutIndex.concat(removedItem));
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
@ -285,7 +293,7 @@ const RecipientsPage: NextPageWithLayout = (props: any) => {
|
|||||||
icon={UserPlusIcon}
|
icon={UserPlusIcon}
|
||||||
className="mt-3"
|
className="mt-3"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
upsertRecipient({
|
createOrUpdateRecipient({
|
||||||
id: "",
|
id: "",
|
||||||
email: "",
|
email: "",
|
||||||
name: "",
|
name: "",
|
||||||
@ -365,7 +373,7 @@ const RecipientsPage: NextPageWithLayout = (props: any) => {
|
|||||||
<Button
|
<Button
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setOpen(false);
|
setOpen(false);
|
||||||
send(props.document).finally(() => {
|
sendSigningRequests(props.document).finally(() => {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
@ -383,69 +391,6 @@ const RecipientsPage: NextPageWithLayout = (props: any) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
// todo encapsulate
|
|
||||||
async function deleteRecipient(recipient: any) {
|
|
||||||
if (!recipient.id) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
return toast.promise(
|
|
||||||
fetch(
|
|
||||||
"/api/documents/" + recipient.documentId + "/recipients/" + recipient.id,
|
|
||||||
{
|
|
||||||
method: "DELETE",
|
|
||||||
headers: {
|
|
||||||
"Content-Type": "application/json",
|
|
||||||
},
|
|
||||||
body: JSON.stringify(recipient),
|
|
||||||
}
|
|
||||||
),
|
|
||||||
{
|
|
||||||
loading: "Deleting...",
|
|
||||||
success: "Deleted.",
|
|
||||||
error: "Could not delete :/",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "delete",
|
|
||||||
style: {
|
|
||||||
minWidth: "200px",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// todo encapsulate
|
|
||||||
async function upsertRecipient(recipient: any): Promise<any> {
|
|
||||||
try {
|
|
||||||
const created = await toast.promise(
|
|
||||||
fetch("/api/documents/" + recipient.documentId + "/recipients", {
|
|
||||||
method: "POST",
|
|
||||||
headers: {
|
|
||||||
"Content-Type": "application/json",
|
|
||||||
},
|
|
||||||
body: JSON.stringify(recipient),
|
|
||||||
}).then((res) => {
|
|
||||||
if (!res.ok) {
|
|
||||||
throw new Error(res.status.toString());
|
|
||||||
}
|
|
||||||
return res.json();
|
|
||||||
}),
|
|
||||||
{
|
|
||||||
loading: "Saving...",
|
|
||||||
success: "Saved.",
|
|
||||||
error: "Could not save :/",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "saving",
|
|
||||||
style: {
|
|
||||||
minWidth: "200px",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
);
|
|
||||||
return created;
|
|
||||||
} catch (error) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
RecipientsPage.getLayout = function getLayout(page: ReactElement) {
|
RecipientsPage.getLayout = function getLayout(page: ReactElement) {
|
||||||
return <Layout>{page}</Layout>;
|
return <Layout>{page}</Layout>;
|
||||||
};
|
};
|
||||||
@ -468,33 +413,4 @@ export async function getServerSideProps(context: any) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo encapsulate
|
|
||||||
async function send(document: any, resendTo: number[] = []) {
|
|
||||||
if (!document || !document.id) return;
|
|
||||||
try {
|
|
||||||
const sent = await toast.promise(
|
|
||||||
fetch(`/api/documents/${document.id}/send`, {
|
|
||||||
body: JSON.stringify({ resendTo: resendTo }),
|
|
||||||
headers: { "Content-Type": "application/json" },
|
|
||||||
method: "POST",
|
|
||||||
})
|
|
||||||
.then((res: any) => {
|
|
||||||
if (!res.ok) {
|
|
||||||
throw new Error(res.status.toString());
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.finally(() => {
|
|
||||||
location.reload();
|
|
||||||
}),
|
|
||||||
{
|
|
||||||
loading: "Sending...",
|
|
||||||
success: `Sent!`,
|
|
||||||
error: "Could not send :/",
|
|
||||||
}
|
|
||||||
);
|
|
||||||
} catch (err) {
|
|
||||||
console.log(err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default RecipientsPage;
|
export default RecipientsPage;
|
||||||
|
|||||||
32
packages/lib/api/createOrUpdateRecipient.ts
Normal file
32
packages/lib/api/createOrUpdateRecipient.ts
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
import toast from "react-hot-toast";
|
||||||
|
|
||||||
|
export const createOrUpdateRecipient = async (recipient: any): Promise<any> => {
|
||||||
|
try {
|
||||||
|
const created = await toast.promise(
|
||||||
|
fetch("/api/documents/" + recipient.documentId + "/recipients", {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
body: JSON.stringify(recipient),
|
||||||
|
}).then((res) => {
|
||||||
|
if (!res.ok) {
|
||||||
|
throw new Error(res.status.toString());
|
||||||
|
}
|
||||||
|
return res.json();
|
||||||
|
}),
|
||||||
|
{
|
||||||
|
loading: "Saving...",
|
||||||
|
success: "Saved.",
|
||||||
|
error: "Could not save :/",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "saving",
|
||||||
|
style: {
|
||||||
|
minWidth: "200px",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
return created;
|
||||||
|
} catch (error) {}
|
||||||
|
};
|
||||||
31
packages/lib/api/deleteRecipient.ts
Normal file
31
packages/lib/api/deleteRecipient.ts
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
import toast from "react-hot-toast";
|
||||||
|
|
||||||
|
export const deleteRecipient = (recipient: any) => {
|
||||||
|
if (!recipient.id) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return toast.promise(
|
||||||
|
fetch(
|
||||||
|
"/api/documents/" + recipient.documentId + "/recipients/" + recipient.id,
|
||||||
|
{
|
||||||
|
method: "DELETE",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
body: JSON.stringify(recipient),
|
||||||
|
}
|
||||||
|
),
|
||||||
|
{
|
||||||
|
loading: "Deleting...",
|
||||||
|
success: "Deleted.",
|
||||||
|
error: "Could not delete :/",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "delete",
|
||||||
|
style: {
|
||||||
|
minWidth: "200px",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
};
|
||||||
@ -4,4 +4,7 @@ export { signDocument } from "./signDocument";
|
|||||||
export { getUser } from "./getUser";
|
export { getUser } from "./getUser";
|
||||||
export { signup } from "./signup";
|
export { signup } from "./signup";
|
||||||
export { getDocuments } from "./getDocuments";
|
export { getDocuments } from "./getDocuments";
|
||||||
export { deleteDocument } from "./deleteDocument";
|
export { deleteDocument } from "./deleteDocument";
|
||||||
|
export { deleteRecipient } from "./deleteRecipient";
|
||||||
|
export { createOrUpdateRecipient } from "./createOrUpdateRecipient";
|
||||||
|
export { sendSigningRequests } from "./sendSigningRequests";
|
||||||
32
packages/lib/api/sendSigningRequests.ts
Normal file
32
packages/lib/api/sendSigningRequests.ts
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
import toast from "react-hot-toast";
|
||||||
|
|
||||||
|
export const sendSigningRequests = async (
|
||||||
|
document: any,
|
||||||
|
resendTo: number[] = []
|
||||||
|
) => {
|
||||||
|
if (!document || !document.id) return;
|
||||||
|
try {
|
||||||
|
const sent = await toast.promise(
|
||||||
|
fetch(`/api/documents/${document.id}/send`, {
|
||||||
|
body: JSON.stringify({ resendTo: resendTo }),
|
||||||
|
headers: { "Content-Type": "application/json" },
|
||||||
|
method: "POST",
|
||||||
|
})
|
||||||
|
.then((res: any) => {
|
||||||
|
if (!res.ok) {
|
||||||
|
throw new Error(res.status.toString());
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
location.reload();
|
||||||
|
}),
|
||||||
|
{
|
||||||
|
loading: "Sending...",
|
||||||
|
success: `Sent!`,
|
||||||
|
error: "Could not send :/",
|
||||||
|
}
|
||||||
|
);
|
||||||
|
} catch (err) {
|
||||||
|
console.log(err);
|
||||||
|
}
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user