Files
documenso/packages/lib/utils/fields.ts
David Nguyen 7f09ba72f4 feat: add envelopes (#2025)
This PR is handles the changes required to support envelopes. The new
envelope editor/signing page will be hidden during release.

The core changes here is to migrate the documents and templates model to
a centralized envelopes model.

Even though Documents and Templates are removed, from the user
perspective they will still exist as we remap envelopes to documents and
templates.
2025-10-14 21:56:36 +11:00

80 lines
2.3 KiB
TypeScript

import { type Envelope, type Field } from '@prisma/client';
import { extractLegacyIds } from '../universal/id';
/**
* Sort the fields by the Y position on the document.
*/
export const sortFieldsByPosition = (fields: Field[]): Field[] => {
const clonedFields: Field[] = JSON.parse(JSON.stringify(fields));
// Sort by page first, then position on page second.
return clonedFields.sort((a, b) => a.page - b.page || Number(a.positionY) - Number(b.positionY));
};
/**
* Validate whether all the provided fields are inserted.
*
* If there are any non-inserted fields it will be highlighted and scrolled into view.
*
* @returns `true` if all fields are inserted, `false` otherwise.
*/
export const validateFieldsInserted = (fields: Field[]): boolean => {
const fieldCardElements = document.getElementsByClassName('field-card-container');
// Attach validate attribute on all fields.
Array.from(fieldCardElements).forEach((element) => {
element.setAttribute('data-validate', 'true');
});
const uninsertedFields = sortFieldsByPosition(fields.filter((field) => !field.inserted));
const firstUninsertedField = uninsertedFields[0];
const firstUninsertedFieldElement =
firstUninsertedField && document.getElementById(`field-${firstUninsertedField.id}`);
if (firstUninsertedFieldElement) {
firstUninsertedFieldElement.scrollIntoView({ behavior: 'smooth', block: 'center' });
return false;
}
return uninsertedFields.length === 0;
};
export const validateFieldsUninserted = (): boolean => {
const fieldCardElements = document.getElementsByClassName('react-draggable');
const errorElements: HTMLElement[] = [];
Array.from(fieldCardElements).forEach((element) => {
const innerDiv = element.querySelector('div');
const hasError = innerDiv?.getAttribute('data-error') === 'true';
if (hasError) {
errorElements.push(element as HTMLElement);
} else {
element.removeAttribute('data-error');
}
});
if (errorElements.length > 0) {
errorElements[0].scrollIntoView({ behavior: 'smooth', block: 'center' });
return false;
}
return errorElements.length === 0;
};
export const mapFieldToLegacyField = (
field: Field,
envelope: Pick<Envelope, 'type' | 'secondaryId'>,
) => {
const legacyId = extractLegacyIds(envelope);
return {
...field,
...legacyId,
};
};