mirror of
https://github.com/documenso/documenso.git
synced 2025-11-13 00:03:33 +10:00
fix: remove marketing (#1562)
This commit is contained in:
@ -1,444 +0,0 @@
|
||||
'use client';
|
||||
|
||||
import { useMemo, useState } from 'react';
|
||||
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { Trans } from '@lingui/macro';
|
||||
import { DateTime } from 'luxon';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { match } from 'ts-pattern';
|
||||
|
||||
import { DEFAULT_DOCUMENT_DATE_FORMAT } from '@documenso/lib/constants/date-formats';
|
||||
import { PDF_VIEWER_PAGE_SELECTOR } from '@documenso/lib/constants/pdf-viewer';
|
||||
import { sortFieldsByPosition, validateFieldsInserted } from '@documenso/lib/utils/fields';
|
||||
import type { Field } from '@documenso/prisma/client';
|
||||
import { FieldType } from '@documenso/prisma/client';
|
||||
import type { FieldWithSignature } from '@documenso/prisma/types/field-with-signature';
|
||||
import type { DocumentFlowStep } from '@documenso/ui/primitives/document-flow/types';
|
||||
|
||||
import { FieldToolTip } from '../../components/field/field-tooltip';
|
||||
import { cn } from '../../lib/utils';
|
||||
import { Card, CardContent } from '../card';
|
||||
import { ElementVisible } from '../element-visible';
|
||||
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from '../form/form';
|
||||
import { Input } from '../input';
|
||||
import { SignaturePad } from '../signature-pad';
|
||||
import { useStep } from '../stepper';
|
||||
import type { TAddSignatureFormSchema } from './add-signature.types';
|
||||
import { ZAddSignatureFormSchema } from './add-signature.types';
|
||||
import {
|
||||
DocumentFlowFormContainerActions,
|
||||
DocumentFlowFormContainerContent,
|
||||
DocumentFlowFormContainerFooter,
|
||||
DocumentFlowFormContainerHeader,
|
||||
DocumentFlowFormContainerStep,
|
||||
} from './document-flow-root';
|
||||
import {
|
||||
SinglePlayerModeCustomTextField,
|
||||
SinglePlayerModeSignatureField,
|
||||
} from './single-player-mode-fields';
|
||||
|
||||
export type AddSignatureFormProps = {
|
||||
defaultValues?: TAddSignatureFormSchema;
|
||||
documentFlow: DocumentFlowStep;
|
||||
fields: FieldWithSignature[];
|
||||
|
||||
onSubmit: (_data: TAddSignatureFormSchema) => Promise<void> | void;
|
||||
requireName?: boolean;
|
||||
requireCustomText?: boolean;
|
||||
requireSignature?: boolean;
|
||||
};
|
||||
|
||||
export const AddSignatureFormPartial = ({
|
||||
defaultValues,
|
||||
documentFlow,
|
||||
fields,
|
||||
|
||||
onSubmit,
|
||||
requireName = false,
|
||||
requireCustomText = false,
|
||||
requireSignature = true,
|
||||
}: AddSignatureFormProps) => {
|
||||
const { currentStep, totalSteps } = useStep();
|
||||
const [validateUninsertedFields, setValidateUninsertedFields] = useState(false);
|
||||
const [isSignatureValid, setIsSignatureValid] = useState(false);
|
||||
|
||||
// Refined schema which takes into account whether to allow an empty name or signature.
|
||||
const refinedSchema = ZAddSignatureFormSchema.superRefine((val, ctx) => {
|
||||
if (requireName && val.name.length === 0) {
|
||||
ctx.addIssue({
|
||||
path: ['name'],
|
||||
code: 'custom',
|
||||
message: 'Name is required',
|
||||
});
|
||||
}
|
||||
|
||||
if (requireCustomText && val.customText.length === 0) {
|
||||
ctx.addIssue({
|
||||
path: ['customText'],
|
||||
code: 'custom',
|
||||
message: 'Text is required',
|
||||
});
|
||||
}
|
||||
|
||||
if (requireSignature && val.signature.length === 0) {
|
||||
ctx.addIssue({
|
||||
path: ['signature'],
|
||||
code: 'custom',
|
||||
message: 'Signature is required',
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
const form = useForm<TAddSignatureFormSchema>({
|
||||
resolver: zodResolver(refinedSchema),
|
||||
defaultValues: defaultValues ?? {
|
||||
name: '',
|
||||
email: '',
|
||||
signature: '',
|
||||
customText: '',
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* A local copy of the provided fields to modify.
|
||||
*/
|
||||
const [localFields, setLocalFields] = useState<Field[]>(JSON.parse(JSON.stringify(fields)));
|
||||
|
||||
const uninsertedFields = useMemo(() => {
|
||||
const fields = localFields.filter((field) => !field.inserted);
|
||||
|
||||
return sortFieldsByPosition(fields);
|
||||
}, [localFields]);
|
||||
|
||||
const onValidateFields = async (values: TAddSignatureFormSchema) => {
|
||||
setValidateUninsertedFields(true);
|
||||
const isFieldsValid = validateFieldsInserted(localFields);
|
||||
|
||||
if (!isFieldsValid) {
|
||||
return;
|
||||
}
|
||||
|
||||
await onSubmit(values);
|
||||
};
|
||||
|
||||
/**
|
||||
* Validates whether the corresponding form for a given field type is valid.
|
||||
*
|
||||
* @returns `true` if the form associated with the provided field is valid, `false` otherwise.
|
||||
*/
|
||||
const validateFieldForm = async (fieldType: Field['type']): Promise<boolean> => {
|
||||
if (fieldType === FieldType.SIGNATURE) {
|
||||
await form.trigger('signature');
|
||||
return !form.formState.errors.signature;
|
||||
}
|
||||
|
||||
if (fieldType === FieldType.NAME) {
|
||||
await form.trigger('name');
|
||||
return !form.formState.errors.name;
|
||||
}
|
||||
|
||||
if (fieldType === FieldType.EMAIL) {
|
||||
await form.trigger('email');
|
||||
return !form.formState.errors.email;
|
||||
}
|
||||
|
||||
if (fieldType === FieldType.TEXT) {
|
||||
await form.trigger('customText');
|
||||
return !form.formState.errors.customText;
|
||||
}
|
||||
|
||||
if (fieldType === FieldType.NUMBER) {
|
||||
await form.trigger('number');
|
||||
return !form.formState.errors.number;
|
||||
}
|
||||
|
||||
if (fieldType === FieldType.RADIO) {
|
||||
await form.trigger('radio');
|
||||
return !form.formState.errors.radio;
|
||||
}
|
||||
|
||||
if (fieldType === FieldType.CHECKBOX) {
|
||||
await form.trigger('checkbox');
|
||||
return !form.formState.errors.checkbox;
|
||||
}
|
||||
|
||||
if (fieldType === FieldType.DROPDOWN) {
|
||||
await form.trigger('dropdown');
|
||||
return !form.formState.errors.dropdown;
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
/**
|
||||
* Insert the corresponding form value into a given field.
|
||||
*/
|
||||
const insertFormValueIntoField = (field: Field) => {
|
||||
return match(field.type)
|
||||
.with(FieldType.DATE, () => ({
|
||||
...field,
|
||||
customText: DateTime.now().toFormat(DEFAULT_DOCUMENT_DATE_FORMAT),
|
||||
inserted: true,
|
||||
}))
|
||||
.with(FieldType.EMAIL, () => ({
|
||||
...field,
|
||||
customText: form.getValues('email'),
|
||||
inserted: true,
|
||||
}))
|
||||
.with(FieldType.NAME, () => ({
|
||||
...field,
|
||||
customText: form.getValues('name'),
|
||||
inserted: true,
|
||||
}))
|
||||
.with(FieldType.TEXT, FieldType.NUMBER, FieldType.RADIO, FieldType.CHECKBOX, () => ({
|
||||
...field,
|
||||
customText: form.getValues('customText'),
|
||||
inserted: true,
|
||||
}))
|
||||
.with(FieldType.SIGNATURE, () => {
|
||||
const value = form.getValues('signature');
|
||||
|
||||
return {
|
||||
...field,
|
||||
value,
|
||||
Signature: {
|
||||
id: -1,
|
||||
recipientId: -1,
|
||||
fieldId: -1,
|
||||
created: new Date(),
|
||||
signatureImageAsBase64: value,
|
||||
typedSignature: null,
|
||||
},
|
||||
inserted: true,
|
||||
};
|
||||
})
|
||||
.otherwise(() => {
|
||||
throw new Error('Unsupported field');
|
||||
});
|
||||
};
|
||||
|
||||
const insertField = (field: Field) => async () => {
|
||||
const isFieldFormValid = await validateFieldForm(field.type);
|
||||
if (!isFieldFormValid) {
|
||||
return;
|
||||
}
|
||||
|
||||
setLocalFields((prev) =>
|
||||
prev.map((prevField) => {
|
||||
if (prevField.id !== field.id) {
|
||||
return prevField;
|
||||
}
|
||||
|
||||
return insertFormValueIntoField(field);
|
||||
}),
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* When a form value changes, reset all the corresponding fields to be uninserted.
|
||||
*/
|
||||
const onFormValueChange = (fieldType: FieldType) => {
|
||||
setLocalFields((fields) =>
|
||||
fields.map((field) => {
|
||||
if (field.type !== fieldType) {
|
||||
return field;
|
||||
}
|
||||
|
||||
return {
|
||||
...field,
|
||||
inserted: false,
|
||||
};
|
||||
}),
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<DocumentFlowFormContainerHeader
|
||||
title={documentFlow.title}
|
||||
description={documentFlow.description}
|
||||
/>
|
||||
|
||||
<Form {...form}>
|
||||
<fieldset className="flex h-full flex-col" disabled={form.formState.isSubmitting}>
|
||||
<DocumentFlowFormContainerContent>
|
||||
<div className="space-y-4">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="email"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel required>
|
||||
<Trans>Email</Trans>
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<Input
|
||||
className="bg-background"
|
||||
type="email"
|
||||
autoComplete="email"
|
||||
{...field}
|
||||
onChange={(value) => {
|
||||
onFormValueChange(FieldType.EMAIL);
|
||||
field.onChange(value);
|
||||
}}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
{requireName && (
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="name"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel required={requireName}>
|
||||
<Trans>Name</Trans>
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<Input
|
||||
className="bg-background"
|
||||
{...field}
|
||||
onChange={(value) => {
|
||||
onFormValueChange(FieldType.NAME);
|
||||
field.onChange(value);
|
||||
}}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
|
||||
{requireSignature && (
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="signature"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel required={requireSignature}>
|
||||
<Trans>Signature</Trans>
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<Card
|
||||
className={cn('mt-2', {
|
||||
'rounded-sm ring-2 ring-red-500 ring-offset-2 transition-all':
|
||||
form.formState.errors.signature,
|
||||
})}
|
||||
gradient={!form.formState.errors.signature}
|
||||
degrees={-120}
|
||||
>
|
||||
<CardContent className="p-0">
|
||||
<SignaturePad
|
||||
className="h-44 w-full"
|
||||
defaultValue={field.value}
|
||||
onBlur={field.onBlur}
|
||||
onValidityChange={(isValid) => {
|
||||
setIsSignatureValid(isValid);
|
||||
if (!isValid) {
|
||||
field.onChange(null);
|
||||
}
|
||||
}}
|
||||
onChange={(value) => {
|
||||
if (isSignatureValid) {
|
||||
onFormValueChange(FieldType.SIGNATURE);
|
||||
field.onChange(value);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
|
||||
{requireCustomText && (
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="customText"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel required={requireCustomText}>
|
||||
<Trans>Custom Text</Trans>
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<Input
|
||||
className="bg-background"
|
||||
{...field}
|
||||
onChange={(value) => {
|
||||
onFormValueChange(FieldType.TEXT);
|
||||
field.onChange(value);
|
||||
}}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</DocumentFlowFormContainerContent>
|
||||
|
||||
<DocumentFlowFormContainerFooter>
|
||||
<DocumentFlowFormContainerStep step={currentStep} maxStep={totalSteps} />
|
||||
|
||||
<DocumentFlowFormContainerActions
|
||||
loading={form.formState.isSubmitting}
|
||||
disabled={form.formState.isSubmitting}
|
||||
onGoBackClick={documentFlow.onBackStep}
|
||||
onGoNextClick={form.handleSubmit(onValidateFields)}
|
||||
/>
|
||||
</DocumentFlowFormContainerFooter>
|
||||
</fieldset>
|
||||
|
||||
{validateUninsertedFields && uninsertedFields[0] && (
|
||||
<FieldToolTip key={uninsertedFields[0].id} field={uninsertedFields[0]} color="warning">
|
||||
<Trans>Click to insert field</Trans>
|
||||
</FieldToolTip>
|
||||
)}
|
||||
|
||||
<ElementVisible target={PDF_VIEWER_PAGE_SELECTOR}>
|
||||
{localFields.map((field) =>
|
||||
match(field.type)
|
||||
.with(
|
||||
FieldType.DATE,
|
||||
FieldType.TEXT,
|
||||
FieldType.EMAIL,
|
||||
FieldType.NAME,
|
||||
FieldType.NUMBER,
|
||||
FieldType.CHECKBOX,
|
||||
FieldType.RADIO,
|
||||
FieldType.DROPDOWN,
|
||||
() => {
|
||||
return (
|
||||
<SinglePlayerModeCustomTextField
|
||||
onClick={insertField(field)}
|
||||
key={field.id}
|
||||
field={field}
|
||||
/>
|
||||
);
|
||||
},
|
||||
)
|
||||
.with(FieldType.SIGNATURE, () => (
|
||||
<SinglePlayerModeSignatureField
|
||||
onClick={insertField(field)}
|
||||
key={field.id}
|
||||
field={field}
|
||||
/>
|
||||
))
|
||||
.otherwise(() => {
|
||||
return null;
|
||||
}),
|
||||
)}
|
||||
</ElementVisible>
|
||||
</Form>
|
||||
</>
|
||||
);
|
||||
};
|
||||
@ -1,18 +0,0 @@
|
||||
import { msg } from '@lingui/macro';
|
||||
import { z } from 'zod';
|
||||
|
||||
export const ZAddSignatureFormSchema = z.object({
|
||||
email: z
|
||||
.string()
|
||||
.min(1, { message: msg`Email is required`.id })
|
||||
.email({ message: msg`Invalid email address`.id }),
|
||||
name: z.string(),
|
||||
customText: z.string(),
|
||||
number: z.number().optional(),
|
||||
radio: z.string().optional(),
|
||||
checkbox: z.boolean().optional(),
|
||||
dropdown: z.string().optional(),
|
||||
signature: z.string(),
|
||||
});
|
||||
|
||||
export type TAddSignatureFormSchema = z.infer<typeof ZAddSignatureFormSchema>;
|
||||
@ -1,249 +0,0 @@
|
||||
'use client';
|
||||
|
||||
import React, { useRef } from 'react';
|
||||
|
||||
import { Caveat } from 'next/font/google';
|
||||
|
||||
import { AnimatePresence, motion } from 'framer-motion';
|
||||
import { CalendarDays, CheckSquare, ChevronDown, Disc, Hash, Mail, Type, User } from 'lucide-react';
|
||||
import { match } from 'ts-pattern';
|
||||
|
||||
import { useElementScaleSize } from '@documenso/lib/client-only/hooks/use-element-scale-size';
|
||||
import { useFieldPageCoords } from '@documenso/lib/client-only/hooks/use-field-page-coords';
|
||||
import {
|
||||
DEFAULT_HANDWRITING_FONT_SIZE,
|
||||
DEFAULT_STANDARD_FONT_SIZE,
|
||||
MIN_HANDWRITING_FONT_SIZE,
|
||||
MIN_STANDARD_FONT_SIZE,
|
||||
} from '@documenso/lib/constants/pdf';
|
||||
import type { Field } from '@documenso/prisma/client';
|
||||
import { FieldType } from '@documenso/prisma/client';
|
||||
import type { FieldWithSignature } from '@documenso/prisma/types/field-with-signature';
|
||||
|
||||
import { FieldRootContainer } from '../../components/field/field';
|
||||
import { cn } from '../../lib/utils';
|
||||
|
||||
const fontCaveat = Caveat({
|
||||
weight: ['500'],
|
||||
subsets: ['latin'],
|
||||
display: 'swap',
|
||||
variable: '--font-caveat',
|
||||
});
|
||||
|
||||
export type SinglePlayerModeFieldContainerProps = {
|
||||
field: FieldWithSignature;
|
||||
children: React.ReactNode;
|
||||
};
|
||||
|
||||
export type SinglePlayerModeFieldProps<T> = {
|
||||
field: T;
|
||||
onClick?: () => void;
|
||||
};
|
||||
|
||||
export function SinglePlayerModeFieldCardContainer({
|
||||
field,
|
||||
children,
|
||||
}: SinglePlayerModeFieldContainerProps) {
|
||||
return (
|
||||
<FieldRootContainer field={field}>
|
||||
<AnimatePresence mode="wait" initial={false}>
|
||||
<motion.div
|
||||
key={field.inserted ? 'inserted' : 'not-inserted'}
|
||||
className="flex items-center justify-center p-2"
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{
|
||||
opacity: 1,
|
||||
}}
|
||||
exit={{ opacity: 0 }}
|
||||
transition={{
|
||||
duration: 0.2,
|
||||
ease: 'easeIn',
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</motion.div>
|
||||
</AnimatePresence>
|
||||
</FieldRootContainer>
|
||||
);
|
||||
}
|
||||
|
||||
export function SinglePlayerModeSignatureField({
|
||||
field,
|
||||
onClick,
|
||||
}: SinglePlayerModeFieldProps<FieldWithSignature>) {
|
||||
const fontVariable = '--font-signature';
|
||||
const fontVariableValue = getComputedStyle(document.documentElement).getPropertyValue(
|
||||
fontVariable,
|
||||
);
|
||||
|
||||
const minFontSize = MIN_HANDWRITING_FONT_SIZE;
|
||||
const maxFontSize = DEFAULT_HANDWRITING_FONT_SIZE;
|
||||
|
||||
if (!isSignatureFieldType(field.type)) {
|
||||
throw new Error('Invalid field type');
|
||||
}
|
||||
|
||||
const { height, width } = useFieldPageCoords(field);
|
||||
|
||||
const insertedBase64Signature = field.inserted && field.Signature?.signatureImageAsBase64;
|
||||
const insertedTypeSignature = field.inserted && field.Signature?.typedSignature;
|
||||
|
||||
const scalingFactor = useElementScaleSize(
|
||||
{
|
||||
height,
|
||||
width,
|
||||
},
|
||||
insertedTypeSignature || '',
|
||||
maxFontSize,
|
||||
fontVariableValue,
|
||||
);
|
||||
|
||||
const fontSize = maxFontSize * scalingFactor;
|
||||
|
||||
return (
|
||||
<SinglePlayerModeFieldCardContainer field={field}>
|
||||
{insertedBase64Signature ? (
|
||||
<img
|
||||
src={insertedBase64Signature}
|
||||
alt="Your signature"
|
||||
className="h-full max-w-full object-contain dark:invert"
|
||||
/>
|
||||
) : insertedTypeSignature ? (
|
||||
<p
|
||||
style={{
|
||||
fontSize: `clamp(${minFontSize}px, ${fontSize}px, ${maxFontSize}px)`,
|
||||
fontFamily: `var(${fontVariable})`,
|
||||
}}
|
||||
className="font-signature"
|
||||
>
|
||||
{insertedTypeSignature}
|
||||
</p>
|
||||
) : (
|
||||
<button
|
||||
onClick={() => onClick?.()}
|
||||
className={cn(
|
||||
'group-hover:text-primary absolute inset-0 h-full w-full duration-200',
|
||||
fontCaveat.className,
|
||||
)}
|
||||
>
|
||||
<span className="text-muted-foreground truncate text-3xl font-medium ">Signature</span>
|
||||
</button>
|
||||
)}
|
||||
</SinglePlayerModeFieldCardContainer>
|
||||
);
|
||||
}
|
||||
|
||||
export function SinglePlayerModeCustomTextField({
|
||||
field,
|
||||
onClick,
|
||||
}: SinglePlayerModeFieldProps<Field>) {
|
||||
const fontVariable = '--font-sans';
|
||||
const fontVariableValue = getComputedStyle(document.documentElement).getPropertyValue(
|
||||
fontVariable,
|
||||
);
|
||||
|
||||
const minFontSize = MIN_STANDARD_FONT_SIZE;
|
||||
const maxFontSize = DEFAULT_STANDARD_FONT_SIZE;
|
||||
|
||||
if (isSignatureFieldType(field.type)) {
|
||||
throw new Error('Invalid field type');
|
||||
}
|
||||
|
||||
const $paragraphEl = useRef<HTMLParagraphElement>(null);
|
||||
|
||||
const { height, width } = useFieldPageCoords(field);
|
||||
|
||||
const scalingFactor = useElementScaleSize(
|
||||
{
|
||||
height,
|
||||
width,
|
||||
},
|
||||
field.customText,
|
||||
maxFontSize,
|
||||
fontVariableValue,
|
||||
);
|
||||
|
||||
const fontSize = maxFontSize * scalingFactor;
|
||||
|
||||
return (
|
||||
<>
|
||||
<SinglePlayerModeFieldCardContainer field={field}>
|
||||
{field.inserted ? (
|
||||
<p
|
||||
ref={$paragraphEl}
|
||||
style={{
|
||||
fontSize: `clamp(${minFontSize}px, ${fontSize}px, ${maxFontSize}px)`,
|
||||
fontFamily: `var(${fontVariable})`,
|
||||
}}
|
||||
>
|
||||
{field.customText ??
|
||||
(field.fieldMeta && typeof field.fieldMeta === 'object' && 'label' in field.fieldMeta
|
||||
? field.fieldMeta.label
|
||||
: '')}
|
||||
</p>
|
||||
) : (
|
||||
<button
|
||||
onClick={() => onClick?.()}
|
||||
className="group-hover:text-primary text-muted-foreground absolute inset-0 h-full w-full text-lg duration-200"
|
||||
>
|
||||
{match(field.type)
|
||||
.with(FieldType.DATE, () => (
|
||||
<div className="text-field-card-foreground flex items-center justify-center gap-x-1 text-xl font-light">
|
||||
<CalendarDays /> Date
|
||||
</div>
|
||||
))
|
||||
.with(FieldType.NAME, () => (
|
||||
<div className="text-field-card-foreground flex items-center justify-center gap-x-1 text-xl font-light">
|
||||
<User /> Name
|
||||
</div>
|
||||
))
|
||||
.with(FieldType.EMAIL, () => (
|
||||
<div className="text-field-card-foreground flex items-center justify-center gap-x-1 text-xl font-light">
|
||||
<Mail /> Email
|
||||
</div>
|
||||
))
|
||||
.with(FieldType.TEXT, () => (
|
||||
<div className="text-field-card-foreground flex items-center justify-center gap-x-1 text-xl font-light">
|
||||
<Type /> Text
|
||||
</div>
|
||||
))
|
||||
.with(FieldType.SIGNATURE, FieldType.FREE_SIGNATURE, () => (
|
||||
<div
|
||||
className={cn(
|
||||
'text-muted-foreground w-full truncate text-3xl font-medium',
|
||||
fontCaveat.className,
|
||||
)}
|
||||
>
|
||||
Signature
|
||||
</div>
|
||||
))
|
||||
.with(FieldType.NUMBER, () => (
|
||||
<div className="text-field-card-foreground flex items-center justify-center gap-x-1 text-xl font-light">
|
||||
<Hash /> Number
|
||||
</div>
|
||||
))
|
||||
.with(FieldType.CHECKBOX, () => (
|
||||
<div className="text-field-card-foreground flex items-center justify-center gap-x-1 text-xl font-light">
|
||||
<CheckSquare /> Checkbox
|
||||
</div>
|
||||
))
|
||||
.with(FieldType.RADIO, () => (
|
||||
<div className="text-field-card-foreground flex items-center justify-center gap-x-1 text-xl font-light">
|
||||
<Disc /> Radio
|
||||
</div>
|
||||
))
|
||||
.with(FieldType.DROPDOWN, () => (
|
||||
<div className="text-field-card-foreground flex items-center justify-center gap-x-1 text-xl font-light">
|
||||
<ChevronDown /> Dropdown
|
||||
</div>
|
||||
))
|
||||
.otherwise(() => '')}
|
||||
</button>
|
||||
)}
|
||||
</SinglePlayerModeFieldCardContainer>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
const isSignatureFieldType = (fieldType: Field['type']) =>
|
||||
fieldType === FieldType.SIGNATURE || fieldType === FieldType.FREE_SIGNATURE;
|
||||
Reference in New Issue
Block a user