mirror of
https://github.com/documenso/documenso.git
synced 2025-11-15 17:21:41 +10:00
chore: finalize template settings
Signed-off-by: Adithya Krishna <aadithya794@gmail.com>
This commit is contained in:
@ -1,16 +1,17 @@
|
||||
/* eslint-disable unused-imports/no-unused-imports */
|
||||
|
||||
/* eslint-disable @typescript-eslint/consistent-type-imports */
|
||||
|
||||
/* eslint-disable unused-imports/no-unused-vars */
|
||||
'use client';
|
||||
|
||||
import { useState } from 'react';
|
||||
|
||||
import { useRouter } from 'next/navigation';
|
||||
|
||||
import { DO_NOT_INVALIDATE_QUERY_ON_MUTATION } from '@documenso/lib/constants/trpc';
|
||||
import type { DocumentData, Field, Recipient, Template, User } from '@documenso/prisma/client';
|
||||
import type {
|
||||
DocumentData,
|
||||
Field,
|
||||
Recipient,
|
||||
Template,
|
||||
TemplateDocumentMeta,
|
||||
User,
|
||||
} from '@documenso/prisma/client';
|
||||
import { trpc } from '@documenso/trpc/react';
|
||||
import { cn } from '@documenso/ui/lib/utils';
|
||||
import { Card, CardContent } from '@documenso/ui/primitives/card';
|
||||
@ -26,13 +27,9 @@ import type { TAddTemplateFieldsFormSchema } from '@documenso/ui/primitives/temp
|
||||
import { AddTemplatePlaceholderRecipientsFormPartial } from '@documenso/ui/primitives/template-flow/add-template-placeholder-recipients';
|
||||
import type { TAddTemplatePlacholderRecipientsFormSchema } from '@documenso/ui/primitives/template-flow/add-template-placeholder-recipients.types';
|
||||
import { AddTemplateSettingsFormPartial } from '@documenso/ui/primitives/template-flow/add-template-settings';
|
||||
import { TTemplateSettingsFormSchema } from '@documenso/ui/primitives/template-flow/add-template-settings.types';
|
||||
import type { TTemplateSettingsFormSchema } from '@documenso/ui/primitives/template-flow/add-template-settings.types';
|
||||
import { useToast } from '@documenso/ui/primitives/use-toast';
|
||||
|
||||
/* eslint-disable unused-imports/no-unused-imports */
|
||||
/* eslint-disable @typescript-eslint/consistent-type-imports */
|
||||
/* eslint-disable unused-imports/no-unused-vars */
|
||||
|
||||
export type EditTemplateFormProps = {
|
||||
className?: string;
|
||||
user: User;
|
||||
@ -40,6 +37,7 @@ export type EditTemplateFormProps = {
|
||||
recipients: Recipient[];
|
||||
fields: Field[];
|
||||
documentData: DocumentData;
|
||||
documentMeta: TemplateDocumentMeta | null;
|
||||
templateRootPath: string;
|
||||
};
|
||||
|
||||
@ -54,16 +52,17 @@ export const EditTemplateForm = ({
|
||||
user: _user,
|
||||
documentData,
|
||||
templateRootPath,
|
||||
documentMeta,
|
||||
}: EditTemplateFormProps) => {
|
||||
const { toast } = useToast();
|
||||
const router = useRouter();
|
||||
|
||||
const [step, setStep] = useState<EditTemplateStep>('signers');
|
||||
const [step, setStep] = useState<EditTemplateStep>('settings');
|
||||
|
||||
const documentFlow: Record<EditTemplateStep, DocumentFlowStep> = {
|
||||
settings: {
|
||||
title: 'General',
|
||||
description: 'Configure general settings for the document.',
|
||||
title: 'Settings',
|
||||
description: 'Configure general settings for the template.',
|
||||
stepIndex: 1,
|
||||
},
|
||||
signers: {
|
||||
@ -82,6 +81,8 @@ export const EditTemplateForm = ({
|
||||
|
||||
const { mutateAsync: addTemplateFields } = trpc.field.addTemplateFields.useMutation();
|
||||
const { mutateAsync: addTemplateSigners } = trpc.recipient.addTemplateSigners.useMutation();
|
||||
const { mutateAsync: setSettingsForTemplate } =
|
||||
trpc.template.setSettingsForTemplate.useMutation();
|
||||
|
||||
const onAddTemplatePlaceholderFormSubmit = async (
|
||||
data: TAddTemplatePlacholderRecipientsFormSchema,
|
||||
@ -105,32 +106,28 @@ export const EditTemplateForm = ({
|
||||
};
|
||||
|
||||
const onAddTemplateSettingsFormSubmit = async (data: TTemplateSettingsFormSchema) => {
|
||||
// try {
|
||||
// const { timezone, dateFormat, redirectUrl } = data.meta;
|
||||
// await setSettingsForDocument({
|
||||
// documentId: document.id,
|
||||
// data: {
|
||||
// title: data.title,
|
||||
// globalAccessAuth: data.globalAccessAuth ?? null,
|
||||
// globalActionAuth: data.globalActionAuth ?? null,
|
||||
// },
|
||||
// meta: {
|
||||
// timezone,
|
||||
// dateFormat,
|
||||
// redirectUrl,
|
||||
// },
|
||||
// });
|
||||
// // Router refresh is here to clear the router cache for when navigating to /documents.
|
||||
// router.refresh();
|
||||
// setStep('signers');
|
||||
// } catch (err) {
|
||||
// console.error(err);
|
||||
// toast({
|
||||
// title: 'Error',
|
||||
// description: 'An error occurred while updating the document settings.',
|
||||
// variant: 'destructive',
|
||||
// });
|
||||
// }
|
||||
try {
|
||||
const { subject, message, timezone, dateFormat, redirectUrl } = data.meta;
|
||||
await setSettingsForTemplate({
|
||||
templateId: template.id,
|
||||
meta: {
|
||||
subject,
|
||||
message,
|
||||
timezone,
|
||||
dateFormat,
|
||||
redirectUrl,
|
||||
},
|
||||
});
|
||||
router.refresh();
|
||||
setStep('signers');
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
toast({
|
||||
title: 'Error',
|
||||
description: 'An error occurred while updating the template settings.',
|
||||
variant: 'destructive',
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const onAddFieldsFormSubmit = async (data: TAddTemplateFieldsFormSchema) => {
|
||||
@ -182,11 +179,12 @@ export const EditTemplateForm = ({
|
||||
setCurrentStep={(step) => setStep(EditTemplateSteps[step - 1])}
|
||||
>
|
||||
<AddTemplateSettingsFormPartial
|
||||
template={template}
|
||||
key={recipients.length}
|
||||
documentFlow={documentFlow.signers}
|
||||
documentFlow={documentFlow.settings}
|
||||
recipients={recipients}
|
||||
fields={fields}
|
||||
onSubmit={onAddTemplateSettingsFormSubmit}
|
||||
documentMeta={documentMeta}
|
||||
/>
|
||||
<AddTemplatePlaceholderRecipientsFormPartial
|
||||
key={recipients.length}
|
||||
|
||||
@ -79,7 +79,7 @@ export const TemplatePageView = async ({ params, team }: TemplatePageViewProps)
|
||||
recipients={templateRecipients}
|
||||
fields={templateFields}
|
||||
documentData={templateDocumentData}
|
||||
documemntMeta={templateDocumentMeta}
|
||||
documentMeta={templateDocumentMeta}
|
||||
templateRootPath={templateRootPath}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@ -21,6 +21,14 @@ export const upsertTemplateDocumentMeta = async ({
|
||||
password,
|
||||
redirectUrl,
|
||||
}: CreateTemplateDocumentMetaOptions) => {
|
||||
const templateDocumentMeta = await prisma.templateDocumentMeta.findFirstOrThrow({
|
||||
where: {
|
||||
templateId: templateId,
|
||||
},
|
||||
include: {
|
||||
template: true,
|
||||
},
|
||||
});
|
||||
return await prisma.$transaction(async (tx) => {
|
||||
const upsertedTemplateDocumentMeta = await tx.templateDocumentMeta.upsert({
|
||||
where: {
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import { TRPCError } from '@trpc/server';
|
||||
|
||||
import { getServerLimits } from '@documenso/ee/server-only/limits/server';
|
||||
import { upsertTemplateDocumentMeta } from '@documenso/lib/server-only/template-document-meta/upsert-template-document-meta';
|
||||
import { createDocumentFromTemplate } from '@documenso/lib/server-only/template/create-document-from-template';
|
||||
import { createTemplate } from '@documenso/lib/server-only/template/create-template';
|
||||
import { deleteTemplate } from '@documenso/lib/server-only/template/delete-template';
|
||||
@ -12,6 +13,7 @@ import {
|
||||
ZCreateTemplateMutationSchema,
|
||||
ZDeleteTemplateMutationSchema,
|
||||
ZDuplicateTemplateMutationSchema,
|
||||
ZSetSettingsForTemplateMutationSchema,
|
||||
} from './schema';
|
||||
|
||||
export const templateRouter = router({
|
||||
@ -104,4 +106,27 @@ export const templateRouter = router({
|
||||
});
|
||||
}
|
||||
}),
|
||||
setSettingsForTemplate: authenticatedProcedure
|
||||
.input(ZSetSettingsForTemplateMutationSchema)
|
||||
.mutation(async ({ input }) => {
|
||||
try {
|
||||
const { meta, templateId } = input;
|
||||
|
||||
return await upsertTemplateDocumentMeta({
|
||||
templateId,
|
||||
subject: meta.subject,
|
||||
message: meta.message,
|
||||
dateFormat: meta.dateFormat,
|
||||
timezone: meta.timezone,
|
||||
redirectUrl: meta.redirectUrl,
|
||||
});
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
|
||||
throw new TRPCError({
|
||||
code: 'BAD_REQUEST',
|
||||
message: 'We were unable to set template settings. Please try again later.',
|
||||
});
|
||||
}
|
||||
}),
|
||||
});
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import { z } from 'zod';
|
||||
|
||||
import { URL_REGEX } from '@documenso/lib/constants/url-regex';
|
||||
import { RecipientRole } from '@documenso/prisma/client';
|
||||
|
||||
export const ZCreateTemplateMutationSchema = z.object({
|
||||
@ -22,6 +23,22 @@ export const ZCreateDocumentFromTemplateMutationSchema = z.object({
|
||||
.optional(),
|
||||
});
|
||||
|
||||
export const ZSetSettingsForTemplateMutationSchema = z.object({
|
||||
templateId: z.number(),
|
||||
meta: z.object({
|
||||
subject: z.string().optional(),
|
||||
message: z.string().optional(),
|
||||
timezone: z.string().optional(),
|
||||
dateFormat: z.string().optional(),
|
||||
redirectUrl: z
|
||||
.string()
|
||||
.optional()
|
||||
.refine((value) => value === undefined || value === '' || URL_REGEX.test(value), {
|
||||
message: 'Please enter a valid URL',
|
||||
}),
|
||||
}),
|
||||
});
|
||||
|
||||
export const ZDuplicateTemplateMutationSchema = z.object({
|
||||
templateId: z.number(),
|
||||
teamId: z.number().optional(),
|
||||
|
||||
@ -7,11 +7,9 @@ import { InfoIcon } from 'lucide-react';
|
||||
import { useForm } from 'react-hook-form';
|
||||
|
||||
import { DATE_FORMATS, DEFAULT_DOCUMENT_DATE_FORMAT } from '@documenso/lib/constants/date-formats';
|
||||
import { DOCUMENT_AUTH_TYPES } from '@documenso/lib/constants/document-auth';
|
||||
import { DEFAULT_DOCUMENT_TIME_ZONE, TIME_ZONES } from '@documenso/lib/constants/time-zones';
|
||||
import { DocumentAccessAuth, DocumentActionAuth } from '@documenso/lib/types/document-auth';
|
||||
import { DocumentStatus, type Field, type Recipient, SendStatus } from '@documenso/prisma/client';
|
||||
import type { DocumentWithData } from '@documenso/prisma/types/document-with-data';
|
||||
import type { Template, TemplateDocumentMeta } from '@documenso/prisma/client';
|
||||
import { type Recipient, SendStatus } from '@documenso/prisma/client';
|
||||
import {
|
||||
Accordion,
|
||||
AccordionContent,
|
||||
@ -32,47 +30,42 @@ import {
|
||||
DocumentFlowFormContainerActions,
|
||||
DocumentFlowFormContainerContent,
|
||||
DocumentFlowFormContainerFooter,
|
||||
DocumentFlowFormContainerHeader,
|
||||
DocumentFlowFormContainerStep,
|
||||
} from '../document-flow/document-flow-root';
|
||||
import { ShowFieldItem } from '../document-flow/show-field-item';
|
||||
import type { DocumentFlowStep } from '../document-flow/types';
|
||||
import { Input } from '../input';
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '../select';
|
||||
import { useStep } from '../stepper';
|
||||
import { Textarea } from '../textarea';
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from '../tooltip';
|
||||
import type { TTemplateSettingsFormSchema } from './add-template-settings.types';
|
||||
import { ZTemplateSettingsFormSchema } from './add-template-settings.types';
|
||||
|
||||
export type AddSettingsFormProps = {
|
||||
template: Template;
|
||||
documentFlow: DocumentFlowStep;
|
||||
recipients: Recipient[];
|
||||
fields: Field[];
|
||||
isDocumentEnterprise: boolean;
|
||||
isDocumentPdfLoaded: boolean;
|
||||
document: DocumentWithData;
|
||||
documentMeta: TemplateDocumentMeta | null;
|
||||
onSubmit: (_data: TTemplateSettingsFormSchema) => void;
|
||||
};
|
||||
|
||||
export const AddTemplateSettingsFormPartial = ({
|
||||
documentFlow,
|
||||
recipients,
|
||||
fields,
|
||||
isDocumentEnterprise,
|
||||
isDocumentPdfLoaded,
|
||||
document,
|
||||
documentMeta,
|
||||
template,
|
||||
onSubmit,
|
||||
}: AddSettingsFormProps) => {
|
||||
const form = useForm<TTemplateSettingsFormSchema>({
|
||||
resolver: zodResolver(ZTemplateSettingsFormSchema),
|
||||
defaultValues: {
|
||||
title: document.title,
|
||||
globalAccessAuth: documentAuthOption?.globalAccessAuth || undefined,
|
||||
globalActionAuth: documentAuthOption?.globalActionAuth || undefined,
|
||||
title: template.title,
|
||||
meta: {
|
||||
timezone: document.documentMeta?.timezone ?? DEFAULT_DOCUMENT_TIME_ZONE,
|
||||
dateFormat: document.documentMeta?.dateFormat ?? DEFAULT_DOCUMENT_DATE_FORMAT,
|
||||
redirectUrl: document.documentMeta?.redirectUrl ?? '',
|
||||
subject: documentMeta?.subject ?? '',
|
||||
message: documentMeta?.message ?? '',
|
||||
timezone: documentMeta?.timezone ?? DEFAULT_DOCUMENT_TIME_ZONE,
|
||||
dateFormat: documentMeta?.dateFormat ?? DEFAULT_DOCUMENT_DATE_FORMAT,
|
||||
redirectUrl: documentMeta?.redirectUrl ?? '',
|
||||
},
|
||||
},
|
||||
});
|
||||
@ -83,8 +76,6 @@ export const AddTemplateSettingsFormPartial = ({
|
||||
(recipient) => recipient.sendStatus === SendStatus.SENT,
|
||||
);
|
||||
|
||||
// We almost always want to set the timezone to the user's local timezone to avoid confusion
|
||||
// when the document is signed.
|
||||
useEffect(() => {
|
||||
if (!form.formState.touchedFields.meta?.timezone && !documentHasBeenSent) {
|
||||
form.setValue('meta.timezone', Intl.DateTimeFormat().resolvedOptions().timeZone);
|
||||
@ -93,17 +84,7 @@ export const AddTemplateSettingsFormPartial = ({
|
||||
|
||||
return (
|
||||
<>
|
||||
<DocumentFlowFormContainerHeader
|
||||
title={documentFlow.title}
|
||||
description={documentFlow.description}
|
||||
/>
|
||||
|
||||
<DocumentFlowFormContainerContent>
|
||||
{isDocumentPdfLoaded &&
|
||||
fields.map((field, index) => (
|
||||
<ShowFieldItem key={index} field={field} recipients={recipients} />
|
||||
))}
|
||||
|
||||
<Form {...form}>
|
||||
<fieldset
|
||||
className="flex h-full flex-col space-y-6"
|
||||
@ -115,144 +96,14 @@ export const AddTemplateSettingsFormPartial = ({
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel required>Title</FormLabel>
|
||||
|
||||
<FormControl>
|
||||
<Input
|
||||
className="bg-background"
|
||||
{...field}
|
||||
disabled={document.status !== DocumentStatus.DRAFT || field.disabled}
|
||||
/>
|
||||
<Input className="bg-background" {...field} disabled={field.disabled} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="globalAccessAuth"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel className="flex flex-row items-center">
|
||||
Document access
|
||||
<Tooltip>
|
||||
<TooltipTrigger>
|
||||
<InfoIcon className="mx-2 h-4 w-4" />
|
||||
</TooltipTrigger>
|
||||
|
||||
<TooltipContent className="text-foreground max-w-md space-y-2 p-4">
|
||||
<h2>
|
||||
<strong>Document access</strong>
|
||||
</h2>
|
||||
|
||||
<p>The authentication required for recipients to view the document.</p>
|
||||
|
||||
<ul className="ml-3.5 list-outside list-disc space-y-0.5 py-2">
|
||||
<li>
|
||||
<strong>Require account</strong> - The recipient must be signed in to
|
||||
view the document
|
||||
</li>
|
||||
<li>
|
||||
<strong>None</strong> - The document can be accessed directly by the URL
|
||||
sent to the recipient
|
||||
</li>
|
||||
</ul>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</FormLabel>
|
||||
|
||||
<FormControl>
|
||||
<Select {...field} onValueChange={field.onChange}>
|
||||
<SelectTrigger className="bg-background text-muted-foreground">
|
||||
<SelectValue data-testid="documentAccessSelectValue" placeholder="None" />
|
||||
</SelectTrigger>
|
||||
|
||||
<SelectContent position="popper">
|
||||
{Object.values(DocumentAccessAuth).map((authType) => (
|
||||
<SelectItem key={authType} value={authType}>
|
||||
{DOCUMENT_AUTH_TYPES[authType].value}
|
||||
</SelectItem>
|
||||
))}
|
||||
|
||||
{/* Note: -1 is remapped in the Zod schema to the required value. */}
|
||||
<SelectItem value={'-1'}>None</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
{isDocumentEnterprise && (
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="globalActionAuth"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel className="flex flex-row items-center">
|
||||
Recipient action authentication
|
||||
<Tooltip>
|
||||
<TooltipTrigger>
|
||||
<InfoIcon className="mx-2 h-4 w-4" />
|
||||
</TooltipTrigger>
|
||||
|
||||
<TooltipContent className="text-foreground max-w-md space-y-2 p-4">
|
||||
<h2>
|
||||
<strong>Global recipient action authentication</strong>
|
||||
</h2>
|
||||
|
||||
<p>
|
||||
The authentication required for recipients to sign the signature field.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
This can be overriden by setting the authentication requirements
|
||||
directly on each recipient in the next step.
|
||||
</p>
|
||||
|
||||
<ul className="ml-3.5 list-outside list-disc space-y-0.5 py-2">
|
||||
<li>
|
||||
<strong>Require account</strong> - The recipient must be signed in
|
||||
</li>
|
||||
<li>
|
||||
<strong>Require passkey</strong> - The recipient must have an account
|
||||
and passkey configured via their settings
|
||||
</li>
|
||||
<li>
|
||||
<strong>Require 2FA</strong> - The recipient must have an account and
|
||||
2FA enabled via their settings
|
||||
</li>
|
||||
<li>
|
||||
<strong>None</strong> - No authentication required
|
||||
</li>
|
||||
</ul>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</FormLabel>
|
||||
|
||||
<FormControl>
|
||||
<Select {...field} onValueChange={field.onChange}>
|
||||
<SelectTrigger className="bg-background text-muted-foreground">
|
||||
<SelectValue data-testid="documentActionSelectValue" placeholder="None" />
|
||||
</SelectTrigger>
|
||||
|
||||
<SelectContent position="popper">
|
||||
{Object.values(DocumentActionAuth).map((authType) => (
|
||||
<SelectItem key={authType} value={authType}>
|
||||
{DOCUMENT_AUTH_TYPES[authType].value}
|
||||
</SelectItem>
|
||||
))}
|
||||
|
||||
{/* Note: -1 is remapped in the Zod schema to the required value. */}
|
||||
<SelectItem value={'-1'}>None</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
|
||||
<Accordion type="multiple" className="mt-6">
|
||||
<AccordionItem value="advanced-options" className="border-none">
|
||||
<AccordionTrigger className="text-foreground mb-2 rounded border px-3 py-2 text-left hover:bg-neutral-200/30 hover:no-underline">
|
||||
@ -293,6 +144,67 @@ export const AddTemplateSettingsFormPartial = ({
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="meta.subject"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel className="flex flex-row items-center">
|
||||
Subject{' '}
|
||||
<Tooltip>
|
||||
<TooltipTrigger>
|
||||
<InfoIcon className="mx-2 h-4 w-4" />
|
||||
</TooltipTrigger>
|
||||
|
||||
<TooltipContent className="text-muted-foreground max-w-xs">
|
||||
Add email subject
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</FormLabel>
|
||||
|
||||
<FormControl>
|
||||
<Input
|
||||
id="subject"
|
||||
className="bg-background mt-2"
|
||||
disabled={field.disabled}
|
||||
{...field}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="meta.message"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel className="flex flex-row items-center">
|
||||
Message{' '}
|
||||
<Tooltip>
|
||||
<TooltipTrigger>
|
||||
<InfoIcon className="mx-2 h-4 w-4" />
|
||||
</TooltipTrigger>
|
||||
|
||||
<TooltipContent className="text-muted-foreground max-w-xs">
|
||||
Add message to send in the email
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</FormLabel>
|
||||
|
||||
<FormControl>
|
||||
<Textarea
|
||||
id="message"
|
||||
className="bg-background mt-2 h-24 resize-none"
|
||||
{...field}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="meta.timezone"
|
||||
|
||||
@ -28,6 +28,8 @@ export const ZTemplateSettingsFormSchema = z.object({
|
||||
ZDocumentActionAuthTypesSchema.optional(),
|
||||
),
|
||||
meta: z.object({
|
||||
subject: z.string().optional(),
|
||||
message: z.string().optional(),
|
||||
timezone: z.string().optional().default(DEFAULT_DOCUMENT_TIME_ZONE),
|
||||
dateFormat: z.string().optional().default(DEFAULT_DOCUMENT_DATE_FORMAT),
|
||||
redirectUrl: z
|
||||
|
||||
Reference in New Issue
Block a user