chore: Add validation error for label create/edit modal (#2381)

Co-authored-by: Pranav Raj S <pranav@chatwoot.com>
This commit is contained in:
Muhsin Keloth
2021-06-09 13:57:42 +05:30
committed by GitHub
parent 1bf7227843
commit 8a0afb912c
6 changed files with 208 additions and 143 deletions

View File

@@ -9,17 +9,15 @@
"404": "There are no labels available in this account.", "404": "There are no labels available in this account.",
"TITLE": "Manage labels", "TITLE": "Manage labels",
"DESC": "Labels let you group the conversations together.", "DESC": "Labels let you group the conversations together.",
"TABLE_HEADER": [ "TABLE_HEADER": ["Name", "Description", "Color"]
"Name",
"Description",
"Color"
]
}, },
"FORM": { "FORM": {
"NAME": { "NAME": {
"LABEL": "Label Name", "LABEL": "Label Name",
"PLACEHOLDER": "Label name", "PLACEHOLDER": "Label name",
"ERROR": "Label Name is required" "REQUIRED_ERROR": "Label name is required",
"MINIMUM_LENGTH_ERROR": "Minimum length 2 is required",
"VALID_ERROR": "Only Alphabets, Numbers, Hyphen and Underscore are allowed"
}, },
"DESCRIPTION": { "DESCRIPTION": {
"LABEL": "Description", "LABEL": "Description",

View File

@@ -1,5 +1,4 @@
<template> <template>
<modal :show.sync="show" :on-close="onClose">
<div class="column content-box"> <div class="column content-box">
<woot-modal-header <woot-modal-header
:header-title="$t('LABEL_MGMT.ADD.TITLE')" :header-title="$t('LABEL_MGMT.ADD.TITLE')"
@@ -12,6 +11,7 @@
class="medium-12 columns" class="medium-12 columns"
:label="$t('LABEL_MGMT.FORM.NAME.LABEL')" :label="$t('LABEL_MGMT.FORM.NAME.LABEL')"
:placeholder="$t('LABEL_MGMT.FORM.NAME.PLACEHOLDER')" :placeholder="$t('LABEL_MGMT.FORM.NAME.PLACEHOLDER')"
:error="getLabelTitleErrorMessage"
@input="$v.title.$touch" @input="$v.title.$touch"
/> />
@@ -37,43 +37,30 @@
</label> </label>
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<woot-submit-button <div class="medium-12 columns">
:disabled="$v.title.$invalid || uiFlags.isCreating" <woot-button
:button-text="$t('LABEL_MGMT.FORM.CREATE')" :is-disabled="$v.title.$invalid || uiFlags.isCreating"
:loading="uiFlags.isCreating" :is-loading="uiFlags.isCreating"
/> >
<button class="button clear" @click.prevent="onClose"> {{ $t('LABEL_MGMT.FORM.CREATE') }}
</woot-button>
<woot-button class="button clear" @click.prevent="onClose">
{{ $t('LABEL_MGMT.FORM.CANCEL') }} {{ $t('LABEL_MGMT.FORM.CANCEL') }}
</button> </woot-button>
</div>
</div> </div>
</form> </form>
</div> </div>
</modal>
</template> </template>
<script> <script>
import WootSubmitButton from '../../../../components/buttons/FormSubmitButton';
import Modal from '../../../../components/Modal';
import alertMixin from 'shared/mixins/alertMixin'; import alertMixin from 'shared/mixins/alertMixin';
import validationMixin from './validationMixin';
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import validations from './validations'; import validations from './validations';
export default { export default {
components: { mixins: [alertMixin, validationMixin],
WootSubmitButton,
Modal,
},
mixins: [alertMixin],
props: {
onClose: {
type: Function,
default: () => {},
},
show: {
type: Boolean,
default: true,
},
},
data() { data() {
return { return {
color: '#000', color: '#000',
@@ -92,6 +79,9 @@ export default {
this.color = this.getRandomColor(); this.color = this.getRandomColor();
}, },
methods: { methods: {
onClose() {
this.$emit('close');
},
getRandomColor() { getRandomColor() {
const letters = '0123456789ABCDEF'; const letters = '0123456789ABCDEF';
let color = '#'; let color = '#';

View File

@@ -1,5 +1,4 @@
<template> <template>
<modal :show.sync="show" :on-close="onClose">
<div class="column content-box"> <div class="column content-box">
<woot-modal-header :header-title="pageTitle" /> <woot-modal-header :header-title="pageTitle" />
<form class="row" @submit.prevent="editLabel"> <form class="row" @submit.prevent="editLabel">
@@ -9,9 +8,9 @@
class="medium-12 columns" class="medium-12 columns"
:label="$t('LABEL_MGMT.FORM.NAME.LABEL')" :label="$t('LABEL_MGMT.FORM.NAME.LABEL')"
:placeholder="$t('LABEL_MGMT.FORM.NAME.PLACEHOLDER')" :placeholder="$t('LABEL_MGMT.FORM.NAME.PLACEHOLDER')"
:error="getLabelTitleErrorMessage"
@input="$v.title.$touch" @input="$v.title.$touch"
/> />
<woot-input <woot-input
v-model.trim="description" v-model.trim="description"
:class="{ error: $v.description.$error }" :class="{ error: $v.description.$error }"
@@ -35,48 +34,34 @@
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<div class="medium-12 columns"> <div class="medium-12 columns">
<woot-submit-button <woot-button
:disabled="$v.title.$invalid || uiFlags.isUpdating" :is-disabled="$v.title.$invalid || uiFlags.isUpdating"
:button-text="$t('LABEL_MGMT.FORM.EDIT')" :is-loading="uiFlags.isUpdating"
:loading="uiFlags.isUpdating" >
/> {{ $t('LABEL_MGMT.FORM.EDIT') }}
<button class="button clear" @click.prevent="onClose"> </woot-button>
<woot-button class="button clear" @click.prevent="onClose">
{{ $t('LABEL_MGMT.FORM.CANCEL') }} {{ $t('LABEL_MGMT.FORM.CANCEL') }}
</button> </woot-button>
</div> </div>
</div> </div>
</form> </form>
</div> </div>
</modal>
</template> </template>
<script> <script>
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import alertMixin from 'shared/mixins/alertMixin'; import alertMixin from 'shared/mixins/alertMixin';
import validationMixin from './validationMixin';
import WootSubmitButton from '../../../../components/buttons/FormSubmitButton';
import Modal from '../../../../components/Modal';
import validations from './validations'; import validations from './validations';
export default { export default {
components: { mixins: [alertMixin, validationMixin],
WootSubmitButton,
Modal,
},
mixins: [alertMixin],
props: { props: {
show: {
type: Boolean,
default: () => {},
},
selectedResponse: { selectedResponse: {
type: Object, type: Object,
default: () => {}, default: () => {},
}, },
onClose: {
type: Function,
default: () => {},
},
}, },
data() { data() {
return { return {
@@ -101,6 +86,9 @@ export default {
this.setFormValues(); this.setFormValues();
}, },
methods: { methods: {
onClose() {
this.$emit('close');
},
setFormValues() { setFormValues() {
this.title = this.selectedResponse.title; this.title = this.selectedResponse.title;
this.description = this.selectedResponse.description; this.description = this.selectedResponse.description;

View File

@@ -73,19 +73,16 @@
<span v-html="$t('LABEL_MGMT.SIDEBAR_TXT')"></span> <span v-html="$t('LABEL_MGMT.SIDEBAR_TXT')"></span>
</div> </div>
</div> </div>
<woot-modal :show.sync="showAddPopup" :on-close="hideAddPopup">
<add-label @close="hideAddPopup" />
</woot-modal>
<add-label <woot-modal :show.sync="showEditPopup" :on-close="hideEditPopup">
v-if="showAddPopup"
:show.sync="showAddPopup"
:on-close="hideAddPopup"
/>
<edit-label <edit-label
v-if="showEditPopup"
:show.sync="showEditPopup"
:selected-response="selectedResponse" :selected-response="selectedResponse"
:on-close="hideEditPopup" @close="hideEditPopup"
/> />
</woot-modal>
<woot-delete-modal <woot-delete-modal
:show.sync="showDeleteConfirmationPopup" :show.sync="showDeleteConfirmationPopup"

View File

@@ -0,0 +1,76 @@
import { shallowMount, createLocalVue } from '@vue/test-utils';
import VueI18n from 'vue-i18n';
import Vuelidate from 'vuelidate';
import validationMixin from '../validationMixin';
import validations from '../validations';
import i18n from 'dashboard/i18n';
const localVue = createLocalVue();
localVue.use(VueI18n);
localVue.use(Vuelidate);
const i18nConfig = new VueI18n({
locale: 'en',
messages: i18n,
});
const Component = {
render() {},
title: 'TestComponent',
mixins: [validationMixin],
validations,
};
describe('validationMixin', () => {
it('it should return empty error message if valid label name passed', async () => {
const wrapper = shallowMount(Component, {
i18n: i18nConfig,
localVue,
data() {
return {
title: 'sales',
};
},
});
expect(wrapper.vm.getLabelTitleErrorMessage).toBe('');
});
it('it should return label required error message if empty name is passed', async () => {
const wrapper = shallowMount(Component, {
i18n: i18nConfig,
localVue,
data() {
return {
title: '',
};
},
});
expect(wrapper.vm.getLabelTitleErrorMessage).toBe('Label name is required');
});
it('it should return label minimum length error message if one charceter label name is passed', async () => {
const wrapper = shallowMount(Component, {
i18n: i18nConfig,
localVue,
data() {
return {
title: 's',
};
},
});
expect(wrapper.vm.getLabelTitleErrorMessage).toBe(
'Minimum length 2 is required'
);
});
it('it should return invalid character error message if invalid lable name passed', async () => {
const wrapper = shallowMount(Component, {
i18n: i18nConfig,
localVue,
data() {
return {
title: 'sales enquiry',
};
},
});
expect(wrapper.vm.getLabelTitleErrorMessage).toBe(
'Only Alphabets, Numbers, Hyphen and Underscore are allowed'
);
});
});

View File

@@ -0,0 +1,16 @@
export default {
computed: {
getLabelTitleErrorMessage() {
if (!this.title) {
return this.$t('LABEL_MGMT.FORM.NAME.REQUIRED_ERROR');
}
if (!this.$v.title.minLength) {
return this.$t('LABEL_MGMT.FORM.NAME.MINIMUM_LENGTH_ERROR');
}
if (!this.$v.title.validLabelCharacters) {
return this.$t('LABEL_MGMT.FORM.NAME.VALID_ERROR');
}
return '';
},
},
};