With the creation of the Customer Preferences Page we add the possibility for the subscriber's administrator to view and edit some of the preferences that are applied customer's wide. We also refactored $errMsg, the function that handles validation error messages globally. The reviewed function displays the error text based on the errorMessages methods in src/validators/index.js Change-Id: Ic9a1b2eab9b71255026447a690d3426097cbaf93mr13.0
parent
aff80a1e1f
commit
0cb6554966
@ -1,12 +1,11 @@
|
||||
|
||||
export default ({ Vue, app }) => {
|
||||
app.config.globalProperties.$errorMessage = (def) => {
|
||||
let message = null
|
||||
if (def.$errors && def.$errors.length) {
|
||||
if (def.$errors[0].$validator) {
|
||||
message = app.i18n.global.tc('validators.' + def.$errors[0].$validator)
|
||||
import { errorMessages } from 'src/validators'
|
||||
export default ({ app }) => {
|
||||
app.config.globalProperties.$errMsg = (v$) => {
|
||||
if (v$ && v$.length) {
|
||||
if (v$[0].$validator && errorMessages[v$[0].$validator]) {
|
||||
return errorMessages[v$[0].$validator](v$[0].$params, v$[0])
|
||||
}
|
||||
}
|
||||
return message
|
||||
return ''
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,161 @@
|
||||
<template>
|
||||
<div>
|
||||
<q-input
|
||||
ref="input"
|
||||
v-model.trim="input"
|
||||
v-bind="$attrs"
|
||||
clearable
|
||||
hide-bottom-space
|
||||
@keyup.enter="add(input)"
|
||||
@clear="clearInput"
|
||||
@blur="blurInput"
|
||||
>
|
||||
<template
|
||||
#append
|
||||
>
|
||||
<q-btn
|
||||
v-if="showAddButton()"
|
||||
icon="add"
|
||||
color="primary"
|
||||
:label="$t('Add')"
|
||||
data-cy="chip-add"
|
||||
size="sm"
|
||||
flat
|
||||
dense
|
||||
@click="add(input)"
|
||||
/>
|
||||
<q-btn
|
||||
v-if="showRemoveAllButton()"
|
||||
icon="delete"
|
||||
color="negative"
|
||||
size="sm"
|
||||
flat
|
||||
dense
|
||||
:label="$t('Remove all')"
|
||||
data-cy="chip-removeall"
|
||||
@click="removeAll"
|
||||
/>
|
||||
</template>
|
||||
</q-input>
|
||||
<div
|
||||
v-if="items && items.length > 0"
|
||||
>
|
||||
<q-chip
|
||||
v-for="(item, index) in items"
|
||||
:key="getItemKey(item, index)"
|
||||
:label="item.label"
|
||||
:removable="!$attrs.disable"
|
||||
:dense="$attrs.dense"
|
||||
@remove="remove(item)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import useValidate from '@vuelidate/core'
|
||||
export default {
|
||||
name: 'CscInputChips',
|
||||
props: {
|
||||
value: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
}
|
||||
},
|
||||
emits: ['input'],
|
||||
data () {
|
||||
return {
|
||||
v$: useValidate(),
|
||||
input: '',
|
||||
items: []
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
itemsAsArray () {
|
||||
const items = []
|
||||
if (this.items) {
|
||||
this.items.forEach((item) => {
|
||||
items.push(item.value)
|
||||
})
|
||||
}
|
||||
return items
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
value (newItems) {
|
||||
this.assignItems(newItems)
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
this.assignItems(this.value)
|
||||
this.resetInput()
|
||||
},
|
||||
methods: {
|
||||
removeAll () {
|
||||
this.$emit('input', [])
|
||||
},
|
||||
remove (removable) {
|
||||
const newItems = this.items.filter(item => item.value !== removable.value)
|
||||
this.$emit('input', newItems.map(item => item.value))
|
||||
},
|
||||
add (value) {
|
||||
let isValid = true
|
||||
if (this.v$.input) {
|
||||
this.v$.input.$touch()
|
||||
isValid = !this.v$.input.$error
|
||||
}
|
||||
if (isValid) {
|
||||
const exists = this.items.find(item => item.value === value)
|
||||
if (value !== undefined && value !== null && value !== '' && !exists) {
|
||||
this.resetInput()
|
||||
this.input = ''
|
||||
this.items.push({
|
||||
value: value,
|
||||
label: value
|
||||
})
|
||||
|
||||
this.$emit('input', this.items.map(item => item.value))
|
||||
}
|
||||
}
|
||||
},
|
||||
assignItems (newItems) {
|
||||
if (newItems) {
|
||||
this.items = []
|
||||
return newItems.forEach((value) => {
|
||||
this.items.push({
|
||||
value: value,
|
||||
label: value
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
this.items = newItems
|
||||
},
|
||||
clearInput () {
|
||||
this.resetInput()
|
||||
this.$refs.input.blur()
|
||||
},
|
||||
resetInput () {
|
||||
if (this.v$.input) {
|
||||
this.v$.input.$reset()
|
||||
}
|
||||
},
|
||||
blurInput () {
|
||||
if (this.input === undefined || this.input === null || this.input === '') {
|
||||
this.resetInput()
|
||||
}
|
||||
},
|
||||
getItemKey (item, index) {
|
||||
return `${String(item.value)}-${String(index)}`
|
||||
},
|
||||
showAddButton () {
|
||||
return this.input !== undefined && this.input !== null && this.input !== ''
|
||||
},
|
||||
showRemoveAllButton () {
|
||||
return (this.input === undefined || this.input === null || this.input === '') &&
|
||||
this.items &&
|
||||
this.items.length > 0
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
@ -0,0 +1,298 @@
|
||||
<template>
|
||||
<csc-page
|
||||
id="csc-page-customer-preferences"
|
||||
class="q-pa-lg row"
|
||||
>
|
||||
<q-list
|
||||
v-if="changes"
|
||||
class="col col-xs-12 col-md-5"
|
||||
>
|
||||
<q-item>
|
||||
<q-item-section>
|
||||
<q-toggle
|
||||
v-model="changes.ignore_cf_when_hunting"
|
||||
class="q-pa-sm"
|
||||
:label="$t('Ignore Members Call Forwards when Hunting')"
|
||||
@update:model-value="ignoreMembers"
|
||||
/>
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
<q-item>
|
||||
<q-item-section>
|
||||
<q-toggle
|
||||
v-model="changes.block_in_mode"
|
||||
class="q-pa-sm"
|
||||
:label="$t('Block Mode for inbound calls')"
|
||||
@update:model-value="blockInMode"
|
||||
/>
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
<q-item>
|
||||
<q-item-section>
|
||||
<csc-input-chips
|
||||
:value="changes.block_in_list"
|
||||
:label="$t('Block List for inbound calls')"
|
||||
:emit-array="true"
|
||||
dense
|
||||
@input="setPreferenceInboundEvent($event)"
|
||||
/>
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
<q-item>
|
||||
<q-item-section>
|
||||
<q-toggle
|
||||
v-model="changes.block_in_clir"
|
||||
class="q-pa-sm"
|
||||
:label="$t('Block anonymous inbound calls')"
|
||||
@update:model-value="blockInClir"
|
||||
/>
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
<q-item>
|
||||
<q-item-section>
|
||||
<q-toggle
|
||||
v-model="changes.block_out_mode"
|
||||
class="q-pa-sm"
|
||||
:label="$t('Block Mode for outbounds calls')"
|
||||
@update:model-value="blockOutMode"
|
||||
/>
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
<q-item>
|
||||
<q-item-section>
|
||||
<csc-input-chips
|
||||
:value="changes.block_out_list"
|
||||
:label="$t('Block List for outbounds calls')"
|
||||
:emit-array="true"
|
||||
dense
|
||||
@input="setPreferenceOutboundEvent($event)"
|
||||
/>
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
<q-item>
|
||||
<q-item-section>
|
||||
<q-input
|
||||
v-model.trim="changes.block_out_override_pin"
|
||||
:label="$t('PIN to bypass outbound Block List')"
|
||||
clearable
|
||||
hide-bottom-space
|
||||
:error="v$.changes.block_out_override_pin.$errors.length > 0"
|
||||
:error-message="$errMsg(v$.changes.block_out_override_pin.$errors)"
|
||||
@keyup.enter="save"
|
||||
>
|
||||
<template
|
||||
v-if="hasBlockOutOverridePinChanged"
|
||||
#append
|
||||
>
|
||||
<csc-input-button-save
|
||||
@click.stop="save"
|
||||
/>
|
||||
<csc-input-button-reset
|
||||
@click.stop="resetBlockOutOverridePin"
|
||||
/>
|
||||
</template>
|
||||
</q-input>
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
<q-item>
|
||||
<q-item-section>
|
||||
<q-toggle
|
||||
v-model="changes.play_announce_before_call_setup"
|
||||
class="q-pa-sm"
|
||||
:label="$t('Play announcement before call setup')"
|
||||
@update:model-value="playAnnounceBeforeCallSetup"
|
||||
/>
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
<q-item>
|
||||
<q-item-section>
|
||||
<q-toggle
|
||||
v-model="changes.play_announce_to_callee"
|
||||
class="q-pa-sm"
|
||||
:label="$t('Play announcement to callee after answer')"
|
||||
@update:model-value="playAnnounceToCallee"
|
||||
/>
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
</q-list>
|
||||
</csc-page>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
mapGetters,
|
||||
mapActions,
|
||||
mapState,
|
||||
mapMutations
|
||||
} from 'vuex'
|
||||
import CscPage from 'components/CscPage'
|
||||
import CscInputChips from 'components/CscInputChips'
|
||||
import CscInputButtonReset from 'components/form/CscInputButtonReset'
|
||||
import CscInputButtonSave from 'components/form/CscInputButtonSave'
|
||||
import { integer } from '@vuelidate/validators'
|
||||
import useValidate from '@vuelidate/core'
|
||||
import _ from 'lodash'
|
||||
export default {
|
||||
name: 'CscPageCustomerPreferences',
|
||||
components: {
|
||||
CscPage,
|
||||
CscInputChips,
|
||||
CscInputButtonReset,
|
||||
CscInputButtonSave
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
v$: useValidate(),
|
||||
changes: null,
|
||||
inputValue: '',
|
||||
items: []
|
||||
}
|
||||
},
|
||||
validations () {
|
||||
return {
|
||||
changes: {
|
||||
block_out_override_pin: {
|
||||
integer
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters('user', [
|
||||
'getCustomerId'
|
||||
]),
|
||||
...mapState('customer', [
|
||||
'customerPreferences',
|
||||
'customerPreferencesSelected'
|
||||
]),
|
||||
hasBlockOutOverridePinChanged () {
|
||||
return this.changes.block_out_override_pin !== this.customerPreferences.block_out_override_pin
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
customerPreferences () {
|
||||
this.changes = this.getCustomerPreferencesData()
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
this.loadCustomerPreferences(this.getCustomerId)
|
||||
this.expandCustomerPreferences()
|
||||
},
|
||||
methods: {
|
||||
...mapActions('customer', [
|
||||
'loadCustomerPreferences',
|
||||
'updateIgnoreMembers',
|
||||
'updateBlockInList',
|
||||
'updateBlockInMode',
|
||||
'updateBlockInClir',
|
||||
'updateBlockOutMode',
|
||||
'updateBlockOutList',
|
||||
'updateBlockOutOverridePin',
|
||||
'updatePlayAnnounceBeforeCallSetup',
|
||||
'updatePlayAnnounceToCallee'
|
||||
]),
|
||||
...mapMutations('customer', [
|
||||
'expandCustomerPreferences'
|
||||
]),
|
||||
getCustomerPreferencesData () {
|
||||
return (this.customerPreferences)
|
||||
? {
|
||||
ignore_cf_when_hunting: this.customerPreferences.ignore_cf_when_hunting ? this.customerPreferences.ignore_cf_when_hunting : false,
|
||||
block_in_mode: this.customerPreferences.block_in_mode ? this.customerPreferences.block_in_mode : false,
|
||||
block_in_clir: this.customerPreferences.block_in_clir ? this.customerPreferences.block_in_clir : false,
|
||||
block_out_mode: this.customerPreferences.block_out_mode ? this.customerPreferences.block_out_mode : false,
|
||||
play_announce_before_call_setup: this.customerPreferences.play_announce_before_call_setup ? this.customerPreferences.play_announce_before_call_setup : false,
|
||||
play_announce_to_callee: this.customerPreferences.play_announce_to_callee ? this.customerPreferences.play_announce_to_callee : false,
|
||||
block_out_override_pin: this.customerPreferences.block_out_override_pin ? this.customerPreferences.block_out_override_pin : undefined,
|
||||
block_in_list: this.customerPreferences.block_in_list ? this.customerPreferences.block_in_list : [],
|
||||
block_out_list: this.customerPreferences.block_out_list ? this.customerPreferences.block_out_list : []
|
||||
}
|
||||
: null
|
||||
},
|
||||
ignoreMembers () {
|
||||
this.updateIgnoreMembers({
|
||||
customerId: this.getCustomerId,
|
||||
ignore_cf: this.changes.ignore_cf_when_hunting
|
||||
})
|
||||
},
|
||||
blockInMode () {
|
||||
this.updateBlockInMode({
|
||||
customerId: this.getCustomerId,
|
||||
block_in_mode: this.changes.block_in_mode
|
||||
})
|
||||
},
|
||||
blockInClir () {
|
||||
this.updateBlockInClir({
|
||||
customerId: this.getCustomerId,
|
||||
block_in_clir: this.changes.block_in_clir
|
||||
})
|
||||
},
|
||||
blockOutMode () {
|
||||
this.updateBlockOutMode({
|
||||
customerId: this.getCustomerId,
|
||||
block_out_mode: this.changes.block_out_mode
|
||||
})
|
||||
},
|
||||
playAnnounceBeforeCallSetup () {
|
||||
this.updatePlayAnnounceBeforeCallSetup({
|
||||
customerId: this.getCustomerId,
|
||||
play_announce_before_call_setup: this.changes.play_announce_before_call_setup
|
||||
})
|
||||
},
|
||||
playAnnounceToCallee () {
|
||||
this.updatePlayAnnounceToCallee({
|
||||
customerId: this.getCustomerId,
|
||||
play_announce_to_callee: this.changes.play_announce_to_callee
|
||||
})
|
||||
},
|
||||
add (value) {
|
||||
if (value !== undefined && value !== null && value !== '') {
|
||||
this.items.push(value.trim())
|
||||
this.inputValue = ''
|
||||
}
|
||||
},
|
||||
removeAll () {
|
||||
if (this.items && this.items.length > 0) {
|
||||
this.items = []
|
||||
}
|
||||
},
|
||||
remove (index) {
|
||||
this.items.splice(index, 1)
|
||||
},
|
||||
setPreferenceInboundEvent (value) {
|
||||
if (_.isString(value)) {
|
||||
value = _.trim(value)
|
||||
}
|
||||
this.updateBlockInList({
|
||||
customerId: this.getCustomerId,
|
||||
block_in_list: value
|
||||
})
|
||||
},
|
||||
setPreferenceOutboundEvent (value) {
|
||||
if (_.isString(value)) {
|
||||
value = _.trim(value)
|
||||
}
|
||||
this.updateBlockOutList({
|
||||
customerId: this.getCustomerId,
|
||||
block_out_list: value
|
||||
})
|
||||
},
|
||||
resetBlockOutOverridePin () {
|
||||
this.changes.block_out_override_pin = this.customerPreferences.block_out_override_pin
|
||||
},
|
||||
save () {
|
||||
let isValid = true
|
||||
this.v$.changes.block_out_override_pin.$touch()
|
||||
isValid = !this.v$.changes.block_out_override_pin.$error
|
||||
if (isValid) {
|
||||
if (this.hasBlockOutOverridePinChanged) {
|
||||
this.updateBlockOutOverridePin({
|
||||
customerId: this.getCustomerId,
|
||||
block_out_override_pin: this.changes.block_out_override_pin
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
@ -0,0 +1,117 @@
|
||||
import { RequestState } from './common'
|
||||
import {
|
||||
getCustomerPreference,
|
||||
setCustomerPreference
|
||||
} from '../api/subscriber'
|
||||
export default {
|
||||
namespaced: true,
|
||||
state: {
|
||||
customerPreferences: null,
|
||||
customerPreferencesLoadingState: RequestState.initiated,
|
||||
customerPreferencesError: null,
|
||||
customerPreferencesSelected: null
|
||||
},
|
||||
getters: {
|
||||
ignoreMembers (state) {
|
||||
return state.ignoreMembers
|
||||
}
|
||||
},
|
||||
mutations: {
|
||||
customerPreferencesLoading (state) {
|
||||
state.customerPreferencesLoadingState = RequestState.requesting
|
||||
state.customerPreferencesError = null
|
||||
},
|
||||
customerPreferencesLoaded (state, customerPreferences) {
|
||||
state.customerPreferencesLoadingState = RequestState.succeeded
|
||||
state.customerPreferences = customerPreferences
|
||||
},
|
||||
customerPreferencesLoadingFailed (state, error) {
|
||||
state.customerPreferencesLoadingState = RequestState.failed
|
||||
state.customerPreferencesError = error
|
||||
},
|
||||
customerPreferencesUpdateLoaded (state, customerPreferences) {
|
||||
state.customerPreferencesLoadingState = RequestState.succeeded
|
||||
state.customerPreferences = customerPreferences
|
||||
},
|
||||
expandCustomerPreferences (state) {
|
||||
state.customerPreferencesSelected = state.customerPreferences
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
loadCustomerPreferences (context, customerId) {
|
||||
return new Promise((resolve, reject) => {
|
||||
context.commit('customerPreferencesLoading')
|
||||
getCustomerPreference(customerId).then((customerPreferences) => {
|
||||
context.commit('customerPreferencesLoaded', customerPreferences)
|
||||
resolve()
|
||||
}).catch((err) => {
|
||||
reject(err)
|
||||
context.commit('customerPreferencesLoadingFailed', err.message)
|
||||
})
|
||||
})
|
||||
},
|
||||
updateIgnoreMembers (context, options) {
|
||||
setCustomerPreference(options.customerId, options.ignore_cf, 'ignore_cf_when_hunting').then((customerPreference) => {
|
||||
context.commit('customerPreferencesUpdateLoaded', customerPreference)
|
||||
}).catch((err) => {
|
||||
context.commit('customerPreferencesLoadingFailed', err.message)
|
||||
})
|
||||
},
|
||||
updateBlockInMode (context, options) {
|
||||
setCustomerPreference(options.customerId, options.block_in_mode, 'block_in_mode').then((customerPreference) => {
|
||||
context.commit('customerPreferencesUpdateLoaded', customerPreference)
|
||||
}).catch((err) => {
|
||||
context.commit('customerPreferencesLoadingFailed', err.message)
|
||||
})
|
||||
},
|
||||
updateBlockInClir (context, options) {
|
||||
setCustomerPreference(options.customerId, options.block_in_clir, 'block_in_clir').then((customerPreference) => {
|
||||
context.commit('customerPreferencesUpdateLoaded', customerPreference)
|
||||
}).catch((err) => {
|
||||
context.commit('customerPreferencesLoadingFailed', err.message)
|
||||
})
|
||||
},
|
||||
updateBlockOutMode (context, options) {
|
||||
setCustomerPreference(options.customerId, options.block_out_mode, 'block_out_mode').then((customerPreference) => {
|
||||
context.commit('customerPreferencesUpdateLoaded', customerPreference)
|
||||
}).catch((err) => {
|
||||
context.commit('customerPreferencesLoadingFailed', err.message)
|
||||
})
|
||||
},
|
||||
updateBlockInList (context, options) {
|
||||
setCustomerPreference(options.customerId, options.block_in_list, 'block_in_list').then((customerPreference) => {
|
||||
context.commit('customerPreferencesUpdateLoaded', customerPreference)
|
||||
}).catch((err) => {
|
||||
context.commit('customerPreferencesLoadingFailed', err.message)
|
||||
})
|
||||
},
|
||||
updateBlockOutList (context, options) {
|
||||
setCustomerPreference(options.customerId, options.block_out_list, 'block_out_list').then((customerPreference) => {
|
||||
context.commit('customerPreferencesUpdateLoaded', customerPreference)
|
||||
}).catch((err) => {
|
||||
context.commit('customerPreferencesLoadingFailed', err.message)
|
||||
})
|
||||
},
|
||||
updateBlockOutOverridePin (context, options) {
|
||||
setCustomerPreference(options.customerId, options.block_out_override_pin, 'block_out_override_pin').then((customerPreference) => {
|
||||
context.commit('customerPreferencesUpdateLoaded', customerPreference)
|
||||
}).catch((err) => {
|
||||
context.commit('customerPreferencesLoadingFailed', err.message)
|
||||
})
|
||||
},
|
||||
updatePlayAnnounceBeforeCallSetup (context, options) {
|
||||
setCustomerPreference(options.customerId, options.play_announce_before_call_setup, 'play_announce_before_call_setup').then((customerPreference) => {
|
||||
context.commit('customerPreferencesUpdateLoaded', customerPreference)
|
||||
}).catch((err) => {
|
||||
context.commit('customerPreferencesLoadingFailed', err.message)
|
||||
})
|
||||
},
|
||||
updatePlayAnnounceToCallee (context, options) {
|
||||
setCustomerPreference(options.customerId, options.play_announce_to_callee, 'play_announce_to_callee').then((customerPreference) => {
|
||||
context.commit('customerPreferencesUpdateLoaded', customerPreference)
|
||||
}).catch((err) => {
|
||||
context.commit('customerPreferencesLoadingFailed', err.message)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
import { i18n } from 'boot/i18n'
|
||||
export const errorMessages = {
|
||||
integer () {
|
||||
return i18n.global.tc('Only none decimal numbers are allowed')
|
||||
},
|
||||
numeric () {
|
||||
return i18n.global.tc('Input must be a valid number')
|
||||
},
|
||||
required () {
|
||||
return i18n.global.tc('Input is required')
|
||||
}
|
||||
}
|
Loading…
Reference in new issue