mirror of
https://github.com/documenso/documenso.git
synced 2025-11-12 15:53:02 +10:00
chore: finish and clean-up redirect post signing
Signed-off-by: Adithya Krishna <adi@documenso.com>
This commit is contained in:
@ -8,7 +8,6 @@ import { useSession } from 'next-auth/react';
|
||||
import { useForm } from 'react-hook-form';
|
||||
|
||||
import { useAnalytics } from '@documenso/lib/client-only/hooks/use-analytics';
|
||||
import { getDocumentMetaByDocumentId } from '@documenso/lib/server-only/document/get-document-meta-by-document-id';
|
||||
import { sortFieldsByPosition, validateFieldsInserted } from '@documenso/lib/utils/fields';
|
||||
import { type Document, type Field, type Recipient, RecipientRole } from '@documenso/prisma/client';
|
||||
import { trpc } from '@documenso/trpc/react';
|
||||
@ -27,9 +26,10 @@ export type SigningFormProps = {
|
||||
document: Document;
|
||||
recipient: Recipient;
|
||||
fields: Field[];
|
||||
redirectUrl?: string | null;
|
||||
};
|
||||
|
||||
export const SigningForm = ({ document, recipient, fields }: SigningFormProps) => {
|
||||
export const SigningForm = ({ document, recipient, fields, redirectUrl }: SigningFormProps) => {
|
||||
const router = useRouter();
|
||||
const analytics = useAnalytics();
|
||||
const { data: session } = useSession();
|
||||
@ -56,7 +56,6 @@ export const SigningForm = ({ document, recipient, fields }: SigningFormProps) =
|
||||
};
|
||||
|
||||
const onFormSubmit = async () => {
|
||||
const documentMeta = await getDocumentMetaByDocumentId({ id: document!.id }).catch(() => null);
|
||||
setValidateUninsertedFields(true);
|
||||
|
||||
const isFieldsValid = validateFieldsInserted(fields);
|
||||
@ -75,9 +74,8 @@ export const SigningForm = ({ document, recipient, fields }: SigningFormProps) =
|
||||
documentId: document.id,
|
||||
timestamp: new Date().toISOString(),
|
||||
});
|
||||
documentMeta?.redirectUrl
|
||||
? router.push(documentMeta.redirectUrl)
|
||||
: router.push(`/sign/${recipient.token}/complete`);
|
||||
|
||||
redirectUrl ? router.push(redirectUrl) : router.push(`/sign/${recipient.token}/complete`);
|
||||
};
|
||||
|
||||
return (
|
||||
|
||||
@ -8,7 +8,6 @@ import { PDF_VIEWER_PAGE_SELECTOR } from '@documenso/lib/constants/pdf-viewer';
|
||||
import { DEFAULT_DOCUMENT_TIME_ZONE } from '@documenso/lib/constants/time-zones';
|
||||
import { getServerComponentSession } from '@documenso/lib/next-auth/get-server-component-session';
|
||||
import { getDocumentAndSenderByToken } from '@documenso/lib/server-only/document/get-document-by-token';
|
||||
import { getDocumentMetaByDocumentId } from '@documenso/lib/server-only/document/get-document-meta-by-document-id';
|
||||
import { viewedDocument } from '@documenso/lib/server-only/document/viewed-document';
|
||||
import { getFieldsForToken } from '@documenso/lib/server-only/field/get-fields-for-token';
|
||||
import { getRecipientByToken } from '@documenso/lib/server-only/recipient/get-recipient-by-token';
|
||||
@ -49,15 +48,13 @@ export default async function SigningPage({ params: { token } }: SigningPageProp
|
||||
viewedDocument({ token }).catch(() => null),
|
||||
]);
|
||||
|
||||
const documentMeta = await getDocumentMetaByDocumentId({ id: document!.id }).catch(() => null);
|
||||
|
||||
if (!document || !document.documentData || !recipient) {
|
||||
return notFound();
|
||||
}
|
||||
|
||||
const truncatedTitle = truncateTitle(document.title);
|
||||
|
||||
const { documentData } = document;
|
||||
const { documentData, documentMeta } = document;
|
||||
|
||||
const { user } = await getServerComponentSession();
|
||||
|
||||
@ -65,8 +62,9 @@ export default async function SigningPage({ params: { token } }: SigningPageProp
|
||||
document.status === DocumentStatus.COMPLETED ||
|
||||
recipient.signingStatus === SigningStatus.SIGNED
|
||||
) {
|
||||
//
|
||||
redirect(`/sign/${token}/complete`);
|
||||
documentMeta?.redirectUrl
|
||||
? redirect(documentMeta.redirectUrl)
|
||||
: redirect(`/sign/${token}/complete`);
|
||||
}
|
||||
|
||||
if (documentMeta?.password) {
|
||||
@ -134,7 +132,12 @@ export default async function SigningPage({ params: { token } }: SigningPageProp
|
||||
</Card>
|
||||
|
||||
<div className="col-span-12 lg:col-span-5 xl:col-span-4">
|
||||
<SigningForm document={document} recipient={recipient} fields={fields} />
|
||||
<SigningForm
|
||||
document={document}
|
||||
recipient={recipient}
|
||||
fields={fields}
|
||||
redirectUrl={documentMeta?.redirectUrl}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
import type { NextRequest } from 'next/server';
|
||||
import { NextResponse } from 'next/server';
|
||||
|
||||
import { getToken } from 'next-auth/jwt';
|
||||
|
||||
|
||||
13
package-lock.json
generated
13
package-lock.json
generated
@ -14610,6 +14610,7 @@
|
||||
"version": "6.9.7",
|
||||
"resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.9.7.tgz",
|
||||
"integrity": "sha512-rUtR77ksqex/eZRLmQ21LKVH5nAAsVicAtAYudK7JgwenEDZ0UIQ1adUGqErz7sMkWYxWTTU1aeP2Jga6WQyJw==",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=6.0.0"
|
||||
}
|
||||
@ -19602,14 +19603,14 @@
|
||||
"@react-email/section": "0.0.10",
|
||||
"@react-email/tailwind": "0.0.9",
|
||||
"@react-email/text": "0.0.6",
|
||||
"nodemailer": "^6.9.3",
|
||||
"nodemailer": "^6.9.9",
|
||||
"react-email": "^1.9.5",
|
||||
"resend": "^2.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@documenso/tailwind-config": "*",
|
||||
"@documenso/tsconfig": "*",
|
||||
"@types/nodemailer": "^6.4.8",
|
||||
"@types/nodemailer": "^6.4.14",
|
||||
"tsup": "^7.1.0"
|
||||
}
|
||||
},
|
||||
@ -19627,6 +19628,14 @@
|
||||
"node": ">=16.0.0"
|
||||
}
|
||||
},
|
||||
"packages/email/node_modules/nodemailer": {
|
||||
"version": "6.9.9",
|
||||
"resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.9.9.tgz",
|
||||
"integrity": "sha512-dexTll8zqQoVJEZPwQAKzxxtFn0qTnjdQTchoU6Re9BUUGBJiOy3YMn/0ShTW6J5M0dfQ1NeDeRTTl4oIWgQMA==",
|
||||
"engines": {
|
||||
"node": ">=6.0.0"
|
||||
}
|
||||
},
|
||||
"packages/eslint-config": {
|
||||
"name": "@documenso/eslint-config",
|
||||
"version": "0.0.0",
|
||||
|
||||
@ -35,14 +35,14 @@
|
||||
"@react-email/section": "0.0.10",
|
||||
"@react-email/tailwind": "0.0.9",
|
||||
"@react-email/text": "0.0.6",
|
||||
"nodemailer": "^6.9.3",
|
||||
"nodemailer": "^6.9.9",
|
||||
"react-email": "^1.9.5",
|
||||
"resend": "^2.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@documenso/tailwind-config": "*",
|
||||
"@documenso/tsconfig": "*",
|
||||
"@types/nodemailer": "^6.4.8",
|
||||
"@types/nodemailer": "^6.4.14",
|
||||
"tsup": "^7.1.0"
|
||||
}
|
||||
}
|
||||
|
||||
2
packages/lib/constants/url-regex.ts
Normal file
2
packages/lib/constants/url-regex.ts
Normal file
@ -0,0 +1,2 @@
|
||||
export const URL_REGEX =
|
||||
/^(https?):\/\/(?:www\.)?[a-zA-Z0-9-]+\.[a-zA-Z0-9()]{2,}(?:\/[a-zA-Z0-9-._?&=/]*)?$/i;
|
||||
@ -28,6 +28,7 @@ export const duplicateDocumentById = async ({ id, userId }: DuplicateDocumentByI
|
||||
dateFormat: true,
|
||||
password: true,
|
||||
timezone: true,
|
||||
redirectUrl: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@ -27,6 +27,7 @@ export const getDocumentAndSenderByToken = async ({
|
||||
include: {
|
||||
User: true,
|
||||
documentData: true,
|
||||
documentMeta: true,
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@ -192,7 +192,7 @@ model DocumentMeta {
|
||||
dateFormat String? @default("yyyy-MM-dd hh:mm a") @db.Text
|
||||
documentId Int @unique
|
||||
document Document @relation(fields: [documentId], references: [id], onDelete: Cascade)
|
||||
redirectUrl String? @db.Text
|
||||
redirectUrl String?
|
||||
}
|
||||
|
||||
enum ReadStatus {
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import { z } from 'zod';
|
||||
|
||||
import { URL_REGEX } from '@documenso/lib/constants/url-regex';
|
||||
import { DocumentStatus, FieldType, RecipientRole } from '@documenso/prisma/client';
|
||||
|
||||
export const ZGetDocumentByIdQuerySchema = z.object({
|
||||
@ -71,7 +72,12 @@ export const ZSendDocumentMutationSchema = z.object({
|
||||
message: z.string(),
|
||||
timezone: z.string(),
|
||||
dateFormat: z.string(),
|
||||
redirectUrl: z.string().optional(),
|
||||
redirectUrl: z
|
||||
.string()
|
||||
.optional()
|
||||
.refine((value) => value === undefined || URL_REGEX.test(value), {
|
||||
message: 'Please enter a valid URL',
|
||||
}),
|
||||
}),
|
||||
});
|
||||
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
|
||||
import { useEffect } from 'react';
|
||||
|
||||
import { Info } from 'lucide-react';
|
||||
import { Controller, useForm } from 'react-hook-form';
|
||||
|
||||
import { DATE_FORMATS, DEFAULT_DOCUMENT_DATE_FORMAT } from '@documenso/lib/constants/date-formats';
|
||||
@ -23,6 +24,7 @@ import {
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from '@documenso/ui/primitives/select';
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from '@documenso/ui/primitives/tooltip';
|
||||
|
||||
import { Combobox } from '../combobox';
|
||||
import { FormErrorMessage } from '../form/form-error-message';
|
||||
@ -69,7 +71,6 @@ export const AddSubjectFormPartial = ({
|
||||
message: document.documentMeta?.message ?? '',
|
||||
timezone: document.documentMeta?.timezone ?? DEFAULT_DOCUMENT_TIME_ZONE,
|
||||
dateFormat: document.documentMeta?.dateFormat ?? DEFAULT_DOCUMENT_DATE_FORMAT,
|
||||
redirectUrl: document.documentMeta?.redirectUrl ?? '',
|
||||
},
|
||||
},
|
||||
});
|
||||
@ -164,7 +165,6 @@ export const AddSubjectFormPartial = ({
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
{hasDateField && (
|
||||
<Accordion type="multiple" className="mt-8 border-none">
|
||||
<AccordionItem value="advanced-options" className="border-none">
|
||||
<AccordionTrigger className="mb-2 border-b text-left hover:no-underline">
|
||||
@ -172,6 +172,8 @@ export const AddSubjectFormPartial = ({
|
||||
</AccordionTrigger>
|
||||
|
||||
<AccordionContent className="text-muted-foreground -mx-1 flex max-w-prose flex-col px-1 text-sm leading-relaxed">
|
||||
{hasDateField && (
|
||||
<>
|
||||
<div className="mt-2 flex flex-col">
|
||||
<Label htmlFor="date-format">
|
||||
Date Format <span className="text-muted-foreground">(Optional)</span>
|
||||
@ -218,21 +220,29 @@ export const AddSubjectFormPartial = ({
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
<div className="flex flex-col">
|
||||
<div className="flex flex-col gap-y-4">
|
||||
<div>
|
||||
<Label htmlFor="redirectUrl">
|
||||
Title
|
||||
<span className="text-destructive ml-1 inline-block font-medium">
|
||||
*
|
||||
</span>
|
||||
<Label htmlFor="redirectUrl" className="flex items-center">
|
||||
Redirect URL{' '}
|
||||
<Tooltip>
|
||||
<TooltipTrigger>
|
||||
<Info className="mx-2 h-4 w-4" />
|
||||
</TooltipTrigger>
|
||||
|
||||
<TooltipContent className="text-muted-foreground max-w-xs">
|
||||
Add a URL to redirect the user to once the document is signed
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</Label>
|
||||
|
||||
<Input
|
||||
id="redirectUrl"
|
||||
type="url"
|
||||
className="bg-background my-2"
|
||||
disabled={isSubmitting}
|
||||
{...register('meta.redirectUrl')}
|
||||
/>
|
||||
|
||||
@ -243,7 +253,6 @@ export const AddSubjectFormPartial = ({
|
||||
</AccordionContent>
|
||||
</AccordionItem>
|
||||
</Accordion>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</DocumentFlowFormContainerContent>
|
||||
|
||||
@ -2,6 +2,7 @@ import { z } from 'zod';
|
||||
|
||||
import { DEFAULT_DOCUMENT_DATE_FORMAT } from '@documenso/lib/constants/date-formats';
|
||||
import { DEFAULT_DOCUMENT_TIME_ZONE } from '@documenso/lib/constants/time-zones';
|
||||
import { URL_REGEX } from '@documenso/lib/constants/url-regex';
|
||||
|
||||
export const ZAddSubjectFormSchema = z.object({
|
||||
meta: z.object({
|
||||
@ -9,7 +10,12 @@ export const ZAddSubjectFormSchema = z.object({
|
||||
message: z.string(),
|
||||
timezone: z.string().optional().default(DEFAULT_DOCUMENT_TIME_ZONE),
|
||||
dateFormat: z.string().optional().default(DEFAULT_DOCUMENT_DATE_FORMAT),
|
||||
redirectUrl: z.string().optional(),
|
||||
redirectUrl: z
|
||||
.string()
|
||||
.optional()
|
||||
.refine((value) => value === undefined || URL_REGEX.test(value), {
|
||||
message: 'Please enter a valid URL',
|
||||
}),
|
||||
}),
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user