chore: Add validation error for label create/edit modal (#2381)
Co-authored-by: Pranav Raj S <pranav@chatwoot.com>
This commit is contained in:
@@ -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",
|
||||||
|
|||||||
@@ -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 = '#';
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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 '';
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user