import type { FormElementDto, FormElementVisibilityCondition, VisibilityConditionOperator } from '~~/.api-client' import { VisibilityConditionOperator as VCOperator, VisibilityConditionType as VCType, FormElementType } from '~~/.api-client' export function useFormElementVisibility() { /** * Evaluates visibility for all form elements based on their visibility conditions. * Returns a map of element key (id or reference) to visibility status. */ function evaluateFormElementVisibility(allFormElements: FormElementDto[]): Map { const formElementsByRef = buildFormElementsMap(allFormElements) const visibilityMap = new Map() allFormElements.forEach((element) => { const isVisible = isElementVisible(element, formElementsByRef) const key = element.id || element.reference if (key) { visibilityMap.set(key, isVisible) } }) return visibilityMap } function buildFormElementsMap(formElements: FormElementDto[]): Map { const map = new Map() formElements.forEach((element) => { if (element.reference) { map.set(element.reference, element) } }) return map } /** * Evaluates if an element is visible based on its visibility conditions. * Multiple conditions use AND logic - all conditions must be met for the element to be visible. */ function isElementVisible(element: FormElementDto, formElementsByRef: Map): boolean { const conditions = element.visibilityConditions if (!conditions || conditions.length === 0) { return true } // All conditions must be met (AND logic) return conditions.every((condition) => evaluateSingleCondition(condition, formElementsByRef)) } /** * Evaluates a single visibility condition against the form state. */ function evaluateSingleCondition( condition: FormElementVisibilityCondition, formElementsByRef: Map ): boolean { const sourceElement = formElementsByRef.get(condition.sourceFormElementReference) if (!sourceElement) { return false } const sourceValue = getFormElementValue(sourceElement) const operator = condition.formElementOperator || VCOperator.Equals const conditionMet = evaluateCondition(sourceValue, condition.formElementExpectedValue, operator) return condition.formElementConditionType === VCType.Show ? conditionMet : !conditionMet } function getFormElementValue(element: FormElementDto): string { // For CHECKBOX with a single option, return the value directly if (element.type === FormElementType.Checkbox && element.options.length === 1) { return element.options[0]?.value || '' } // For other element types (RADIOBUTTON, SELECT, etc.), find the selected option and return its label const selectedOption = element.options.find((option) => option.value === 'true') return selectedOption?.label || '' } function evaluateCondition( actualValue: string, expectedValue: string, operator: VisibilityConditionOperator ): boolean { switch (operator) { case VCOperator.Equals: return actualValue.toLowerCase() === expectedValue.toLowerCase() case VCOperator.NotEquals: return actualValue.toLowerCase() !== expectedValue.toLowerCase() case VCOperator.IsEmpty: return actualValue === '' case VCOperator.IsNotEmpty: return actualValue !== '' default: return false } } return { evaluateFormElementVisibility } }