mirror of
https://github.com/documenso/documenso.git
synced 2025-11-14 00:32:43 +10:00
feat: add custom text to singleplayer
This commit is contained in:
@ -256,6 +256,7 @@ export const SinglePlayerClient = () => {
|
|||||||
fields={fields}
|
fields={fields}
|
||||||
onSubmit={onSignSubmit}
|
onSubmit={onSignSubmit}
|
||||||
requireName={Boolean(fields.find((field) => field.type === 'NAME'))}
|
requireName={Boolean(fields.find((field) => field.type === 'NAME'))}
|
||||||
|
requireCustomText={Boolean(fields.find((field) => field.type === 'TEXT'))}
|
||||||
requireSignature={Boolean(fields.find((field) => field.type === 'SIGNATURE'))}
|
requireSignature={Boolean(fields.find((field) => field.type === 'SIGNATURE'))}
|
||||||
/>
|
/>
|
||||||
</Stepper>
|
</Stepper>
|
||||||
|
|||||||
@ -22,6 +22,7 @@ export const mapField = (
|
|||||||
.with(FieldType.DATE, () => DateTime.now().toFormat('yyyy-MM-dd hh:mm a'))
|
.with(FieldType.DATE, () => DateTime.now().toFormat('yyyy-MM-dd hh:mm a'))
|
||||||
.with(FieldType.EMAIL, () => signer.email)
|
.with(FieldType.EMAIL, () => signer.email)
|
||||||
.with(FieldType.NAME, () => signer.name)
|
.with(FieldType.NAME, () => signer.name)
|
||||||
|
.with(FieldType.TEXT, () => signer.customText)
|
||||||
.otherwise(() => '');
|
.otherwise(() => '');
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@ -12,6 +12,7 @@ export const ZCreateSinglePlayerDocumentMutationSchema = z.object({
|
|||||||
email: z.string().email().min(1),
|
email: z.string().email().min(1),
|
||||||
name: z.string(),
|
name: z.string(),
|
||||||
signature: z.string(),
|
signature: z.string(),
|
||||||
|
customText: z.string(),
|
||||||
}),
|
}),
|
||||||
fields: z.array(
|
fields: z.array(
|
||||||
z.object({
|
z.object({
|
||||||
|
|||||||
@ -23,6 +23,7 @@ import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from '
|
|||||||
import { Input } from '../input';
|
import { Input } from '../input';
|
||||||
import { SignaturePad } from '../signature-pad';
|
import { SignaturePad } from '../signature-pad';
|
||||||
import { useStep } from '../stepper';
|
import { useStep } from '../stepper';
|
||||||
|
import { Textarea } from '../textarea';
|
||||||
import type { TAddSignatureFormSchema } from './add-signature.types';
|
import type { TAddSignatureFormSchema } from './add-signature.types';
|
||||||
import { ZAddSignatureFormSchema } from './add-signature.types';
|
import { ZAddSignatureFormSchema } from './add-signature.types';
|
||||||
import {
|
import {
|
||||||
@ -44,6 +45,7 @@ export type AddSignatureFormProps = {
|
|||||||
|
|
||||||
onSubmit: (_data: TAddSignatureFormSchema) => Promise<void> | void;
|
onSubmit: (_data: TAddSignatureFormSchema) => Promise<void> | void;
|
||||||
requireName?: boolean;
|
requireName?: boolean;
|
||||||
|
requireCustomText?: boolean;
|
||||||
requireSignature?: boolean;
|
requireSignature?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -54,6 +56,7 @@ export const AddSignatureFormPartial = ({
|
|||||||
|
|
||||||
onSubmit,
|
onSubmit,
|
||||||
requireName = false,
|
requireName = false,
|
||||||
|
requireCustomText = false,
|
||||||
requireSignature = true,
|
requireSignature = true,
|
||||||
}: AddSignatureFormProps) => {
|
}: AddSignatureFormProps) => {
|
||||||
const { currentStep, totalSteps } = useStep();
|
const { currentStep, totalSteps } = useStep();
|
||||||
@ -70,6 +73,14 @@ export const AddSignatureFormPartial = ({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (requireCustomText && val.customText.length === 0) {
|
||||||
|
ctx.addIssue({
|
||||||
|
path: ['customText'],
|
||||||
|
code: 'custom',
|
||||||
|
message: 'Text is required',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (requireSignature && val.signature.length === 0) {
|
if (requireSignature && val.signature.length === 0) {
|
||||||
ctx.addIssue({
|
ctx.addIssue({
|
||||||
path: ['signature'],
|
path: ['signature'],
|
||||||
@ -85,6 +96,7 @@ export const AddSignatureFormPartial = ({
|
|||||||
name: '',
|
name: '',
|
||||||
email: '',
|
email: '',
|
||||||
signature: '',
|
signature: '',
|
||||||
|
customText: '',
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -131,6 +143,11 @@ export const AddSignatureFormPartial = ({
|
|||||||
return !form.formState.errors.email;
|
return !form.formState.errors.email;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (fieldType === FieldType.TEXT) {
|
||||||
|
await form.trigger('customText');
|
||||||
|
return !form.formState.errors.customText;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -154,6 +171,11 @@ export const AddSignatureFormPartial = ({
|
|||||||
customText: form.getValues('name'),
|
customText: form.getValues('name'),
|
||||||
inserted: true,
|
inserted: true,
|
||||||
}))
|
}))
|
||||||
|
.with(FieldType.TEXT, () => ({
|
||||||
|
...field,
|
||||||
|
customText: form.getValues('customText'),
|
||||||
|
inserted: true,
|
||||||
|
}))
|
||||||
.with(FieldType.SIGNATURE, () => {
|
.with(FieldType.SIGNATURE, () => {
|
||||||
const value = form.getValues('signature');
|
const value = form.getValues('signature');
|
||||||
|
|
||||||
@ -302,6 +324,29 @@ export const AddSignatureFormPartial = ({
|
|||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{requireCustomText && (
|
||||||
|
<FormField
|
||||||
|
control={form.control}
|
||||||
|
name="customText"
|
||||||
|
render={({ field }) => (
|
||||||
|
<FormItem>
|
||||||
|
<FormLabel required={requireCustomText}>Custom Text</FormLabel>
|
||||||
|
<FormControl>
|
||||||
|
<Textarea
|
||||||
|
className="bg-background h-44"
|
||||||
|
{...field}
|
||||||
|
onChange={(value) => {
|
||||||
|
onFormValueChange(FieldType.TEXT);
|
||||||
|
field.onChange(value);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</DocumentFlowFormContainerContent>
|
</DocumentFlowFormContainerContent>
|
||||||
|
|
||||||
@ -330,7 +375,7 @@ export const AddSignatureFormPartial = ({
|
|||||||
<ElementVisible target={PDF_VIEWER_PAGE_SELECTOR}>
|
<ElementVisible target={PDF_VIEWER_PAGE_SELECTOR}>
|
||||||
{localFields.map((field) =>
|
{localFields.map((field) =>
|
||||||
match(field.type)
|
match(field.type)
|
||||||
.with(FieldType.DATE, FieldType.EMAIL, FieldType.NAME, () => {
|
.with(FieldType.DATE, FieldType.TEXT, FieldType.EMAIL, FieldType.NAME, () => {
|
||||||
return (
|
return (
|
||||||
<SinglePlayerModeCustomTextField
|
<SinglePlayerModeCustomTextField
|
||||||
onClick={insertField(field)}
|
onClick={insertField(field)}
|
||||||
|
|||||||
@ -6,6 +6,7 @@ export const ZAddSignatureFormSchema = z.object({
|
|||||||
.min(1, { message: 'Email is required' })
|
.min(1, { message: 'Email is required' })
|
||||||
.email({ message: 'Invalid email address' }),
|
.email({ message: 'Invalid email address' }),
|
||||||
name: z.string(),
|
name: z.string(),
|
||||||
|
customText: z.string(),
|
||||||
signature: z.string(),
|
signature: z.string(),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -226,7 +226,7 @@ export const AddSubjectFormPartial = ({
|
|||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<div className="flex flex-col">
|
<div className="mt-2 flex flex-col">
|
||||||
<div className="flex flex-col gap-y-4">
|
<div className="flex flex-col gap-y-4">
|
||||||
<div>
|
<div>
|
||||||
<Label htmlFor="redirectUrl" className="flex items-center">
|
<Label htmlFor="redirectUrl" className="flex items-center">
|
||||||
|
|||||||
@ -172,6 +172,7 @@ export function SinglePlayerModeCustomTextField({
|
|||||||
.with(FieldType.DATE, () => 'Date')
|
.with(FieldType.DATE, () => 'Date')
|
||||||
.with(FieldType.NAME, () => 'Name')
|
.with(FieldType.NAME, () => 'Name')
|
||||||
.with(FieldType.EMAIL, () => 'Email')
|
.with(FieldType.EMAIL, () => 'Email')
|
||||||
|
.with(FieldType.TEXT, () => 'Text')
|
||||||
.with(FieldType.SIGNATURE, FieldType.FREE_SIGNATURE, () => 'Signature')
|
.with(FieldType.SIGNATURE, FieldType.FREE_SIGNATURE, () => 'Signature')
|
||||||
.otherwise(() => '')}
|
.otherwise(() => '')}
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@ -511,6 +511,28 @@ export const AddTemplateFieldsFormPartial = ({
|
|||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className="group h-full w-full"
|
||||||
|
onClick={() => setSelectedField(FieldType.TEXT)}
|
||||||
|
onMouseDown={() => setSelectedField(FieldType.TEXT)}
|
||||||
|
data-selected={selectedField === FieldType.TEXT ? true : undefined}
|
||||||
|
>
|
||||||
|
<Card className="group-data-[selected]:border-documenso h-full w-full cursor-pointer group-disabled:opacity-50">
|
||||||
|
<CardContent className="flex flex-col items-center justify-center px-6 py-4">
|
||||||
|
<p
|
||||||
|
className={cn(
|
||||||
|
'text-muted-foreground group-data-[selected]:text-foreground text-xl font-medium',
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{'Text'}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p className="text-muted-foreground mt-2 text-xs">Custom Text</p>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user