mirror of
https://github.com/documenso/documenso.git
synced 2025-11-18 02:32:00 +10:00
chore: finish and clean-up redirect post signing
Signed-off-by: Adithya Krishna <adi@documenso.com>
This commit is contained in:
@ -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,86 +165,94 @@ 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">
|
||||
Advanced Options
|
||||
</AccordionTrigger>
|
||||
<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">
|
||||
Advanced Options
|
||||
</AccordionTrigger>
|
||||
|
||||
<AccordionContent className="text-muted-foreground -mx-1 flex max-w-prose flex-col px-1 text-sm leading-relaxed">
|
||||
<div className="mt-2 flex flex-col">
|
||||
<Label htmlFor="date-format">
|
||||
Date Format <span className="text-muted-foreground">(Optional)</span>
|
||||
</Label>
|
||||
<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>
|
||||
</Label>
|
||||
|
||||
<Controller
|
||||
control={control}
|
||||
name={`meta.dateFormat`}
|
||||
disabled={documentHasBeenSent}
|
||||
render={({ field: { value, onChange, disabled } }) => (
|
||||
<Select value={value} onValueChange={onChange} disabled={disabled}>
|
||||
<SelectTrigger className="bg-background mt-2">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<Controller
|
||||
control={control}
|
||||
name={`meta.dateFormat`}
|
||||
disabled={documentHasBeenSent}
|
||||
render={({ field: { value, onChange, disabled } }) => (
|
||||
<Select value={value} onValueChange={onChange} disabled={disabled}>
|
||||
<SelectTrigger className="bg-background mt-2">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
|
||||
<SelectContent>
|
||||
{DATE_FORMATS.map((format) => (
|
||||
<SelectItem key={format.key} value={format.value}>
|
||||
{format.label}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<SelectContent>
|
||||
{DATE_FORMATS.map((format) => (
|
||||
<SelectItem key={format.key} value={format.value}>
|
||||
{format.label}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="mt-4 flex flex-col">
|
||||
<Label htmlFor="time-zone">
|
||||
Time Zone <span className="text-muted-foreground">(Optional)</span>
|
||||
</Label>
|
||||
<div className="mt-4 flex flex-col">
|
||||
<Label htmlFor="time-zone">
|
||||
Time Zone <span className="text-muted-foreground">(Optional)</span>
|
||||
</Label>
|
||||
|
||||
<Controller
|
||||
control={control}
|
||||
name={`meta.timezone`}
|
||||
render={({ field: { value, onChange } }) => (
|
||||
<Combobox
|
||||
className="bg-background"
|
||||
options={TIME_ZONES}
|
||||
value={value}
|
||||
onChange={(value) => value && onChange(value)}
|
||||
disabled={documentHasBeenSent}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<Controller
|
||||
control={control}
|
||||
name={`meta.timezone`}
|
||||
render={({ field: { value, onChange } }) => (
|
||||
<Combobox
|
||||
className="bg-background"
|
||||
options={TIME_ZONES}
|
||||
value={value}
|
||||
onChange={(value) => value && onChange(value)}
|
||||
disabled={documentHasBeenSent}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</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>
|
||||
<div className="flex flex-col">
|
||||
<div className="flex flex-col gap-y-4">
|
||||
<div>
|
||||
<Label htmlFor="redirectUrl" className="flex items-center">
|
||||
Redirect URL{' '}
|
||||
<Tooltip>
|
||||
<TooltipTrigger>
|
||||
<Info className="mx-2 h-4 w-4" />
|
||||
</TooltipTrigger>
|
||||
|
||||
<Input
|
||||
id="redirectUrl"
|
||||
className="bg-background my-2"
|
||||
disabled={isSubmitting}
|
||||
{...register('meta.redirectUrl')}
|
||||
/>
|
||||
<TooltipContent className="text-muted-foreground max-w-xs">
|
||||
Add a URL to redirect the user to once the document is signed
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</Label>
|
||||
|
||||
<FormErrorMessage className="mt-2" error={errors.meta} />
|
||||
</div>
|
||||
<Input
|
||||
id="redirectUrl"
|
||||
type="url"
|
||||
className="bg-background my-2"
|
||||
{...register('meta.redirectUrl')}
|
||||
/>
|
||||
|
||||
<FormErrorMessage className="mt-2" error={errors.meta} />
|
||||
</div>
|
||||
</div>
|
||||
</AccordionContent>
|
||||
</AccordionItem>
|
||||
</Accordion>
|
||||
)}
|
||||
</div>
|
||||
</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