Skip to content

Commit

Permalink
Field Logic Error Handling - frontend (#162)
Browse files Browse the repository at this point in the history
* Field Logic Error Handling - frontend

* Fix test case

* fix expected_type for multi select

* fix variable

---------

Co-authored-by: Julien Nahum <[email protected]>
  • Loading branch information
formsdev and JhumanJ authored Aug 30, 2023
1 parent ec26c21 commit 057bfde
Show file tree
Hide file tree
Showing 6 changed files with 184 additions and 11 deletions.
7 changes: 4 additions & 3 deletions app/Rules/FormPropertyLogicRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -605,6 +605,8 @@ private function checkActions($conditions)
break;
}
}
} else {
$this->isActionCorrect = false;
}
}

Expand All @@ -620,10 +622,9 @@ public function passes($attribute, $value)
$this->setProperty($attribute);
if(isset($value["conditions"])){
$this->checkConditions($value["conditions"]);
$this->checkActions($value['actions'] ?? null);
}
if(isset($value["actions"])){
$this->checkActions($value["actions"]);
}

return ($this->isConditionCorrect && $this->isActionCorrect);
}

Expand Down
4 changes: 2 additions & 2 deletions resources/data/open_filters.json
Original file line number Diff line number Diff line change
Expand Up @@ -342,13 +342,13 @@
"multi_select": {
"comparators": {
"contains": {
"expected_type": "object",
"expected_type": ["object", "string"],
"format": {
"type": "uuid"
}
},
"does_not_contain": {
"expected_type": "object",
"expected_type": ["object", "string"],
"format": {
"type": "uuid"
}
Expand Down
4 changes: 3 additions & 1 deletion resources/js/components/open/forms/components/FormEditor.vue
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ import FormEditorPreview from './form-components/FormEditorPreview.vue'
import FormSecurityPrivacy from './form-components/FormSecurityPrivacy.vue'
import FormCustomSeo from './form-components/FormCustomSeo.vue'
import saveUpdateAlert from '../../../../mixins/forms/saveUpdateAlert.js'
import fieldsLogic from '../../../../mixins/forms/fieldsLogic.js'
export default {
name: 'FormEditor',
Expand All @@ -85,7 +86,7 @@ export default {
FormSecurityPrivacy,
FormCustomSeo
},
mixins: [saveUpdateAlert],
mixins: [saveUpdateAlert, fieldsLogic],
props: {
isEdit: {
required: false,
Expand Down Expand Up @@ -176,6 +177,7 @@ export default {
this.showFormErrorModal = true
},
saveForm() {
this.form.properties = this.validateFieldsLogic(this.form.properties)
if(this.isGuest) {
this.saveFormGuest()
} else if (this.isEdit) {
Expand Down
123 changes: 123 additions & 0 deletions resources/js/forms/FormPropertyLogicRule.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
import OpenFilters from '../../data/open_filters.json'
class FormPropertyLogicRule {
property = null
logic = null
isConditionCorrect = true
isActionCorrect = true
ACTIONS_VALUES = [
'show-block',
'hide-block',
'make-it-optional',
'require-answer',
'enable-block',
'disable-block'
]
CONDITION_MAPPING = OpenFilters

constructor (property) {
this.property = property
this.logic = (property.logic !== undefined && property.logic) ? property.logic : null
}

isValid () {
if (this.logic && this.logic['conditions']) {
this.checkConditions(this.logic['conditions'])
this.checkActions((this.logic && this.logic['actions']) ? this.logic['actions'] : null)
}

return this.isConditionCorrect && this.isActionCorrect
}

checkConditions (conditions) {
if (conditions && conditions['operatorIdentifier']) {
if ((conditions['operatorIdentifier'] !== 'and') && (conditions['operatorIdentifier'] !== 'or')) {
this.isConditionCorrect = false
return
}

if (conditions['operatorIdentifier']['children'] !== undefined || !Array.isArray(conditions['children'])) {
this.isConditionCorrect = false
return
}

conditions['children'].forEach(childrenCondition => {
this.checkConditions(childrenCondition)
})
} else if (conditions && conditions['identifier']) {
this.checkBaseCondition(conditions)
}
}

checkBaseCondition (condition) {
if (condition['value'] === undefined ||
condition['value']['property_meta'] === undefined ||
condition['value']['property_meta']['type'] === undefined ||
condition['value']['operator'] === undefined ||
condition['value']['value'] === undefined
) {
this.isConditionCorrect = false
return
}

const typeField = condition['value']['property_meta']['type']
const operator = condition['value']['operator']
const value = condition['value']['value']

if (this.CONDITION_MAPPING[typeField] === undefined ||
this.CONDITION_MAPPING[typeField]['comparators'][operator] === undefined
) {
this.isConditionCorrect = false
return
}

const type = this.CONDITION_MAPPING[typeField]['comparators'][operator]['expected_type']
if (Array.isArray(type)) {
let foundCorrectType = false
type.forEach(subtype => {
if (this.valueHasCorrectType(subtype, value)) {
foundCorrectType = true
}
})
if (!foundCorrectType) {
this.isConditionCorrect = false
}
} else {
if (!this.valueHasCorrectType(type, value)) {
this.isConditionCorrect = false
}
}
}

valueHasCorrectType (type, value) {
if (
(type === 'string' && typeof value !== 'string') ||
(type === 'boolean' && typeof value !== 'boolean') ||
(type === 'number' && typeof value !== 'number') ||
(type === 'object' && !Array.isArray(value))
) {
return false
}
return true
}

checkActions (conditions) {
if (Array.isArray(conditions) && conditions.length > 0) {
conditions.forEach(val => {
if (this.ACTIONS_VALUES.indexOf(val) === -1 ||
(['nf-text', 'nf-code', 'nf-page-break', 'nf-divider', 'nf-image'].indexOf(this.property["type"]) > -1 && ['hide-block', 'show-block'].indexOf(val) === -1) ||
(this.property["hidden"] !== undefined && this.property["hidden"] && ['show-block', 'require-answer'].indexOf(val) === -1) ||
(this.property["required"] !== undefined && this.property["required"] && ['make-it-optional', 'hide-block', 'disable-block'].indexOf(val) === -1) ||
(this.property["disabled"] !== undefined && this.property["disabled"] && ['enable-block', 'require-answer', 'make-it-optional'].indexOf(val) === -1)
) {
this.isActionCorrect = false
return
}
})
} else {
this.isActionCorrect = false
}
}

}

export default FormPropertyLogicRule
17 changes: 17 additions & 0 deletions resources/js/mixins/forms/fieldsLogic.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import FormPropertyLogicRule from '../../forms/FormPropertyLogicRule.js'
export default {
methods: {
validateFieldsLogic (properties) {
properties.forEach((field) => {
const isValid = (new FormPropertyLogicRule(field)).isValid()
if(!isValid){
field.logic = {
conditions: null,
actions: []
}
}
})
return properties
}
}
}
40 changes: 35 additions & 5 deletions tests/Feature/Forms/FormPropertyLogicTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,22 @@
'hidden' => true,
'required' => false,
'logic' => [
"conditions" => null,
"conditions" => [
"operatorIdentifier"=> "and",
"children"=> [
[
"identifier"=> "title",
"value"=> [
"operator"=> "equals",
"property_meta"=> [
"id"=> "title",
"type"=> "text"
],
"value"=> "TEST"
]
]
]
],
"actions" => ['hide-block']
]
]
Expand All @@ -51,7 +66,22 @@
'name' => "Custom Test",
'type' => 'nf-text',
'logic' => [
"conditions" => null,
"conditions" => [
"operatorIdentifier"=> "and",
"children"=> [
[
"identifier"=> "title",
"value"=> [
"operator"=> "equals",
"property_meta"=> [
"id"=> "title",
"type"=> "text"
],
"value"=> "TEST"
]
]
]
],
"actions" => ['require-answer']
]
]
Expand Down Expand Up @@ -93,7 +123,7 @@
]
]
],
"actions" => []
"actions" => ['hide-block']
]
]
]
Expand Down Expand Up @@ -126,7 +156,7 @@
]
]
],
"actions" => []
"actions" => ['hide-block']
]
]
]
Expand Down Expand Up @@ -160,7 +190,7 @@
]
]
],
"actions" => []
"actions" => ['hide-block']
]
]
]
Expand Down

0 comments on commit 057bfde

Please sign in to comment.