diff --git a/README.md b/README.md index 436e5150d..a6c0ab8ad 100644 --- a/README.md +++ b/README.md @@ -78,7 +78,7 @@ The current project goal is to [release a production ready version](https://g Documenso is built using awesome open source tech including: - [Typescript](https://www.typescriptlang.org/) -- [Javascript (when neccessary)](https://developer.mozilla.org/en-US/docs/Web/JavaScript) +- [Javascript (when necessary)](https://developer.mozilla.org/en-US/docs/Web/JavaScript) - [NextJS (JS Fullstack Framework)](https://nextjs.org/) - [Postgres SQL (Database)](https://www.postgresql.org/) - [Prisma (ORM - Object-relational mapping)](https://www.prisma.io/) @@ -96,7 +96,7 @@ Documenso is built using awesome open source tech including: To run Documenso locally you need - [Node.js (Version: >=18.x)](https://nodejs.org/en/download/) -- Node Package Manger NPM - included in Node.js +- Node Package Manager NPM - included in Node.js - [PostgreSQL (local or remote)](https://www.postgresql.org/download/) ## Developer Quickstart @@ -128,7 +128,7 @@ Your database will also be available on port `5432`. You can connect to it using ## Developer Setup -Follow these steps to setup documenso on you local machnine: +Follow these steps to setup documenso on you local machine: - [Clone the repository](https://help.github.com/articles/cloning-a-repository/) it to your local device. ```sh @@ -138,12 +138,12 @@ Follow these steps to setup documenso on you local machnine: - Rename .env.example to .env - Set DATABASE_URL value in .env file - You can use the provided test database url (may be wiped at any point) - - Or setup a local postgres sql instance (recommened) + - Or setup a local postgres sql instance (recommended) - Create the database scheme by running db-migrate:dev - Setup your mail provider - Set SENDGRID_API_KEY value in .env file - You need a SendGrid account, which you can create [here](https://signup.sendgrid.com/). - - Documenso uses [Nodemailer](https://nodemailer.com/about/) so you can easily use your own SMTP server by setting the SMTP\_\* varibles in your .env + - Documenso uses [Nodemailer](https://nodemailer.com/about/) so you can easily use your own SMTP server by setting the SMTP\_\* variables in your .env - Run npm run dev root directory to start - Register a new user at http://localhost:3000/signup @@ -154,20 +154,20 @@ Follow these steps to setup documenso on you local machnine: - Optional: Create your own signing certificate - A demo certificate is provided in /app/web/ressources/certificate.p12 - - To generate you own using these steps and a linux Terminal or Windows Linux Subsystem see **Create your own signging certificate**. + - To generate your own using these steps and a linux Terminal or Windows Linux Subsystem see **Create your own signing certificate**. ## Updating -- If you pull the newest version from main, using git pull, it may be neccessary to regenerate your database client +- 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: ```sh npx prisma generate ``` -- This is not neccessary on first clone +- This is not necessary on first clone -# Creating your own signging certificate +# Creating your own signing certificate -For the digital signature of you documents you need a signign 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 formate (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/components/editor/pdf-signer.tsx b/apps/web/components/editor/pdf-signer.tsx index 797745a4c..a4a4cd2c6 100644 --- a/apps/web/components/editor/pdf-signer.tsx +++ b/apps/web/components/editor/pdf-signer.tsx @@ -80,12 +80,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..bd968ddc6 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

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/pages/api/documents/[id]/sign.ts b/apps/web/pages/api/documents/[id]/sign.ts index 537d7ee72..853dd3500 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 eaad896a5..af6752d47 100644 --- a/apps/web/pages/documents.tsx +++ b/apps/web/pages/documents.tsx @@ -27,7 +27,13 @@ const DocumentsPage: NextPageWithLayout = (props: any) => { const [filteredDocuments, setFilteredDocuments] = useState([]); const [loading, setLoading] = useState(true); - const statusFilters = [ + + type statusFilterType = { + label: string; + value: DocumentStatus | "ALL"; + }; + + const statusFilters: statusFilterType[] = [ { label: "All", value: "ALL" }, { label: "Draft", value: "DRAFT" }, { label: "Waiting for others", value: "PENDING" }, @@ -83,6 +89,20 @@ const DocumentsPage: NextPageWithLayout = (props: any) => { return filteredDocuments; } + function handleStatusFilterChange(status: statusFilterType) { + router.replace( + { + pathname: router.pathname, + query: { filter: status.value }, + }, + undefined, + { + shallow: true, // Perform a shallow update, without reloading the page + } + ); + setSelectedStatusFilter(status); + } + function wasXDaysAgoOrLess(documentDate: Date, lastXDays: number): boolean { if (lastXDays < 0) return true; @@ -122,26 +142,26 @@ const DocumentsPage: NextPageWithLayout = (props: any) => { -
-
+
+
{filteredDocuments.length != 1 ? filteredDocuments.length + " Documents" : "1 Document"}
-