chore: Add validation error for label create/edit modal (#2381)
Co-authored-by: Pranav Raj S <pranav@chatwoot.com>
This commit is contained in:
parent
1bf7227843
commit
8a0afb912c
6 changed files with 208 additions and 143 deletions
|
@ -9,17 +9,15 @@
|
|||
"404": "There are no labels available in this account.",
|
||||
"TITLE": "Manage labels",
|
||||
"DESC": "Labels let you group the conversations together.",
|
||||
"TABLE_HEADER": [
|
||||
"Name",
|
||||
"Description",
|
||||
"Color"
|
||||
]
|
||||
"TABLE_HEADER": ["Name", "Description", "Color"]
|
||||
},
|
||||
"FORM": {
|
||||
"NAME": {
|
||||
"LABEL": "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": {
|
||||
"LABEL": "Description",
|
||||
|
|
|
@ -1,79 +1,66 @@
|
|||
<template>
|
||||
<modal :show.sync="show" :on-close="onClose">
|
||||
<div class="column content-box">
|
||||
<woot-modal-header
|
||||
:header-title="$t('LABEL_MGMT.ADD.TITLE')"
|
||||
:header-content="$t('LABEL_MGMT.ADD.DESC')"
|
||||
<div class="column content-box">
|
||||
<woot-modal-header
|
||||
:header-title="$t('LABEL_MGMT.ADD.TITLE')"
|
||||
: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
|
||||
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
|
||||
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"
|
||||
/>
|
||||
|
||||
<div class="medium-12">
|
||||
<label>
|
||||
{{ $t('LABEL_MGMT.FORM.COLOR.LABEL') }}
|
||||
<woot-color-picker v-model="color" />
|
||||
</label>
|
||||
</div>
|
||||
<div class="medium-12">
|
||||
<input v-model="showOnSidebar" type="checkbox" :value="true" />
|
||||
<label for="conversation_creation">
|
||||
{{ $t('LABEL_MGMT.FORM.SHOW_ON_SIDEBAR.LABEL') }}
|
||||
</label>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<woot-submit-button
|
||||
:disabled="$v.title.$invalid || uiFlags.isCreating"
|
||||
:button-text="$t('LABEL_MGMT.FORM.CREATE')"
|
||||
:loading="uiFlags.isCreating"
|
||||
/>
|
||||
<button class="button clear" @click.prevent="onClose">
|
||||
<div class="medium-12">
|
||||
<label>
|
||||
{{ $t('LABEL_MGMT.FORM.COLOR.LABEL') }}
|
||||
<woot-color-picker v-model="color" />
|
||||
</label>
|
||||
</div>
|
||||
<div class="medium-12">
|
||||
<input v-model="showOnSidebar" type="checkbox" :value="true" />
|
||||
<label for="conversation_creation">
|
||||
{{ $t('LABEL_MGMT.FORM.SHOW_ON_SIDEBAR.LABEL') }}
|
||||
</label>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<div class="medium-12 columns">
|
||||
<woot-button
|
||||
:is-disabled="$v.title.$invalid || uiFlags.isCreating"
|
||||
:is-loading="uiFlags.isCreating"
|
||||
>
|
||||
{{ $t('LABEL_MGMT.FORM.CREATE') }}
|
||||
</woot-button>
|
||||
<woot-button class="button clear" @click.prevent="onClose">
|
||||
{{ $t('LABEL_MGMT.FORM.CANCEL') }}
|
||||
</button>
|
||||
</woot-button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</modal>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import WootSubmitButton from '../../../../components/buttons/FormSubmitButton';
|
||||
import Modal from '../../../../components/Modal';
|
||||
import alertMixin from 'shared/mixins/alertMixin';
|
||||
import validationMixin from './validationMixin';
|
||||
import { mapGetters } from 'vuex';
|
||||
import validations from './validations';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
WootSubmitButton,
|
||||
Modal,
|
||||
},
|
||||
mixins: [alertMixin],
|
||||
props: {
|
||||
onClose: {
|
||||
type: Function,
|
||||
default: () => {},
|
||||
},
|
||||
show: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
},
|
||||
mixins: [alertMixin, validationMixin],
|
||||
data() {
|
||||
return {
|
||||
color: '#000',
|
||||
|
@ -92,6 +79,9 @@ export default {
|
|||
this.color = this.getRandomColor();
|
||||
},
|
||||
methods: {
|
||||
onClose() {
|
||||
this.$emit('close');
|
||||
},
|
||||
getRandomColor() {
|
||||
const letters = '0123456789ABCDEF';
|
||||
let color = '#';
|
||||
|
|
|
@ -1,82 +1,67 @@
|
|||
<template>
|
||||
<modal :show.sync="show" :on-close="onClose">
|
||||
<div class="column content-box">
|
||||
<woot-modal-header :header-title="pageTitle" />
|
||||
<form class="row" @submit.prevent="editLabel">
|
||||
<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"
|
||||
/>
|
||||
<div class="column content-box">
|
||||
<woot-modal-header :header-title="pageTitle" />
|
||||
<form class="row" @submit.prevent="editLabel">
|
||||
<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"
|
||||
/>
|
||||
<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
|
||||
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"
|
||||
/>
|
||||
|
||||
<div class="medium-12">
|
||||
<label>
|
||||
{{ $t('LABEL_MGMT.FORM.COLOR.LABEL') }}
|
||||
<woot-color-picker v-model="color" />
|
||||
</label>
|
||||
<div class="medium-12">
|
||||
<label>
|
||||
{{ $t('LABEL_MGMT.FORM.COLOR.LABEL') }}
|
||||
<woot-color-picker v-model="color" />
|
||||
</label>
|
||||
</div>
|
||||
<div class="medium-12">
|
||||
<input v-model="showOnSidebar" type="checkbox" :value="true" />
|
||||
<label for="conversation_creation">
|
||||
{{ $t('LABEL_MGMT.FORM.SHOW_ON_SIDEBAR.LABEL') }}
|
||||
</label>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<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 class="medium-12">
|
||||
<input v-model="showOnSidebar" type="checkbox" :value="true" />
|
||||
<label for="conversation_creation">
|
||||
{{ $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>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters } from 'vuex';
|
||||
import alertMixin from 'shared/mixins/alertMixin';
|
||||
|
||||
import WootSubmitButton from '../../../../components/buttons/FormSubmitButton';
|
||||
import Modal from '../../../../components/Modal';
|
||||
import validationMixin from './validationMixin';
|
||||
import validations from './validations';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
WootSubmitButton,
|
||||
Modal,
|
||||
},
|
||||
mixins: [alertMixin],
|
||||
mixins: [alertMixin, validationMixin],
|
||||
props: {
|
||||
show: {
|
||||
type: Boolean,
|
||||
default: () => {},
|
||||
},
|
||||
selectedResponse: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
onClose: {
|
||||
type: Function,
|
||||
default: () => {},
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
@ -101,6 +86,9 @@ export default {
|
|||
this.setFormValues();
|
||||
},
|
||||
methods: {
|
||||
onClose() {
|
||||
this.$emit('close');
|
||||
},
|
||||
setFormValues() {
|
||||
this.title = this.selectedResponse.title;
|
||||
this.description = this.selectedResponse.description;
|
||||
|
|
|
@ -73,19 +73,16 @@
|
|||
<span v-html="$t('LABEL_MGMT.SIDEBAR_TXT')"></span>
|
||||
</div>
|
||||
</div>
|
||||
<woot-modal :show.sync="showAddPopup" :on-close="hideAddPopup">
|
||||
<add-label @close="hideAddPopup" />
|
||||
</woot-modal>
|
||||
|
||||
<add-label
|
||||
v-if="showAddPopup"
|
||||
:show.sync="showAddPopup"
|
||||
:on-close="hideAddPopup"
|
||||
/>
|
||||
|
||||
<edit-label
|
||||
v-if="showEditPopup"
|
||||
:show.sync="showEditPopup"
|
||||
:selected-response="selectedResponse"
|
||||
:on-close="hideEditPopup"
|
||||
/>
|
||||
<woot-modal :show.sync="showEditPopup" :on-close="hideEditPopup">
|
||||
<edit-label
|
||||
:selected-response="selectedResponse"
|
||||
@close="hideEditPopup"
|
||||
/>
|
||||
</woot-modal>
|
||||
|
||||
<woot-delete-modal
|
||||
:show.sync="showDeleteConfirmationPopup"
|
||||
|
|
|
@ -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'
|
||||
);
|
||||
});
|
||||
});
|
|
@ -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 '';
|
||||
},
|
||||
},
|
||||
};
|
Loading…
Reference in a new issue