mirror of
https://github.com/documenso/documenso.git
synced 2025-11-09 20:12:31 +10:00
Compare commits
1 Commits
1650c55b19
...
exp/custom
| Author | SHA1 | Date | |
|---|---|---|---|
| 986030cc38 |
@ -20,6 +20,7 @@ export interface SetFieldsForDocumentOptions {
|
||||
pageY: number;
|
||||
pageWidth: number;
|
||||
pageHeight: number;
|
||||
label: string;
|
||||
}[];
|
||||
requestMetadata?: RequestMetadata;
|
||||
}
|
||||
|
||||
@ -0,0 +1,2 @@
|
||||
-- AlterTable
|
||||
ALTER TABLE "Field" ADD COLUMN "label" TEXT;
|
||||
@ -210,15 +210,15 @@ model DocumentData {
|
||||
}
|
||||
|
||||
model DocumentMeta {
|
||||
id String @id @default(cuid())
|
||||
subject String?
|
||||
message String?
|
||||
timezone String? @default("Etc/UTC") @db.Text
|
||||
password String?
|
||||
dateFormat String? @default("yyyy-MM-dd hh:mm a") @db.Text
|
||||
documentId Int @unique
|
||||
document Document @relation(fields: [documentId], references: [id], onDelete: Cascade)
|
||||
redirectUrl String?
|
||||
id String @id @default(cuid())
|
||||
subject String?
|
||||
message String?
|
||||
timezone String? @default("Etc/UTC") @db.Text
|
||||
password String?
|
||||
dateFormat String? @default("yyyy-MM-dd hh:mm a") @db.Text
|
||||
documentId Int @unique
|
||||
document Document @relation(fields: [documentId], references: [id], onDelete: Cascade)
|
||||
redirectUrl String?
|
||||
}
|
||||
|
||||
enum ReadStatus {
|
||||
@ -283,6 +283,7 @@ model Field {
|
||||
documentId Int?
|
||||
templateId Int?
|
||||
recipientId Int?
|
||||
label String?
|
||||
type FieldType
|
||||
page Int
|
||||
positionX Decimal @default(0)
|
||||
|
||||
@ -33,6 +33,7 @@ export const fieldRouter = router({
|
||||
pageY: field.pageY,
|
||||
pageWidth: field.pageWidth,
|
||||
pageHeight: field.pageHeight,
|
||||
label: field.label,
|
||||
})),
|
||||
requestMetadata: extractNextApiRequestMetadata(ctx.req),
|
||||
});
|
||||
|
||||
@ -15,6 +15,7 @@ export const ZAddFieldsMutationSchema = z.object({
|
||||
pageY: z.number().min(0),
|
||||
pageWidth: z.number().min(0),
|
||||
pageHeight: z.number().min(0),
|
||||
label: z.string(),
|
||||
}),
|
||||
),
|
||||
});
|
||||
|
||||
@ -4,6 +4,7 @@ import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||
|
||||
import { Caveat } from 'next/font/google';
|
||||
|
||||
import { Label } from '@radix-ui/react-label';
|
||||
import { Check, ChevronsUpDown, Info } from 'lucide-react';
|
||||
import { useFieldArray, useForm } from 'react-hook-form';
|
||||
|
||||
@ -20,6 +21,7 @@ import { cn } from '../../lib/utils';
|
||||
import { Button } from '../button';
|
||||
import { Card, CardContent } from '../card';
|
||||
import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem } from '../command';
|
||||
import { Input } from '../input';
|
||||
import { Popover, PopoverContent, PopoverTrigger } from '../popover';
|
||||
import { useStep } from '../stepper';
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from '../tooltip';
|
||||
@ -32,6 +34,7 @@ import {
|
||||
DocumentFlowFormContainerStep,
|
||||
} from './document-flow-root';
|
||||
import { FieldItem } from './field-item';
|
||||
import type { TDocumentFlowFormSchema } from './types';
|
||||
import { type DocumentFlowStep, FRIENDLY_FIELD_TYPE } from './types';
|
||||
|
||||
const fontCaveat = Caveat({
|
||||
@ -47,6 +50,8 @@ const DEFAULT_WIDTH_PERCENT = 15;
|
||||
const MIN_HEIGHT_PX = 60;
|
||||
const MIN_WIDTH_PX = 200;
|
||||
|
||||
type ActiveField = TDocumentFlowFormSchema['fields'][0];
|
||||
|
||||
export type AddFieldsFormProps = {
|
||||
documentFlow: DocumentFlowStep;
|
||||
hideRecipients?: boolean;
|
||||
@ -69,6 +74,7 @@ export const AddFieldsFormPartial = ({
|
||||
control,
|
||||
handleSubmit,
|
||||
formState: { isSubmitting },
|
||||
setValue,
|
||||
} = useForm<TAddFieldsFormSchema>({
|
||||
defaultValues: {
|
||||
fields: fields.map((field) => ({
|
||||
@ -82,11 +88,23 @@ export const AddFieldsFormPartial = ({
|
||||
pageHeight: Number(field.height),
|
||||
signerEmail:
|
||||
recipients.find((recipient) => recipient.id === field.recipientId)?.email ?? '',
|
||||
label: field.label ?? '',
|
||||
})),
|
||||
},
|
||||
});
|
||||
|
||||
// const addLabelForm = useForm<TAddCustomLabelFormSchema>({
|
||||
// defaultValues: {
|
||||
// label: '',
|
||||
// },
|
||||
// });
|
||||
|
||||
// const onCustomLabelFormSubmit = (data: TAddCustomLabelFormSchema) => {
|
||||
// console.log('Custom label', data);
|
||||
// };
|
||||
|
||||
const onFormSubmit = handleSubmit(onSubmit);
|
||||
// const onAddCustomLabelFormSubmit = addLabelForm.handleSubmit(onCustomLabelFormSubmit);
|
||||
|
||||
const {
|
||||
append,
|
||||
@ -101,6 +119,8 @@ export const AddFieldsFormPartial = ({
|
||||
const [selectedField, setSelectedField] = useState<FieldType | null>(null);
|
||||
const [selectedSigner, setSelectedSigner] = useState<Recipient | null>(null);
|
||||
const [showRecipientsSelector, setShowRecipientsSelector] = useState(false);
|
||||
const [activeField, setActiveField] = useState<ActiveField | null>(null);
|
||||
const [fieldLabel, setFieldLabel] = useState<Record<string, string> | null>({});
|
||||
|
||||
const hasSelectedSignerBeenSent = selectedSigner?.sendStatus === SendStatus.SENT;
|
||||
|
||||
@ -186,12 +206,13 @@ export const AddFieldsFormPartial = ({
|
||||
pageWidth: fieldPageWidth,
|
||||
pageHeight: fieldPageHeight,
|
||||
signerEmail: selectedSigner.email,
|
||||
label: activeField?.label ?? fieldLabel?.[activeField?.formId ?? ''] ?? '',
|
||||
});
|
||||
|
||||
setIsFieldWithinBounds(false);
|
||||
setSelectedField(null);
|
||||
},
|
||||
[append, isWithinPageBounds, selectedField, selectedSigner, getPage],
|
||||
[append, isWithinPageBounds, selectedField, selectedSigner, activeField, fieldLabel, getPage],
|
||||
);
|
||||
|
||||
const onFieldResize = useCallback(
|
||||
@ -257,7 +278,7 @@ export const AddFieldsFormPartial = ({
|
||||
window.removeEventListener('mousemove', onMouseMove);
|
||||
window.removeEventListener('mouseup', onMouseClick);
|
||||
};
|
||||
}, [onMouseClick, onMouseMove, selectedField]);
|
||||
}, [onMouseClick, onMouseMove, selectedField, activeField]);
|
||||
|
||||
useEffect(() => {
|
||||
const observer = new MutationObserver((_mutations) => {
|
||||
@ -311,6 +332,8 @@ export const AddFieldsFormPartial = ({
|
||||
);
|
||||
}, [recipientsByRole]);
|
||||
|
||||
console.log(localFields[0].label);
|
||||
|
||||
return (
|
||||
<>
|
||||
<DocumentFlowFormContainerHeader
|
||||
@ -342,19 +365,24 @@ export const AddFieldsFormPartial = ({
|
||||
</Card>
|
||||
)}
|
||||
|
||||
{localFields.map((field, index) => (
|
||||
<FieldItem
|
||||
key={index}
|
||||
field={field}
|
||||
disabled={selectedSigner?.email !== field.signerEmail || hasSelectedSignerBeenSent}
|
||||
minHeight={fieldBounds.current.height}
|
||||
minWidth={fieldBounds.current.width}
|
||||
passive={isFieldWithinBounds && !!selectedField}
|
||||
onResize={(options) => onFieldResize(options, index)}
|
||||
onMove={(options) => onFieldMove(options, index)}
|
||||
onRemove={() => remove(index)}
|
||||
/>
|
||||
))}
|
||||
{localFields.map((field, index) => {
|
||||
return (
|
||||
<FieldItem
|
||||
key={index}
|
||||
field={field}
|
||||
disabled={selectedSigner?.email !== field.signerEmail || hasSelectedSignerBeenSent}
|
||||
minHeight={fieldBounds.current.height}
|
||||
minWidth={fieldBounds.current.width}
|
||||
passive={isFieldWithinBounds && !!selectedField}
|
||||
onResize={(options) => onFieldResize(options, index)}
|
||||
onClick={(field) => {
|
||||
setActiveField(field);
|
||||
}}
|
||||
onMove={(options) => onFieldMove(options, index)}
|
||||
onRemove={() => remove(index)}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
|
||||
{!hideRecipients && (
|
||||
<Popover open={showRecipientsSelector} onOpenChange={setShowRecipientsSelector}>
|
||||
@ -462,7 +490,7 @@ export const AddFieldsFormPartial = ({
|
||||
</Popover>
|
||||
)}
|
||||
|
||||
<div className="-mx-2 flex-1 overflow-y-auto px-2">
|
||||
<div className="-mx-2 flex-1 px-2">
|
||||
<fieldset disabled={isFieldsDisabled} className="grid grid-cols-2 gap-x-4 gap-y-8">
|
||||
<button
|
||||
type="button"
|
||||
@ -554,6 +582,40 @@ export const AddFieldsFormPartial = ({
|
||||
</button>
|
||||
</fieldset>
|
||||
</div>
|
||||
|
||||
{activeField && (
|
||||
<div className="-mx-2 my-8 flex-1 gap-1.5 px-2">
|
||||
<Label htmlFor="form-label">Custom Label</Label>
|
||||
<div className="mt-2 flex w-full items-center space-x-2">
|
||||
<Input
|
||||
type="text"
|
||||
className="w-full"
|
||||
placeholder="Label"
|
||||
id="form-label"
|
||||
value={fieldLabel?.[activeField.formId] ?? activeField.label}
|
||||
onChange={(e) => {
|
||||
setFieldLabel((prev) => ({
|
||||
...prev,
|
||||
[activeField.formId]: e.target.value,
|
||||
}));
|
||||
|
||||
setValue(
|
||||
'fields',
|
||||
localFields.map((field) => {
|
||||
if (field.formId === activeField.formId) {
|
||||
return {
|
||||
...field,
|
||||
label: fieldLabel?.[activeField.formId] ?? activeField.label ?? '',
|
||||
};
|
||||
}
|
||||
return field;
|
||||
}),
|
||||
);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</DocumentFlowFormContainerContent>
|
||||
|
||||
|
||||
@ -14,6 +14,7 @@ export const ZAddFieldsFormSchema = z.object({
|
||||
pageY: z.number().min(0),
|
||||
pageWidth: z.number().min(0),
|
||||
pageHeight: z.number().min(0),
|
||||
label: z.string().min(1),
|
||||
}),
|
||||
),
|
||||
});
|
||||
|
||||
@ -23,6 +23,7 @@ export type FieldItemProps = {
|
||||
minWidth?: number;
|
||||
onResize?: (_node: HTMLElement) => void;
|
||||
onMove?: (_node: HTMLElement) => void;
|
||||
onClick?: (field: Field) => void;
|
||||
onRemove?: () => void;
|
||||
};
|
||||
|
||||
@ -35,6 +36,7 @@ export const FieldItem = ({
|
||||
onResize,
|
||||
onMove,
|
||||
onRemove,
|
||||
onClick,
|
||||
}: FieldItemProps) => {
|
||||
const [active, setActive] = useState(false);
|
||||
const [coords, setCoords] = useState({
|
||||
@ -106,7 +108,10 @@ export const FieldItem = ({
|
||||
width: coords.pageWidth,
|
||||
}}
|
||||
bounds={`${PDF_VIEWER_PAGE_SELECTOR}[data-page-number="${field.pageNumber}"]`}
|
||||
onDragStart={() => setActive(true)}
|
||||
onDragStart={() => {
|
||||
setActive(true);
|
||||
onClick?.(field);
|
||||
}}
|
||||
onResizeStart={() => setActive(true)}
|
||||
onResizeStop={(_e, _d, ref) => {
|
||||
setActive(false);
|
||||
|
||||
@ -30,6 +30,7 @@ export const ZDocumentFlowFormSchema = z.object({
|
||||
pageY: z.number().min(0),
|
||||
pageWidth: z.number().min(0),
|
||||
pageHeight: z.number().min(0),
|
||||
label: z.string().optional(),
|
||||
}),
|
||||
),
|
||||
|
||||
|
||||
Reference in New Issue
Block a user