diff --git a/README.md b/README.md index a6c0ab8ad..c70655905 100644 --- a/README.md +++ b/README.md @@ -71,7 +71,7 @@ The current project goal is to [release a production ready version](https://g - To contribute please see our [contribution guide](https://github.com/documenso/documenso/blob/main/CONTRIBUTING.md). -## Tools + # Tech @@ -86,7 +86,7 @@ Documenso is built using awesome open source tech including: - [Node SignPDF (Digital Signature)](https://github.com/vbuch/node-signpdf) - [React-PDF for viewing PDFs](https://github.com/wojtekmaj/react-pdf) - [PDF-Lib for PDF manipulation](https://github.com/Hopding/pdf-lib) -- Check out /packages.json and /apps/web/package.json for more +- Check out `/package.json` and `/apps/web/package.json` for more - Support for [opensignpdf (requires Java on server)](https://github.com/open-pdf-sign) is currently planned. # Getting Started @@ -111,7 +111,7 @@ Want to get up and running quickly? Follow these steps: git clone https://github.com/documenso/documenso ``` -- Set up your .env file using the recommendations in the .env.example file. +- Set up your `.env` file using the recommendations in the `.env.example` file. - Run `npm run dx` in the root directory - This will spin up a postgres database and inbucket mail server in docker containers. - Run `npm run dev` in the root directory @@ -124,7 +124,7 @@ That's it! You should now be able to access the app at http://localhost:3000 Incoming mail will be available at http://localhost:9000 -Your database will also be available on port `5432`. You can connect to it using your favorite database client. +Your database will also be available on port `54320`. You can connect to it using your favorite database client. ## Developer Setup @@ -150,24 +150,24 @@ Follow these steps to setup documenso on you local machine: --- - Optional: Seed the database using npm run db-seed to create a test user and document -- Optional: Upload and sign apps\web\ressources\example.pdf manually to test your setup +- Optional: Upload and sign apps/web/ressources/example.pdf manually to test your setup - Optional: Create your own signing certificate - - A demo certificate is provided in /app/web/ressources/certificate.p12 - - To generate your own using these steps and a linux Terminal or Windows Linux Subsystem see **Create your own signing certificate**. + - A demo certificate is provided in `/app/web/ressources/certificate.p12` + - To generate your own using these steps and a Linux Terminal or Windows Subsystem for Linux (WSL) see **[Create your own signing certificate](#creating-your-own-signing-certificate)**. ## Updating - If you pull the newest version from main, using git pull, it may be necessary to regenerate your database client -- You can do this by running the generate command in /packages/prisma: +- You can do this by running the generate command in `/packages/prisma`: ```sh npx prisma generate ``` -- This is not necessary on first clone +- This is not necessary on first clone. # Creating your own signing certificate -For the digital signature of your documents you need a signing certificate in .p12 formate (public and private key). You can buy one (not recommended for dev) or use the steps to create a self-signed one: +For the digital signature of your documents you need a signing certificate in .p12 format (public and private key). You can buy one (not recommended for dev) or use the steps to create a self-signed one: 1. Generate a private key using the OpenSSL command. You can run the following command to generate a 2048-bit RSA key:\ openssl genrsa -out private.key 2048 diff --git a/apps/web/.babelrc b/apps/web/.babelrc deleted file mode 100644 index 9fcef0394..000000000 --- a/apps/web/.babelrc +++ /dev/null @@ -1,4 +0,0 @@ -{ - "presets": ["next/babel"], - "plugins": [] -} diff --git a/apps/web/.eslintrc.json b/apps/web/.eslintrc.json index a2ceebebd..bd8a0104e 100644 --- a/apps/web/.eslintrc.json +++ b/apps/web/.eslintrc.json @@ -1,3 +1,8 @@ { - "extends": ["next/babel", "next/core-web-vitals"] -} + "extends": [ + "next/core-web-vitals" + ], + "rules": { + "react/no-unescaped-entities": "off" + } +} \ No newline at end of file diff --git a/apps/web/components/editor/pdf-signer.tsx b/apps/web/components/editor/pdf-signer.tsx index 8ef8ee5f2..561adc18a 100644 --- a/apps/web/components/editor/pdf-signer.tsx +++ b/apps/web/components/editor/pdf-signer.tsx @@ -198,12 +198,11 @@ export default function PDFSigner(props: any) { : props.document.User.email}{" "} would like you to sign this document.

-

+

- + canvasProps={{ + className: "sigCanvas border-b b-2 border-slate w-full h-full mb-3", + }} + clearOnResize={true} + onEnd={() => { + setSignatureEmpty(signCanvasRef?.isEmpty()); + }} + /> + )} + +

