mirror of
https://github.com/documenso/documenso.git
synced 2025-11-09 20:12:31 +10:00
104 lines
3.0 KiB
TypeScript
104 lines
3.0 KiB
TypeScript
import { FieldType } from '@prisma/client';
|
|
|
|
import { validateCheckboxLength } from '@documenso/lib/advanced-fields-validation/validate-checkbox';
|
|
import { AppError, AppErrorCode } from '@documenso/lib/errors/app-error';
|
|
import type { TFieldCheckbox } from '@documenso/lib/types/field';
|
|
import { parseCheckboxCustomText } from '@documenso/lib/utils/fields';
|
|
import type { TSignEnvelopeFieldValue } from '@documenso/trpc/server/envelope-router/sign-envelope-field.types';
|
|
import { checkboxValidationSigns } from '@documenso/ui/primitives/document-flow/field-items-advanced-settings/constants';
|
|
|
|
import { SignFieldCheckboxDialog } from '~/components/dialogs/sign-field-checkbox-dialog';
|
|
|
|
type HandleCheckboxFieldClickOptions = {
|
|
field: TFieldCheckbox;
|
|
clickedCheckboxIndex: number;
|
|
};
|
|
|
|
export const handleCheckboxFieldClick = async (
|
|
options: HandleCheckboxFieldClickOptions,
|
|
): Promise<Extract<TSignEnvelopeFieldValue, { type: typeof FieldType.CHECKBOX }> | null> => {
|
|
const { field, clickedCheckboxIndex } = options;
|
|
|
|
if (field.type !== FieldType.CHECKBOX) {
|
|
throw new AppError(AppErrorCode.INVALID_REQUEST, {
|
|
message: 'Invalid field type',
|
|
});
|
|
}
|
|
|
|
const { values = [], validationRule, validationLength } = field.fieldMeta;
|
|
const { customText } = field;
|
|
|
|
const currentCheckedIndices: number[] = customText ? parseCheckboxCustomText(customText) : [];
|
|
|
|
const newValues = values.map((_value, i) => {
|
|
let isChecked = currentCheckedIndices.includes(i);
|
|
|
|
if (i === clickedCheckboxIndex) {
|
|
isChecked = !isChecked;
|
|
}
|
|
|
|
return {
|
|
index: i,
|
|
isChecked,
|
|
};
|
|
});
|
|
|
|
let checkedValues: number[] | null = newValues.filter((v) => v.isChecked).map((v) => v.index);
|
|
|
|
if (checkedValues.length === 0) {
|
|
return {
|
|
type: FieldType.CHECKBOX,
|
|
value: [],
|
|
};
|
|
}
|
|
|
|
if (validationRule && validationLength) {
|
|
const checkboxValidationRule = checkboxValidationSigns.find(
|
|
(sign) => sign.label === validationRule,
|
|
);
|
|
|
|
if (!checkboxValidationRule) {
|
|
throw new AppError(AppErrorCode.INVALID_REQUEST, {
|
|
message: 'Invalid checkbox validation rule',
|
|
});
|
|
}
|
|
|
|
// Custom logic to make it flow better.
|
|
// If "at most" OR "exactly" 1 value then just return the new selected value if exists.
|
|
if (
|
|
(checkboxValidationRule.value === '=' || checkboxValidationRule.value === '<=') &&
|
|
validationLength === 1
|
|
) {
|
|
return {
|
|
type: FieldType.CHECKBOX,
|
|
value: [clickedCheckboxIndex],
|
|
};
|
|
}
|
|
|
|
const isValid = validateCheckboxLength(
|
|
checkedValues.length,
|
|
checkboxValidationRule.value,
|
|
validationLength,
|
|
);
|
|
|
|
// Only render validation dialog if validation is invalid.
|
|
if (!isValid) {
|
|
checkedValues = await SignFieldCheckboxDialog.call({
|
|
fieldMeta: field.fieldMeta,
|
|
validationRule: checkboxValidationRule.value,
|
|
validationLength,
|
|
preselectedIndices: checkedValues,
|
|
});
|
|
}
|
|
}
|
|
|
|
if (!checkedValues) {
|
|
return null;
|
|
}
|
|
|
|
return {
|
|
type: FieldType.CHECKBOX,
|
|
value: checkedValues,
|
|
};
|
|
};
|