diff --git a/app/javascript/dashboard/components/widgets/AutomationActionInput.vue b/app/javascript/dashboard/components/widgets/AutomationActionInput.vue index a94667fcd..b64484fe1 100644 --- a/app/javascript/dashboard/components/widgets/AutomationActionInput.vue +++ b/app/javascript/dashboard/components/widgets/AutomationActionInput.vue @@ -96,11 +96,8 @@ :placeholder="$t('AUTOMATION.ACTION.TEAM_MESSAGE_INPUT_PLACEHOLDER')" class="action-message" /> -

- {{ $t('FILTER.EMPTY_VALUE_ERROR') }} +

+ {{ errorMessage }}

@@ -128,9 +125,9 @@ export default { type: Array, default: () => [], }, - v: { - type: Object, - default: () => null, + errorMessage: { + type: String, + default: '', }, showActionInput: { type: Boolean, @@ -172,7 +169,7 @@ export default { }, actionInputStyles() { return { - 'has-error': this.v.action_params.$dirty && this.v.action_params.$error, + 'has-error': this.errorMessage, 'is-a-macro': this.isMacro, }; }, diff --git a/app/javascript/dashboard/components/widgets/conversation/ConversationAdvancedFilter.vue b/app/javascript/dashboard/components/widgets/conversation/ConversationAdvancedFilter.vue index 0f72ab627..cb6ff8fa0 100644 --- a/app/javascript/dashboard/components/widgets/conversation/ConversationAdvancedFilter.vue +++ b/app/javascript/dashboard/components/widgets/conversation/ConversationAdvancedFilter.vue @@ -88,7 +88,7 @@ import { filterAttributeGroups } from './advancedFilterItems'; import filterMixin from 'shared/mixins/filterMixin'; import * as OPERATORS from 'dashboard/components/widgets/FilterInput/FilterOperatorTypes.js'; import { CONVERSATION_EVENTS } from '../../../helper/AnalyticsHelper/events'; -import { validateConversationOrContactFilters } from 'dashboard/helper/conversationAdvancedFilterValidation.js'; +import { validateConversationOrContactFilters } from 'dashboard/helper/validations.js'; export default { components: { diff --git a/app/javascript/dashboard/helper/conversationAdvancedFilterValidation.js b/app/javascript/dashboard/helper/conversationAdvancedFilterValidation.js deleted file mode 100644 index 5e689cc4c..000000000 --- a/app/javascript/dashboard/helper/conversationAdvancedFilterValidation.js +++ /dev/null @@ -1,24 +0,0 @@ -export const validateConversationOrContactFilters = filters => { - const errors = {}; - - filters.forEach((filter, index) => { - if (!filter.attribute_key) { - errors[`filter_${index}`] = 'Attribute key is required'; - } else if (!filter.filter_operator) { - errors[`filter_${index}`] = 'Filter operator is required'; - } else if ( - filter.filter_operator !== 'is_present' && - filter.filter_operator !== 'is_not_present' && - !filter.values - ) { - errors[`filter_${index}`] = 'Value is required'; - } else if ( - filter.filter_operator === 'days_before' && - (parseInt(filter.values, 10) <= 0 || parseInt(filter.values, 10) >= 999) - ) { - errors[`filter_${index}`] = 'Value must be between 1 and 998'; - } - }); - - return errors; -}; diff --git a/app/javascript/dashboard/helper/validations.js b/app/javascript/dashboard/helper/validations.js new file mode 100644 index 000000000..482d04bd2 --- /dev/null +++ b/app/javascript/dashboard/helper/validations.js @@ -0,0 +1,75 @@ +export const validateConversationOrContactFilters = filters => { + const errors = {}; + + filters.forEach((filter, index) => { + if (!filter.attribute_key) { + errors[`filter_${index}`] = 'Attribute key is required'; + } else if (!filter.filter_operator) { + errors[`filter_${index}`] = 'Filter operator is required'; + } else if ( + filter.filter_operator !== 'is_present' && + filter.filter_operator !== 'is_not_present' && + !filter.values + ) { + errors[`filter_${index}`] = 'Value is required'; + } else if ( + filter.filter_operator === 'days_before' && + (parseInt(filter.values, 10) <= 0 || parseInt(filter.values, 10) >= 999) + ) { + errors[`filter_${index}`] = 'Value must be between 1 and 998'; + } + }); + + return errors; +}; + +export const validateAutomation = automation => { + const errors = {}; + + if (!automation.name) { + errors.name = 'Name is required'; + } + + if (!automation.description) { + errors.description = 'Description is required'; + } + + if (!automation.event_name) { + errors.event_name = 'Event name is required'; + } + + if (!automation.conditions || automation.conditions.length === 0) { + errors.conditions = 'At least one condition is required'; + } else { + automation.conditions.forEach((condition, index) => { + if ( + !( + condition.filter_operator === 'is_present' || + condition.filter_operator === 'is_not_present' + ) && + !condition.values + ) { + errors[`condition_${index}`] = 'Value is required'; + } + }); + } + + if (!automation.actions || automation.actions.length === 0) { + errors.actions = 'At least one action is required'; + } else { + automation.actions.forEach((action, index) => { + if ( + !( + action.action_name === 'mute_conversation' || + action.action_name === 'snooze_conversation' || + action.action_name === 'resolve_conversation' + ) && + (!action.action_params || action.action_params.length === 0) + ) { + errors[`action_${index}`] = 'Action parameters are required'; + } + }); + } + + return errors; +}; diff --git a/app/javascript/dashboard/mixins/automations/methodsMixin.js b/app/javascript/dashboard/mixins/automations/methodsMixin.js index 7797417a5..13b090c34 100644 --- a/app/javascript/dashboard/mixins/automations/methodsMixin.js +++ b/app/javascript/dashboard/mixins/automations/methodsMixin.js @@ -1,6 +1,6 @@ import languages from 'dashboard/components/widgets/conversation/advancedFilterItems/languages'; import countries from 'shared/constants/countries'; -import { useVuelidate } from '@vuelidate/core'; +import { validateAutomation } from 'dashboard/helper/validations'; import { generateCustomAttributeTypes, @@ -21,9 +21,6 @@ import { import { mapGetters } from 'vuex'; export default { - setup() { - return { v$: useVuelidate() }; - }, computed: { ...mapGetters({ agents: 'agents/getAgents', @@ -156,10 +153,11 @@ export default { } }, submitAutomation() { - this.v$.$touch(); - if (this.v$.$invalid) return; - const automation = generateAutomationPayload(this.automation); - this.$emit('saveAutomation', automation, this.mode); + this.errors = validateAutomation(this.automation); + if (Object.keys(this.errors).length === 0) { + const automation = generateAutomationPayload(this.automation); + this.$emit('saveAutomation', automation, this.mode); + } }, resetFilter(index, currentCondition) { this.automation.conditions[index].filter_operator = this.automationTypes[ diff --git a/app/javascript/dashboard/routes/dashboard/contacts/components/ContactsAdvancedFilters.vue b/app/javascript/dashboard/routes/dashboard/contacts/components/ContactsAdvancedFilters.vue index 85631271d..5581962db 100644 --- a/app/javascript/dashboard/routes/dashboard/contacts/components/ContactsAdvancedFilters.vue +++ b/app/javascript/dashboard/routes/dashboard/contacts/components/ContactsAdvancedFilters.vue @@ -97,7 +97,7 @@ import { filterAttributeGroups } from '../contactFilterItems'; import filterMixin from 'shared/mixins/filterMixin'; import * as OPERATORS from 'dashboard/components/widgets/FilterInput/FilterOperatorTypes.js'; import { CONTACTS_EVENTS } from '../../../../helper/AnalyticsHelper/events'; -import { validateConversationOrContactFilters } from 'dashboard/helper/conversationAdvancedFilterValidation.js'; +import { validateConversationOrContactFilters } from 'dashboard/helper/validations.js'; export default { components: { diff --git a/app/javascript/dashboard/routes/dashboard/settings/automation/AddAutomationRule.vue b/app/javascript/dashboard/routes/dashboard/settings/automation/AddAutomationRule.vue index 152b55aae..3ea836977 100644 --- a/app/javascript/dashboard/routes/dashboard/settings/automation/AddAutomationRule.vue +++ b/app/javascript/dashboard/routes/dashboard/settings/automation/AddAutomationRule.vue @@ -8,11 +8,7 @@ :label="$t('AUTOMATION.ADD.FORM.NAME.LABEL')" type="text" :class="{ error: $v.automation.name.$error }" - :error=" - $v.automation.name.$error - ? $t('AUTOMATION.ADD.FORM.NAME.ERROR') - : '' - " + :error="errors.name || ''" :placeholder="$t('AUTOMATION.ADD.FORM.NAME.PLACEHOLDER')" @blur="$v.automation.name.$touch" /> @@ -21,11 +17,7 @@ :label="$t('AUTOMATION.ADD.FORM.DESC.LABEL')" type="text" :class="{ error: $v.automation.description.$error }" - :error=" - $v.automation.description.$error - ? $t('AUTOMATION.ADD.FORM.DESC.ERROR') - : '' - " + :error="errors.description || ''" :placeholder="$t('AUTOMATION.ADD.FORM.DESC.PLACEHOLDER')" @blur="$v.automation.description.$touch" /> @@ -73,7 +65,7 @@ :custom-attribute-type=" getCustomAttributeType(automation.conditions[i].attribute_key) " - :v="$v.automation.conditions.$each[i]" + :error-message="errors[`condition_${i}`] || ''" @resetFilter="resetFilter(i, automation.conditions[i])" @removeFilter="removeFilter(i)" /> @@ -147,7 +139,6 @@ import { mapGetters } from 'vuex'; import alertMixin from 'shared/mixins/alertMixin'; import automationMethodsMixin from 'dashboard/mixins/automations/methodsMixin'; -import automationValidationsMixin from 'dashboard/mixins/automations/validationsMixin'; import filterInputBox from 'dashboard/components/widgets/FilterInput/Index.vue'; import automationActionInput from 'dashboard/components/widgets/AutomationActionInput.vue'; @@ -161,7 +152,7 @@ export default { filterInputBox, automationActionInput, }, - mixins: [alertMixin, automationMethodsMixin, automationValidationsMixin], + mixins: [alertMixin, automationMethodsMixin], props: { onClose: { type: Function, @@ -199,6 +190,7 @@ export default { showDeleteConfirmationModal: false, allCustomAttributes: [], mode: 'create', + errors: {}, }; }, computed: {