TT#44661 Upload a custom "busy" greeting sound

What has been done:
- TT#44661 Voicebox: As a Customer, I want to upload a custom "busy"
  greeting sound
- TT#44663, Voicebox: As a Customer, I want to delete/reset the custom
  "busy" greeting sound
- Refactoring of CscVoiceMailPlayer to more generic CscAudioPlayer

Change-Id: I24f9d607b9d1acece56cd47c0bd8c99d125d45b4
changes/59/24059/19
raxelsen 7 years ago committed by Hans-Peter Herzog
parent 2fb4691943
commit f872d4de20

@ -4,7 +4,6 @@ import { saveAs } from 'file-saver'
import Vue from 'vue'
import { getList } from './common'
export function getConversations(options) {
return new Promise((resolve, reject)=>{
let type = _.get(options, 'type', null);

@ -1,7 +1,9 @@
import _ from 'lodash'
import Vue from 'vue';
import {
get,
getList,
patchReplace
} from './common'
@ -28,10 +30,25 @@ export function setVoiceboxDelete(options) {
}
export function setVoiceboxAttach(options) {
return patchReplace({
path: `api/voicemailsettings/${options.subscriberId}`,
fieldPath: 'attach',
value: options.value
return new Promise((resolve, reject)=>{
Promise.resolve().then(()=>{
if(options.value === false) {
return setVoiceboxDelete(options);
}
else {
return Promise.resolve();
}
}).then(()=>{
return patchReplace({
path: `api/voicemailsettings/${options.subscriberId}`,
fieldPath: 'attach',
value: options.value
});
}).then(()=>{
resolve();
}).catch((err)=>{
reject(err);
});
});
}
@ -50,3 +67,78 @@ export function setVoiceboxEmail(options) {
value: options.value
});
}
export function getVoiceboxGreetingByType(options) {
return new Promise((resolve, reject) => {
getList({
path: 'api/voicemailgreetings/',
root: '_embedded.ngcp:voicemailgreetings',
params: { subscriber_id: options.id, type: options.type }
}).then((result) => {
resolve(result);
}).catch((err)=>{
reject(err);
});
});
}
export function deleteVoiceboxGreetingById(id) {
return new Promise((resolve, reject) => {
Vue.http.delete(`api/voicemailgreetings/${id}`).then(() => {
resolve();
}).catch((err)=>{
reject(err);
});
});
}
export function createNewGreeting(formData, onProgress) {
return new Promise((resolve, reject) => {
Vue.http.post('api/voicemailgreetings/', formData, {
before(request) {
Vue.previousRequest = request;
},
progress(e) {
if (e.lengthComputable) {
onProgress(Math.ceil((e.loaded / e.total ) * 100));
}
}
}).then(() => {
resolve();
}).catch((err)=>{
reject(err);
});
});
}
export function uploadGreeting(options) {
return new Promise((resolve, reject) => {
var formData = new FormData();
var fields = _.clone(options.data);
delete fields.file;
var json = JSON.stringify(fields);
formData.append('json', json);
if (options.data.file) {
formData.append('greetingfile', options.data.file);
}
Promise.resolve().then(() => {
return getVoiceboxGreetingByType({
id: options.data.subscriber_id,
type: options.data.type
});
}).then((greetings) => {
if (_.some(greetings.items, { dir: options.data.dir })) {
deleteVoiceboxGreetingById(greetings.items[0].id);
}
return createNewGreeting(formData, options.onProgress);
}).then(() => {
resolve();
}).catch((err) => {
reject(err);
});
});
}
export function abortPreviousRequest() {
Vue.previousRequest.abort();
}

@ -1,6 +1,6 @@
<template>
<div class="voicemail-player">
<audio :src="soundFileUrl" ref="voiceMailSound" preload="auto" @timeupdate="timeupdate($event)"/>
<audio :src="fileUrl" ref="audio" preload="auto" @timeupdate="timeupdate($event)"/>
<div class="control-btns">
<q-btn class="play-pause-btn" round flat small color="primary"
:icon="playPauseIcon" @click="toggle()" />
@ -12,28 +12,28 @@
</template>
<script>
import { mapGetters } from 'vuex'
import { QProgress, QBtn } from 'quasar-framework'
export default {
name: 'csc-voice-mail-player',
props: {
id: Number
},
name: 'csc-audio-player',
props: [
'fileUrl',
'loaded'
],
mounted() {
this.$refs.voiceMailSound.addEventListener('play', ()=>{
this.$refs.audio.addEventListener('play', ()=>{
this.playing = true;
});
this.$refs.voiceMailSound.addEventListener('playing', ()=>{
this.$refs.audio.addEventListener('playing', ()=>{
this.playing = true;
});
this.$refs.voiceMailSound.addEventListener('ended', ()=>{
this.$refs.audio.addEventListener('ended', ()=>{
this.playing = false;
this.stop();
});
this.$refs.voiceMailSound.addEventListener('canplay', ()=>{
this.$refs.audio.addEventListener('canplay', ()=>{
if(!this.paused && this.playing) {
this.$refs.voiceMailSound.play();
this.$refs.audio.play();
}
});
},
@ -43,7 +43,6 @@
},
data () {
return {
platform: this.$q.platform.is,
playing: false,
paused: false,
progressPercentage: 0
@ -52,63 +51,53 @@
computed: {
playPauseIcon() {
return this.playing ? 'pause': 'play_arrow';
},
soundFileFormat() {
return this.platform.mozilla ? 'ogg' : 'mp3';
},
soundFileUrl() {
let getter = this.playVoiceMailUrl;
return getter(this.id);
},
...mapGetters('conversations', [
'playVoiceMailState',
'playVoiceMailUrl'
])
}
},
methods: {
play() {
this.$refs.voiceMailSound.play();
this.$refs.audio.play();
this.playing = true;
this.paused = false;
},
pause() {
this.$refs.voiceMailSound.pause();
this.$refs.audio.pause();
this.playing = false;
this.paused = true;
},
stop() {
this.$refs.voiceMailSound.currentTime = 0;
this.$refs.audio.currentTime = 0;
this.pause();
},
load() {
this.$emit('play-voice-mail', {
id: this.id,
format: this.soundFileFormat
});
setPlayingTrue() {
this.playing = true;
},
setPausedFalse() {
this.paused = false;
},
timeupdate(e) {
let newPercentage = Math.floor((e.target.currentTime / e.target.duration) * 100);
this.progressPercentage = newPercentage;
},
load() {
this.$emit('load');
},
toggle() {
if(this.playVoiceMailState(this.id) !== 'succeeded') {
if (!this.loaded) {
this.load();
}
else if (this.$refs.voiceMailSound.paused) {
else if (this.$refs.audio.paused) {
this.play();
}
else {
this.pause();
}
},
timeupdate(e) {
let newPercentage = Math.floor((e.target.currentTime / e.target.duration) * 100);
this.progressPercentage = newPercentage;
}
}
}
</script>
<style lang="stylus" rel="stylesheet/stylus">
@import '../../../themes/app.common'
@import '../themes/app.common'
.voicemail-player
width 100%

@ -51,7 +51,7 @@
</q-field>
<q-field class="upload-field">
<label
for="file-upload"
for="fax-file-upload"
class="upload-label"
>
<div class="upload-label">
@ -61,10 +61,10 @@
class="upload-button"
flat
dark
@click="$refs.upload.click()"
icon-right="cloud_upload"
@click="$refs.faxUpload.click()"
icon="cloud_upload"
>
{{ $t('communication.label.uploadFile') }}
{{ $t('buttons.select') }}
</q-btn>
<span class="upload-filename">
{{ selectedFile }}
@ -79,8 +79,8 @@
/>
</label>
<input
ref="upload"
id="file-upload"
ref="faxUpload"
id="fax-file-upload"
type="file"
accept=".pdf,.tiff,.txt,.ps"
@change="processFile($event)"
@ -139,7 +139,7 @@
pageHeader: null,
data: null,
quality: 'normal',
file: null
file: {}
},
qualityOptions: [
{ label: this.$t('communication.quality.normal'), value: 'normal' },
@ -231,10 +231,12 @@
},
methods: {
resetFile() {
this.form.file = null;
this.form.file = {};
this.selectedFile = '';
this.$refs.faxUpload.value = '';
},
processFile(event) {
console.log('processFile()');
let file = event.target.files[0];
let fileName = file ? file.name : '';
let fileNameSplit = fileName.split('.');
@ -306,7 +308,7 @@
.upload-filename
color black
#file-upload
#fax-file-upload
display none
#csc-error-label

@ -0,0 +1,172 @@
<template>
<q-field
class="csc-upload-field"
:icon="icon"
>
<q-input
readonly
:float-label="label"
:value="inputValue"
:after="inputButtons"
/>
<input
v-show="false"
ref="fileUpload"
type="file"
@change="inputChange"
/>
<div
v-show="uploading"
class="row no-wrap csc-upload-progress-field"
>
<q-chip
square
color="primary"
class="upload-chip"
>
{{ `${progress}%` }}
</q-chip>
<q-progress
stripe
animate
color="primary"
:percentage="progress"
class="upload-progress"
/>
</div>
<div
class="csc-file-upload-actions"
>
<q-btn
v-if="selectedFile != null"
flat
color="default"
icon="clear"
@click="cancel"
>
{{ $t('buttons.cancel') }}
</q-btn>
<q-btn
flat
v-if="selectedFile != null && !uploading"
color="primary"
icon="cloud_upload"
@click="upload"
>
{{ $t('buttons.upload') }}
</q-btn>
<q-btn
flat
v-if="uploaded && selectedFile == null"
color="primary"
icon="undo"
@click="undo"
>
{{ $t('buttons.resetDefaults') }}
</q-btn>
</div>
</q-field>
</template>
<script>
import {
QInput,
QField,
QBtn,
QChip,
QProgress
} from 'quasar-framework'
export default {
name: 'csc-sound-file-upload',
components: {
QInput,
QField,
QBtn,
QChip,
QProgress
},
props: [
'icon',
'label',
'value',
'uploading',
'uploaded',
'progress',
'fileTypes'
],
data () {
return {
selectedFile: null
}
},
computed: {
inputValue() {
if(this.selectedFile === null) {
return this.value;
}
else {
return this.selectedFile.name;
}
},
inputButtons() {
let buttons = [];
let self = this;
buttons.push({
icon: 'folder',
error: false,
handler (event) {
event.stopPropagation();
self.$refs.fileUpload.click();
}
}
);
return buttons;
}
},
methods: {
inputChange(event) {
this.selectedFile = event.target.files[0];
},
cancel() {
this.selectedFile = null;
this.$refs.fileUpload.value = null;
if(this.uploading) {
this.abort();
}
},
upload() {
this.$emit('upload', this.selectedFile);
},
abort() {
this.$emit('abort');
},
reset() {
this.cancel();
},
undo() {
this.$emit('reset');
}
}
}
</script>
<style lang="stylus" rel="stylesheet/stylus">
@import '../../themes/quasar.variables';
.csc-file-upload-actions
padding-top $flex-gutter-xs
.csc-upload-field
.q-field-icon
color $primary
.csc-upload-progress-field
margin 10px 0 5px 0
.upload-chip
min-height 20px
height 20px
width 50px
border-top-right-radius 0
border-bottom-right-radius 0
.upload-progress
height 20px
</style>

@ -0,0 +1,202 @@
<template>
<q-field
class="csc-form-field upload-field"
icon="music_note"
>
<label
for="voicemail-file-upload"
class="upload-label"
>
{{ $t('voicebox.label.busyGreeting') }}
</label>
<span
v-show="selectedFile.length === 0"
>
<slot name="status-label" />
</span>
<div
v-show="requesting"
class="row no-wrap progress-field"
>
<q-chip
square
color="primary"
class="upload-chip"
>
{{ `${progress}%` }}
</q-chip>
<q-progress
stripe
animate
color="primary"
:percentage="progress"
class="upload-progress"
/>
</div>
<div class="upload-filename">
{{ selectedFile }}
</div>
<span
v-show="selectedFile.length === 0 && id"
>
<slot name="extra-buttons" />
</span>
<q-btn
v-show="selectedFile.length > 0"
flat
color="negative"
icon="cancel"
@click="cancel"
>
{{ $t('buttons.cancel') }}
</q-btn>
<q-btn
v-show="!requesting"
flat
color="primary"
@click="$refs.upload.click()"
icon="folder"
>
{{ selectLabel }}
</q-btn>
<q-btn
flat
v-show="selectedFile.length > 0 && !requesting"
color="primary"
icon="cloud_upload"
@click="upload"
>
{{ $t('buttons.upload') }}
</q-btn>
<input
ref="upload"
id="voicemail-file-upload"
type="file"
:accept="fileTypes"
@change="processFile($event)"
/>
</q-field>
</template>
<script>
import {
QField,
QInput,
QBtn,
QProgress,
QChip
} from 'quasar-framework'
export default {
name: 'csc-upload-file',
props: [
'progress',
'requesting',
'fileTypes',
'id'
],
data () {
return {
selectedFile: '',
file: null
}
},
components: {
QField,
QInput,
QBtn,
QProgress,
QChip
},
computed: {
selectLabel() {
return this.id ? this.$t('buttons.selectNew') :
this.$t('buttons.select');
}
},
methods: {
cancel() {
if (this.requesting) {
this.abort();
}
else if (this.selectedFile.length > 0) {
this.$emit('reset');
}
},
reset() {
this.file = null;
this.selectedFile = '';
this.$refs.upload.value = '';
},
processFile(event) {
let file = event.target.files[0];
let fileName = file ? file.name : '';
let fileNameSplit = fileName.split('.');
let extension = fileNameSplit[1] ? fileNameSplit[1] : null;
if (fileName.length > 22 && extension) {
fileName = `${fileName.substring(0, 14)}...${extension}`;
}
else if (fileName.length > 22 && !extension) {
fileName = `${fileName.substring(0, 17)}...`;
}
this.file = file;
this.selectedFile = fileName;
},
upload() {
this.$emit('upload', this.file);
},
abort() {
this.$emit('abort');
}
}
}
</script>
<style lang="stylus" rel="stylesheet/stylus">
@import '../../themes/quasar.variables.styl'
#voicemail-file-upload
display none
.upload-field
margin-bottom 10px
.upload-label
display block
color $csc-label
font-size 16px
margin-bottom 5px
.reset-button
padding 0
.q-icon
margin 0
.upload-filename
color $black
margin-bottom 10px
.q-field-icon
margin-top 20px
.inactive-label
color $secondary
.active-label
color $primary
.progress-field
margin 10px 0 5px 0
.upload-chip
min-height 20px
height 20px
width 50px
border-top-right-radius 0
border-bottom-right-radius 0
.upload-progress
height 20px
</style>

@ -33,10 +33,12 @@
{{ $t('pages.conversations.seconds') }}
</q-item-tile>
<q-item-tile>
<csc-voice-mail-player
:id="voiceMail.id"
<csc-audio-player
ref="voicemailPlayer"
:file-url="soundFileUrl"
:loaded="voiceMailLoaded"
class="csc-voice-mail-player"
@play-voice-mail="playVoiceMail"
@load="load"
/>
</q-item-tile>
</q-item-main>
@ -73,8 +75,9 @@
</template>
<script>
import { mapGetters } from 'vuex'
import CscCallOptionList from './CscCallOptionList'
import CscVoiceMailPlayer from './CscVoiceMailPlayer'
import CscAudioPlayer from '../../CscAudioPlayer'
import {
QItem,
QItemSide,
@ -96,13 +99,19 @@
QItemTile,
QPopover,
QBtn,
CscVoiceMailPlayer,
CscAudioPlayer,
CscCallOptionList
},
data () {
return {}
return {
platform: this.$q.platform.is
}
},
computed: {
...mapGetters('conversations', [
'playVoiceMailState',
'playVoiceMailUrl'
]),
direction() {
if(this.voiceMail.direction === 'out') {
return 'to';
@ -110,6 +119,16 @@
else {
return 'from';
}
},
soundFileFormat() {
return this.platform.mozilla ? 'ogg' : 'mp3';
},
soundFileUrl() {
let getter = this.playVoiceMailUrl;
return getter(this.voiceMail.id);
},
voiceMailLoaded() {
return this.playVoiceMailState(this.voiceMail.id) === 'succeeded';
}
},
methods: {
@ -121,10 +140,18 @@
});
},
playVoiceMail() {
this.$emit('play-voice-mail', this.voiceMail);
this.$emit('play-voice-mail', {
id: this.voiceMail.id,
format: this.soundFileFormat
});
},
downloadVoiceMail() {
this.$emit('download-voice-mail', this.voiceMail);
},
load() {
this.playVoiceMail();
this.$refs.voicemailPlayer.setPlayingTrue();
this.$refs.voicemailPlayer.setPausedFalse();
}
}
}

@ -6,8 +6,13 @@
icon="lock"
:error-label="pinErrorMessage"
>
<q-inner-loading :visible="pinRequesting">
<q-spinner-dots
color="primary"
:size="24"
/>
</q-inner-loading>
<q-input
:loading="pinRequesting"
:disable="pinRequesting"
:float-label="$t('voicebox.label.changePin')"
v-model="changes.pin"
@ -23,8 +28,13 @@
icon="email"
:error-label="emailErrorMessage"
>
<q-inner-loading :visible="emailRequesting">
<q-spinner-dots
color="primary"
:size="24"
/>
</q-inner-loading>
<q-input
:loading="emailRequesting"
:disable="emailRequesting"
:float-label="$t('voicebox.label.changeEmail')"
v-model="changes.email"
@ -36,25 +46,39 @@
/>
</q-field>
<q-field class="csc-form-field">
<q-inner-loading :visible="attachRequesting">
<q-spinner-dots
color="primary"
:size="24"
/>
</q-inner-loading>
<q-toggle
:class="attachClasses"
:disable="attachRequesting"
:label="attachLabel"
v-model="changes.attach"
@input="toggleAttach"
checked-icon="attach_file"
unchecked-icon="attach_file"
/>
</q-field>
<q-field class="csc-form-field">
<q-inner-loading :visible="deleteRequesting">
<q-spinner-dots
color="primary"
:size="24"
/>
</q-inner-loading>
<q-toggle
:class="deleteClasses"
:disable="deleteRequesting || !canToggleDelete"
:label="deleteLabel"
v-model="changes.delete"
@input="toggle('delete')"
@input="toggleDelete"
checked-icon="delete"
unchecked-icon="delete"
/>
</q-field>
<q-field class="csc-form-field">
<q-toggle
:disable="attachRequesting || !canToggleAttachment"
:label="attachLabel"
v-model="changes.attach"
@input="toggle('attach')"
checked-icon="attach_file"
unchecked-icon="attach_file"
/>
</q-field>
</div>
</template>
@ -66,18 +90,23 @@
import {
QField,
QInput,
QToggle
QToggle,
QSpinnerDots,
QInnerLoading
} from 'quasar-framework'
export default {
name: 'csc-voicebox-settings',
props: [
'settings',
'deleteRequesting',
'attachRequesting',
'pinRequesting',
'emailRequesting',
'attachLabel',
'deleteLabel'
'deleteLabel',
'attach',
'delete',
'pin',
'email'
],
data () {
return {
@ -87,7 +116,9 @@
components: {
QField,
QInput,
QToggle
QToggle,
QSpinnerDots,
QInnerLoading
},
validations: {
changes: {
@ -110,16 +141,13 @@
return this.$t('validationErrors.email');
},
canToggleDelete() {
return this.settings.attach;
},
canToggleAttachment() {
return !this.settings.delete;
return this.attach;
},
pinHasChanged() {
return this.changes.pin !== this.settings.pin;
return this.changes.pin !== this.pin;
},
emailHasChanged() {
return this.changes.email !== this.settings.email;
return this.changes.email !== this.email;
},
pinButtons() {
let buttons = [];
@ -166,33 +194,69 @@
);
}
return buttons;
},
attachClasses() {
let classes = [];
if(this.attach) {
classes.push('csc-toggle-enabled');
}
else {
classes.push('csc-toggle-disabled');
}
return classes;
},
deleteClasses() {
let classes = [];
if(this.delete) {
classes.push('csc-toggle-enabled');
}
else {
classes.push('csc-toggle-disabled');
}
return classes;
}
},
methods: {
getSettings() {
return {
delete: this.settings.delete,
attach: this.settings.attach,
pin: this.settings.pin,
email: this.settings.email
delete: this.delete,
attach: this.attach,
pin: this.pin,
email: this.email
}
},
resetFields() {
this.changes = this.getSettings();
},
toggle(field) {
if (field === 'delete') {
this.$store.dispatch('voicebox/toggleDelete');
}
else if (field === 'attach') {
this.$store.dispatch('voicebox/toggleAttach');
}
toggleDelete() {
this.$store.dispatch('voicebox/toggleDelete');
},
toggleAttach() {
this.$store.dispatch('voicebox/toggleAttach');
},
updatePin() {
this.$store.dispatch('voicebox/updatePin', this.changes.pin);
if(this.pinHasChanged) {
this.$store.dispatch('voicebox/updatePin', this.changes.pin);
}
},
updateEmail() {
this.$store.dispatch('voicebox/updateEmail', this.changes.email);
if(this.emailHasChanged) {
this.$store.dispatch('voicebox/updateEmail', this.changes.email);
}
}
},
watch: {
pin() {
this.changes.pin = this.pin;
},
delete() {
this.changes.delete = this.delete;
},
attach() {
this.changes.attach = this.attach;
},
email() {
this.changes.email = this.email;
}
}
}

@ -1,23 +1,97 @@
<template>
<csc-page class="csc-simple-page">
<csc-voicebox-settings
v-if="isSettingsLoaded"
:settings="voiceboxSettings"
:deleteRequesting="isDeleteRequesting"
:attachRequesting="isAttachRequesting"
:pinRequesting="isPinRequesting"
:emailRequesting="isEmailRequesting"
:deleteLabel="deleteLabel"
:attachLabel="attachLabel"
/>
<div
class="row"
>
<div
class="col col-xs-12 col-md-6"
>
<csc-voicebox-settings
:attach="voiceboxAttach"
:delete="voiceboxDelete"
:pin="voiceboxPin"
:email="voiceboxEmail"
:deleteRequesting="isDeleteRequesting"
:attachRequesting="isAttachRequesting"
:pinRequesting="isPinRequesting"
:emailRequesting="isEmailRequesting"
:deleteLabel="deleteLabel"
:attachLabel="attachLabel"
/>
<csc-sound-file-upload
ref="uploadBusyGreeting"
icon="music_note"
:label="$t('voicebox.label.busyGreeting')"
:value="busyGreetingLabel"
:progress="uploadProgress"
:uploading="uploadBusyGreetingRequesting"
:uploaded="busyGreetingId !== null"
@upload="uploadBusyGreeting"
@abort="abort"
@reset="deleteBusy"
/>
<!--<q-field-->
<!--icon="music_note"-->
<!--&gt;-->
<!--<q-input-->
<!--readonly-->
<!--:float-label="$t('voicebox.label.busyGreeting')"-->
<!--:value="busyGreetingLabel"-->
<!--:after="busyGreetingButtons"-->
<!--/>-->
<!--<input-->
<!--v-show="false"-->
<!--ref="busyGreetingUpload"-->
<!--type="file"-->
<!--@change="busyGreetingFileChange"-->
<!--/>-->
<!--</q-field>-->
<!--<csc-upload-file-->
<!--ref="uploadBusyGreeting"-->
<!--:progress="uploadProgress"-->
<!--:requesting="uploadBusyGreetingRequesting"-->
<!--:id="busyGreetingId"-->
<!--file-types=".wav,.mp3"-->
<!--@reset="resetBusyFile"-->
<!--@upload="uploadBusyGreeting"-->
<!--@abort="abort"-->
<!--&gt;-->
<!--<div-->
<!--slot="status-label"-->
<!--:class="busyGreetingLabelClasses"-->
<!--&gt;-->
<!--{{ busyGreetingLabel }}-->
<!--</div>-->
<!--<q-btn-->
<!--slot="extra-buttons"-->
<!--flat-->
<!--color="negative"-->
<!--icon="delete"-->
<!--@click="deleteBusy"-->
<!--&gt;-->
<!--{{ $t('buttons.remove') }}-->
<!--</q-btn>-->
<!--</csc-upload-file>-->
</div>
</div>
</csc-page>
</template>
<script>
import {
QBtn,
QField,
QInput,
Dialog
} from 'quasar-framework'
import { mapGetters } from 'vuex'
import CscPage from '../../CscPage'
import CscVoiceboxSettings from './CscVoiceboxSettings'
import CscSoundFileUpload from '../../form/CscSoundFileUpload'
import {
startLoading,
stopLoading,
@ -30,15 +104,23 @@
}
},
components: {
CscSoundFileUpload,
CscPage,
CscVoiceboxSettings
CscVoiceboxSettings,
QBtn,
QField,
QInput
},
created() {
mounted() {
this.$store.dispatch('voicebox/getVoiceboxSettings');
this.loadBusyGreeting();
},
computed: {
...mapGetters('voicebox', [
'voiceboxSettings',
'voiceboxAttach',
'voiceboxDelete',
'voiceboxEmail',
'voiceboxPin',
'deleteLabel',
'attachLabel',
'isDeleteRequesting',
@ -46,8 +128,8 @@
'isPinRequesting',
'isEmailRequesting',
'isSettingsLoaded',
'loadingState',
'loadingError',
'loadSettingsState',
'loadSettingsError',
'toggleDeleteState',
'toggleDeleteError',
'toggleAttachState',
@ -56,44 +138,102 @@
'updatePinError',
'updateEmailState',
'updateEmailError',
])
},
watch: {
loadingState(state) {
if (state === 'requesting') {
startLoading();
'uploadProgress',
'uploadBusyGreetingState',
'uploadBusyGreetingError',
'uploadBusyGreetingRequesting',
'busyGreetingId',
'unavailGreetingId',
'deleteGreetingState',
'deleteGreetingError',
'isBusyGreetingLoaded',
'busyGreetingLabel'
]),
busyGreetingLabelClasses() {
let classes = ['csc-upload-file-label'];
if(this.busyGreetingId) {
classes.push('active-label');
}
else if (state === 'succeeded') {
stopLoading();
else {
classes.push('inactive-label');
}
else if (state === 'failed') {
stopLoading();
showGlobalError(this.loadingError);
return classes;
},
busyGreetingButtons() {
let buttons = [];
let self = this;
buttons.push({
icon: 'folder',
error: false,
handler (event) {
event.stopPropagation();
self.$refs.busyGreetingUpload.click();
}
}
);
return buttons;
}
},
methods: {
busyGreetingFileChange() {
},
resetBusyFile() {
this.$refs.uploadBusyGreeting.reset();
this.$store.commit('voicebox/resetProgress');
},
uploadBusyGreeting(file) {
this.$store.dispatch('voicebox/uploadGreeting', {
dir: 'busy',
file: file
});
},
abort() {
this.$store.dispatch('voicebox/abortPreviousRequest');
},
deleteBusy() {
let self = this;
let store = this.$store;
Dialog.create({
title: self.$t('voicebox.deleteCustomDialogTitle'),
message: self.$t('voicebox.deleteCustomDialogText', {
type: 'busy'
}),
buttons: [
self.$t('buttons.cancel'),
{
label: self.$t('buttons.reset'),
color: 'negative',
handler () {
store.dispatch('voicebox/deleteGreeting', self.busyGreetingId)
}
}
]
});
},
loadBusyGreeting() {
this.$store.dispatch('voicebox/loadBusyGreeting');
}
},
watch: {
loadSettingsState(state) {
if (state === 'failed') {
showGlobalError(this.loadSettingsError);
}
},
toggleDeleteState(state) {
if (state === 'requesting') {
startLoading();
}
else if (state === 'succeeded') {
stopLoading();
if (state === 'succeeded') {
showToast(this.$t('voicebox.toggleDeleteSuccessMessage'));
}
else if (state === 'failed') {
stopLoading();
showGlobalError(this.toggleDeleteError);
}
},
toggleAttachState(state) {
if (state === 'requesting') {
startLoading();
}
else if (state === 'succeeded') {
stopLoading();
if (state === 'succeeded') {
showToast(this.$t('voicebox.toggleAttachSuccessMessage'));
}
else if (state === 'failed') {
stopLoading();
showGlobalError(this.toggleAttachError);
}
},
@ -112,10 +252,40 @@
else if (state === 'failed') {
showGlobalError(this.updateEmailError);
}
},
uploadBusyGreetingState(state) {
if (state === 'succeeded') {
showToast(this.$t('voicebox.uploadGreetingSuccessMessage'));
this.resetBusyFile();
}
else if (state === 'failed') {
showGlobalError(this.uploadBusyGreetingError);
if (this.uploadProgress > 0) {
this.resetBusyFile();
}
}
},
deleteGreetingState(state) {
if (state === 'requesting') {
startLoading();
}
else if (state === 'succeeded') {
stopLoading();
showToast(this.$t('voicebox.deleteGreetingSuccessMessage'));
}
else if (state === 'failed') {
stopLoading();
showGlobalError(this.deleteGreetingError);
}
}
}
}
</script>
<style lang="stylus" rel="stylesheet/stylus">
@import '../../../themes/quasar.variables';
.csc-upload-file-label
margin-bottom $flex-gutter-sm
</style>

@ -17,7 +17,12 @@
"moveUp": "Move up",
"moveDown": "Move down",
"dismiss": "Dismiss",
"reset": "Reset"
"reset": "Reset",
"select": "Select",
"upload": "Upload",
"abort": "Abort",
"selectNew": "Select new",
"resetDefaults": "Reset to defaults"
},
"toasts": {
"callAvailable": "You are now able to start and receive calls",
@ -183,10 +188,10 @@
"removeDialogTitle": "Remove call forward destination",
"removeDialogText": "You are about to remove the destination {destination}",
"removeSuccessMessage": "Removed destination {destination}",
"removeErrorMessage": "An error occured while trying to delete the destination. Please try again.",
"removeErrorMessage": "An error occured while trying to delete the destination. Please try again",
"addDestinationButton": "Add destination",
"addDestinationSuccessMessage": "Added destination {destination}",
"addErrorMessage": "An error occured while trying to add the destination. Please try again.",
"addErrorMessage": "An error occured while trying to add the destination. Please try again",
"addInputError": "Input a valid number or subscriber name",
"timeout": "Timeout",
"destination": "Destination",
@ -205,13 +210,13 @@
"removeLastDialogTitle": "Remove last call forward time",
"removeLastDialogText": "WARNING: Removing the last time entry will also delete this timeset and all corresponding destinations. Are you sure you want to do this?",
"removeSuccessMessage": "Removed time entry for {day}",
"removeErrorMessage": "An error occured while trying to delete the time entry. Please try again.",
"removeErrorMessage": "An error occured while trying to delete the time entry. Please try again",
"removeTimesetSuccessMessage": "Removed timeset",
"resetErrorMessage": "An error occured while trying to reset the timesets. Please try again.",
"resetErrorMessage": "An error occured while trying to reset the timesets. Please try again",
"resetSuccessMessage": "Reset of timesets completed",
"addTimeSuccessMessage": "Created new timeset",
"addTimeErrorMessage": "An error occured while trying to create the timeset. Please try again.",
"loadDestinationErrorMessage": "An error occured while trying to load the destinations. Please try again.",
"addTimeErrorMessage": "An error occured while trying to create the timeset. Please try again",
"loadDestinationErrorMessage": "An error occured while trying to load the destinations. Please try again",
"noTimeSet": "no time set",
"addTimeButton": "Add Time",
"timesetIncompatible": "The {timeset} timeset contains incompatible values. You can resolve this by resetting the {timeset} timeset.",
@ -238,17 +243,17 @@
"sourceset": "Sourceset",
"source": "Source",
"fieldMissing": "Both sourceset name and source is required. Please provide both and try again.",
"addSourcesetErrorMessage": "An error occured while trying to create the sourceset. Please try again.",
"addSourcesetErrorMessage": "An error occured while trying to create the sourceset. Please try again",
"addSourceButton": "Add source",
"addSourceSuccessMessage": "Added new source {source}",
"addSourceErrorMessage": "An error occured while trying to add the source. Please try again.",
"addSourceErrorMessage": "An error occured while trying to add the source. Please try again",
"removeSourcesetButton": "Delete sourceset",
"removeSourcesetErrorMessage": "An error occured while trying to delete the sourceset. Please try again.",
"removeSourcesetErrorMessage": "An error occured while trying to delete the sourceset. Please try again",
"removeSourcesetSuccessMessage": "Removed sourceset {sourceset}",
"removeSourcesetDialogTitle": "Remove call forward sourceset",
"removeSourcesetDialogText": "You are about to remove the sourceset {sourceset}",
"removeSourceSuccessMessage": "Removed source {source}",
"removeSourceErrorMessage": "An error occured while trying to remove the source. Please try again.",
"removeSourceErrorMessage": "An error occured while trying to remove the source. Please try again",
"removeSourceDialogTitle": "Remove call forward source",
"removeSourceDialogText": "You are about to remove the source entry for {source}",
"removeLastSourceDialogText": "Removing the last source entry is not allowed."
@ -390,48 +395,56 @@
"pageHeader": "Page Header",
"content": "Content",
"file": "File",
"faxFile": "Fax File",
"uploadFile": "Upload File"
"faxFile": "Fax File"
},
"send": "Send",
"cancel": "Cancel",
"createFaxErrorMessage": "An error occured while trying to send the fax. Please try again.",
"createFaxErrorMessage": "An error occured while trying to send the fax. Please try again",
"createFaxSuccessMessage": "Sending fax completed successfully."
},
"speedDial": {
"whenIDial": "When I dial {slot} ...",
"ring": "ring",
"loadSpeedDialErrorMessage": "An error occured while trying to load the speed dials. Please try again.",
"loadSpeedDialErrorMessage": "An error occured while trying to load the speed dials. Please try again",
"noResultsMessage": "No speed dials found",
"removeDialogTitle": "Remove speed dial",
"removeDialogText": "You are about to remove the speed dial {slot}",
"unassignSlotErrorMessage": "An error occured while trying to unassign the speed dial slot. Please try again.",
"unassignSlotErrorMessage": "An error occured while trying to unassign the speed dial slot. Please try again",
"unassignSlotSuccessMessage": "Unassigned slot {slot}",
"addSpeedDial": "Add Speed Dial",
"slot": "Slot",
"destination": "Destination",
"addNoSlotsDialogText": "All available speed dial slots have already been assigned. Please delete one first.",
"assignSlotErrorMessage": "An error occured while trying to assign the speed dial slot. Please try again.",
"assignSlotErrorMessage": "An error occured while trying to assign the speed dial slot. Please try again",
"assignSlotSuccessMessage": "Assigned slot {slot}"
},
"voicebox": {
"label": {
"changeEmail": "Change Email",
"changePin": "Change PIN",
"deletionEnabled": "Voicemail will be deleted after email notification is delivered",
"deletionDisabled": "Voicemail will not be deleted after email notification is delivered",
"attachmentEnabled": "Voicemail will be attached to email notification",
"attachmentDisabled": "Voicemail will not be attached to email notification"
"deletionEnabled": "Deleted voicemail after email notification is delivered",
"deletionDisabled": "Deleted voicemail after email notification is delivered",
"attachmentEnabled": "Attach voicemail to email notification",
"attachmentDisabled": "Attach voicemail to email notification",
"busyGreeting": "Busy Greeting",
"customSoundActive": "Custom sound",
"defaultSoundActive": "Default sound"
},
"pin": "PIN",
"loadSettingsErrorMessage": "An error occured while trying to load the settings. Please reload the page or check your network connection.",
"toggleDeleteSuccessMessage": "Toggled deletion successfully.",
"toggleDeleteErrorMessage": "An error occured while trying to toggle the delete option. Please try again.",
"toggleAttachSuccessMessage": "Toggled attachment successfully.",
"toggleAttachErrorMessage": "An error occured while trying to toggle the attach option. Please try again.",
"loadSettingsErrorMessage": "An error occured while trying to load the settings. Please reload the page or check your network connection",
"toggleDeleteSuccessMessage": "Toggled deletion successfully",
"toggleDeleteErrorMessage": "An error occured while trying to toggle the delete option. Please try again",
"toggleAttachSuccessMessage": "Toggled attachment successfully",
"toggleAttachErrorMessage": "An error occured while trying to toggle the attach option. Please try again",
"updatePinSuccessMessage": "Changed PIN successfully.",
"updatePinErrorMessage": "An error occured while trying to update the pin field. Please try again.",
"updateEmailSuccessMessage": "Changed email successfully.",
"updateEmailErrorMessage": "An error occured while trying to update the email field. Please try again."
"updatePinErrorMessage": "An error occured while trying to update the pin field. Please try again",
"updateEmailSuccessMessage": "Changed email successfully",
"updateEmailErrorMessage": "An error occured while trying to update the email field. Please try again",
"uploadGreetingSuccessMessage": "Uploaded greeting sound successfully",
"uploadGreetingErrorMessage": "An error occured while trying to upload the greeting sound. Please try again",
"deleteGreetingSuccessMessage": "Deleted greeting sound successfully",
"deleteGreetingErrorMessage": "An error occured while trying to delete the greeting sound. Please try again",
"deleteCustomDialogTitle": "Reset busy greeting sound",
"deleteCustomDialogText": "You are about to reset the custom {type} greeting sound to defaults"
}
}

@ -1,30 +1,29 @@
'use strict';
import _ from 'lodash'
import { RequestState } from './common'
import {
getVoiceboxSettings,
setVoiceboxDelete,
setVoiceboxAttach,
setVoiceboxPin,
setVoiceboxEmail
setVoiceboxEmail,
uploadGreeting,
abortPreviousRequest,
getVoiceboxGreetingByType,
deleteVoiceboxGreetingById
} from '../api/voicebox';
import { i18n } from '../i18n';
export default {
namespaced: true,
state: {
voiceboxSettings: {
attach: null,
delete: null,
email: '',
id: null,
pin: null,
sms_number: ''
},
loadingState: RequestState.initial,
loadingError: null,
voiceboxSettingDelete: false,
voiceboxSettingAttach: false,
voiceboxSettingPin: '',
voiceboxSettingEmail: '',
loadSettingsState: RequestState.initial,
loadSettingsError: null,
toggleDeleteState: RequestState.initial,
toggleDeleteError: null,
toggleAttachState: RequestState.initial,
@ -32,47 +31,66 @@ export default {
updatePinState: RequestState.initial,
updatePinError: null,
updateEmailState: RequestState.initial,
updateEmailError: null
updateEmailError: null,
uploadBusyGreetingState: RequestState.initial,
uploadBusyGreetingError: null,
uploadProgress: 0,
busyGreetingId: null,
unavailGreetingId: null,
loadBusyGreetingState: RequestState.initial,
loadBusyGreetingError: null,
deleteGreetingState: RequestState.initial,
deleteGreetingError: null
},
getters: {
subscriberId(state, getters, rootState, rootGetters) {
return parseInt(rootGetters['user/getSubscriberId']);
},
isSettingsLoaded(state) {
return state.loadingState === 'succeeded';
return state.loadSettingsState === 'succeeded';
},
isDeleteRequesting(state) {
return state.toggleDeleteState === 'requesting';
return state.loadSettingsState === 'requesting' ||
state.toggleDeleteState === 'requesting';
},
isAttachRequesting(state) {
return state.toggleAttachState === 'requesting';
return state.loadSettingsState === 'requesting' ||
state.toggleAttachState === 'requesting';
},
isPinRequesting(state) {
return state.updatePinState === 'requesting';
return state.loadSettingsState === 'requesting' ||
state.updatePinState === 'requesting';
},
isEmailRequesting(state) {
return state.updateEmailState === 'requesting';
return state.loadSettingsState === 'requesting' ||
state.updateEmailState === 'requesting';
},
loadingState(state) {
return state.loadingState;
loadSettingsState(state) {
return state.loadSettingsState;
},
loadingError(state) {
return state.loadingError ||
loadSettingsError(state) {
return state.loadSettingsError ||
i18n.t('voicebox.loadSettingsErrorMessage');
},
voiceboxDelete(state) {
return _.get(state.voiceboxSettings, 'delete', false);
return state.voiceboxSettingDelete;
},
voiceboxAttach(state) {
return _.get(state.voiceboxSettings, 'attach', false);
return state.voiceboxSettingAttach;
},
deleteLabel(state) {
return state.voiceboxSettings.delete ?
voiceboxPin(state) {
return state.voiceboxSettingPin;
},
voiceboxEmail(state) {
return state.voiceboxSettingEmail;
},
deleteLabel(state, getters) {
return getters.voiceboxDelete ?
i18n.t('voicebox.label.deletionEnabled') :
i18n.t('voicebox.label.deletionDisabled');
},
attachLabel(state) {
return state.voiceboxSettings.attach ?
attachLabel(state, getters) {
return getters.voiceboxAttach ?
i18n.t('voicebox.label.attachmentEnabled') :
i18n.t('voicebox.label.attachmentDisabled');
},
@ -106,21 +124,64 @@ export default {
updateEmailError(state) {
return state.updateEmailError ||
i18n.t('voicebox.updateEmailErrorMessage');
},
uploadBusyGreetingState(state) {
return state.uploadBusyGreetingState;
},
uploadBusyGreetingError(state) {
return state.uploadBusyGreetingError ||
i18n.t('voicebox.uploadGreetingErrorMessage');
},
uploadProgress(state) {
return state.uploadProgress;
},
uploadBusyGreetingRequesting(state) {
return state.uploadBusyGreetingState === 'requesting';
},
busyGreetingId(state) {
return state.busyGreetingId;
},
unavailGreetingId(state) {
return state.unavailGreetingId;
},
deleteGreetingState(state) {
return state.deleteGreetingState;
},
deleteGreetingError(state) {
return state.deleteGreetingError ||
i18n.t('voicebox.deleteGreetingErrorMessage');
},
isBusyGreetingLoaded(state) {
return state.loadBusyGreetingState === 'succeeded';
},
busyGreetingLabel(state) {
return state.busyGreetingId ? i18n.t('voicebox.label.customSoundActive') :
i18n.t('voicebox.label.defaultSoundActive');
}
},
mutations: {
loadingRequesting(state) {
state.loadingState = RequestState.requesting;
state.loadingError = null;
},
loadingSucceeded(state, settings) {
state.loadingState = RequestState.succeeded;
state.voiceboxSettings = settings;
state.loadingError = null;
},
loadingFailed(state, error) {
state.loadingState = RequestState.failed;
state.loadingError = error;
loadedSettings(state, settings) {
state.voiceboxSettingDelete = settings.delete;
state.voiceboxSettingAttach = settings.attach;
state.voiceboxSettingPin = settings.pin;
state.voiceboxSettingEmail = settings.email;
state.loadSettingsError = null;
},
loadSettingsRequesting(state) {
state.loadSettingsState = RequestState.requesting;
state.loadSettingsError = null;
},
loadSettingsSucceeded(state, settings) {
state.loadSettingsState = RequestState.succeeded;
state.loadSettingsError = null;
state.voiceboxSettingDelete = settings.delete;
state.voiceboxSettingAttach = settings.attach;
state.voiceboxSettingPin = settings.pin;
state.voiceboxSettingEmail = settings.email;
},
loadSettingsFailed(state, error) {
state.loadSettingsState = RequestState.succeeded;
state.loadSettingsError = error;
},
toggleDeleteRequesting(state) {
state.toggleDeleteState = RequestState.requesting;
@ -169,16 +230,62 @@ export default {
updateEmailFailed(state, error) {
state.updateEmailState = RequestState.failed;
state.updateEmailError = error;
},
uploadBusyGreetingRequesting(state) {
state.uploadBusyGreetingState = RequestState.requesting;
state.uploadBusyGreetingError = null;
},
uploadBusyGreetingSucceeded(state) {
state.uploadBusyGreetingState = RequestState.succeeded;
state.uploadBusyGreetingError = null;
},
uploadBusyGreetingFailed(state, error) {
state.uploadBusyGreetingState = RequestState.failed;
state.uploadBusyGreetingError = error;
},
uploadProgress(state, progress) {
state.uploadProgress = progress;
},
resetProgress(state) {
state.uploadProgress = 0;
},
loadBusyGreetingRequesting(state) {
state.busyGreetingId = null,
state.loadBusyGreetingState = RequestState.requesting;
state.loadBusyGreetingError = null;
},
loadBusyGreetingSucceeded(state, greetings) {
if (greetings.length > 0) {
state.busyGreetingId = greetings[0].id;
}
state.loadBusyGreetingState = RequestState.succeeded;
state.loadBusyGreetingError = null;
},
loadBusyGreetingFailed(state, error) {
state.loadBusyGreetingState = RequestState.failed;
state.loadBusyGreetingError = error;
},
deleteGreetingRequesting(state) {
state.deleteGreetingState = RequestState.requesting;
state.deleteGreetingError = null;
},
deleteGreetingSucceeded(state) {
state.deleteGreetingState = RequestState.succeeded;
state.deleteGreetingError = null;
},
deleteGreetingFailed(state, error) {
state.deleteGreetingState = RequestState.failed;
state.deleteGreetingError = error;
}
},
actions: {
getVoiceboxSettings(context) {
context.commit('loadingRequesting');
context.commit('loadSettingsRequesting');
getVoiceboxSettings(context.getters.subscriberId).then((settings) => {
context.commit('loadingSucceeded', settings);
context.commit('loadSettingsSucceeded', settings);
}).catch((err) => {
context.commit('loadingFailed', err.message);
})
context.commit('loadSettingsFailed', err.message);
});
},
toggleDelete(context) {
context.commit('toggleDeleteRequesting');
@ -186,8 +293,10 @@ export default {
subscriberId: context.getters.subscriberId,
value: !context.getters.voiceboxDelete
}).then(() => {
return getVoiceboxSettings(context.getters.subscriberId);
}).then((settings)=>{
context.commit('loadedSettings', settings);
context.commit('toggleDeleteSucceeded');
context.dispatch('getVoiceboxSettings');
}).catch((err) => {
context.commit('toggleDeleteFailed', err.message);
context.dispatch('getVoiceboxSettings');
@ -199,8 +308,10 @@ export default {
subscriberId: context.getters.subscriberId,
value: !context.getters.voiceboxAttach
}).then(() => {
return getVoiceboxSettings(context.getters.subscriberId);
}).then((settings)=>{
context.commit('loadedSettings', settings);
context.commit('toggleAttachSucceeded');
context.dispatch('getVoiceboxSettings');
}).catch((err) => {
context.commit('toggleAttachFailed', err.message);
context.dispatch('getVoiceboxSettings');
@ -212,8 +323,10 @@ export default {
subscriberId: context.getters.subscriberId,
value: value
}).then(() => {
return getVoiceboxSettings(context.getters.subscriberId);
}).then((settings)=>{
context.commit('loadedSettings', settings);
context.commit('updatePinSucceeded');
context.dispatch('getVoiceboxSettings');
}).catch((err) => {
context.commit('updatePinFailed', err.message);
});
@ -224,11 +337,58 @@ export default {
subscriberId: context.getters.subscriberId,
value: value
}).then(() => {
return getVoiceboxSettings(context.getters.subscriberId);
}).then((settings)=>{
context.commit('loadedSettings', settings);
context.commit('updateEmailSucceeded');
context.dispatch('getVoiceboxSettings');
}).catch((err) => {
context.commit('updateEmailFailed', err.message);
});
},
uploadGreeting(context, $options) {
let options = Object.assign($options, {
subscriber_id: context.getters.subscriberId,
type: $options.dir
});
context.commit('uploadBusyGreetingRequesting');
uploadGreeting({
data: options,
onProgress: (progress) => { context.commit('uploadProgress', progress) }
}).then(() => {
context.commit('loadBusyGreetingRequesting');
return getVoiceboxGreetingByType({
id: context.getters.subscriberId,
type: 'busy'
})
}).then((greetings)=>{
context.commit('loadBusyGreetingSucceeded', greetings.items);
context.commit('uploadBusyGreetingSucceeded');
}).catch((err) => {
context.commit('uploadBusyGreetingFailed', err.message);
});
},
abortPreviousRequest() {
abortPreviousRequest();
},
loadBusyGreeting(context) {
context.commit('loadBusyGreetingRequesting');
getVoiceboxGreetingByType({
id: context.getters.subscriberId,
type: 'busy'
}).then((greetings) => {
context.commit('loadBusyGreetingSucceeded', greetings.items);
}).catch((err) => {
context.commit('loadBusyGreetingFailed', err.message);
});
},
deleteGreeting(context, id) {
context.commit('deleteGreetingRequesting');
deleteVoiceboxGreetingById(id).then(() => {
context.commit('deleteGreetingSucceeded');
context.dispatch('loadBusyGreeting');
}).catch((err) => {
context.commit('deleteGreetingFailed', err.message);
});
}
}
};

@ -1,6 +1,13 @@
@import 'quasar.variables'
.q-field
position relative
.csc-toggle-disabled
.q-option-label
color: $faded
.q-list-highlight
.csc-item-expanded:hover
background-color white
@ -118,3 +125,6 @@
.q-field-icon
color $primary
.csc-black-label
color black

@ -4,20 +4,22 @@
import Vue from 'vue';
import VueResource from 'vue-resource';
import {
get
get,
getList
} from '../../src/api/common';
import {
getVoiceboxSettings
getVoiceboxSettings,
getVoiceboxGreetingByType
} from '../../src/api/voicebox';
import { assert } from 'chai';
Vue.use(VueResource);
describe('Voicebox', function(){
describe('Voicebox', function() {
const subscriberId = 123;
it('should get subscriber\'s voicebox settings', function(done){
it('should get subscriber\'s voicebox settings', function(done) {
let data = {
"_links" : {
@ -64,15 +66,50 @@ describe('Voicebox', function(){
};
Vue.http.interceptors = [];
Vue.http.interceptors.unshift((request, next)=>{
Vue.http.interceptors.unshift((request, next) => {
next(request.respondWith(JSON.stringify(data), {
status: 200
}));
});
getVoiceboxSettings(subscriberId).then((result)=>{
getVoiceboxSettings(subscriberId).then((result) => {
assert.deepEqual(result, settings);
done();
}).catch((err)=>{
}).catch((err) => {
done(err);
});
});
it('should get subscriber\'s busy greeting', function(done) {
let data = {
"_embedded" : {
"ngcp:voicemailgreetings" : [
{
"dir" : "busy",
"id" : 1,
"subscriber_id" : 123
}
]
},
"total_count" : 1
};
let greeting = {
"dir" : "busy",
"id" : 1,
"subscriber_id" : 123
};
Vue.http.interceptors = [];
Vue.http.interceptors.unshift((request, next) => {
next(request.respondWith(JSON.stringify(data), {
status: 200
}));
});
getVoiceboxGreetingByType({id: subscriberId, type: 'busy'}).then((result) => {
assert.deepEqual(result.items[0], greeting);
done();
}).catch((err) => {
done(err);
});
});

@ -8,14 +8,10 @@ describe('Voicebox', function(){
it('should load all voicebox settings into store', function(){
let state = {
voiceboxSettings: {
attach: null,
delete: null,
email: '',
id: null,
pin: null,
sms_number: ''
}
voiceboxSettingDelete: false,
voiceboxSettingAttach: false,
voiceboxSettingPin: '',
voiceboxSettingEmail: '',
};
let settings = {
attach: true,
@ -25,8 +21,25 @@ describe('Voicebox', function(){
pin: 1234,
sms_number: ''
};
VoiceboxModule.mutations.loadingSucceeded(state, settings);
assert.deepEqual(state.voiceboxSettings, settings);
VoiceboxModule.mutations.loadSettingsSucceeded(state, settings);
assert.equal(state.voiceboxSettingDelete, settings.delete);
assert.equal(state.voiceboxSettingAttach, settings.attach);
assert.equal(state.voiceboxSettingEmail, settings.email);
assert.equal(state.voiceboxSettingPin, settings.pin);
});
it('should load all busy greeting id into store', function(){
let state = {
busyGreetingId: null
};
let greetings = [
{
id: 1
}
];
VoiceboxModule.mutations.loadBusyGreetingSucceeded(state, greetings);
assert.deepEqual(state.busyGreetingId, greetings[0].id);
});
});

Loading…
Cancel
Save