From 5ec8e4ccc7104c75a364af7ccfbdc672f08af44e Mon Sep 17 00:00:00 2001 From: Pete Matsyburka Date: Thu, 30 Jul 2026 10:43:59 +0300 Subject: [PATCH] text formula --- .../submission_form/accessibility_areas.vue | 5 ++-- .../submission_form/formula_areas.vue | 23 +++++++++++++++++-- app/javascript/template_builder/builder.vue | 21 ++++++++++++++++- .../template_builder/field_context_menu.vue | 2 +- .../template_builder/field_settings.vue | 2 +- .../template_builder/formula_modal.vue | 12 ++++++++-- lib/submitters/submit_values.rb | 15 ++++++++++-- 7 files changed, 69 insertions(+), 11 deletions(-) diff --git a/app/javascript/submission_form/accessibility_areas.vue b/app/javascript/submission_form/accessibility_areas.vue index 6e720e93..8f05d4c9 100644 --- a/app/javascript/submission_form/accessibility_areas.vue +++ b/app/javascript/submission_form/accessibility_areas.vue @@ -69,8 +69,8 @@ :attachments-index="attachmentsIndex" /> 10) return '' + + return field.preferences.formula.replace(/{{(.*?)}}/g, (match, uuid) => { + const formulaField = this.fieldsUuidIndex[uuid] + + if (formulaField?.preferences?.formula) { + if (formulaField.type === 'text') { + return this.evalTextFormula(formulaField, depth + 1) + } else if (this.isMathLoaded) { + return this.calculateFormula(formulaField) + } + } + + const value = this.readonlyValues[uuid] ?? this.values[uuid] + + return Array.isArray(value) ? value.join(', ') : (value ?? '') + }) } } } diff --git a/app/javascript/template_builder/builder.vue b/app/javascript/template_builder/builder.vue index d6e3198e..5b0546af 100644 --- a/app/javascript/template_builder/builder.vue +++ b/app/javascript/template_builder/builder.vue @@ -1259,7 +1259,7 @@ export default { return formulaFields.reduce((acc, f) => { if (this.conditionalFieldIndex[f.uuid] !== false) { - acc[f.uuid] = this.calculateFormula(f) + acc[f.uuid] = f.type === 'text' ? this.evalTextFormula(f) : this.calculateFormula(f) } return acc @@ -1526,6 +1526,25 @@ export default { return this.math.evaluate(transformedFormula.toLowerCase()) }, + evalTextFormula (field, depth = 0) { + if (depth > 10) return '' + + return field.preferences.formula.replace(/{{(.*?)}}/g, (match, uuid) => { + const formulaField = this.fieldsUuidIndex[uuid] + + if (formulaField?.preferences?.formula) { + if (formulaField.type === 'text') { + return this.evalTextFormula(formulaField, depth + 1) + } else if (this.isMathLoaded) { + return this.calculateFormula(formulaField) + } + } + + const value = formulaField?.default_value + + return Array.isArray(value) ? value.join(', ') : (value ?? '') + }) + }, hasFormulaDependencyValue (field) { const normalized = this.normalizeFormula(field.preferences.formula) diff --git a/app/javascript/template_builder/field_context_menu.vue b/app/javascript/template_builder/field_context_menu.vue index f7223d79..0ab8f1dd 100644 --- a/app/javascript/template_builder/field_context_menu.vue +++ b/app/javascript/template_builder/field_context_menu.vue @@ -611,7 +611,7 @@ export default { return this.withCondition && !['stamp', 'heading'].includes(this.field.type) }, showFormula () { - return this.field.type === 'number' || this.field.type === 'payment' + return this.field.type === 'number' || this.field.type === 'payment' || !!this.field.preferences?.formula }, showRequired () { return this.withRequired && !['phone', 'stamp', 'verification', 'strikethrough', 'heading'].includes(this.field.type) diff --git a/app/javascript/template_builder/field_settings.vue b/app/javascript/template_builder/field_settings.vue index a5930565..ef76d2b0 100644 --- a/app/javascript/template_builder/field_settings.vue +++ b/app/javascript/template_builder/field_settings.vue @@ -500,7 +500,7 @@