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
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 208 additions and 143 deletions

View file

@ -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",

View file

@ -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 = '#';

View file

@ -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;

View file

@ -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"

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 '';
},
},
};