Files
gremiumhub/legalconsenthub/app/composables/useFormElementVisibility.ts

101 lines
3.5 KiB
TypeScript

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<string, boolean> {
const formElementsByRef = buildFormElementsMap(allFormElements)
const visibilityMap = new Map<string, boolean>()
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<string, FormElementDto> {
const map = new Map<string, FormElementDto>()
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<string, FormElementDto>): 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<string, FormElementDto>
): 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
}
}