MT#58743 Create a new Pbx Configuration -> Customer Preferences page

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: Ic9a1b2eab9b71255026447a690d3426097cbaf93
mr13.0
Nouhaila Idrissi Zouggari 11 months ago
parent aff80a1e1f
commit 0cb6554966

@ -57,8 +57,12 @@ To keep translation files consistent and updated please run **i18n:extract** com
yarn run i18n:extract
That CLI command will collect all new translation keys from the JS source code, and will place those keys into all translation files in a proper format.
That CLI command will collect all new translation keys from the JS source code, and will place those keys into all translation files in a proper format. Note that currently the command is set to use bash. If you prefer using sh change the package.json as below:
````
"i18n:extract": "sh ./bin/vue-i18n-extract/extract.sh",
"i18n:extract-report": "sh ./bin/vue-i18n-extract/extract.sh report"
````
Example of the JS code with translations:
```javascript

@ -854,3 +854,50 @@ export async function getSubscriberProfile (id) {
})
return profile
}
export function getCustomerPreference (id) {
return new Promise((resolve, reject) => {
get({
path: 'api/customerpreferences/' + id
}).then((customerPreferences) => {
resolve(customerPreferences)
}).catch((err) => {
reject(err)
})
})
}
export function setCustomerPreference (customerId, customerValue, fieldName) {
return new Promise((resolve, reject) => {
Promise.resolve().then(() => {
if (customerValue === undefined || customerValue === null || customerValue === '' || (Array.isArray(customerValue) && !customerValue.length)) {
return patchRemove({
path: 'api/customerpreferences/' + customerId,
fieldPath: fieldName
}).then((customer) => {
resolve(customer.data)
})
}
return patchReplaceFull({
path: 'api/customerpreferences/' + customerId,
fieldPath: fieldName,
value: customerValue
})
}).then((customer) => {
resolve(customer)
}).catch((err) => {
const errCode = err.status + ''
if (errCode === '422') {
return patchAdd({
path: 'api/customerpreferences/' + customerId,
fieldPath: fieldName,
value: customerValue
})
}
}).then((customer) => {
resolve(customer.data)
}).catch((err) => {
reject(err)
})
})
}

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

@ -108,7 +108,7 @@ export default {
{
to: '/user/call-blocking/incoming',
icon: 'call_received',
label: this.$t('Block incoming'),
label: this.$t('Block Incoming'),
visible: this.hasSubscriberProfileAttributes(PROFILE_ATTRIBUTES_MAP.callBlockingIncoming)
},
{
@ -216,6 +216,12 @@ export default {
icon: 'person',
label: this.$t('Customer Phonebook'),
visible: true
},
{
to: '/user/pbx-configuration/customer-preferences',
icon: 'fas fa-user-cog',
label: this.$t('Customer Preferences'),
visible: true
}
]
},

@ -19,7 +19,7 @@
:label="$t('Username')"
type="text"
:error="v$.username.$errors.length > 0"
:error-message="$errorMessage(v$.username)"
:error-message="$errMsg(v$.username.$errors)"
@blur="v$.username.$touch()"
>
<template

@ -52,9 +52,12 @@
"Auto Attendant": "Anrufmenü",
"Block Incoming": "Eingehende Anrufe blockieren",
"Block Incoming/Outgoing": "Ein-/Ausgehende Anrufe blockieren",
"Block List for inbound calls": "Block List for inbound calls",
"Block List for outbounds calls": "Block List for outbounds calls",
"Block Mode for inbound calls": "Block Mode for inbound calls",
"Block Mode for outbounds calls": "Block Mode for outbounds calls",
"Block Outgoing": "Ausgehende Anrufe blockieren",
"Block incoming": "Eingehende blockieren",
"Block outgoing": "Ausgehende blockieren",
"Block anonymous inbound calls": "Block anonymous inbound calls",
"Busy Greeting": "Begrüßung, wenn besetzt",
"Busy Lamp Field": "Besetztlampenfeld",
"CDR": "CDR",
@ -129,6 +132,7 @@
"Custom sound": "Benutzerdefinierter Sound",
"Customer Details": "Kunden-Details",
"Customer Phonebook": "Customer Phonebook",
"Customer Preferences": "Customer Preferences",
"Daily": "Täglich",
"Dashboard": "Übersicht",
"Data is in the clipboard": "Daten wurden in die Zwischenablage kopiert",
@ -250,6 +254,8 @@
"Input a valid email address": "Geben sie eine gültige E-Mail-Addresse ein",
"Input a valid mac address": "Geben Sie eine gültige MAC-Adresse ein",
"Input a valid phone number": "Geben Sie eine gültige Telefonnummer ein",
"Input is required": "Eingabe erforderlich",
"Input must be a valid number": "Eingabe muss eine gültige Nummer sein",
"Interval when the secret key is automatically renewed.": "Zeitraum, nach dem der Geheimschlüssel automatisch erneuert wird.",
"Italian": "Italienisch",
"Join conference": "Konferenz beitreten",
@ -335,6 +341,7 @@
"Office Hours Announcement": "Bürozeiten Ansage",
"On weekdays": "An Werktagen",
"Only incoming calls from listed numbers are allowed": "Es sind nur eingehende Anrufe von aufgelisteten Nummern erlaubt",
"Only none decimal numbers are allowed": "Es sind nur Zahlen zugelassen, die keine Dezimalzahlen sind",
"Only once": "Nur einmal",
"Only outgoing calls to listed numbers are allowed": "Es sind nur ausgehende Anrufe an aufgelistete Nummern erlaubt",
"Out": "Out",
@ -342,6 +349,7 @@
"PBX Configuration": "PBX-Konfiguration",
"PBX Statistics": "PBX-Statistiken",
"PIN": "PIN",
"PIN to bypass outbound Block List": "PIN to bypass outbound Block List",
"Page Header": "Seitenkopf",
"Page not found": "Seite wurde nicht gefunden",
"Parallel Ringing": "Paralleles Klingeln",
@ -393,6 +401,7 @@
"Remove Destination": "Ziel entfernen",
"Remove Fax": "Fax entfernen",
"Remove Voicemail": "Sprachnachricht entfernen",
"Remove all": "Remove all",
"Remove call queue": "Anrufwarteschlange löschen",
"Remove device": "Gerät löschen",
"Remove file": "Datei entfernen",

@ -51,9 +51,12 @@
"Auto Attendant": "Auto Attendant",
"Block Incoming": "Block Incoming",
"Block Incoming/Outgoing": "Block Incoming/Outgoing",
"Block List for inbound calls": "Block List for inbound calls",
"Block List for outbounds calls": "Block List for outbounds calls",
"Block Mode for inbound calls": "Block Mode for inbound calls",
"Block Mode for outbounds calls": "Block Mode for outbounds calls",
"Block Outgoing": "Block Outgoing",
"Block incoming": "Block incoming",
"Block outgoing": "Block outgoing",
"Block anonymous inbound calls": "Block anonymous inbound calls",
"Busy Greeting": "Busy Greeting",
"Busy Lamp Field": "Busy Lamp Field",
"CDR": "CDR",
@ -126,6 +129,7 @@
"Custom sound": "Custom sound",
"Customer Details": "Customer Details",
"Customer Phonebook": "Customer Phonebook",
"Customer Preferences": "Customer Preferences",
"Daily": "Daily",
"Dashboard": "Dashboard",
"Data is in the clipboard": "Data is in the clipboard",
@ -246,6 +250,8 @@
"Input a valid email address": "Input a valid email address",
"Input a valid mac address": "Input a valid mac address",
"Input a valid phone number": "Input a valid phone number",
"Input is required": "Input is required",
"Input must be a valid number": "Input must be a valid number",
"Interval when the secret key is automatically renewed.": "Interval when the secret key is automatically renewed.",
"Italian": "Italian",
"Lamp/Key": "Lamp/Key",
@ -321,6 +327,7 @@
"Office Hours Announcement": "Office Hours Announcement",
"On weekdays": "On weekdays",
"Only incoming calls from listed numbers are allowed": "Only incoming calls from listed numbers are allowed",
"Only none decimal numbers are allowed": "Only none decimal numbers are allowed",
"Only once": "Only once",
"Only outgoing calls to listed numbers are allowed": "Only outgoing calls to listed numbers are allowed",
"Out": "Out",
@ -328,6 +335,7 @@
"PBX Configuration": "PBX Configuration",
"PBX Statistics": "PBX Statistics",
"PIN": "PIN",
"PIN to bypass outbound Block List": "PIN to bypass outbound Block List",
"Page Header": "Page Header",
"Page not found": "Page not found",
"Parallel Ringing": "Parallel Ringing",
@ -378,6 +386,7 @@
"Remove Destination": "Remove Destination",
"Remove Fax": "Remove Fax",
"Remove Voicemail": "Remove Voicemail",
"Remove all": "Remove all",
"Remove call queue": "Remove call queue",
"Remove device": "Remove device",
"Remove file": "Remove file",

@ -52,9 +52,12 @@
"Auto Attendant": "Asistente Automático",
"Block Incoming": "Bloquear Entrantes",
"Block Incoming/Outgoing": "Bloquear Entrantes/Salientes",
"Block List for inbound calls": "Block List for inbound calls",
"Block List for outbounds calls": "Block List for outbounds calls",
"Block Mode for inbound calls": "Block Mode for inbound calls",
"Block Mode for outbounds calls": "Block Mode for outbounds calls",
"Block Outgoing": "Bloquear Salientes",
"Block incoming": "Bloquear entrantes",
"Block outgoing": "Bloquear Salientes",
"Block anonymous inbound calls": "Block anonymous inbound calls",
"Busy Greeting": "Saludo de Ocupado",
"Busy Lamp Field": "Campo de lámpara ocupado",
"CDR": "CDR",
@ -129,6 +132,7 @@
"Custom sound": "Sonido personalizado",
"Customer Details": "Detalles de cliente",
"Customer Phonebook": "Customer Phonebook",
"Customer Preferences": "Customer Preferences",
"Daily": "Diariamente",
"Dashboard": "Tablero",
"Data is in the clipboard": "Data is in the clipboard",
@ -250,6 +254,8 @@
"Input a valid email address": "Ingrese una dirección de correo electrónico válida",
"Input a valid mac address": "Ingrese una dirección MAC válida",
"Input a valid phone number": "Ingrese un número de teléfono válido",
"Input is required": "El campo es obligatorio",
"Input must be a valid number": "El campo debe ser un número válido",
"Interval when the secret key is automatically renewed.": "Intervalo en el que la clave secreta se renueva automáticamente.",
"Italian": "Italiano",
"Join conference": "Unirse a la conferencia",
@ -334,6 +340,7 @@
"Office Hours Announcement": "Office Hours Announcement",
"On weekdays": "En días de la semana",
"Only incoming calls from listed numbers are allowed": "Permitir solo los números listados",
"Only none decimal numbers are allowed": "Sólo se permiten números no decimales",
"Only once": "Solo una vez",
"Only outgoing calls to listed numbers are allowed": "Permitir solo los números listados",
"Out": "Out",
@ -341,6 +348,7 @@
"PBX Configuration": "Configuración PBX",
"PBX Statistics": "PBX Statistics",
"PIN": "PIN",
"PIN to bypass outbound Block List": "PIN to bypass outbound Block List",
"Page Header": "Encabezado de página",
"Page not found": "Página no encontrada",
"Parallel Ringing": "Llamada en paralelo",
@ -392,6 +400,7 @@
"Remove Destination": "Eliminar destino",
"Remove Fax": "Remove Fax",
"Remove Voicemail": "Eliminar el buzón de voz",
"Remove all": "Remove all",
"Remove call queue": "Remover cola de Llamadas",
"Remove device": "Eliminar dispositivo",
"Remove file": "Remover archivo",

@ -52,9 +52,12 @@
"Auto Attendant": "Association auto",
"Block Incoming": "Bloquer les appels entrants",
"Block Incoming/Outgoing": "Bloquer les entrants/sortants",
"Block List for inbound calls": "Liste de blocage pour les appels entrants",
"Block List for outbounds calls": "Liste de blocage pour les appels sortants",
"Block Mode for inbound calls": "Mode blocage pour les appels entrants",
"Block Mode for outbounds calls": "Mode blocage pour les appels sortants",
"Block Outgoing": "Bloquer les sortants",
"Block incoming": "Bloquer les entrants",
"Block outgoing": "Bloquer les sortants",
"Block anonymous inbound calls": "Bloquer les appels entrants anonymes",
"Busy Greeting": "Message d'accueil en cas d'occupation",
"Busy Lamp Field": "Champ de la lampe occupée",
"CDR": "CDR",
@ -129,6 +132,7 @@
"Custom sound": "Son personnalisé",
"Customer Details": "Détails du client",
"Customer Phonebook": "Annuaire du client",
"Customer Preferences": "Préférences du client",
"Daily": "Quotidien",
"Dashboard": "Tableau de bord",
"Data is in the clipboard": "Données dans le presse-papiers",
@ -250,6 +254,8 @@
"Input a valid email address": "Veuillez saisir une adresse e-mail valide",
"Input a valid mac address": "Entrez une adresse mac valide",
"Input a valid phone number": "Saisissez un numéro de téléphone valide",
"Input is required": "Le champ est obligatoire",
"Input must be a valid number": "Le champ doit être un nombre valide",
"Interval when the secret key is automatically renewed.": "Intervalle où la clé secrète est automatiquement renouvelée.",
"Italian": "Italien",
"Join conference": "Rejoindre la conférence",
@ -335,6 +341,7 @@
"Office Hours Announcement": "Office Hours Announcement",
"On weekdays": "Les jours de semaine",
"Only incoming calls from listed numbers are allowed": "Seuls les appels entrants provenant des numéros listés sont autorisés",
"Only none decimal numbers are allowed": "Seuls les nombres non décimaux sont autorisés",
"Only once": "Une seule fois",
"Only outgoing calls to listed numbers are allowed": "Seuls les appels sortants vers les numéros listés sont autorisés",
"Out": "Out",
@ -342,6 +349,7 @@
"PBX Configuration": "Configuration du PBX",
"PBX Statistics": "PBX Statistics",
"PIN": "PIN",
"PIN to bypass outbound Block List": "Code PIN pour contourner la liste de blocage sortante",
"Page Header": "En-tête de page",
"Page not found": "Page introuvable",
"Parallel Ringing": "Sonnerie parallèle",
@ -393,6 +401,7 @@
"Remove Destination": "Supprimer la destination",
"Remove Fax": "Remove Fax",
"Remove Voicemail": "Supprimer la messagerie vocale",
"Remove all": "Supprimer tout",
"Remove call queue": "Supprimer la file dattente",
"Remove device": "Supprimer le poste",
"Remove file": "Supprimer le fichier",

@ -48,11 +48,14 @@
"Assigned slot {slot}": "Slot assegnato: {slot}",
"Attach voicemail to email notification": "Allega messaggio vocale all'email di notifica",
"Auto Attendant": "Risponditore Automatico",
"Block Incoming": "Blocca entranti",
"Block Incoming/Outgoing": "Blocca entranti/uscenti",
"Block Outgoing": "Blocca uscenti",
"Block incoming": "Block incoming",
"Block outgoing": "Block outgoing",
"Block Incoming": "Blocca chiamate entranti",
"Block Incoming/Outgoing": "Blocca chiamate in entrata/uscita",
"Block List for inbound calls": "Lista numeri bloccati in entrata",
"Block List for outbounds calls": "Lista numeri bloccati in uscita",
"Block Mode for inbound calls": "Modalità di blocco per le chiamate in entrata",
"Block Mode for outbounds calls": "Modalità di blocco per le chiamate in uscita",
"Block Outgoing": "Blocca chiamate in uscita",
"Block anonymous inbound calls": "Blocca chiamate anonime in entrata",
"Busy Greeting": "Messaggio per numero occupato",
"Busy Lamp Field": "Busy Lamp Field",
"CDR": "CDR",
@ -127,6 +130,7 @@
"Custom sound": "Audio personalizzato",
"Customer Details": "Dettagli cliente",
"Customer Phonebook": "Rubrica cliente",
"Customer Preferences": "Customer Preferences",
"Daily": "Giornaliero",
"Dashboard": "Dashboard",
"Data is in the clipboard": "I dati sono negli appunti",
@ -246,6 +250,8 @@
"Input a valid email address": "Inserisci un indirizzo email valido",
"Input a valid mac address": "Inserire un indirizzo mac valido",
"Input a valid phone number": "Inserire un numero di telefono valido",
"Input is required": "Il campo è obbligatorio",
"Input must be a valid number": "Il campo deve essere un numero valido",
"Interval when the secret key is automatically renewed.": "Interval when the secret key is automatically renewed.",
"Italian": "Italian",
"Join conference with name": "Partecipa alla conferenza con nome",
@ -327,6 +333,7 @@
"Office Hours Announcement": "Office Hours Announcement",
"On weekdays": "Nei giorni feriali",
"Only incoming calls from listed numbers are allowed": "Solo ammesse solo chiamate dai numeri in elenco",
"Only none decimal numbers are allowed": "Sono ammessi solo numeri non decimali",
"Only once": "Solo una volta",
"Only outgoing calls to listed numbers are allowed": "Solo ammesse solo le chiamate ai numeri in elenco",
"Out": "Out",
@ -334,6 +341,7 @@
"PBX Configuration": "Configurazione PBX",
"PBX Statistics": "PBX Statistics",
"PIN": "PIN",
"PIN to bypass outbound Block List": "PIN to bypass outbound Block List",
"Page Header": "Intestazione di pagina",
"Page not found": "Page not found",
"Parallel Ringing": "Squilli in parallelo",
@ -385,6 +393,7 @@
"Remove Destination": "Remove Destination",
"Remove Fax": "Remove Fax",
"Remove Voicemail": "Remove Voicemail",
"Remove all": "Remove all",
"Remove call queue": "Elimina coda chiamate",
"Remove device": "Elimina dispositivo",
"Remove file": "Elimina file",
@ -487,7 +496,7 @@
"There are no ACLs yet": "There are no ACLs yet",
"There are no Key Renew Notify Emails yet": "There are no Key Renew Notify Emails yet",
"There was an error, please retry later": "There was an error, please retry later",
"This number is already in use.": "This number is already in use.",
"This number is already in use.": "Questo numero è già in uso.",
"Thursday": "Giovedì",
"Time": "Orario",
"Time is invalid": "Orario non valido",
@ -523,7 +532,7 @@
"Use language specific preset": "Usa i valori preimpostati per la lingua",
"User Agent": "User Agent",
"User config priority over provisioning": "Priorità di configurazione utente sul provisioning",
"User settings": "impostazioni utente",
"User settings": "Impostazioni utente",
"Username": "Nome utente",
"Using Bye": "Using Bye",
"Using Cancel": "Using Cancel",

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

@ -42,7 +42,7 @@ import CscPageSubscriberPhonebookDetails from 'src/pages/CscPageSubscriberPhoneb
import CscPageUserSettings from 'src/pages/CscPageUserSettings'
import CscPageVoicebox from 'src/pages/CscPageVoicebox'
import CscRecoverPassword from 'src/pages/CscRecoverPassword'
import CscPageCustomerPreferences from 'src/pages/CscPageCustomerPreferences'
import { i18n } from 'src/boot/i18n'
const getToken = (route) => {
@ -396,6 +396,18 @@ const routes = [
profileAttribute: PROFILE_ATTRIBUTE_MAP.auto_attendant
}
},
{
path: 'pbx-configuration/customer-preferences',
component: CscPageCustomerPreferences,
meta: {
get title () {
return i18n.global.tc('PBX Configuration')
},
get subtitle () {
return i18n.global.tc('Customer Preferences')
}
}
},
{
path: 'voicebox',
component: CscPageVoicebox,

@ -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)
})
}
}
}

@ -25,6 +25,8 @@ import FaxModule from './fax'
import VoiceboxModule from './voicebox'
import DashboardModule from './dashboard'
import Customer from './customer'
import { INTERNAL_DATE_FORMAT_SLASH, INTERNAL_DATE_FORMAT_DASH, INTERNAL_DATE_FORMAT_DASH_HOUR } from 'src/constants'
/*
@ -59,7 +61,8 @@ export default function (/* { ssrContext } */) {
pbxMsConfigs: PbxMsConfigsModule,
callForwarding: CallForwardingModule,
pbxAutoAttendants: PbxAutoAttendants,
dashboard: DashboardModule
dashboard: DashboardModule,
customer: Customer
},
state: {
route: null

@ -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…
Cancel
Save