add number conditions

master^2
Pete Matsyburka 4 days ago
parent 56d4fe7fa9
commit d7682f4ebd

@ -64,6 +64,22 @@ export default class extends HTMLElement {
if (action === 'empty' || action === 'unchecked') return this.isEmpty(actual) if (action === 'empty' || action === 'unchecked') return this.isEmpty(actual)
if (action === 'not_empty' || action === 'checked') return !this.isEmpty(actual) if (action === 'not_empty' || action === 'checked') return !this.isEmpty(actual)
if (['equal', 'not_equal', 'greater_than', 'less_than'].includes(action) && this.sourceEl?.getAttribute('type') === 'number') {
if (this.isEmpty(actual) || this.isEmpty(expected)) return false
const actualNumber = parseFloat(actual)
const expectedNumber = parseFloat(expected)
if (Number.isNaN(actualNumber) || Number.isNaN(expectedNumber)) return false
if (action === 'equal') return Math.abs(actualNumber - expectedNumber) < Number.EPSILON
if (action === 'not_equal') return Math.abs(actualNumber - expectedNumber) > Number.EPSILON
if (action === 'greater_than') return actualNumber > expectedNumber
if (action === 'less_than') return actualNumber < expectedNumber
return false
}
if (action === 'equal') { if (action === 'equal') {
const list = Array.isArray(actual) ? actual : [actual] const list = Array.isArray(actual) ? actual : [actual]
return list.filter((v) => v !== null && v !== undefined).map(String).includes(String(expected)) return list.filter((v) => v !== null && v !== undefined).map(String).includes(String(expected))

@ -1261,7 +1261,7 @@ export default {
checkFieldCondition (condition, cache = {}) { checkFieldCondition (condition, cache = {}) {
const field = this.fieldsUuidIndex[condition.field_uuid] const field = this.fieldsUuidIndex[condition.field_uuid]
if (['not_empty', 'checked', 'equal', 'contains'].includes(condition.action) && field && !this.checkFieldConditions(field, cache)) { if (['not_empty', 'checked', 'equal', 'contains', 'greater_than', 'less_than'].includes(condition.action) && field && !this.checkFieldConditions(field, cache)) {
return false return false
} }
@ -1271,6 +1271,22 @@ export default {
return isEmpty(this.values[condition.field_uuid] ?? defaultValue) return isEmpty(this.values[condition.field_uuid] ?? defaultValue)
} else if (['not_empty', 'checked'].includes(condition.action)) { } else if (['not_empty', 'checked'].includes(condition.action)) {
return !isEmpty(this.values[condition.field_uuid] ?? defaultValue) return !isEmpty(this.values[condition.field_uuid] ?? defaultValue)
} else if (field?.type === 'number' && ['equal', 'not_equal', 'greater_than', 'less_than'].includes(condition.action)) {
const value = this.values[condition.field_uuid] ?? defaultValue
if (isEmpty(value) || isEmpty(condition.value)) return false
const actual = parseFloat(value)
const expected = parseFloat(condition.value)
if (Number.isNaN(actual) || Number.isNaN(expected)) return false
if (condition.action === 'equal') return Math.abs(actual - expected) < Number.EPSILON
if (condition.action === 'not_equal') return Math.abs(actual - expected) > Number.EPSILON
if (condition.action === 'greater_than') return actual > expected
if (condition.action === 'less_than') return actual < expected
return false
} else if (['equal', 'contains'].includes(condition.action) && field) { } else if (['equal', 'contains'].includes(condition.action) && field) {
if (field.options) { if (field.options) {
const option = field.options.find((o) => o.uuid === condition.value) const option = field.options.find((o) => o.uuid === condition.value)

@ -124,6 +124,16 @@
{{ option.value || `${t('option')} ${index + 1}` }} {{ option.value || `${t('option')} ${index + 1}` }}
</option> </option>
</select> </select>
<input
v-else-if="conditionField(condition)?.type === 'number' && ['equal', 'not_equal', 'greater_than', 'less_than'].includes(condition.action)"
v-model="condition.value"
type="number"
step="any"
class="input input-bordered input-sm w-full bg-white h-11 pl-4 text-base font-normal"
:class="{ 'text-gray-300': !condition.value }"
:placeholder="t('type_value')"
required
>
</div> </div>
</div> </div>
<a <a
@ -222,6 +232,8 @@ export default {
actions.push('equal', 'not_equal') actions.push('equal', 'not_equal')
} else if (['multiple'].includes(field.type)) { } else if (['multiple'].includes(field.type)) {
actions.push('contains', 'does_not_contain') actions.push('contains', 'does_not_contain')
} else if (field.type === 'number') {
actions.push('not_empty', 'empty', 'equal', 'not_equal', 'greater_than', 'less_than')
} else { } else {
actions.push('not_empty', 'empty') actions.push('not_empty', 'empty')
} }

@ -52,6 +52,8 @@ const en = {
type_value: 'Type value', type_value: 'Type value',
equal: 'Equal', equal: 'Equal',
not_equal: 'Not equal', not_equal: 'Not equal',
greater_than: 'Greater than',
less_than: 'Less than',
contains: 'Contains', contains: 'Contains',
does_not_contain: 'Does not contain', does_not_contain: 'Does not contain',
not_empty: 'Not empty', not_empty: 'Not empty',
@ -264,6 +266,8 @@ const es = {
price: 'Precio', price: 'Precio',
equal: 'Igual', equal: 'Igual',
not_equal: 'No es igual', not_equal: 'No es igual',
greater_than: 'Mayor que',
less_than: 'Menor que',
contains: 'Contiene', contains: 'Contiene',
does_not_contain: 'No contiene', does_not_contain: 'No contiene',
not_empty: 'No vacío', not_empty: 'No vacío',
@ -474,6 +478,8 @@ const it = {
type_value: 'Inserisci valore', type_value: 'Inserisci valore',
equal: 'Uguale', equal: 'Uguale',
not_equal: 'Non uguale', not_equal: 'Non uguale',
greater_than: 'Maggiore di',
less_than: 'Minore di',
contains: 'Contiene', contains: 'Contiene',
does_not_contain: 'Non contiene', does_not_contain: 'Non contiene',
not_empty: 'Non vuoto', not_empty: 'Non vuoto',
@ -686,6 +692,8 @@ const pt = {
price: 'Preço', price: 'Preço',
equal: 'Igual', equal: 'Igual',
not_equal: 'Não é igual', not_equal: 'Não é igual',
greater_than: 'Maior que',
less_than: 'Menor que',
contains: 'Contém', contains: 'Contém',
does_not_contain: 'Não contém', does_not_contain: 'Não contém',
not_empty: 'Não vazio', not_empty: 'Não vazio',
@ -896,6 +904,8 @@ const fr = {
type_value: 'Saisir une valeur', type_value: 'Saisir une valeur',
equal: 'Égal', equal: 'Égal',
not_equal: 'Différent', not_equal: 'Différent',
greater_than: 'Supérieur à',
less_than: 'Inférieur à',
contains: 'Contient', contains: 'Contient',
does_not_contain: 'Ne contient pas', does_not_contain: 'Ne contient pas',
not_empty: 'Non vide', not_empty: 'Non vide',
@ -1107,6 +1117,8 @@ const de = {
type_value: 'Wert eingeben', type_value: 'Wert eingeben',
equal: 'Gleich', equal: 'Gleich',
not_equal: 'Ungleich', not_equal: 'Ungleich',
greater_than: 'Größer als',
less_than: 'Kleiner als',
contains: 'Enthält', contains: 'Enthält',
does_not_contain: 'Enthält nicht', does_not_contain: 'Enthält nicht',
not_empty: 'Nicht leer', not_empty: 'Nicht leer',
@ -1318,6 +1330,8 @@ const nl = {
type_value: 'Typ waarde', type_value: 'Typ waarde',
equal: 'Gelijk aan', equal: 'Gelijk aan',
not_equal: 'Niet gelijk aan', not_equal: 'Niet gelijk aan',
greater_than: 'Groter dan',
less_than: 'Kleiner dan',
contains: 'Bevat', contains: 'Bevat',
does_not_contain: 'Bevat niet', does_not_contain: 'Bevat niet',
not_empty: 'Niet leeg', not_empty: 'Niet leeg',

@ -317,17 +317,33 @@ module Submitters
end.exclude?(false) end.exclude?(false)
end end
# rubocop:disable Metrics
def check_field_condition(condition, submitter_values, fields_uuid_index) def check_field_condition(condition, submitter_values, fields_uuid_index)
value = submitter_values[condition['field_uuid']] value = submitter_values[condition['field_uuid']]
field = fields_uuid_index[condition['field_uuid']]
case condition['action'] case condition['action']
when 'empty', 'unchecked' when 'empty', 'unchecked'
value.blank? value.blank?
when 'not_empty', 'checked' when 'not_empty', 'checked'
value.present? value.present?
when 'equal', 'contains' when ->(action) { action == 'equal' && field&.dig('type') == 'number' }
field = fields_uuid_index[condition['field_uuid']] return false if value.blank? || condition['value'].blank?
(value.to_f - condition['value'].to_f).abs < Float::EPSILON
when ->(action) { action == 'not_equal' && field&.dig('type') == 'number' }
return false if value.blank? || condition['value'].blank?
(value.to_f - condition['value'].to_f).abs > Float::EPSILON
when 'greater_than'
return false if field.nil? || value.blank? || condition['value'].blank?
value.to_f > condition['value'].to_f
when 'less_than'
return false if field.nil? || value.blank? || condition['value'].blank?
value.to_f < condition['value'].to_f
when 'equal', 'contains'
return true unless field return true unless field
values = Array.wrap(value) values = Array.wrap(value)
@ -340,8 +356,6 @@ module Submitters
values.include?(option['value'].presence || "#{I18n.t('option')} #{field['options'].index(option) + 1}") values.include?(option['value'].presence || "#{I18n.t('option')} #{field['options'].index(option) + 1}")
when 'not_equal', 'does_not_contain' when 'not_equal', 'does_not_contain'
field = fields_uuid_index[condition['field_uuid']]
return true unless field return true unless field
return false unless field['options'] return false unless field['options']
@ -356,6 +370,7 @@ module Submitters
true true
end end
end end
# rubocop:enable Metrics
def replace_default_variables(value, attrs, submission, with_time: false) def replace_default_variables(value, attrs, submission, with_time: false)
return value if value.in?([true, false]) || value.is_a?(Numeric) || value.is_a?(Array) return value if value.in?([true, false]) || value.is_a?(Numeric) || value.is_a?(Array)

Loading…
Cancel
Save