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,79 +1,66 @@
<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')" :header-content="$t('LABEL_MGMT.ADD.DESC')"
:header-content="$t('LABEL_MGMT.ADD.DESC')" />
<form class="row" @submit.prevent="addLabel">
<woot-input
v-model.trim="title"
:class="{ error: $v.title.$error }"
class="medium-12 columns"
:label="$t('LABEL_MGMT.FORM.NAME.LABEL')"
:placeholder="$t('LABEL_MGMT.FORM.NAME.PLACEHOLDER')"
:error="getLabelTitleErrorMessage"
@input="$v.title.$touch"
/> />
<form class="row" @submit.prevent="addLabel">
<woot-input
v-model.trim="title"
:class="{ error: $v.title.$error }"
class="medium-12 columns"
:label="$t('LABEL_MGMT.FORM.NAME.LABEL')"
:placeholder="$t('LABEL_MGMT.FORM.NAME.PLACEHOLDER')"
@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 }"
class="medium-12 columns" class="medium-12 columns"
:label="$t('LABEL_MGMT.FORM.DESCRIPTION.LABEL')" :label="$t('LABEL_MGMT.FORM.DESCRIPTION.LABEL')"
:placeholder="$t('LABEL_MGMT.FORM.DESCRIPTION.PLACEHOLDER')" :placeholder="$t('LABEL_MGMT.FORM.DESCRIPTION.PLACEHOLDER')"
@input="$v.description.$touch" @input="$v.description.$touch"
/> />
<div class="medium-12"> <div class="medium-12">
<label> <label>
{{ $t('LABEL_MGMT.FORM.COLOR.LABEL') }} {{ $t('LABEL_MGMT.FORM.COLOR.LABEL') }}
<woot-color-picker v-model="color" /> <woot-color-picker v-model="color" />
</label> </label>
</div> </div>
<div class="medium-12"> <div class="medium-12">
<input v-model="showOnSidebar" type="checkbox" :value="true" /> <input v-model="showOnSidebar" type="checkbox" :value="true" />
<label for="conversation_creation"> <label for="conversation_creation">
{{ $t('LABEL_MGMT.FORM.SHOW_ON_SIDEBAR.LABEL') }} {{ $t('LABEL_MGMT.FORM.SHOW_ON_SIDEBAR.LABEL') }}
</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>
</form> </div>
</div> </form>
</modal> </div>
</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,82 +1,67 @@
<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"> <woot-input
<woot-input v-model.trim="title"
v-model.trim="title" :class="{ error: $v.title.$error }"
:class="{ error: $v.title.$error }" 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
v-model.trim="description"
:class="{ error: $v.description.$error }"
class="medium-12 columns"
:label="$t('LABEL_MGMT.FORM.DESCRIPTION.LABEL')"
:placeholder="$t('LABEL_MGMT.FORM.DESCRIPTION.PLACEHOLDER')"
@input="$v.description.$touch"
/>
<woot-input <div class="medium-12">
v-model.trim="description" <label>
:class="{ error: $v.description.$error }" {{ $t('LABEL_MGMT.FORM.COLOR.LABEL') }}
class="medium-12 columns" <woot-color-picker v-model="color" />
:label="$t('LABEL_MGMT.FORM.DESCRIPTION.LABEL')" </label>
:placeholder="$t('LABEL_MGMT.FORM.DESCRIPTION.PLACEHOLDER')" </div>
@input="$v.description.$touch" <div class="medium-12">
/> <input v-model="showOnSidebar" type="checkbox" :value="true" />
<label for="conversation_creation">
<div class="medium-12"> {{ $t('LABEL_MGMT.FORM.SHOW_ON_SIDEBAR.LABEL') }}
<label> </label>
{{ $t('LABEL_MGMT.FORM.COLOR.LABEL') }} </div>
<woot-color-picker v-model="color" /> <div class="modal-footer">
</label> <div class="medium-12 columns">
<woot-button
:is-disabled="$v.title.$invalid || uiFlags.isUpdating"
:is-loading="uiFlags.isUpdating"
>
{{ $t('LABEL_MGMT.FORM.EDIT') }}
</woot-button>
<woot-button class="button clear" @click.prevent="onClose">
{{ $t('LABEL_MGMT.FORM.CANCEL') }}
</woot-button>
</div> </div>
<div class="medium-12"> </div>
<input v-model="showOnSidebar" type="checkbox" :value="true" /> </form>
<label for="conversation_creation"> </div>
{{ $t('LABEL_MGMT.FORM.SHOW_ON_SIDEBAR.LABEL') }}
</label>
</div>
<div class="modal-footer">
<div class="medium-12 columns">
<woot-submit-button
:disabled="$v.title.$invalid || uiFlags.isUpdating"
:button-text="$t('LABEL_MGMT.FORM.EDIT')"
:loading="uiFlags.isUpdating"
/>
<button class="button clear" @click.prevent="onClose">
{{ $t('LABEL_MGMT.FORM.CANCEL') }}
</button>
</div>
</div>
</form>
</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" <edit-label
:show.sync="showAddPopup" :selected-response="selectedResponse"
:on-close="hideAddPopup" @close="hideEditPopup"
/> />
</woot-modal>
<edit-label
v-if="showEditPopup"
:show.sync="showEditPopup"
:selected-response="selectedResponse"
:on-close="hideEditPopup"
/>
<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 '';
},
},
};