Compare commits

...

2 Commits

Author SHA1 Message Date
Ephraim Duncan
347e7a0b40 Merge branch 'feat/rr7' into feat/bulk-add-fields 2025-03-04 11:59:30 +00:00
Ephraim Atta-Duncan
10f6163a00 feat: duplicate fields on multiple pages 2025-03-04 01:41:47 +00:00
3 changed files with 48 additions and 6 deletions

View File

@@ -3,9 +3,8 @@ import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { msg } from '@lingui/core/macro'; import { msg } from '@lingui/core/macro';
import { useLingui } from '@lingui/react'; import { useLingui } from '@lingui/react';
import { Trans } from '@lingui/react/macro'; import { Trans } from '@lingui/react/macro';
import { Prisma } from '@prisma/client';
import type { Field, Recipient } from '@prisma/client'; import type { Field, Recipient } from '@prisma/client';
import { FieldType, RecipientRole, SendStatus } from '@prisma/client'; import { FieldType, Prisma, RecipientRole, SendStatus } from '@prisma/client';
import { import {
CalendarDays, CalendarDays,
Check, Check,
@@ -411,8 +410,11 @@ export const AddFieldsFormPartial = ({
); );
const onFieldCopy = useCallback( const onFieldCopy = useCallback(
(event?: KeyboardEvent | null, options?: { duplicate?: boolean }) => { (
const { duplicate = false } = options ?? {}; event?: KeyboardEvent | null,
options?: { duplicate?: boolean; duplicateAllPages?: boolean },
) => {
const { duplicate = false, duplicateAllPages = false } = options ?? {};
if (lastActiveField) { if (lastActiveField) {
event?.preventDefault(); event?.preventDefault();
@@ -428,6 +430,31 @@ export const AddFieldsFormPartial = ({
return; return;
} }
if (duplicateAllPages) {
const pages = Array.from(document.querySelectorAll(PDF_VIEWER_PAGE_SELECTOR));
const totalPages = pages.length;
for (let pageNumber = 1; pageNumber <= totalPages; pageNumber++) {
if (pageNumber !== lastActiveField.pageNumber) {
const newField: TAddFieldsFormSchema['fields'][0] = {
...structuredClone(lastActiveField),
formId: nanoid(12),
signerEmail: selectedSigner?.email ?? lastActiveField.signerEmail,
pageNumber,
};
append(newField);
}
}
toast({
title: 'Field duplicated',
description: 'Field has been duplicated across all pages',
});
return;
}
const newField: TAddFieldsFormSchema['fields'][0] = { const newField: TAddFieldsFormSchema['fields'][0] = {
...structuredClone(lastActiveField), ...structuredClone(lastActiveField),
formId: nanoid(12), formId: nanoid(12),
@@ -653,6 +680,9 @@ export const AddFieldsFormPartial = ({
onMove={(options) => onFieldMove(options, index)} onMove={(options) => onFieldMove(options, index)}
onRemove={() => remove(index)} onRemove={() => remove(index)}
onDuplicate={() => onFieldCopy(null, { duplicate: true })} onDuplicate={() => onFieldCopy(null, { duplicate: true })}
onDuplicateAllPages={() =>
onFieldCopy(null, { duplicate: true, duplicateAllPages: true })
}
onAdvancedSettings={() => { onAdvancedSettings={() => {
setCurrentField(field); setCurrentField(field);
handleAdvancedSettings(); handleAdvancedSettings();

View File

@@ -303,6 +303,7 @@ export const FieldAdvancedSettings = forwardRef<HTMLDivElement, FieldAdvancedSet
/> />
)) ))
.otherwise(() => null)} .otherwise(() => null)}
{errors.length > 0 && ( {errors.length > 0 && (
<div className="mt-4"> <div className="mt-4">
<ul> <ul>
@@ -315,6 +316,7 @@ export const FieldAdvancedSettings = forwardRef<HTMLDivElement, FieldAdvancedSet
</div> </div>
)} )}
</DocumentFlowFormContainerContent> </DocumentFlowFormContainerContent>
<DocumentFlowFormContainerFooter className="mt-auto"> <DocumentFlowFormContainerFooter className="mt-auto">
<DocumentFlowFormContainerActions <DocumentFlowFormContainerActions
goNextLabel={msg`Save`} goNextLabel={msg`Save`}

View File

@@ -1,7 +1,7 @@
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { FieldType } from '@prisma/client'; import { FieldType } from '@prisma/client';
import { CopyPlus, Settings2, Trash } from 'lucide-react'; import { Copy, CopyPlus, Settings2, Trash } from 'lucide-react';
import { createPortal } from 'react-dom'; import { createPortal } from 'react-dom';
import { Rnd } from 'react-rnd'; import { Rnd } from 'react-rnd';
import { match } from 'ts-pattern'; import { match } from 'ts-pattern';
@@ -31,6 +31,7 @@ export type FieldItemProps = {
onMove?: (_node: HTMLElement) => void; onMove?: (_node: HTMLElement) => void;
onRemove?: () => void; onRemove?: () => void;
onDuplicate?: () => void; onDuplicate?: () => void;
onDuplicateAllPages?: () => void;
onAdvancedSettings?: () => void; onAdvancedSettings?: () => void;
onFocus?: () => void; onFocus?: () => void;
onBlur?: () => void; onBlur?: () => void;
@@ -54,9 +55,10 @@ export const FieldItem = ({
onMove, onMove,
onRemove, onRemove,
onDuplicate, onDuplicate,
onDuplicateAllPages,
onAdvancedSettings,
onFocus, onFocus,
onBlur, onBlur,
onAdvancedSettings,
recipientIndex = 0, recipientIndex = 0,
hideRecipients = false, hideRecipients = false,
hasErrors, hasErrors,
@@ -325,6 +327,14 @@ export const FieldItem = ({
<CopyPlus className="h-3 w-3" /> <CopyPlus className="h-3 w-3" />
</button> </button>
<button
className="dark:text-muted-foreground/50 dark:hover:text-muted-foreground dark:hover:bg-foreground/10 rounded-sm p-1.5 text-gray-400 transition-colors hover:bg-white/10 hover:text-gray-100"
onClick={onDuplicateAllPages}
onTouchEnd={onDuplicateAllPages}
>
<Copy className="h-3 w-3" />
</button>
<button <button
className="dark:text-muted-foreground/50 dark:hover:text-muted-foreground dark:hover:bg-foreground/10 rounded-sm p-1.5 text-gray-400 transition-colors hover:bg-white/10 hover:text-gray-100" className="dark:text-muted-foreground/50 dark:hover:text-muted-foreground dark:hover:bg-foreground/10 rounded-sm p-1.5 text-gray-400 transition-colors hover:bg-white/10 hover:text-gray-100"
onClick={onRemove} onClick={onRemove}