From 37a807dd0f84b644b8d1377ae98b8bb2f037bc03 Mon Sep 17 00:00:00 2001 From: nouhaila Date: Fri, 23 Jun 2023 17:00:57 +0200 Subject: [PATCH] MT#57080 Expose Phonebook in the CSC Change-Id: Iffc7ae9ed6acda2ea7cdb742aeee51ce924d2309 --- src/api/subscriber.js | 93 ++++++++- src/components/CscMainMenuTop.vue | 6 + src/components/call/CscCall.vue | 17 +- src/layouts/CscLayoutMain.vue | 2 +- src/pages/CscPageHome.vue | 2 +- src/pages/CscPageSubscriberPhonebook.vue | 193 ++++++++++++++++++ src/pages/CscPageSubscriberPhonebookAdd.vue | 143 +++++++++++++ .../CscPageSubscriberPhonebookDetails.vue | 132 ++++++++++++ src/router/routes.js | 31 +++ src/store/user.js | 40 +++- 10 files changed, 644 insertions(+), 15 deletions(-) create mode 100644 src/pages/CscPageSubscriberPhonebook.vue create mode 100644 src/pages/CscPageSubscriberPhonebookAdd.vue create mode 100644 src/pages/CscPageSubscriberPhonebookDetails.vue diff --git a/src/api/subscriber.js b/src/api/subscriber.js index f561d18a..7ff8a7d8 100644 --- a/src/api/subscriber.js +++ b/src/api/subscriber.js @@ -55,14 +55,39 @@ export async function setPreference (id, field, value) { } } } - +export async function setPreferencePhonebook (id, field, value) { + if (value === undefined || value === null || value === '' || (Array.isArray(value) && !value.length)) { + await removePreferencePhonebook(id, field) + } else { + try { + await replacePreferencePhonebook(id, field, value) + } catch (err) { + const errCode = err.status + '' + if (errCode === '422') { + // eslint-disable-next-line no-useless-catch + try { + await addPreferencePhonebook(id, field, value) + } catch (innerErr) { + throw innerErr + } + } else { + throw err + } + } + } +} export async function removePreference (id, field) { return await patchRemove({ path: 'api/subscriberpreferences/' + id, fieldPath: field }) } - +export async function removePreferencePhonebook (id, field) { + return await patchRemove({ + path: 'api/phonebookentries/' + id, + fieldPath: field + }) +} export function addPreference (id, field, value) { return new Promise((resolve, reject) => { patchAdd({ @@ -76,7 +101,19 @@ export function addPreference (id, field, value) { }) }) } - +export function addPreferencePhonebook (id, field, value) { + return new Promise((resolve, reject) => { + patchAdd({ + path: 'api/phonebookentries/' + id, + fieldPath: field, + value: value + }).then(() => { + resolve() + }).catch((err) => { + reject(err) + }) + }) +} export function addPreferenceFull (id, field, value) { return new Promise((resolve, reject) => { patchAddFull({ @@ -104,7 +141,19 @@ export function replacePreference (id, field, value) { }) }) } - +export function replacePreferencePhonebook (id, field, value) { + return new Promise((resolve, reject) => { + patchReplace({ + path: 'api/phonebookentries/' + id, + fieldPath: field, + value: value + }).then(() => { + resolve() + }).catch((err) => { + reject(err) + }) + }) +} export function prependItemToArrayPreference (id, field, value) { return new Promise((resolve, reject) => { Promise.resolve().then(() => { @@ -652,7 +701,41 @@ export async function getSubscriberRegistrations (options) { }) return list } - +export async function getSubscriberPhonebook (options) { + let all = false + if (options.rows === 0) { + delete options.rows + delete options.page + all = true + } + if (!options.order_by) { + delete options.order_by + delete options.order_by_direction + } + const list = await getList({ + resource: 'phonebookentries', + all, + params: options + }) + return list +} +export async function createPhonebook (data) { + const payLoad = { + name: data.name, + number: data.number, + shared: data.shared + } + return await Vue.http.post('api/phonebookentries/', payLoad) +} +export function setValueShared (id, value) { + return setPreferencePhonebook(id, 'shared', value) +} +export function setValueName (id, value) { + return setPreferencePhonebook(id, 'name', value) +} +export function setValueNumber (id, value) { + return setPreferencePhonebook(id, 'number', value) +} export async function getRecordingStream (fileId) { return await getAsBlob({ path: 'api/callrecordingfiles/' + fileId diff --git a/src/components/CscMainMenuTop.vue b/src/components/CscMainMenuTop.vue index bdd5d841..bd4eb1f9 100644 --- a/src/components/CscMainMenuTop.vue +++ b/src/components/CscMainMenuTop.vue @@ -76,6 +76,12 @@ export default { sublabel: this.$t('Calls, Faxes, VoiceMails'), visible: this.hasSubscriberProfileAttribute(PROFILE_ATTRIBUTE_MAP.conversations) }, + { + to: '/user/subscriber-phonebook', + icon: 'fas fa-user', + label: this.$t('Subscriber Phonebook'), + visible: true + }, { icon: 'settings_phone', label: this.$t('Call Settings'), diff --git a/src/components/call/CscCall.vue b/src/components/call/CscCall.vue index 00ef8711..3107ddc7 100644 --- a/src/components/call/CscCall.vue +++ b/src/components/call/CscCall.vue @@ -47,21 +47,21 @@ - {{ $t('Calling {number}...', {number: callNumberFormatted}) }} + {{ $t('Calling {number}...', {number: callNumberFormatted || callNumberQuery }) }} - {{ $t('Ringing at {number}...', {number: callNumberFormatted}) }} + {{ $t('Ringing at {number}...', {number: callNumberFormatted || callNumberQuery }) }} - {{ $t('Incoming call from {number}...', {number: callNumberFormatted}) }} + {{ $t('Incoming call from {number}...', {number: callNumberFormatted || callNumberQuery }) }}
- {{ endedReason | startCase }} ({{ callNumberFormatted }}) + {{ endedReason | startCase }} ({{ callNumberFormatted || callNumberQuery }})
@@ -86,7 +86,7 @@ size="24px" />
- {{ $t('In call with {number}', {number: callNumberFormatted}) }} + {{ $t('In call with {number}', {number: callNumberFormatted || callNumberQuery }) }}
- {{ callNumberFormatted }} + {{ callNumberFormatted || callNumberQuery }} @@ -302,7 +302,7 @@
- {{ callNumberFormatted }} + {{ callNumberFormatted || callNumberQuery }}
@@ -481,6 +481,9 @@ export default { callNumberFormatted () { return normalizeDestination(this.callNumber) }, + callNumberQuery () { + return normalizeDestination(this.$route.query.number) + }, iconToggleMicrophone () { if (this.microphoneEnabled) { return 'mic' diff --git a/src/layouts/CscLayoutMain.vue b/src/layouts/CscLayoutMain.vue index 1bc984a2..c1b7220c 100644 --- a/src/layouts/CscLayoutMain.vue +++ b/src/layouts/CscLayoutMain.vue @@ -489,7 +489,7 @@ export default { this.faxDialog = false }, startCall (localMedia) { - if (this.callNumberInput !== '' && this.callNumberInput !== null) { + if (this.$route.query.number !== '' && this.$route.query.number !== null || this.callNumberInput !== '' && this.callNumberInput !== null) { this.$store.dispatch('call/start', localMedia) } }, diff --git a/src/pages/CscPageHome.vue b/src/pages/CscPageHome.vue index 6881ea46..298c9f1a 100644 --- a/src/pages/CscPageHome.vue +++ b/src/pages/CscPageHome.vue @@ -16,7 +16,7 @@ id="csc-call-number-input" :label="$t('Enter a number to dial')" data-cy="csc-call-number-input" - :value="callNumberInput" + :value="callNumberInput || $route.query.number" :readonly="dialpadOpened" clearable :disable="!isCallEnabled" diff --git a/src/pages/CscPageSubscriberPhonebook.vue b/src/pages/CscPageSubscriberPhonebook.vue new file mode 100644 index 00000000..e299b8ca --- /dev/null +++ b/src/pages/CscPageSubscriberPhonebook.vue @@ -0,0 +1,193 @@ + + + + diff --git a/src/pages/CscPageSubscriberPhonebookAdd.vue b/src/pages/CscPageSubscriberPhonebookAdd.vue new file mode 100644 index 00000000..1cb9b9f9 --- /dev/null +++ b/src/pages/CscPageSubscriberPhonebookAdd.vue @@ -0,0 +1,143 @@ + + + \ No newline at end of file diff --git a/src/pages/CscPageSubscriberPhonebookDetails.vue b/src/pages/CscPageSubscriberPhonebookDetails.vue new file mode 100644 index 00000000..dd7a977f --- /dev/null +++ b/src/pages/CscPageSubscriberPhonebookDetails.vue @@ -0,0 +1,132 @@ + + + diff --git a/src/router/routes.js b/src/router/routes.js index 5b15e5df..9f908f8f 100644 --- a/src/router/routes.js +++ b/src/router/routes.js @@ -31,11 +31,14 @@ import CscRecoverPassword from 'src/pages/CscRecoverPassword' import CscPageCf from 'pages/CscPageCf' import CscPageCallSettings from 'pages/CscPageCallSettings' import CscPageRegisteredDevices from 'pages/CscPageRegisteredDevices' +import CscPageSubscriberPhonebook from 'pages/CscPageSubscriberPhonebook' import CscPagePbxSettingsAutoAttendant from 'pages/CscPagePbxSettingsAutoAttendant' import CscPageDashboard from 'pages/CscPageDashboard' import CscPagePbxSettingsMsConfigs from 'pages/CscPagePbxSettingsMsConfigs' import CscPagePbxSettingsCallQueues from 'pages/CscPagePbxSettingsCallQueues' import CscPagePbxSoundSetDetails from 'src/pages/CscPagePbxSoundSetDetails' +import CscPageSubscriberPhonebookDetails from 'src/pages/CscPageSubscriberPhonebookDetails' +import CscPageSubscriberPhonebookAdd from 'src/pages/CscPageSubscriberPhonebookAdd' const getToken = (route) => { return { @@ -84,6 +87,34 @@ export default function routes (app) { profileAttribute: PROFILE_ATTRIBUTE_MAP.conversations } }, + { + path: 'subscriber-phonebook', + name: 'SubscriberPhonebook', + component: CscPageSubscriberPhonebook, + meta: { + get title () { + return i18n.t('Subscriber Phonebook') + } + } + }, + { + path: 'subscriber-phonebook/create', + component: CscPageSubscriberPhonebookAdd, + meta: { + get title () { + return i18n.t('Add Phonebook') + } + } + }, + { + path: 'subscriber-phonebook/:id', + component: CscPageSubscriberPhonebookDetails, + meta: { + get title () { + return i18n.t('Subscriber Phonebook') + } + } + }, { path: 'call-forwarding', component: CscPageCf, diff --git a/src/store/user.js b/src/store/user.js index 5e4d9d6a..41d1b2bc 100644 --- a/src/store/user.js +++ b/src/store/user.js @@ -15,8 +15,13 @@ import { recoverPassword, getBrandingLogo, getSubscriberRegistrations, + getSubscriberPhonebook, getSubscriberProfile, - changeSIPPassword + setValueShared, + setValueName, + setValueNumber, + changeSIPPassword, + createPhonebook } from '../api/subscriber' import { deleteJwt, getJwt, getSubscriberId, setJwt, setSubscriberId } from 'src/auth' import QRCode from 'qrcode' @@ -56,6 +61,8 @@ export default { resellerBranding: null, defaultBranding: {}, subscriberRegistrations: [], + subscriberPhonebook: [], + phonebookMap: {}, platformInfo: null, qrCode: null, qrExpiringTime: null @@ -273,6 +280,9 @@ export default { setSubscriberRegistrations (state, value) { state.subscriberRegistrations = value }, + setSubscriberPhonebook (state, value) { + state.subscriberPhonebook = value + }, setProfile (state, value) { state.profile = value }, @@ -398,9 +408,37 @@ export default { throw err } }, + async loadSubscriberPhonebook ({ commit, dispatch, state, rootGetters }, options) { + try { + const list = await getSubscriberPhonebook({ + ...options + }) + commit('setSubscriberPhonebook', list.items) + return list.totalCount + } catch (err) { + commit('setSubscriberPhonebook', []) + throw err + } + }, async removeSubscriberRegistration (context, row) { await Vue.http.delete('api/subscriberregistrations/' + row.id) }, + async getPhonebookDetails (context, id) { + const list = await Vue.http.get('api/phonebookentries/' + id) + return list + }, + async getValueShared (context, options) { + await setValueShared(options.phonebookId, options.shared) + }, + async getValueName (context, options) { + await setValueName(options.phonebookId, options.name) + }, + async getValueNumber (context, options) { + await setValueNumber(options.phonebookId, options.number) + }, + async createPhonebookSubscriber (context, data) { + await createPhonebook(data) + }, async fetchAuthToken ({ commit, state, getters }, expiringTime = 300) { const subscriber = state.subscriber const expireDate = date.addToDate(new Date(), { seconds: expiringTime })