mirror of
https://github.com/hanzoai/sign.git
synced 2026-10-21 01:21:51 +00:00
fix(forms): type the app's other forms by their schema's input
The same @hookform/resolvers 5 change, in the dialogs, settings forms, the envelope editor and embedded authoring: `useForm<T>` pinned a form to its schema's output, the resolver no longer matches that, so each form lets the resolver type it, and whatever takes its control or context says input and output — Control<Input, unknown, Output>, UseFormReturn likewise. What the input exposed: - zod 4 types z.preprocess's input as unknown unless the function names it. The distribute dialog's and the settings dialog's emailReplyTo hold a string or nothing, and now say so, as the two flow steps do. - Combobox and ColorPicker already render an unset value as their placeholder and default; their props now allow one. - The embed's signature types and the editor's signers' actionAuth may be unset in the form. The multiselect reads `?? []` and the signer check `?? []`, the schemas' own defaults; every writer sets both, so nothing reachable changes. Co-authored-by: Hanzo Dev <[email protected]>
This commit is contained in:
@@ -65,7 +65,7 @@ export const ZEnvelopeDistributeFormSchema = z.object({
|
||||
meta: z.object({
|
||||
emailId: z.string().nullable(),
|
||||
emailReplyTo: z.preprocess(
|
||||
(val) => (val === '' ? undefined : val),
|
||||
(val: string | undefined) => (val === '' ? undefined : val),
|
||||
z.string().email().optional(),
|
||||
),
|
||||
subject: z.string(),
|
||||
@@ -99,7 +99,7 @@ export const EnvelopeDistributeDialog = ({
|
||||
'envelope.distribute',
|
||||
);
|
||||
|
||||
const form = useForm<TEnvelopeDistributeFormSchema>({
|
||||
const form = useForm({
|
||||
defaultValues: {
|
||||
meta: {
|
||||
emailId: envelope.documentMeta?.emailId ?? null,
|
||||
@@ -401,7 +401,7 @@ export const EnvelopeDistributeDialog = ({
|
||||
<TooltipTrigger type="button">
|
||||
<InfoIcon className="mx-2 h-4 w-4" />
|
||||
</TooltipTrigger>
|
||||
<TooltipContent className="p-4 text-muted-foreground">
|
||||
<TooltipContent className="text-muted-foreground p-4">
|
||||
<DocumentSendEmailMessageHelper />
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
@@ -409,7 +409,7 @@ export const EnvelopeDistributeDialog = ({
|
||||
|
||||
<FormControl>
|
||||
<Textarea
|
||||
className="mt-2 h-16 resize-none bg-background"
|
||||
className="bg-background mt-2 h-16 resize-none"
|
||||
{...field}
|
||||
maxLength={5000}
|
||||
/>
|
||||
@@ -429,7 +429,7 @@ export const EnvelopeDistributeDialog = ({
|
||||
exit={{ opacity: 0, transition: { duration: 0.15 } }}
|
||||
className="min-h-60 rounded-lg border"
|
||||
>
|
||||
<div className="py-24 text-center text-sm text-muted-foreground">
|
||||
<div className="text-muted-foreground py-24 text-center text-sm">
|
||||
<p>
|
||||
<Trans>We won't send anything to notify recipients.</Trans>
|
||||
</p>
|
||||
@@ -477,7 +477,7 @@ export const EnvelopeDistributeDialog = ({
|
||||
<AlertDescription>
|
||||
<Trans>The following signers are missing signature fields:</Trans>
|
||||
|
||||
<ul className="ml-2 mt-1 list-inside list-disc">
|
||||
<ul className="mt-1 ml-2 list-inside list-disc">
|
||||
{recipientsMissingSignatureFields.map((recipient) => (
|
||||
<li key={recipient.id}>
|
||||
{recipient.email || recipient.name || t`Recipient ${recipient.index + 1}`}
|
||||
@@ -490,7 +490,7 @@ export const EnvelopeDistributeDialog = ({
|
||||
<AlertDescription>
|
||||
<Trans>The following recipients require an email address:</Trans>
|
||||
|
||||
<ul className="ml-2 mt-1 list-inside list-disc">
|
||||
<ul className="mt-1 ml-2 list-inside list-disc">
|
||||
{recipientsMissingRequiredEmail.map((recipient) => (
|
||||
<li key={recipient.id}>
|
||||
{recipient.email || recipient.name || t`Recipient ${recipient.index + 1}`}
|
||||
|
||||
@@ -49,7 +49,7 @@ export const TemplateBulkSendDialog = ({
|
||||
|
||||
const team = useCurrentTeam();
|
||||
|
||||
const form = useForm<TBulkSendFormSchema>({
|
||||
const form = useForm({
|
||||
resolver: zodResolver(ZBulkSendFormSchema),
|
||||
defaultValues: {
|
||||
sendImmediately: false,
|
||||
@@ -141,12 +141,12 @@ export const TemplateBulkSendDialog = ({
|
||||
|
||||
<Form {...form}>
|
||||
<form onSubmit={form.handleSubmit(onSubmit)} className="flex flex-col gap-y-4">
|
||||
<div className="rounded-lg border bg-muted/70 p-4">
|
||||
<div className="bg-muted/70 rounded-lg border p-4">
|
||||
<h3 className="text-sm font-medium">
|
||||
<Trans>CSV Structure</Trans>
|
||||
</h3>
|
||||
|
||||
<p className="mt-1 text-sm text-muted-foreground">
|
||||
<p className="text-muted-foreground mt-1 text-sm">
|
||||
<Trans>
|
||||
For each recipient, provide their email (required) and name (optional) in separate
|
||||
columns. Download the template CSV below for the correct format.
|
||||
@@ -157,7 +157,7 @@ export const TemplateBulkSendDialog = ({
|
||||
<Trans>Current recipients:</Trans>
|
||||
</p>
|
||||
|
||||
<ul className="mt-2 list-inside list-disc text-sm text-muted-foreground">
|
||||
<ul className="text-muted-foreground mt-2 list-inside list-disc text-sm">
|
||||
{recipients.map((recipient, index) => (
|
||||
<li key={index}>
|
||||
{recipient.name ? `${recipient.name} (${recipient.email})` : recipient.email}
|
||||
@@ -171,7 +171,7 @@ export const TemplateBulkSendDialog = ({
|
||||
<Trans>Download Template CSV</Trans>
|
||||
</Button>
|
||||
|
||||
<p className="text-xs text-muted-foreground">
|
||||
<p className="text-muted-foreground text-xs">
|
||||
<Trans>Pre-formatted CSV template with example data.</Trans>
|
||||
</p>
|
||||
</div>
|
||||
@@ -204,14 +204,14 @@ export const TemplateBulkSendDialog = ({
|
||||
) : (
|
||||
<div className="flex h-10 items-center rounded-md border px-3">
|
||||
<div className="flex flex-1 items-center gap-2">
|
||||
<FileIcon className="h-4 w-4 text-muted-foreground" />
|
||||
<FileIcon className="text-muted-foreground h-4 w-4" />
|
||||
<span className="flex-1 truncate text-sm">{value.name}</span>
|
||||
</div>
|
||||
|
||||
<Button
|
||||
type="button"
|
||||
variant="link"
|
||||
className="p-0 text-xs text-destructive hover:text-destructive"
|
||||
className="text-destructive hover:text-destructive p-0 text-xs"
|
||||
onClick={() => onChange(null)}
|
||||
disabled={form.formState.isSubmitting}
|
||||
>
|
||||
@@ -224,9 +224,9 @@ export const TemplateBulkSendDialog = ({
|
||||
)}
|
||||
</FormControl>
|
||||
|
||||
{error && <p className="text-sm text-destructive">{error.message}</p>}
|
||||
{error && <p className="text-destructive text-sm">{error.message}</p>}
|
||||
|
||||
<p className="text-xs text-muted-foreground">
|
||||
<p className="text-muted-foreground text-xs">
|
||||
<Trans>
|
||||
Maximum file size: 4MB. Maximum 100 rows per upload. Blank values will use
|
||||
template defaults.
|
||||
@@ -251,7 +251,7 @@ export const TemplateBulkSendDialog = ({
|
||||
|
||||
<label
|
||||
htmlFor="send-immediately"
|
||||
className="ml-2 flex items-center text-sm text-muted-foreground"
|
||||
className="text-muted-foreground ml-2 flex items-center text-sm"
|
||||
>
|
||||
<Trans>Send documents to recipients immediately</Trans>
|
||||
</label>
|
||||
|
||||
@@ -149,7 +149,7 @@ export function TemplateUseDialog({
|
||||
};
|
||||
};
|
||||
|
||||
const form = useForm<TAddRecipientsForNewDocumentSchema>({
|
||||
const form = useForm({
|
||||
resolver: zodResolver(ZAddRecipientsForNewDocumentSchema),
|
||||
defaultValues: generateDefaultFormValues(),
|
||||
});
|
||||
@@ -252,7 +252,7 @@ export function TemplateUseDialog({
|
||||
<DialogTrigger asChild>
|
||||
{trigger || (
|
||||
<Button variant="outline" className="bg-background">
|
||||
<Plus className="-ml-1 mr-2 h-4 w-4" />
|
||||
<Plus className="mr-2 -ml-1 h-4 w-4" />
|
||||
<Trans>Use Template</Trans>
|
||||
</Button>
|
||||
)}
|
||||
@@ -365,7 +365,7 @@ export function TemplateUseDialog({
|
||||
|
||||
{documentDistributionMethod === DocumentDistributionMethod.EMAIL && (
|
||||
<label
|
||||
className="ml-2 flex items-center text-sm text-muted-foreground"
|
||||
className="text-muted-foreground ml-2 flex items-center text-sm"
|
||||
htmlFor="distributeDocument"
|
||||
>
|
||||
<Trans>Send document</Trans>
|
||||
@@ -374,7 +374,7 @@ export function TemplateUseDialog({
|
||||
<InfoIcon className="mx-1 h-4 w-4" />
|
||||
</TooltipTrigger>
|
||||
|
||||
<TooltipContent className="z-[99999] max-w-md space-y-2 p-4 text-muted-foreground">
|
||||
<TooltipContent className="text-muted-foreground z-[99999] max-w-md space-y-2 p-4">
|
||||
<p>
|
||||
<Trans>
|
||||
The document will be immediately sent to recipients if this
|
||||
@@ -394,7 +394,7 @@ export function TemplateUseDialog({
|
||||
|
||||
{documentDistributionMethod === DocumentDistributionMethod.NONE && (
|
||||
<label
|
||||
className="ml-2 flex items-center text-sm text-muted-foreground"
|
||||
className="text-muted-foreground ml-2 flex items-center text-sm"
|
||||
htmlFor="distributeDocument"
|
||||
>
|
||||
<Trans>Create as pending</Trans>
|
||||
@@ -402,7 +402,7 @@ export function TemplateUseDialog({
|
||||
<TooltipTrigger type="button">
|
||||
<InfoIcon className="mx-1 h-4 w-4" />
|
||||
</TooltipTrigger>
|
||||
<TooltipContent className="z-[99999] max-w-md space-y-2 p-4 text-muted-foreground">
|
||||
<TooltipContent className="text-muted-foreground z-[99999] max-w-md space-y-2 p-4">
|
||||
<p>
|
||||
<Trans>
|
||||
Create the document as pending and ready to sign.
|
||||
@@ -448,7 +448,7 @@ export function TemplateUseDialog({
|
||||
}}
|
||||
/>
|
||||
<label
|
||||
className="ml-2 flex items-center text-sm text-muted-foreground"
|
||||
className="text-muted-foreground ml-2 flex items-center text-sm"
|
||||
htmlFor="useCustomDocument"
|
||||
>
|
||||
<Trans>Upload custom document</Trans>
|
||||
@@ -456,7 +456,7 @@ export function TemplateUseDialog({
|
||||
<TooltipTrigger type="button">
|
||||
<InfoIcon className="mx-1 h-4 w-4" />
|
||||
</TooltipTrigger>
|
||||
<TooltipContent className="z-[99999] max-w-md space-y-2 p-4 text-muted-foreground">
|
||||
<TooltipContent className="text-muted-foreground z-[99999] max-w-md space-y-2 p-4">
|
||||
<p>
|
||||
<Trans>
|
||||
Upload a custom document to use instead of the template's default
|
||||
@@ -486,19 +486,19 @@ export function TemplateUseDialog({
|
||||
<FormControl>
|
||||
<div
|
||||
key={item.id}
|
||||
className="flex items-center gap-4 rounded-lg border border-border bg-card p-4 transition-colors hover:bg-accent/10"
|
||||
className="border-border bg-card hover:bg-accent/10 flex items-center gap-4 rounded-lg border p-4 transition-colors"
|
||||
>
|
||||
<div className="flex-shrink-0">
|
||||
<div className="flex h-10 w-10 items-center justify-center rounded-lg bg-primary/10">
|
||||
<FileTextIcon className="h-5 w-5 text-primary" />
|
||||
<div className="bg-primary/10 flex h-10 w-10 items-center justify-center rounded-lg">
|
||||
<FileTextIcon className="text-primary h-5 w-5" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="min-w-0 flex-1">
|
||||
<h4 className="truncate text-sm font-medium text-foreground">
|
||||
<h4 className="text-foreground truncate text-sm font-medium">
|
||||
{item.title}
|
||||
</h4>
|
||||
<p className="mt-0.5 text-xs text-muted-foreground">
|
||||
<p className="text-muted-foreground mt-0.5 text-xs">
|
||||
{field.value ? (
|
||||
<div>
|
||||
<Trans>
|
||||
|
||||
@@ -35,10 +35,13 @@ import { Textarea } from '@hanzo/esign-ui/primitives/textarea';
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from '@hanzo/esign-ui/primitives/tooltip';
|
||||
|
||||
import { useConfigureDocument } from './configure-document-context';
|
||||
import type { TConfigureEmbedFormSchema } from './configure-document-view.types';
|
||||
import type {
|
||||
TConfigureEmbedFormInput,
|
||||
TConfigureEmbedFormSchema,
|
||||
} from './configure-document-view.types';
|
||||
|
||||
interface ConfigureDocumentAdvancedSettingsProps {
|
||||
control: Control<TConfigureEmbedFormSchema>;
|
||||
control: Control<TConfigureEmbedFormInput, unknown, TConfigureEmbedFormSchema>;
|
||||
isSubmitting: boolean;
|
||||
}
|
||||
|
||||
@@ -48,7 +51,7 @@ export const ConfigureDocumentAdvancedSettings = ({
|
||||
}: ConfigureDocumentAdvancedSettingsProps) => {
|
||||
const { _ } = useLingui();
|
||||
|
||||
const form = useFormContext<TConfigureEmbedFormSchema>();
|
||||
const form = useFormContext<TConfigureEmbedFormInput, unknown, TConfigureEmbedFormSchema>();
|
||||
const { features } = useConfigureDocument();
|
||||
|
||||
const { watch, setValue } = form;
|
||||
@@ -98,7 +101,7 @@ export const ConfigureDocumentAdvancedSettings = ({
|
||||
label: _(option.label),
|
||||
value: option.value,
|
||||
}))}
|
||||
selectedValues={field.value}
|
||||
selectedValues={field.value ?? []}
|
||||
onChange={field.onChange}
|
||||
className="bg-background w-full"
|
||||
emptySelectionPlaceholder={t`Select signature types`}
|
||||
|
||||
@@ -27,13 +27,16 @@ import { Input } from '@hanzo/esign-ui/primitives/input';
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from '@hanzo/esign-ui/primitives/tooltip';
|
||||
|
||||
import { useConfigureDocument } from './configure-document-context';
|
||||
import type { TConfigureEmbedFormSchema } from './configure-document-view.types';
|
||||
import type {
|
||||
TConfigureEmbedFormInput,
|
||||
TConfigureEmbedFormSchema,
|
||||
} from './configure-document-view.types';
|
||||
|
||||
// Define a type for signer items
|
||||
type SignerItem = TConfigureEmbedFormSchema['signers'][number];
|
||||
|
||||
export interface ConfigureDocumentRecipientsProps {
|
||||
control: Control<TConfigureEmbedFormSchema>;
|
||||
control: Control<TConfigureEmbedFormInput, unknown, TConfigureEmbedFormSchema>;
|
||||
isSubmitting: boolean;
|
||||
}
|
||||
|
||||
@@ -57,7 +60,11 @@ export const ConfigureDocumentRecipients = ({
|
||||
name: 'signers',
|
||||
});
|
||||
|
||||
const { getValues, watch, setValue } = useFormContext<TConfigureEmbedFormSchema>();
|
||||
const { getValues, watch, setValue } = useFormContext<
|
||||
TConfigureEmbedFormInput,
|
||||
unknown,
|
||||
TConfigureEmbedFormSchema
|
||||
>();
|
||||
|
||||
const signingOrder = watch('meta.signingOrder');
|
||||
|
||||
@@ -158,7 +165,7 @@ export const ConfigureDocumentRecipients = ({
|
||||
control={control}
|
||||
name="meta.signingOrder"
|
||||
render={({ field }) => (
|
||||
<FormItem className="mb-6 flex flex-row items-center space-x-2 space-y-0">
|
||||
<FormItem className="mb-6 flex flex-row items-center space-y-0 space-x-2">
|
||||
<FormControl>
|
||||
<Checkbox
|
||||
{...field}
|
||||
@@ -186,7 +193,7 @@ export const ConfigureDocumentRecipients = ({
|
||||
control={control}
|
||||
name="meta.allowDictateNextSigner"
|
||||
render={({ field: { value, ...field } }) => (
|
||||
<FormItem className="mb-6 flex flex-row items-center space-x-2 space-y-0">
|
||||
<FormItem className="mb-6 flex flex-row items-center space-y-0 space-x-2">
|
||||
<FormControl>
|
||||
<Checkbox
|
||||
{...field}
|
||||
@@ -276,7 +283,7 @@ export const ConfigureDocumentRecipients = ({
|
||||
type="number"
|
||||
max={signers.length}
|
||||
min={1}
|
||||
className="w-full text-center [appearance:textfield] [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:appearance-none"
|
||||
className="w-full [appearance:textfield] text-center [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:appearance-none"
|
||||
{...field}
|
||||
disabled={isSubmitting || snapshot.isDragging}
|
||||
onChange={(e) => {
|
||||
@@ -403,7 +410,7 @@ export const ConfigureDocumentRecipients = ({
|
||||
disabled={isSubmitting}
|
||||
onClick={onAddSigner}
|
||||
>
|
||||
<Plus className="-ml-1 mr-2 h-5 w-5" />
|
||||
<Plus className="mr-2 -ml-1 h-5 w-5" />
|
||||
<Trans>Add Signer</Trans>
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -20,7 +20,10 @@ import {
|
||||
import { useToast } from '@hanzo/esign-ui/primitives/use-toast';
|
||||
|
||||
import { useConfigureDocument } from './configure-document-context';
|
||||
import type { TConfigureEmbedFormSchema } from './configure-document-view.types';
|
||||
import type {
|
||||
TConfigureEmbedFormInput,
|
||||
TConfigureEmbedFormSchema,
|
||||
} from './configure-document-view.types';
|
||||
|
||||
export interface ConfigureDocumentUploadProps {
|
||||
isSubmitting?: boolean;
|
||||
@@ -31,7 +34,7 @@ export const ConfigureDocumentUpload = ({ isSubmitting = false }: ConfigureDocum
|
||||
const { toast } = useToast();
|
||||
const { isPersisted } = useConfigureDocument();
|
||||
|
||||
const form = useFormContext<TConfigureEmbedFormSchema>();
|
||||
const form = useFormContext<TConfigureEmbedFormInput, unknown, TConfigureEmbedFormSchema>();
|
||||
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@ export const ConfigureDocumentView = ({
|
||||
}: ConfigureDocumentViewProps) => {
|
||||
const { isTemplate } = useConfigureDocument();
|
||||
|
||||
const form = useForm<TConfigureEmbedFormSchema>({
|
||||
const form = useForm({
|
||||
resolver: zodResolver(
|
||||
type === 'template' ? ZConfigureTemplateEmbedFormSchema : ZConfigureEmbedFormSchema,
|
||||
),
|
||||
|
||||
@@ -11,6 +11,9 @@ import { DocumentDistributionMethod } from '@hanzo/esign-prisma/generated/types'
|
||||
// Define the schema for configuration
|
||||
export type TConfigureEmbedFormSchema = z.infer<typeof ZConfigureEmbedFormSchema>;
|
||||
|
||||
// What the form holds, before the schema fills in its defaults.
|
||||
export type TConfigureEmbedFormInput = z.input<typeof ZConfigureEmbedFormSchema>;
|
||||
|
||||
export const ZConfigureEmbedFormSchema = z.object({
|
||||
title: z.string().min(1, { message: 'Title is required' }),
|
||||
signers: z
|
||||
|
||||
@@ -10,7 +10,10 @@ import { z } from 'zod';
|
||||
import { useCurrentOrganisation } from '@hanzo/esign-lib/client-only/providers/organisation';
|
||||
import { useSession } from '@hanzo/esign-lib/client-only/providers/session';
|
||||
import { DATE_FORMATS } from '@hanzo/esign-lib/constants/date-formats';
|
||||
import { DOCUMENT_SIGNATURE_TYPES, DocumentSignatureType } from '@hanzo/esign-lib/constants/document';
|
||||
import {
|
||||
DOCUMENT_SIGNATURE_TYPES,
|
||||
DocumentSignatureType,
|
||||
} from '@hanzo/esign-lib/constants/document';
|
||||
import {
|
||||
type TEnvelopeExpirationPeriod,
|
||||
ZEnvelopeExpirationPeriod,
|
||||
@@ -136,7 +139,7 @@ export const DocumentPreferencesForm = ({
|
||||
envelopeExpirationPeriod: ZEnvelopeExpirationPeriod.nullable(),
|
||||
});
|
||||
|
||||
const form = useForm<TDocumentPreferencesFormSchema>({
|
||||
const form = useForm({
|
||||
defaultValues: {
|
||||
documentVisibility: settings.documentVisibility,
|
||||
documentLanguage: isValidLanguageCode(settings.documentLanguage)
|
||||
@@ -347,7 +350,7 @@ export const DocumentPreferencesForm = ({
|
||||
}))}
|
||||
selectedValues={field.value}
|
||||
onChange={field.onChange}
|
||||
className="w-full bg-background"
|
||||
className="bg-background w-full"
|
||||
enableSearch={false}
|
||||
emptySelectionPlaceholder={
|
||||
canInherit ? t`Inherit from organisation` : t`Select signature types`
|
||||
@@ -413,7 +416,7 @@ export const DocumentPreferencesForm = ({
|
||||
</FormControl>
|
||||
|
||||
<div className="pt-2">
|
||||
<div className="text-xs font-medium text-muted-foreground">
|
||||
<div className="text-muted-foreground text-xs font-medium">
|
||||
<Trans>Preview</Trans>
|
||||
</div>
|
||||
|
||||
@@ -599,7 +602,7 @@ export const DocumentPreferencesForm = ({
|
||||
}
|
||||
secondaryText={
|
||||
recipient.name ? (
|
||||
<span className="text-xs text-muted-foreground">
|
||||
<span className="text-muted-foreground text-xs">
|
||||
{recipient.email}
|
||||
</span>
|
||||
) : undefined
|
||||
|
||||
@@ -10,8 +10,8 @@ import {
|
||||
DEFAULT_DOCUMENT_EMAIL_SETTINGS,
|
||||
ZDocumentEmailSettingsSchema,
|
||||
} from '@hanzo/esign-lib/types/document-email';
|
||||
import { useZapQuery } from '@hanzo/esign-trpc/zap/react';
|
||||
import type { TFindOrganisationEmailsResponse } from '@hanzo/esign-trpc/server/organisation-router/find-organisation-emails.types';
|
||||
import { useZapQuery } from '@hanzo/esign-trpc/zap/react';
|
||||
import { DocumentEmailCheckboxes } from '@hanzo/esign-ui/components/document/document-email-checkboxes';
|
||||
import { Button } from '@hanzo/esign-ui/primitives/button';
|
||||
import {
|
||||
@@ -59,7 +59,7 @@ export const EmailPreferencesForm = ({
|
||||
}: EmailPreferencesFormProps) => {
|
||||
const organisation = useCurrentOrganisation();
|
||||
|
||||
const form = useForm<TEmailPreferencesFormSchema>({
|
||||
const form = useForm({
|
||||
defaultValues: {
|
||||
emailId: settings.emailId,
|
||||
emailReplyTo: settings.emailReplyTo,
|
||||
|
||||
+10
-10
@@ -16,13 +16,13 @@ import { useFieldArray, useWatch } from 'react-hook-form';
|
||||
import { useRevalidator, useSearchParams } from 'react-router';
|
||||
import { isDeepEqual } from 'remeda';
|
||||
|
||||
import { useLimits } from '@hanzo/esign-lib/server-only/limits/provider/client';
|
||||
import { useDebouncedValue } from '@hanzo/esign-lib/client-only/hooks/use-debounced-value';
|
||||
import { ZEditorRecipientsFormSchema } from '@hanzo/esign-lib/client-only/hooks/use-editor-recipients';
|
||||
import { useCurrentEnvelopeEditor } from '@hanzo/esign-lib/client-only/providers/envelope-editor-provider';
|
||||
import { useCurrentOrganisation } from '@hanzo/esign-lib/client-only/providers/organisation';
|
||||
import { useOptionalSession } from '@hanzo/esign-lib/client-only/providers/session';
|
||||
import type { TDetectedRecipientSchema } from '@hanzo/esign-lib/server-only/ai/envelope/detect-recipients/schema';
|
||||
import { useLimits } from '@hanzo/esign-lib/server-only/limits/provider/client';
|
||||
import { ZRecipientAuthOptionsSchema } from '@hanzo/esign-lib/types/document-auth';
|
||||
import { nanoid } from '@hanzo/esign-lib/universal/id';
|
||||
import { canRecipientBeModified as utilCanRecipientBeModified } from '@hanzo/esign-lib/utils/recipients';
|
||||
@@ -162,7 +162,7 @@ export const EnvelopeEditorRecipientForm = () => {
|
||||
|
||||
const formHasActionAuth = form
|
||||
.getValues('signers')
|
||||
.find((signer) => signer.actionAuth.length > 0);
|
||||
.find((signer) => (signer.actionAuth ?? []).length > 0);
|
||||
|
||||
return recipientHasAuthOptions !== undefined || formHasActionAuth !== undefined;
|
||||
}, [recipients, form]);
|
||||
@@ -658,7 +658,7 @@ export const EnvelopeEditorRecipientForm = () => {
|
||||
disabled={isSubmitting || signers.length >= remaining.recipients}
|
||||
onClick={() => onAddSigner()}
|
||||
>
|
||||
<PlusIcon className="-ml-1 mr-1 h-5 w-5" />
|
||||
<PlusIcon className="mr-1 -ml-1 h-5 w-5" />
|
||||
<Trans>Add Signer</Trans>
|
||||
</Button>
|
||||
</div>
|
||||
@@ -667,7 +667,7 @@ export const EnvelopeEditorRecipientForm = () => {
|
||||
<CardContent>
|
||||
<Form {...form}>
|
||||
<div
|
||||
className={cn('-mt-2 mb-2 space-y-4 rounded-md bg-accent/50 p-4', {
|
||||
className={cn('bg-accent/50 -mt-2 mb-2 space-y-4 rounded-md p-4', {
|
||||
hidden:
|
||||
!editorConfig.recipients?.allowConfigureSigningOrder &&
|
||||
!organisation.organisationClaim.flags.cfr21,
|
||||
@@ -695,7 +695,7 @@ export const EnvelopeEditorRecipientForm = () => {
|
||||
control={form.control}
|
||||
name="signingOrder"
|
||||
render={({ field }) => (
|
||||
<FormItem className="flex flex-row items-center space-x-2 space-y-0">
|
||||
<FormItem className="flex flex-row items-center space-y-0 space-x-2">
|
||||
<FormControl>
|
||||
<Checkbox
|
||||
{...field}
|
||||
@@ -735,7 +735,7 @@ export const EnvelopeEditorRecipientForm = () => {
|
||||
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<span className="ml-1 cursor-help text-muted-foreground">
|
||||
<span className="text-muted-foreground ml-1 cursor-help">
|
||||
<HelpCircleIcon className="h-3.5 w-3.5" />
|
||||
</span>
|
||||
</TooltipTrigger>
|
||||
@@ -756,7 +756,7 @@ export const EnvelopeEditorRecipientForm = () => {
|
||||
control={form.control}
|
||||
name="allowDictateNextSigner"
|
||||
render={({ field: { value, ...field } }) => (
|
||||
<FormItem className="flex flex-row items-center space-x-2 space-y-0">
|
||||
<FormItem className="flex flex-row items-center space-y-0 space-x-2">
|
||||
<FormControl>
|
||||
<Checkbox
|
||||
{...field}
|
||||
@@ -779,7 +779,7 @@ export const EnvelopeEditorRecipientForm = () => {
|
||||
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<span className="ml-1 cursor-help text-muted-foreground">
|
||||
<span className="text-muted-foreground ml-1 cursor-help">
|
||||
<HelpCircleIcon className="h-3.5 w-3.5" />
|
||||
</span>
|
||||
</TooltipTrigger>
|
||||
@@ -838,7 +838,7 @@ export const EnvelopeEditorRecipientForm = () => {
|
||||
{...provided.draggableProps}
|
||||
{...provided.dragHandleProps}
|
||||
className={cn('py-1', {
|
||||
'pointer-events-none rounded-md bg-widget-foreground pt-2':
|
||||
'bg-widget-foreground pointer-events-none rounded-md pt-2':
|
||||
snapshot.isDragging,
|
||||
})}
|
||||
>
|
||||
@@ -860,7 +860,7 @@ export const EnvelopeEditorRecipientForm = () => {
|
||||
render={({ field }) => (
|
||||
<FormItem
|
||||
className={cn(
|
||||
'mt-auto flex items-center gap-x-1 space-y-0',
|
||||
'mt-auto flex items-center space-y-0 gap-x-1',
|
||||
{
|
||||
'mb-6':
|
||||
form.formState.errors.signers?.[index] &&
|
||||
|
||||
+11
-11
@@ -136,7 +136,7 @@ export const ZAddSettingsFormSchema = z.object({
|
||||
.default('en'),
|
||||
emailId: z.string().nullable(),
|
||||
emailReplyTo: z.preprocess(
|
||||
(val) => (val === '' ? undefined : val),
|
||||
(val: string | undefined) => (val === '' ? undefined : val),
|
||||
z.string().email().optional(),
|
||||
),
|
||||
emailSettings: ZDocumentEmailSettingsSchema,
|
||||
@@ -224,7 +224,7 @@ export const EnvelopeEditorSettingsDialog = ({
|
||||
};
|
||||
};
|
||||
|
||||
const form = useForm<TAddSettingsFormSchema>({
|
||||
const form = useForm({
|
||||
resolver: zodResolver(ZAddSettingsFormSchema),
|
||||
defaultValues: createDefaultValues(),
|
||||
});
|
||||
@@ -363,7 +363,7 @@ export const EnvelopeEditorSettingsDialog = ({
|
||||
|
||||
<DialogContent className="flex w-full !max-w-5xl flex-row gap-0 p-0">
|
||||
{/* Sidebar. */}
|
||||
<div className="flex w-80 flex-col border-r bg-accent/20">
|
||||
<div className="bg-accent/20 flex w-80 flex-col border-r">
|
||||
<DialogHeader className="p-6 pb-4" data-testid="envelope-editor-settings-dialog-header">
|
||||
<DialogTitle>
|
||||
<Trans>Document Settings</Trans>
|
||||
@@ -423,7 +423,7 @@ export const EnvelopeEditorSettingsDialog = ({
|
||||
<InfoIcon className="mx-2 h-4 w-4" />
|
||||
</TooltipTrigger>
|
||||
|
||||
<TooltipContent className="max-w-md space-y-2 p-4 text-foreground">
|
||||
<TooltipContent className="text-foreground max-w-md space-y-2 p-4">
|
||||
<Trans>
|
||||
Controls the language for the document, including the language
|
||||
to be used for email notifications, and the final certificate
|
||||
@@ -479,7 +479,7 @@ export const EnvelopeEditorSettingsDialog = ({
|
||||
)}
|
||||
selectedValues={field.value}
|
||||
onChange={field.onChange}
|
||||
className="w-full bg-background"
|
||||
className="bg-background w-full"
|
||||
emptySelectionPlaceholder="Select signature types"
|
||||
/>
|
||||
</FormControl>
|
||||
@@ -564,7 +564,7 @@ export const EnvelopeEditorSettingsDialog = ({
|
||||
<InfoIcon className="mx-2 h-4 w-4" />
|
||||
</TooltipTrigger>
|
||||
|
||||
<TooltipContent className="max-w-xs text-muted-foreground">
|
||||
<TooltipContent className="text-muted-foreground max-w-xs">
|
||||
<Trans>
|
||||
Add an external ID to the document. This can be used to identify
|
||||
the document in external systems.
|
||||
@@ -594,7 +594,7 @@ export const EnvelopeEditorSettingsDialog = ({
|
||||
<InfoIcon className="mx-2 h-4 w-4" />
|
||||
</TooltipTrigger>
|
||||
|
||||
<TooltipContent className="max-w-xs text-muted-foreground">
|
||||
<TooltipContent className="text-muted-foreground max-w-xs">
|
||||
<Trans>
|
||||
Add a URL to redirect the user to once the document is signed
|
||||
</Trans>
|
||||
@@ -624,7 +624,7 @@ export const EnvelopeEditorSettingsDialog = ({
|
||||
<InfoIcon className="mx-2 h-4 w-4" />
|
||||
</TooltipTrigger>
|
||||
|
||||
<TooltipContent className="max-w-md space-y-2 p-4 text-foreground">
|
||||
<TooltipContent className="text-foreground max-w-md space-y-2 p-4">
|
||||
<h2>
|
||||
<strong>
|
||||
<Trans>Document Distribution Method</Trans>
|
||||
@@ -697,7 +697,7 @@ export const EnvelopeEditorSettingsDialog = ({
|
||||
<InfoIcon className="mx-2 h-4 w-4" />
|
||||
</TooltipTrigger>
|
||||
|
||||
<TooltipContent className="max-w-xs text-muted-foreground">
|
||||
<TooltipContent className="text-muted-foreground max-w-xs">
|
||||
<Trans>
|
||||
How long recipients have to complete this document after it is
|
||||
sent. Uses the team default when set to inherit.
|
||||
@@ -825,14 +825,14 @@ export const EnvelopeEditorSettingsDialog = ({
|
||||
<TooltipTrigger>
|
||||
<InfoIcon className="mx-2 h-4 w-4" />
|
||||
</TooltipTrigger>
|
||||
<TooltipContent className="p-4 text-muted-foreground">
|
||||
<TooltipContent className="text-muted-foreground p-4">
|
||||
<DocumentSendEmailMessageHelper />
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</FormLabel>
|
||||
|
||||
<FormControl>
|
||||
<Textarea className="h-16 resize-none bg-background" {...field} />
|
||||
<Textarea className="bg-background h-16 resize-none" {...field} />
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
|
||||
@@ -54,7 +54,7 @@ export default function AdminBannerPage({ loaderData }: Route.ComponentProps) {
|
||||
const { _ } = useLingui();
|
||||
const { revalidate } = useRevalidator();
|
||||
|
||||
const form = useForm<TBannerFormSchema>({
|
||||
const form = useForm({
|
||||
resolver: zodResolver(ZBannerFormSchema),
|
||||
defaultValues: {
|
||||
id: SITE_SETTINGS_BANNER_ID,
|
||||
|
||||
@@ -34,6 +34,9 @@ export const ZEditorRecipientsFormSchema = z.object({
|
||||
|
||||
export type TEditorRecipientsFormSchema = z.infer<typeof ZEditorRecipientsFormSchema>;
|
||||
|
||||
// What the form holds while it is edited, before the schema fills in its defaults.
|
||||
export type TEditorRecipientsFormInput = z.input<typeof ZEditorRecipientsFormSchema>;
|
||||
|
||||
type EditorRecipientsProps = {
|
||||
envelope: TEditorEnvelope;
|
||||
};
|
||||
@@ -44,7 +47,7 @@ type ResetFormOptions = {
|
||||
};
|
||||
|
||||
type UseEditorRecipientsResponse = {
|
||||
form: UseFormReturn<TEditorRecipientsFormSchema>;
|
||||
form: UseFormReturn<TEditorRecipientsFormInput, unknown, TEditorRecipientsFormSchema>;
|
||||
resetForm: (options?: ResetFormOptions) => void;
|
||||
};
|
||||
|
||||
@@ -88,7 +91,7 @@ export const useEditorRecipients = ({
|
||||
};
|
||||
};
|
||||
|
||||
const form = useForm<TEditorRecipientsFormSchema>({
|
||||
const form = useForm({
|
||||
defaultValues: generateDefaultValues(),
|
||||
resolver: zodResolver(ZEditorRecipientsFormSchema),
|
||||
mode: 'onChange', // Used for autosave purposes, maybe can try onBlur instead?
|
||||
|
||||
@@ -8,7 +8,7 @@ import { Popover, PopoverContent, PopoverTrigger } from './popover';
|
||||
|
||||
export type ColorPickerProps = {
|
||||
disabled?: boolean;
|
||||
value: string;
|
||||
value?: string;
|
||||
defaultValue?: string;
|
||||
onChange: (color: string) => void;
|
||||
} & HTMLAttributes<HTMLDivElement>;
|
||||
|
||||
@@ -13,7 +13,7 @@ import { Popover, PopoverContent, PopoverTrigger } from './popover';
|
||||
type ComboboxProps = {
|
||||
className?: string;
|
||||
options: string[];
|
||||
value: string | null;
|
||||
value?: string | null;
|
||||
onChange: (_value: string | null) => void;
|
||||
triggerPlaceholder?: string;
|
||||
placeholder?: string;
|
||||
|
||||
Reference in New Issue
Block a user