mirror of
https://github.com/lingble/chatwoot.git
synced 2025-11-01 19:48:08 +00:00
feat: Rewrite labels/validationMixin mixin to a helper (#9818)
This commit is contained in:
@@ -1,17 +1,17 @@
|
||||
<template>
|
||||
<div class="h-auto overflow-auto flex flex-col">
|
||||
<div class="flex flex-col h-auto overflow-auto">
|
||||
<woot-modal-header
|
||||
:header-title="$t('LABEL_MGMT.ADD.TITLE')"
|
||||
:header-content="$t('LABEL_MGMT.ADD.DESC')"
|
||||
/>
|
||||
<form class="mx-0 flex flex-wrap" @submit.prevent="addLabel">
|
||||
<form class="flex flex-wrap mx-0" @submit.prevent="addLabel">
|
||||
<woot-input
|
||||
v-model.trim="title"
|
||||
:class="{ error: $v.title.$error }"
|
||||
class="w-full label-name--input"
|
||||
:label="$t('LABEL_MGMT.FORM.NAME.LABEL')"
|
||||
:placeholder="$t('LABEL_MGMT.FORM.NAME.PLACEHOLDER')"
|
||||
:error="getLabelTitleErrorMessage"
|
||||
:error="labelTitleErrorMessage"
|
||||
data-testid="label-title"
|
||||
@input="$v.title.$touch"
|
||||
/>
|
||||
@@ -32,13 +32,13 @@
|
||||
<woot-color-picker v-model="color" />
|
||||
</label>
|
||||
</div>
|
||||
<div class="w-full flex items-center gap-2">
|
||||
<div class="flex items-center w-full gap-2">
|
||||
<input v-model="showOnSidebar" type="checkbox" :value="true" />
|
||||
<label for="conversation_creation">
|
||||
{{ $t('LABEL_MGMT.FORM.SHOW_ON_SIDEBAR.LABEL') }}
|
||||
</label>
|
||||
</div>
|
||||
<div class="flex justify-end items-center py-2 px-0 gap-2 w-full">
|
||||
<div class="flex items-center justify-end w-full gap-2 px-0 py-2">
|
||||
<woot-button
|
||||
:is-disabled="$v.title.$invalid || uiFlags.isCreating"
|
||||
:is-loading="uiFlags.isCreating"
|
||||
@@ -56,13 +56,12 @@
|
||||
|
||||
<script>
|
||||
import alertMixin from 'shared/mixins/alertMixin';
|
||||
import validationMixin from './validationMixin';
|
||||
import { mapGetters } from 'vuex';
|
||||
import validations from './validations';
|
||||
import validations, { getLabelTitleErrorMessage } from './validations';
|
||||
import { getRandomColor } from 'dashboard/helper/labelColor';
|
||||
|
||||
export default {
|
||||
mixins: [alertMixin, validationMixin],
|
||||
mixins: [alertMixin],
|
||||
props: {
|
||||
prefillTitle: {
|
||||
type: String,
|
||||
@@ -82,6 +81,10 @@ export default {
|
||||
...mapGetters({
|
||||
uiFlags: 'labels/getUIFlags',
|
||||
}),
|
||||
labelTitleErrorMessage() {
|
||||
const errorMessage = getLabelTitleErrorMessage(this.$v);
|
||||
return this.$t(errorMessage);
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.color = getRandomColor();
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
<template>
|
||||
<div class="h-auto overflow-auto flex flex-col">
|
||||
<div class="flex flex-col h-auto overflow-auto">
|
||||
<woot-modal-header :header-title="pageTitle" />
|
||||
<form class="mx-0 flex flex-wrap" @submit.prevent="editLabel">
|
||||
<form class="flex flex-wrap mx-0" @submit.prevent="editLabel">
|
||||
<woot-input
|
||||
v-model.trim="title"
|
||||
:class="{ error: $v.title.$error }"
|
||||
class="w-full label-name--input"
|
||||
:label="$t('LABEL_MGMT.FORM.NAME.LABEL')"
|
||||
:placeholder="$t('LABEL_MGMT.FORM.NAME.PLACEHOLDER')"
|
||||
:error="getLabelTitleErrorMessage"
|
||||
:error="labelTitleErrorMessage"
|
||||
@input="$v.title.$touch"
|
||||
/>
|
||||
<woot-input
|
||||
@@ -26,13 +26,13 @@
|
||||
<woot-color-picker v-model="color" />
|
||||
</label>
|
||||
</div>
|
||||
<div class="w-full flex items-center gap-2">
|
||||
<div class="flex items-center w-full gap-2">
|
||||
<input v-model="showOnSidebar" type="checkbox" :value="true" />
|
||||
<label for="conversation_creation">
|
||||
{{ $t('LABEL_MGMT.FORM.SHOW_ON_SIDEBAR.LABEL') }}
|
||||
</label>
|
||||
</div>
|
||||
<div class="flex justify-end items-center py-2 px-0 gap-2 w-full">
|
||||
<div class="flex items-center justify-end w-full gap-2 px-0 py-2">
|
||||
<woot-button
|
||||
:is-disabled="$v.title.$invalid || uiFlags.isUpdating"
|
||||
:is-loading="uiFlags.isUpdating"
|
||||
@@ -50,11 +50,10 @@
|
||||
<script>
|
||||
import { mapGetters } from 'vuex';
|
||||
import alertMixin from 'shared/mixins/alertMixin';
|
||||
import validationMixin from './validationMixin';
|
||||
import validations from './validations';
|
||||
import validations, { getLabelTitleErrorMessage } from './validations';
|
||||
|
||||
export default {
|
||||
mixins: [alertMixin, validationMixin],
|
||||
mixins: [alertMixin],
|
||||
props: {
|
||||
selectedResponse: {
|
||||
type: Object,
|
||||
@@ -79,6 +78,10 @@ export default {
|
||||
this.selectedResponse.title
|
||||
}`;
|
||||
},
|
||||
labelTitleErrorMessage() {
|
||||
const errorMessage = getLabelTitleErrorMessage(this.$v);
|
||||
return this.$t(errorMessage);
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.setFormValues();
|
||||
|
||||
@@ -1,72 +0,0 @@
|
||||
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' };
|
||||
},
|
||||
});
|
||||
wrapper.vm.$v.$touch();
|
||||
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: '' };
|
||||
},
|
||||
});
|
||||
wrapper.vm.$v.$touch();
|
||||
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' };
|
||||
},
|
||||
});
|
||||
wrapper.vm.$v.$touch();
|
||||
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' };
|
||||
},
|
||||
});
|
||||
wrapper.vm.$v.$touch();
|
||||
expect(wrapper.vm.getLabelTitleErrorMessage).toBe(
|
||||
'Only Alphabets, Numbers, Hyphen and Underscore are allowed'
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -1,4 +1,7 @@
|
||||
import { validLabelCharacters } from '../validations';
|
||||
import {
|
||||
validLabelCharacters,
|
||||
getLabelTitleErrorMessage,
|
||||
} from '../validations';
|
||||
|
||||
describe('#validLabelCharacters', () => {
|
||||
it('validates the label', () => {
|
||||
@@ -8,3 +11,64 @@ describe('#validLabelCharacters', () => {
|
||||
expect(validLabelCharacters('str-str')).toEqual(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#getLabelTitleErrorMessage', () => {
|
||||
const createValidation = titleValidation => ({
|
||||
title: {
|
||||
$error: titleValidation.$error,
|
||||
required: titleValidation.required,
|
||||
minLength: titleValidation.minLength,
|
||||
validLabelCharacters: titleValidation.validLabelCharacters,
|
||||
},
|
||||
});
|
||||
|
||||
it('returns an empty string when there are no validation errors', () => {
|
||||
const validation = createValidation({
|
||||
$error: false,
|
||||
required: true,
|
||||
minLength: true,
|
||||
validLabelCharacters: true,
|
||||
});
|
||||
|
||||
expect(getLabelTitleErrorMessage(validation)).toEqual('');
|
||||
});
|
||||
|
||||
it('returns a required error message when the title is required but not provided', () => {
|
||||
const validation = createValidation({
|
||||
$error: true,
|
||||
required: false,
|
||||
minLength: true,
|
||||
validLabelCharacters: true,
|
||||
});
|
||||
|
||||
expect(getLabelTitleErrorMessage(validation)).toEqual(
|
||||
'LABEL_MGMT.FORM.NAME.REQUIRED_ERROR'
|
||||
);
|
||||
});
|
||||
|
||||
it('returns a minimum length error message when the title is too short', () => {
|
||||
const validation = createValidation({
|
||||
$error: true,
|
||||
required: true,
|
||||
minLength: false,
|
||||
validLabelCharacters: true,
|
||||
});
|
||||
|
||||
expect(getLabelTitleErrorMessage(validation)).toEqual(
|
||||
'LABEL_MGMT.FORM.NAME.MINIMUM_LENGTH_ERROR'
|
||||
);
|
||||
});
|
||||
|
||||
it('returns a valid label characters error message when the title has invalid characters', () => {
|
||||
const validation = createValidation({
|
||||
$error: true,
|
||||
required: true,
|
||||
minLength: true,
|
||||
validLabelCharacters: false,
|
||||
});
|
||||
|
||||
expect(getLabelTitleErrorMessage(validation)).toEqual(
|
||||
'LABEL_MGMT.FORM.NAME.VALID_ERROR'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
export default {
|
||||
computed: {
|
||||
getLabelTitleErrorMessage() {
|
||||
let errorMessage = '';
|
||||
if (!this.$v.title.$error) {
|
||||
errorMessage = '';
|
||||
} else if (!this.$v.title.required) {
|
||||
errorMessage = this.$t('LABEL_MGMT.FORM.NAME.REQUIRED_ERROR');
|
||||
} else if (!this.$v.title.minLength) {
|
||||
errorMessage = this.$t('LABEL_MGMT.FORM.NAME.MINIMUM_LENGTH_ERROR');
|
||||
} else if (!this.$v.title.validLabelCharacters) {
|
||||
errorMessage = this.$t('LABEL_MGMT.FORM.NAME.VALID_ERROR');
|
||||
}
|
||||
return errorMessage;
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -2,6 +2,20 @@ import { required, minLength } from 'vuelidate/lib/validators';
|
||||
|
||||
export const validLabelCharacters = (str = '') => !!str && !str.includes(' ');
|
||||
|
||||
export const getLabelTitleErrorMessage = validation => {
|
||||
let errorMessage = '';
|
||||
if (!validation.title.$error) {
|
||||
errorMessage = '';
|
||||
} else if (!validation.title.required) {
|
||||
errorMessage = 'LABEL_MGMT.FORM.NAME.REQUIRED_ERROR';
|
||||
} else if (!validation.title.minLength) {
|
||||
errorMessage = 'LABEL_MGMT.FORM.NAME.MINIMUM_LENGTH_ERROR';
|
||||
} else if (!validation.title.validLabelCharacters) {
|
||||
errorMessage = 'LABEL_MGMT.FORM.NAME.VALID_ERROR';
|
||||
}
|
||||
return errorMessage;
|
||||
};
|
||||
|
||||
export default {
|
||||
title: {
|
||||
required,
|
||||
|
||||
Reference in New Issue
Block a user