+ { + signCanvasRef?.clear(); + setSignatureEmpty(signCanvasRef?.isEmpty()); + }} + /> + +
+ + + +
) : ( diff --git a/apps/web/components/login.tsx b/apps/web/components/login.tsx index 4bbb784a1..2d9262c2a 100644 --- a/apps/web/components/login.tsx +++ b/apps/web/components/login.tsx @@ -111,7 +111,7 @@ export default function Login(props: any) {
- + Forgot your password?
@@ -123,7 +123,7 @@ export default function Login(props: any) { className="group relative flex w-full"> @@ -141,7 +141,7 @@ export default function Login(props: any) { {props.allowSignup ? (

Are you new here?{" "} - + Create a new Account

@@ -151,7 +151,7 @@ export default function Login(props: any) { - Hosted Documenso will be availible soon™ + Hosted Documenso will be available soon™

)} diff --git a/apps/web/components/signup.tsx b/apps/web/components/signup.tsx index d7b27ba7b..8092c0198 100644 --- a/apps/web/components/signup.tsx +++ b/apps/web/components/signup.tsx @@ -187,7 +187,7 @@ export default function Signup(props: { source: string }) {

Already have an account?{" "} - + Sign In

diff --git a/apps/web/hooks/use-debounced-value.ts b/apps/web/hooks/use-debounced-value.ts new file mode 100644 index 000000000..eebbec716 --- /dev/null +++ b/apps/web/hooks/use-debounced-value.ts @@ -0,0 +1,18 @@ +import { useEffect, useState } from "react"; + +export function useDebouncedValue(value: T, delay: number) { + // State and setters for debounced value + const [debouncedValue, setDebouncedValue] = useState(value); + + useEffect(() => { + const handler = setTimeout(() => { + setDebouncedValue(value); + }, delay); + + return () => { + clearTimeout(handler); + }; + }, [value, delay]); + + return debouncedValue; +} diff --git a/apps/web/package.json b/apps/web/package.json index b0a57aabc..1f5c72873 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -16,27 +16,16 @@ "@headlessui/react": "^1.7.4", "@heroicons/react": "^2.0.13", "@pdf-lib/fontkit": "^1.1.1", - "@tailwindcss/forms": "^0.5.3", - "@types/bcryptjs": "^2.4.2", - "@types/filesystem": "^0.0.32", - "@types/react-dom": "18.0.9", "avatar-from-initials": "^1.0.3", "base64-arraybuffer": "^1.0.2", "bcryptjs": "^2.4.3", - "dotenv": "^16.0.3", - "eslint": "8.27.0", - "eslint-config-next": "13.0.3", - "file-loader": "^6.2.0", "formidable": "^3.2.5", - "install": "^0.13.0", - "next": "13.0.3", - "next-auth": ">=4.20.1", - "next-transpile-modules": "^10.0.0", + "next": "13.2.4", + "next-auth": "^4.22.0", "node-forge": "^1.3.1", "node-signpdf": "^1.5.0", "nodemailer": "^6.9.0", "nodemailer-sendgrid": "^1.0.3", - "npm": "^9.1.3", "pdf-lib": "^1.17.1", "placeholder-loading": "^0.6.0", "react": "18.2.0", @@ -46,12 +35,14 @@ "react-pdf": "^6.2.2", "react-resizable": "^3.0.4", "react-tooltip": "^5.7.2", - "sass": "^1.57.1", "short-uuid": "^4.2.2", - "string-to-color": "^2.2.2", - "typescript": "4.8.4" + "string-to-color": "^2.2.2" }, "devDependencies": { + "@tailwindcss/forms": "^0.5.3", + "@types/bcryptjs": "^2.4.2", + "@types/filesystem": "^0.0.32", + "@types/react-dom": "18.0.9", "@types/formidable": "^2.0.5", "@types/node": "^18.11.18", "@types/nodemailer": "^6.4.7", @@ -59,7 +50,14 @@ "@types/react-pdf": "^6.2.0", "@types/react-resizable": "^3.0.3", "autoprefixer": "^10.4.13", + "dotenv": "^16.0.3", + "eslint": "8.27.0", + "eslint-config-next": "13.0.3", + "file-loader": "^6.2.0", + "next-transpile-modules": "^10.0.0", "postcss": "^8.4.19", - "tailwindcss": "^3.2.4" + "sass": "^1.57.1", + "tailwindcss": "^3.2.4", + "typescript": "4.8.4" } -} +} \ No newline at end of file diff --git a/apps/web/pages/api/documents/[id]/sign.ts b/apps/web/pages/api/documents/[id]/sign.ts index 352acbe76..0dc31126f 100644 --- a/apps/web/pages/api/documents/[id]/sign.ts +++ b/apps/web/pages/api/documents/[id]/sign.ts @@ -63,6 +63,7 @@ async function postHandler(req: NextApiRequest, res: NextApiResponse) { }, data: { signingStatus: SigningStatus.SIGNED, + signedAt: new Date(), }, }); @@ -86,7 +87,11 @@ async function postHandler(req: NextApiRequest, res: NextApiResponse) { where: { documentId: document.id, type: { in: [FieldType.DATE, FieldType.TEXT] }, + recipientId: { in: signedRecipients.map((r) => r.id) }, }, + include: { + Recipient: true, + } }); // Insert fields other than signatures @@ -98,7 +103,7 @@ async function postHandler(req: NextApiRequest, res: NextApiResponse) { month: "long", day: "numeric", year: "numeric", - }).format(new Date()) + }).format(field.Recipient?.signedAt ?? new Date()) : field.customText || "", field.positionX, field.positionY, diff --git a/apps/web/pages/dashboard.tsx b/apps/web/pages/dashboard.tsx index 324560f5a..5d3d93d94 100644 --- a/apps/web/pages/dashboard.tsx +++ b/apps/web/pages/dashboard.tsx @@ -1,4 +1,4 @@ -import { ReactElement } from "react"; +import { ChangeEvent, ReactElement } from "react"; import Head from "next/head"; import Link from "next/link"; import { uploadDocument } from "@documenso/features"; @@ -62,26 +62,27 @@ const DashboardPage: NextPageWithLayout = (props: any) => {
{stats.map((item) => ( -
-
+
+
{item.name}
-
+
{getStat(item.name, props)}
))}
+
{ + onChange={(event: ChangeEvent) => { uploadDocument(event); }} hidden @@ -91,9 +92,10 @@ const DashboardPage: NextPageWithLayout = (props: any) => { onClick={() => { document?.getElementById("fileUploadHelper")?.click(); }} - className="hover:border-neon relative block w-full cursor-pointer rounded-lg border-2 border-dashed border-gray-300 p-12 text-center focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2"> + className="group hover:border-neon-600 duration-200 relative block w-full cursor-pointer rounded-lg border-2 border-dashed border-gray-300 p-12 text-center focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2"> + { d="M19.5 14.25v-2.625a3.375 3.375 0 00-3.375-3.375h-1.5A1.125 1.125 0 0113.5 7.125v-1.5a3.375 3.375 0 00-3.375-3.375H8.25m3.75 9v6m3-3H9m1.5-12H5.625c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 00-9-9z" /> - + + Add a new PDF document.
diff --git a/apps/web/pages/documents.tsx b/apps/web/pages/documents.tsx index dbd8f7d80..af6752d47 100644 --- a/apps/web/pages/documents.tsx +++ b/apps/web/pages/documents.tsx @@ -142,26 +142,26 @@ const DocumentsPage: NextPageWithLayout = (props: any) => { -
-
+
+
{filteredDocuments.length != 1 ? filteredDocuments.length + " Documents" : "1 Document"}
-