mirror of
https://github.com/documenso/documenso.git
synced 2025-11-16 09:41:35 +10:00
feat: implement auto-save functionality for signers in document edit form (#1792)
This commit is contained in:
@ -21,6 +21,7 @@ import { useFieldArray, useForm } from 'react-hook-form';
|
||||
import { useHotkeys } from 'react-hotkeys-hook';
|
||||
|
||||
import { getBoundingClientRect } from '@documenso/lib/client-only/get-bounding-client-rect';
|
||||
import { useAutoSave } from '@documenso/lib/client-only/hooks/use-autosave';
|
||||
import { useDocumentElement } from '@documenso/lib/client-only/hooks/use-document-element';
|
||||
import { PDF_VIEWER_PAGE_SELECTOR } from '@documenso/lib/constants/pdf-viewer';
|
||||
import { RECIPIENT_ROLES_DESCRIPTION } from '@documenso/lib/constants/recipient-roles';
|
||||
@ -73,6 +74,7 @@ export type AddTemplateFieldsFormProps = {
|
||||
recipients: Recipient[];
|
||||
fields: Field[];
|
||||
onSubmit: (_data: TAddTemplateFieldsFormSchema) => void;
|
||||
onAutoSave: (_data: TAddTemplateFieldsFormSchema) => Promise<void>;
|
||||
teamId: number;
|
||||
};
|
||||
|
||||
@ -81,6 +83,7 @@ export const AddTemplateFieldsFormPartial = ({
|
||||
recipients,
|
||||
fields,
|
||||
onSubmit,
|
||||
onAutoSave,
|
||||
teamId,
|
||||
}: AddTemplateFieldsFormProps) => {
|
||||
const { _ } = useLingui();
|
||||
@ -121,6 +124,20 @@ export const AddTemplateFieldsFormPartial = ({
|
||||
|
||||
const onFormSubmit = form.handleSubmit(onSubmit);
|
||||
|
||||
const { scheduleSave } = useAutoSave(onAutoSave);
|
||||
|
||||
const handleAutoSave = async () => {
|
||||
const isFormValid = await form.trigger();
|
||||
|
||||
if (!isFormValid) {
|
||||
return;
|
||||
}
|
||||
|
||||
const formData = form.getValues();
|
||||
|
||||
scheduleSave(formData);
|
||||
};
|
||||
|
||||
const {
|
||||
append,
|
||||
remove,
|
||||
@ -160,6 +177,7 @@ export const AddTemplateFieldsFormPartial = ({
|
||||
};
|
||||
|
||||
append(newField);
|
||||
void handleAutoSave();
|
||||
|
||||
return;
|
||||
}
|
||||
@ -187,6 +205,7 @@ export const AddTemplateFieldsFormPartial = ({
|
||||
append(newField);
|
||||
});
|
||||
|
||||
void handleAutoSave();
|
||||
return;
|
||||
}
|
||||
|
||||
@ -198,7 +217,15 @@ export const AddTemplateFieldsFormPartial = ({
|
||||
});
|
||||
}
|
||||
},
|
||||
[append, lastActiveField, selectedSigner?.email, selectedSigner?.id, toast],
|
||||
[
|
||||
append,
|
||||
lastActiveField,
|
||||
selectedSigner?.email,
|
||||
selectedSigner?.id,
|
||||
selectedSigner?.token,
|
||||
toast,
|
||||
handleAutoSave,
|
||||
],
|
||||
);
|
||||
|
||||
const onFieldPaste = useCallback(
|
||||
@ -218,9 +245,18 @@ export const AddTemplateFieldsFormPartial = ({
|
||||
pageX: copiedField.pageX + 3,
|
||||
pageY: copiedField.pageY + 3,
|
||||
});
|
||||
|
||||
void handleAutoSave();
|
||||
}
|
||||
},
|
||||
[append, fieldClipboard, selectedSigner?.email, selectedSigner?.id, selectedSigner?.token],
|
||||
[
|
||||
append,
|
||||
fieldClipboard,
|
||||
selectedSigner?.email,
|
||||
selectedSigner?.id,
|
||||
selectedSigner?.token,
|
||||
handleAutoSave,
|
||||
],
|
||||
);
|
||||
|
||||
useHotkeys(['ctrl+c', 'meta+c'], (evt) => onFieldCopy(evt));
|
||||
@ -378,8 +414,10 @@ export const AddTemplateFieldsFormPartial = ({
|
||||
pageWidth,
|
||||
pageHeight,
|
||||
});
|
||||
|
||||
void handleAutoSave();
|
||||
},
|
||||
[getFieldPosition, localFields, update],
|
||||
[getFieldPosition, localFields, update, handleAutoSave],
|
||||
);
|
||||
|
||||
const onFieldMove = useCallback(
|
||||
@ -401,8 +439,10 @@ export const AddTemplateFieldsFormPartial = ({
|
||||
pageX,
|
||||
pageY,
|
||||
});
|
||||
|
||||
void handleAutoSave();
|
||||
},
|
||||
[getFieldPosition, localFields, update],
|
||||
[getFieldPosition, localFields, update, handleAutoSave],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
@ -504,6 +544,7 @@ export const AddTemplateFieldsFormPartial = ({
|
||||
});
|
||||
|
||||
form.setValue('fields', updatedFields);
|
||||
void handleAutoSave();
|
||||
};
|
||||
|
||||
return (
|
||||
@ -519,6 +560,10 @@ export const AddTemplateFieldsFormPartial = ({
|
||||
fields={localFields}
|
||||
onAdvancedSettings={handleAdvancedSettings}
|
||||
onSave={handleSavedFieldSettings}
|
||||
onAutoSave={async (fieldState) => {
|
||||
handleSavedFieldSettings(fieldState);
|
||||
await handleAutoSave();
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<>
|
||||
@ -566,12 +611,22 @@ export const AddTemplateFieldsFormPartial = ({
|
||||
defaultWidth={DEFAULT_WIDTH_PX}
|
||||
passive={isFieldWithinBounds && !!selectedField}
|
||||
onFocus={() => setLastActiveField(field)}
|
||||
onBlur={() => setLastActiveField(null)}
|
||||
onBlur={() => {
|
||||
setLastActiveField(null);
|
||||
void handleAutoSave();
|
||||
}}
|
||||
onResize={(options) => onFieldResize(options, index)}
|
||||
onMove={(options) => onFieldMove(options, index)}
|
||||
onRemove={() => remove(index)}
|
||||
onDuplicate={() => onFieldCopy(null, { duplicate: true })}
|
||||
onDuplicateAllPages={() => onFieldCopy(null, { duplicateAll: true })}
|
||||
onRemove={() => {
|
||||
remove(index);
|
||||
void handleAutoSave();
|
||||
}}
|
||||
onDuplicate={() => {
|
||||
onFieldCopy(null, { duplicate: true });
|
||||
}}
|
||||
onDuplicateAllPages={() => {
|
||||
onFieldCopy(null, { duplicateAll: true });
|
||||
}}
|
||||
onAdvancedSettings={() => {
|
||||
setCurrentField(field);
|
||||
handleAdvancedSettings();
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { useCallback, useEffect, useId, useMemo, useRef, useState } from 'react';
|
||||
import { useCallback, useId, useMemo, useRef, useState } from 'react';
|
||||
|
||||
import type { DropResult, SensorAPI } from '@hello-pangea/dnd';
|
||||
import { DragDropContext, Draggable, Droppable } from '@hello-pangea/dnd';
|
||||
@ -12,6 +12,7 @@ import { motion } from 'framer-motion';
|
||||
import { GripVerticalIcon, HelpCircle, Link2Icon, Plus, Trash } from 'lucide-react';
|
||||
import { useFieldArray, useForm } from 'react-hook-form';
|
||||
|
||||
import { useAutoSave } from '@documenso/lib/client-only/hooks/use-autosave';
|
||||
import { useCurrentOrganisation } from '@documenso/lib/client-only/providers/organisation';
|
||||
import { useSession } from '@documenso/lib/client-only/providers/session';
|
||||
import { isTemplateRecipientEmailPlaceholder } from '@documenso/lib/constants/template';
|
||||
@ -55,6 +56,7 @@ export type AddTemplatePlaceholderRecipientsFormProps = {
|
||||
allowDictateNextSigner?: boolean;
|
||||
templateDirectLink?: TemplateDirectLink | null;
|
||||
onSubmit: (_data: TAddTemplatePlacholderRecipientsFormSchema) => void;
|
||||
onAutoSave: (_data: TAddTemplatePlacholderRecipientsFormSchema) => Promise<void>;
|
||||
isDocumentPdfLoaded: boolean;
|
||||
};
|
||||
|
||||
@ -67,6 +69,7 @@ export const AddTemplatePlaceholderRecipientsFormPartial = ({
|
||||
allowDictateNextSigner,
|
||||
isDocumentPdfLoaded,
|
||||
onSubmit,
|
||||
onAutoSave,
|
||||
}: AddTemplatePlaceholderRecipientsFormProps) => {
|
||||
const initialId = useId();
|
||||
const $sensorApi = useRef<SensorAPI | null>(null);
|
||||
@ -123,15 +126,38 @@ export const AddTemplatePlaceholderRecipientsFormPartial = ({
|
||||
},
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
form.reset({
|
||||
signers: generateDefaultFormSigners(),
|
||||
signingOrder: signingOrder || DocumentSigningOrder.PARALLEL,
|
||||
allowDictateNextSigner: allowDictateNextSigner ?? false,
|
||||
});
|
||||
const emptySigners = useCallback(
|
||||
() => form.getValues('signers').filter((signer) => signer.email === ''),
|
||||
[form],
|
||||
);
|
||||
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [recipients]);
|
||||
const { scheduleSave } = useAutoSave(onAutoSave);
|
||||
|
||||
const handleAutoSave = async () => {
|
||||
if (emptySigners().length > 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const isFormValid = await form.trigger();
|
||||
|
||||
if (!isFormValid) {
|
||||
return;
|
||||
}
|
||||
|
||||
const formData = form.getValues();
|
||||
|
||||
scheduleSave(formData);
|
||||
};
|
||||
|
||||
// useEffect(() => {
|
||||
// form.reset({
|
||||
// signers: generateDefaultFormSigners(),
|
||||
// signingOrder: signingOrder || DocumentSigningOrder.PARALLEL,
|
||||
// allowDictateNextSigner: allowDictateNextSigner ?? false,
|
||||
// });
|
||||
|
||||
// // eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
// }, [recipients]);
|
||||
|
||||
// Always show advanced settings if any recipient has auth options.
|
||||
const alwaysShowAdvancedSettings = useMemo(() => {
|
||||
@ -204,7 +230,12 @@ export const AddTemplatePlaceholderRecipientsFormPartial = ({
|
||||
const onRemoveSigner = (index: number) => {
|
||||
removeSigner(index);
|
||||
const updatedSigners = signers.filter((_, idx) => idx !== index);
|
||||
form.setValue('signers', normalizeSigningOrders(updatedSigners));
|
||||
form.setValue('signers', normalizeSigningOrders(updatedSigners), {
|
||||
shouldValidate: true,
|
||||
shouldDirty: true,
|
||||
});
|
||||
|
||||
void handleAutoSave();
|
||||
};
|
||||
|
||||
const isSignerDirectRecipient = (
|
||||
@ -231,7 +262,10 @@ export const AddTemplatePlaceholderRecipientsFormPartial = ({
|
||||
signingOrder: index + 1,
|
||||
}));
|
||||
|
||||
form.setValue('signers', updatedSigners);
|
||||
form.setValue('signers', updatedSigners, {
|
||||
shouldValidate: true,
|
||||
shouldDirty: true,
|
||||
});
|
||||
|
||||
const lastSigner = updatedSigners[updatedSigners.length - 1];
|
||||
if (lastSigner.role === RecipientRole.ASSISTANT) {
|
||||
@ -244,8 +278,10 @@ export const AddTemplatePlaceholderRecipientsFormPartial = ({
|
||||
}
|
||||
|
||||
await form.trigger('signers');
|
||||
|
||||
void handleAutoSave();
|
||||
},
|
||||
[form, watchedSigners, toast],
|
||||
[form, watchedSigners, toast, handleAutoSave],
|
||||
);
|
||||
|
||||
const handleSigningOrderChange = useCallback(
|
||||
@ -273,7 +309,10 @@ export const AddTemplatePlaceholderRecipientsFormPartial = ({
|
||||
signingOrder: idx + 1,
|
||||
}));
|
||||
|
||||
form.setValue('signers', updatedSigners);
|
||||
form.setValue('signers', updatedSigners, {
|
||||
shouldValidate: true,
|
||||
shouldDirty: true,
|
||||
});
|
||||
|
||||
if (signer.role === RecipientRole.ASSISTANT && newPosition === remainingSigners.length - 1) {
|
||||
toast({
|
||||
@ -283,8 +322,10 @@ export const AddTemplatePlaceholderRecipientsFormPartial = ({
|
||||
),
|
||||
});
|
||||
}
|
||||
|
||||
void handleAutoSave();
|
||||
},
|
||||
[form, toast],
|
||||
[form, toast, handleAutoSave],
|
||||
);
|
||||
|
||||
const handleRoleChange = useCallback(
|
||||
@ -294,7 +335,10 @@ export const AddTemplatePlaceholderRecipientsFormPartial = ({
|
||||
|
||||
// Handle parallel to sequential conversion for assistants
|
||||
if (role === RecipientRole.ASSISTANT && signingOrder === DocumentSigningOrder.PARALLEL) {
|
||||
form.setValue('signingOrder', DocumentSigningOrder.SEQUENTIAL);
|
||||
form.setValue('signingOrder', DocumentSigningOrder.SEQUENTIAL, {
|
||||
shouldValidate: true,
|
||||
shouldDirty: true,
|
||||
});
|
||||
toast({
|
||||
title: _(msg`Signing order is enabled.`),
|
||||
description: _(msg`You cannot add assistants when signing order is disabled.`),
|
||||
@ -309,7 +353,10 @@ export const AddTemplatePlaceholderRecipientsFormPartial = ({
|
||||
signingOrder: idx + 1,
|
||||
}));
|
||||
|
||||
form.setValue('signers', updatedSigners);
|
||||
form.setValue('signers', updatedSigners, {
|
||||
shouldValidate: true,
|
||||
shouldDirty: true,
|
||||
});
|
||||
|
||||
if (role === RecipientRole.ASSISTANT && index === updatedSigners.length - 1) {
|
||||
toast({
|
||||
@ -319,8 +366,10 @@ export const AddTemplatePlaceholderRecipientsFormPartial = ({
|
||||
),
|
||||
});
|
||||
}
|
||||
|
||||
void handleAutoSave();
|
||||
},
|
||||
[form, toast],
|
||||
[form, toast, handleAutoSave],
|
||||
);
|
||||
|
||||
const [showSigningOrderConfirmation, setShowSigningOrderConfirmation] = useState(false);
|
||||
@ -334,10 +383,21 @@ export const AddTemplatePlaceholderRecipientsFormPartial = ({
|
||||
role: signer.role === RecipientRole.ASSISTANT ? RecipientRole.SIGNER : signer.role,
|
||||
}));
|
||||
|
||||
form.setValue('signers', updatedSigners);
|
||||
form.setValue('signingOrder', DocumentSigningOrder.PARALLEL);
|
||||
form.setValue('allowDictateNextSigner', false);
|
||||
}, [form]);
|
||||
form.setValue('signers', updatedSigners, {
|
||||
shouldValidate: true,
|
||||
shouldDirty: true,
|
||||
});
|
||||
form.setValue('signingOrder', DocumentSigningOrder.PARALLEL, {
|
||||
shouldValidate: true,
|
||||
shouldDirty: true,
|
||||
});
|
||||
form.setValue('allowDictateNextSigner', false, {
|
||||
shouldValidate: true,
|
||||
shouldDirty: true,
|
||||
});
|
||||
|
||||
void handleAutoSave();
|
||||
}, [form, handleAutoSave]);
|
||||
|
||||
return (
|
||||
<>
|
||||
@ -382,8 +442,13 @@ export const AddTemplatePlaceholderRecipientsFormPartial = ({
|
||||
|
||||
// If sequential signing is turned off, disable dictate next signer
|
||||
if (!checked) {
|
||||
form.setValue('allowDictateNextSigner', false);
|
||||
form.setValue('allowDictateNextSigner', false, {
|
||||
shouldValidate: true,
|
||||
shouldDirty: true,
|
||||
});
|
||||
}
|
||||
|
||||
void handleAutoSave();
|
||||
}}
|
||||
disabled={isSubmitting}
|
||||
/>
|
||||
@ -409,7 +474,10 @@ export const AddTemplatePlaceholderRecipientsFormPartial = ({
|
||||
{...field}
|
||||
id="allowDictateNextSigner"
|
||||
checked={value}
|
||||
onCheckedChange={field.onChange}
|
||||
onCheckedChange={(checked) => {
|
||||
field.onChange(checked);
|
||||
void handleAutoSave();
|
||||
}}
|
||||
disabled={isSubmitting || !isSigningOrderSequential}
|
||||
/>
|
||||
</FormControl>
|
||||
@ -500,6 +568,7 @@ export const AddTemplatePlaceholderRecipientsFormPartial = ({
|
||||
<Input
|
||||
type="number"
|
||||
max={signers.length}
|
||||
data-testid="placeholder-recipient-signing-order-input"
|
||||
className={cn(
|
||||
'w-full text-center',
|
||||
'[appearance:textfield] [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:appearance-none',
|
||||
@ -558,6 +627,8 @@ export const AddTemplatePlaceholderRecipientsFormPartial = ({
|
||||
signers[index].email === user?.email ||
|
||||
isSignerDirectRecipient(signer)
|
||||
}
|
||||
onBlur={handleAutoSave}
|
||||
data-testid="placeholder-recipient-email-input"
|
||||
/>
|
||||
</FormControl>
|
||||
|
||||
@ -592,6 +663,8 @@ export const AddTemplatePlaceholderRecipientsFormPartial = ({
|
||||
signers[index].email === user?.email ||
|
||||
isSignerDirectRecipient(signer)
|
||||
}
|
||||
onBlur={handleAutoSave}
|
||||
data-testid="placeholder-recipient-name-input"
|
||||
/>
|
||||
</FormControl>
|
||||
|
||||
@ -633,10 +706,10 @@ export const AddTemplatePlaceholderRecipientsFormPartial = ({
|
||||
<FormControl>
|
||||
<RecipientRoleSelect
|
||||
{...field}
|
||||
onValueChange={(value) =>
|
||||
onValueChange={(value) => {
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
||||
handleRoleChange(index, value as RecipientRole)
|
||||
}
|
||||
handleRoleChange(index, value as RecipientRole);
|
||||
}}
|
||||
disabled={isSubmitting}
|
||||
hideCCRecipients={isSignerDirectRecipient(signer)}
|
||||
/>
|
||||
@ -672,6 +745,7 @@ export const AddTemplatePlaceholderRecipientsFormPartial = ({
|
||||
className="col-span-1 mt-auto inline-flex h-10 w-10 items-center justify-center text-slate-500 hover:opacity-80 disabled:cursor-not-allowed disabled:opacity-50"
|
||||
disabled={isSubmitting || signers.length === 1}
|
||||
onClick={() => onRemoveSigner(index)}
|
||||
data-testid="remove-placeholder-recipient-button"
|
||||
>
|
||||
<Trash className="h-5 w-5" />
|
||||
</button>
|
||||
|
||||
@ -9,6 +9,7 @@ import { InfoIcon } from 'lucide-react';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { match } from 'ts-pattern';
|
||||
|
||||
import { useAutoSave } from '@documenso/lib/client-only/hooks/use-autosave';
|
||||
import { useCurrentOrganisation } from '@documenso/lib/client-only/providers/organisation';
|
||||
import { DATE_FORMATS, DEFAULT_DOCUMENT_DATE_FORMAT } from '@documenso/lib/constants/date-formats';
|
||||
import {
|
||||
@ -83,6 +84,7 @@ export type AddTemplateSettingsFormProps = {
|
||||
template: TTemplate;
|
||||
currentTeamMemberRole?: TeamMemberRole;
|
||||
onSubmit: (_data: TAddTemplateSettingsFormSchema) => void;
|
||||
onAutoSave: (_data: TAddTemplateSettingsFormSchema) => Promise<void>;
|
||||
};
|
||||
|
||||
export const AddTemplateSettingsFormPartial = ({
|
||||
@ -93,6 +95,7 @@ export const AddTemplateSettingsFormPartial = ({
|
||||
template,
|
||||
currentTeamMemberRole,
|
||||
onSubmit,
|
||||
onAutoSave,
|
||||
}: AddTemplateSettingsFormProps) => {
|
||||
const { t, i18n } = useLingui();
|
||||
|
||||
@ -160,6 +163,28 @@ export const AddTemplateSettingsFormPartial = ({
|
||||
}
|
||||
}, [form, form.setValue, form.formState.touchedFields.meta?.timezone]);
|
||||
|
||||
const { scheduleSave } = useAutoSave(onAutoSave);
|
||||
|
||||
const handleAutoSave = async () => {
|
||||
const isFormValid = await form.trigger();
|
||||
|
||||
if (!isFormValid) {
|
||||
return;
|
||||
}
|
||||
|
||||
const formData = form.getValues();
|
||||
|
||||
/*
|
||||
* Parse the form data through the Zod schema to handle transformations
|
||||
* (like -1 -> undefined for the Document Global Auth Access)
|
||||
*/
|
||||
const parseResult = ZAddTemplateSettingsFormSchema.safeParse(formData);
|
||||
|
||||
if (parseResult.success) {
|
||||
scheduleSave(parseResult.data);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<DocumentFlowFormContainerHeader
|
||||
@ -191,7 +216,7 @@ export const AddTemplateSettingsFormPartial = ({
|
||||
</FormLabel>
|
||||
|
||||
<FormControl>
|
||||
<Input className="bg-background" {...field} />
|
||||
<Input className="bg-background" {...field} onBlur={handleAutoSave} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
@ -219,7 +244,13 @@ export const AddTemplateSettingsFormPartial = ({
|
||||
</FormLabel>
|
||||
|
||||
<FormControl>
|
||||
<Select {...field} onValueChange={field.onChange}>
|
||||
<Select
|
||||
{...field}
|
||||
onValueChange={(value) => {
|
||||
field.onChange(value);
|
||||
void handleAutoSave();
|
||||
}}
|
||||
>
|
||||
<SelectTrigger className="bg-background">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
@ -250,9 +281,13 @@ export const AddTemplateSettingsFormPartial = ({
|
||||
|
||||
<FormControl>
|
||||
<DocumentGlobalAuthAccessSelect
|
||||
{...field}
|
||||
onValueChange={(value) => {
|
||||
field.onChange(value);
|
||||
void handleAutoSave();
|
||||
}}
|
||||
value={field.value}
|
||||
disabled={field.disabled}
|
||||
onValueChange={field.onChange}
|
||||
/>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
@ -275,7 +310,10 @@ export const AddTemplateSettingsFormPartial = ({
|
||||
canUpdateVisibility={canUpdateVisibility}
|
||||
currentTeamMemberRole={currentTeamMemberRole}
|
||||
{...field}
|
||||
onValueChange={field.onChange}
|
||||
onValueChange={(value) => {
|
||||
field.onChange(value);
|
||||
void handleAutoSave();
|
||||
}}
|
||||
/>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
@ -334,7 +372,13 @@ export const AddTemplateSettingsFormPartial = ({
|
||||
</FormLabel>
|
||||
|
||||
<FormControl>
|
||||
<Select {...field} onValueChange={field.onChange}>
|
||||
<Select
|
||||
{...field}
|
||||
onValueChange={(value) => {
|
||||
field.onChange(value);
|
||||
void handleAutoSave();
|
||||
}}
|
||||
>
|
||||
<SelectTrigger className="bg-background text-muted-foreground">
|
||||
<SelectValue data-testid="documentDistributionMethodSelectValue" />
|
||||
</SelectTrigger>
|
||||
@ -371,7 +415,10 @@ export const AddTemplateSettingsFormPartial = ({
|
||||
value: option.value,
|
||||
}))}
|
||||
selectedValues={field.value}
|
||||
onChange={field.onChange}
|
||||
onChange={(value) => {
|
||||
field.onChange(value);
|
||||
void handleAutoSave();
|
||||
}}
|
||||
className="bg-background w-full"
|
||||
emptySelectionPlaceholder="Select signature types"
|
||||
/>
|
||||
@ -395,9 +442,13 @@ export const AddTemplateSettingsFormPartial = ({
|
||||
|
||||
<FormControl>
|
||||
<DocumentGlobalAuthActionSelect
|
||||
{...field}
|
||||
onValueChange={(value) => {
|
||||
field.onChange(value);
|
||||
void handleAutoSave();
|
||||
}}
|
||||
value={field.value}
|
||||
disabled={field.disabled}
|
||||
onValueChange={field.onChange}
|
||||
/>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
@ -488,7 +539,7 @@ export const AddTemplateSettingsFormPartial = ({
|
||||
</FormLabel>
|
||||
|
||||
<FormControl>
|
||||
<Input {...field} />
|
||||
<Input {...field} onBlur={handleAutoSave} />
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
@ -515,7 +566,11 @@ export const AddTemplateSettingsFormPartial = ({
|
||||
</FormLabel>
|
||||
|
||||
<FormControl>
|
||||
<Textarea className="bg-background h-16 resize-none" {...field} />
|
||||
<Textarea
|
||||
className="bg-background h-16 resize-none"
|
||||
{...field}
|
||||
onBlur={handleAutoSave}
|
||||
/>
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
@ -525,7 +580,12 @@ export const AddTemplateSettingsFormPartial = ({
|
||||
|
||||
<DocumentEmailCheckboxes
|
||||
value={emailSettings}
|
||||
onChange={(value) => form.setValue('meta.emailSettings', value)}
|
||||
onChange={(value) => {
|
||||
form.setValue('meta.emailSettings', value, {
|
||||
shouldDirty: true,
|
||||
});
|
||||
void handleAutoSave();
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</AccordionContent>
|
||||
@ -563,7 +623,7 @@ export const AddTemplateSettingsFormPartial = ({
|
||||
</FormLabel>
|
||||
|
||||
<FormControl>
|
||||
<Input className="bg-background" {...field} />
|
||||
<Input className="bg-background" {...field} onBlur={handleAutoSave} />
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
@ -581,7 +641,13 @@ export const AddTemplateSettingsFormPartial = ({
|
||||
</FormLabel>
|
||||
|
||||
<FormControl>
|
||||
<Select {...field} onValueChange={field.onChange}>
|
||||
<Select
|
||||
{...field}
|
||||
onValueChange={(value) => {
|
||||
field.onChange(value);
|
||||
void handleAutoSave();
|
||||
}}
|
||||
>
|
||||
<SelectTrigger className="bg-background">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
@ -615,7 +681,10 @@ export const AddTemplateSettingsFormPartial = ({
|
||||
className="bg-background time-zone-field"
|
||||
options={TIME_ZONES}
|
||||
{...field}
|
||||
onChange={(value) => value && field.onChange(value)}
|
||||
onChange={(value) => {
|
||||
value && field.onChange(value);
|
||||
void handleAutoSave();
|
||||
}}
|
||||
/>
|
||||
</FormControl>
|
||||
|
||||
@ -645,7 +714,7 @@ export const AddTemplateSettingsFormPartial = ({
|
||||
</FormLabel>
|
||||
|
||||
<FormControl>
|
||||
<Input className="bg-background" {...field} />
|
||||
<Input className="bg-background" {...field} onBlur={handleAutoSave} />
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
|
||||
Reference in New Issue
Block a user