165 lines
6.3 KiB
TypeScript
165 lines
6.3 KiB
TypeScript
import type { FormElementDto, VisibilityConditionGroup, VisibilityConditionNode } from '~~/.api-client'
|
|
import {
|
|
VisibilityConditionType as VCType,
|
|
VisibilityConditionNodeNodeTypeEnum as VCNodeTypeEnum,
|
|
VisibilityConditionGroupOperatorEnum as VCGroupOperatorEnum,
|
|
VisibilityConditionNodeGroupOperatorEnum as VCNodeGroupOperatorEnum,
|
|
VisibilityConditionOperator as VCOperator,
|
|
FormElementType
|
|
} from '~~/.api-client'
|
|
|
|
export function useFormElementVisibility() {
|
|
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
|
|
}
|
|
|
|
/**
|
|
* Evaluates visibility conditions for a FormOption (e.g., table column).
|
|
* Unlike evaluateFormElementVisibility which works on FormElements,
|
|
* this evaluates standalone condition groups for options/columns.
|
|
*/
|
|
function isFormOptionVisible(
|
|
conditions: VisibilityConditionGroup | undefined,
|
|
allFormElements: FormElementDto[]
|
|
): boolean {
|
|
if (!conditions || !conditions.conditions || conditions.conditions.length === 0) {
|
|
return true
|
|
}
|
|
const formElementsByRef = buildFormElementsMap(allFormElements)
|
|
return evaluateGroup(conditions, formElementsByRef)
|
|
}
|
|
|
|
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
|
|
}
|
|
|
|
function isElementVisible(element: FormElementDto, formElementsByRef: Map<string, FormElementDto>): boolean {
|
|
const group = element.visibilityConditions
|
|
if (!group || !group.conditions || group.conditions.length === 0) {
|
|
return true
|
|
}
|
|
|
|
return evaluateGroup(group, formElementsByRef)
|
|
}
|
|
|
|
function evaluateGroup(group: VisibilityConditionGroup, formElementsByRef: Map<string, FormElementDto>): boolean {
|
|
if (!group.conditions || group.conditions.length === 0) {
|
|
return true
|
|
}
|
|
const results = group.conditions.map((c) => evaluateNode(c, formElementsByRef))
|
|
return group.operator === VCGroupOperatorEnum.And ? results.every(Boolean) : results.some(Boolean)
|
|
}
|
|
|
|
function evaluateNode(node: VisibilityConditionNode, formElementsByRef: Map<string, FormElementDto>): boolean {
|
|
if (node.nodeType === VCNodeTypeEnum.Group) {
|
|
return evaluateNodeGroup(node, formElementsByRef)
|
|
}
|
|
return evaluateLeafCondition(node, formElementsByRef)
|
|
}
|
|
|
|
function evaluateNodeGroup(node: VisibilityConditionNode, formElementsByRef: Map<string, FormElementDto>): boolean {
|
|
if (!node.conditions || node.conditions.length === 0) {
|
|
return true
|
|
}
|
|
const results = node.conditions.map((c) => evaluateNode(c, formElementsByRef))
|
|
return node.groupOperator === VCNodeGroupOperatorEnum.And ? results.every(Boolean) : results.some(Boolean)
|
|
}
|
|
|
|
function evaluateLeafCondition(
|
|
leaf: VisibilityConditionNode,
|
|
formElementsByRef: Map<string, FormElementDto>
|
|
): boolean {
|
|
if (!leaf.sourceFormElementReference) {
|
|
return false
|
|
}
|
|
const sourceElement = formElementsByRef.get(leaf.sourceFormElementReference)
|
|
if (!sourceElement) {
|
|
return false
|
|
}
|
|
|
|
// Special handling for CHECKBOX with multiple options
|
|
if (sourceElement.type === FormElementType.Checkbox && sourceElement.options.length > 1) {
|
|
const operator = leaf.formElementOperator || VCOperator.Equals
|
|
const conditionMet = evaluateCheckboxCondition(sourceElement, leaf.formElementExpectedValue || '', operator)
|
|
return leaf.formElementConditionType === VCType.Hide ? !conditionMet : conditionMet
|
|
}
|
|
|
|
const sourceValue = getFormElementValue(sourceElement)
|
|
const operator = leaf.formElementOperator || VCOperator.Equals
|
|
const conditionMet = evaluateCondition(sourceValue, leaf.formElementExpectedValue || '', operator)
|
|
|
|
return leaf.formElementConditionType === VCType.Hide ? !conditionMet : conditionMet
|
|
}
|
|
|
|
function getFormElementValue(element: FormElementDto): string {
|
|
if (element.type === FormElementType.Checkbox && element.options.length === 1) {
|
|
return element.options[0]?.value || ''
|
|
}
|
|
|
|
const selectedOption = element.options.find((option) => option.value === 'true')
|
|
return selectedOption?.label || ''
|
|
}
|
|
|
|
function evaluateCheckboxCondition(element: FormElementDto, expectedValue: string, operator: string): boolean {
|
|
const selectedLabels = element.options.filter((option) => option.value === 'true').map((option) => option.label)
|
|
|
|
switch (operator) {
|
|
case VCOperator.Equals:
|
|
return selectedLabels.some((label) => label.toLowerCase() === expectedValue.toLowerCase())
|
|
case VCOperator.NotEquals:
|
|
return !selectedLabels.some((label) => label.toLowerCase() === expectedValue.toLowerCase())
|
|
case VCOperator.Contains:
|
|
return selectedLabels.some((label) => label.toLowerCase() === expectedValue.toLowerCase())
|
|
case VCOperator.NotContains:
|
|
return !selectedLabels.some((label) => label.toLowerCase() === expectedValue.toLowerCase())
|
|
case VCOperator.IsEmpty:
|
|
return selectedLabels.length === 0
|
|
case VCOperator.IsNotEmpty:
|
|
return selectedLabels.length > 0
|
|
default:
|
|
return false
|
|
}
|
|
}
|
|
|
|
function evaluateCondition(actualValue: string, expectedValue: string, operator: string): boolean {
|
|
switch (operator) {
|
|
case VCOperator.Equals:
|
|
return actualValue.toLowerCase() === expectedValue.toLowerCase()
|
|
case VCOperator.NotEquals:
|
|
return actualValue.toLowerCase() !== expectedValue.toLowerCase()
|
|
case VCOperator.Contains:
|
|
return actualValue.toLowerCase().includes(expectedValue.toLowerCase())
|
|
case VCOperator.NotContains:
|
|
return !actualValue.toLowerCase().includes(expectedValue.toLowerCase())
|
|
case VCOperator.IsEmpty:
|
|
return actualValue === ''
|
|
case VCOperator.IsNotEmpty:
|
|
return actualValue !== ''
|
|
default:
|
|
return false
|
|
}
|
|
}
|
|
|
|
return {
|
|
evaluateFormElementVisibility,
|
|
isFormOptionVisible
|
|
}
|
|
}
|