Files
motor-de-encuestas/lib/conditional.ts
2026-06-02 10:27:52 -03:00

54 lines
1.6 KiB
TypeScript

import type { ConditionalRule, FormAnswers, Question } from './types'
/** Returns true if the question should be shown given the current answers. */
export function isQuestionVisible(
question: Question,
answers: FormAnswers
): boolean {
const rules = question.conditional_rules
if (!rules || rules.length === 0) return true
// All rules must pass (AND semantics)
return rules.every((rule) => evaluateRule(rule, answers))
}
function evaluateRule(rule: ConditionalRule, answers: FormAnswers): boolean {
if (rule.op === 'eq') {
return answers[rule.if_question] === rule.value
}
return false
}
/**
* Returns the codes of questions that will become hidden when `triggerCode`
* changes to `newValue`. Used to clear those answers reactively.
*/
export function getHiddenCodes(
triggerCode: string,
newValue: string | string[] | number | null,
questions: Question[],
currentAnswers: FormAnswers
): string[] {
const projected = { ...currentAnswers, [triggerCode]: newValue }
return questions
.filter((q) => {
if (!q.conditional_rules?.length) return false
const dependsOnTrigger = q.conditional_rules.some(
(r) => r.if_question === triggerCode
)
if (!dependsOnTrigger) return false
return !isQuestionVisible(q, projected)
})
.map((q) => q.code)
}
/** All trigger codes in the survey (questions that have dependents). */
export function getTriggerCodes(questions: Question[]): Set<string> {
const triggers = new Set<string>()
for (const q of questions) {
for (const rule of q.conditional_rules ?? []) {
triggers.add(rule.if_question)
}
}
return triggers
}