import { NEXT_PUBLIC_WEBAPP_URL } from "@documenso/lib/constants"; import { useRouter } from "next/router"; import dynamic from "next/dynamic"; import { Fragment, useState } from "react"; import toast from "react-hot-toast"; import { FieldType } from "@prisma/client"; import { Listbox, RadioGroup, Transition } from "@headlessui/react"; import { CheckIcon, ChevronUpDownIcon } from "@heroicons/react/24/outline"; import { classNames } from "@documenso/lib"; const stc = require("string-to-color"); const PDFViewer = dynamic(() => import("./pdf-viewer"), { ssr: false, }); export default function PDFEditor(props: any) { const [selectedRecipient, setSelectedRecipient]: any = useState( props?.document?.Recipient[0] ); const noRecipients = props?.document?.Recipient?.length === 0; const [fields, setFields] = useState(props.document.Field); const [adding, setAdding] = useState(false); const router = useRouter(); const fieldTypes = [ { name: "Signature" }, { name: "Text" }, { name: "Date" }, ]; const [selectedFieldType, setSelectedFieldType] = useState( fieldTypes[0].name ); function onPositionChangedHandler(position: any, id: any) { if (!position) return; const movedField = fields.find((e) => e.id == id); movedField.positionX = position.x.toFixed(0); movedField.positionY = position.y.toFixed(0); upsertField(props.document, movedField); // no instant redraw neccessary, postion information for saving or later rerender is enough // setFields(newFields); } function onDeleteHandler(id: any) { const field = fields.find((e) => e.id == id); const fieldIndex = fields.map((item) => item.id).indexOf(id); if (fieldIndex > -1) { const fieldWithoutRemoved = [...fields]; const removedField = fieldWithoutRemoved.splice(fieldIndex, 1); setFields(fieldWithoutRemoved); deleteField(field).catch((err) => { setFields(fieldWithoutRemoved.concat(removedField)); }); } } return ( <>
{ e.preventDefault(); e.stopPropagation(); if (adding) { console.log("adding to page " + page); addField(e, page); setAdding(false); } }} onMouseDown={(e: any, page: number) => { addField(e, page); }} >
); function addField(e: any, page: number) { var rect = e.target.getBoundingClientRect(); var newFieldX = e.clientX - rect.left; //x position within the element. var newFieldY = e.clientY - rect.top; //y position within the element. const signatureField = { id: -1, page: page, type: FieldType.SIGNATURE, positionX: newFieldX.toFixed(0), positionY: newFieldY.toFixed(0), Recipient: selectedRecipient, }; upsertField(props?.document, signatureField).then((res) => { setFields(fields.concat(res)); }); } } async function upsertField(document: any, field: any): Promise { try { const created = await toast.promise( fetch("/api/documents/" + document.id + "/fields", { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify(field), }).then((res) => { if (!res.ok) { throw new Error(res.status.toString()); } return res.json(); }), { loading: "Saving...", success: "Saved.", error: "Could not save :/", }, { id: "saving field", style: { minWidth: "200px", }, } ); return created; } catch (error) {} } async function deleteField(field: any) { if (!field.id) { return; } try { const deleted = toast.promise( fetch("/api/documents/" + 0 + "/fields/" + field.id, { method: "DELETE", headers: { "Content-Type": "application/json", }, body: JSON.stringify(field), }).then((res) => { if (!res.ok) { throw new Error(res.status.toString()); } return res; }), { loading: "Deleting...", success: "Deleted.", error: "Could not delete :/", }, { id: "delete", style: { minWidth: "200px", }, } ); return deleted; } catch (error) {} }