diff --git a/src/api/voicebox.js b/src/api/voicebox.js index 347a4074..b2a07ce4 100644 --- a/src/api/voicebox.js +++ b/src/api/voicebox.js @@ -141,6 +141,21 @@ export function uploadGreeting(options) { } export function abortPreviousRequest(name) { - let requestKey = `previous${_.capitalize(name)}Request`; - Vue[requestKey].abort(); + return new Promise((resolve) => { + let requestKey = `previous${_.capitalize(name)}Request`; + Vue[requestKey].abort(); + resolve(); + }); +} + +export function playGreeting(options) { + return new Promise((resolve, reject)=>{ + let params = { format: options.format }; + Vue.http.get(`api/voicemailgreetings/${options.id}`, { params: params, responseType: 'blob' }) + .then((res) => { + resolve(URL.createObjectURL(res.body)); + }).catch((err) => { + reject(err); + }); + }); } diff --git a/src/components/CscAudioPlayer.vue b/src/components/CscAudioPlayer.vue index 28be2457..0d03bfca 100644 --- a/src/components/CscAudioPlayer.vue +++ b/src/components/CscAudioPlayer.vue @@ -1,13 +1,49 @@ @@ -17,22 +53,24 @@ export default { name: 'csc-audio-player', props: [ - 'fileUrl', - 'loaded' + 'fileUrl', + 'loaded', + 'disable', + 'pausable' ], mounted() { - this.$refs.audio.addEventListener('play', ()=>{ + this.$refs.audio.addEventListener('play', ()=> { this.playing = true; }); - this.$refs.audio.addEventListener('playing', ()=>{ + this.$refs.audio.addEventListener('playing', ()=> { this.playing = true; }); - this.$refs.audio.addEventListener('ended', ()=>{ + this.$refs.audio.addEventListener('ended', ()=> { this.playing = false; this.stop(); }); - this.$refs.audio.addEventListener('canplay', ()=>{ - if(!this.paused && this.playing) { + this.$refs.audio.addEventListener('canplay', ()=> { + if (!this.paused && this.playing) { this.$refs.audio.play(); } }); @@ -58,6 +96,7 @@ this.$refs.audio.play(); this.playing = true; this.paused = false; + this.$emit('playing'); }, pause() { this.$refs.audio.pause(); @@ -67,6 +106,7 @@ stop() { this.$refs.audio.currentTime = 0; this.pause(); + this.$emit('stopped'); }, setPlayingTrue() { this.playing = true; @@ -74,9 +114,8 @@ setPausedFalse() { this.paused = false; }, - timeupdate(e) { - let newPercentage = Math.floor((e.target.currentTime / e.target.duration) * 100); - this.progressPercentage = newPercentage; + timeUpdate() { + this.progressPercentage = this.$refs.audio.currentTime * 100 / this.$refs.audio.duration; }, load() { this.$emit('load'); @@ -91,6 +130,14 @@ else { this.pause(); } + }, + playLoad() { + if (!this.loaded) { + this.load(); + } + else if (this.$refs.audio.paused) { + this.play(); + } } } } @@ -99,15 +146,17 @@ diff --git a/src/components/pages/Conversations/CscVoiceMailItem.vue b/src/components/pages/Conversations/CscVoiceMailItem.vue index 6ac6e6d5..f48f35c6 100644 --- a/src/components/pages/Conversations/CscVoiceMailItem.vue +++ b/src/components/pages/Conversations/CscVoiceMailItem.vue @@ -39,6 +39,7 @@ :loaded="voiceMailLoaded" class="csc-voice-mail-player" @load="load" + :pausable="true" /> diff --git a/src/components/pages/Voicebox/Voicebox.vue b/src/components/pages/Voicebox/Voicebox.vue index 96e30ce5..08852059 100644 --- a/src/components/pages/Voicebox/Voicebox.vue +++ b/src/components/pages/Voicebox/Voicebox.vue @@ -20,7 +20,7 @@ :attachLabel="attachLabel" /> @@ -68,6 +74,7 @@ export default { data () { return { + platform: this.$q.platform.is } }, components: { @@ -117,16 +124,23 @@ 'deleteGreetingState', 'deleteGreetingError', 'busyGreetingLabel', - 'unavailGreetingLabel' - ]) + 'unavailGreetingLabel', + 'playBusyGreetingLoaded', + 'playBusyGreetingUrl', + 'playUnavailGreetingLoaded', + 'playUnavailGreetingUrl' + ]), + soundFileFormat() { + return this.platform.mozilla ? 'ogg' : 'mp3'; + } }, methods: { resetBusyFile() { - this.$refs.uploadBusyGreeting.reset(); + this.$refs.uploadBusy.reset(); this.$store.commit('voicebox/resetBusyProgress'); }, resetUnavailFile() { - this.$refs.uploadUnavailGreeting.reset(); + this.$refs.uploadUnavail.reset(); this.$store.commit('voicebox/resetUnavailProgress'); }, uploadBusyGreeting(file) { @@ -140,10 +154,10 @@ }); }, abortBusy() { - this.$store.dispatch('voicebox/abortPreviousRequest', 'busy'); + this.$store.dispatch('voicebox/abortUploadBusyGreeting'); }, abortUnavail() { - this.$store.dispatch('voicebox/abortPreviousRequest', 'unavail'); + this.$store.dispatch('voicebox/abortUploadUnavailGreeting'); }, deleteBusy() { let self = this; @@ -202,6 +216,22 @@ }, loadUnavailGreeting() { this.$store.dispatch('voicebox/loadUnavailGreeting'); + }, + playBusyGreeting() { + this.$store.dispatch('voicebox/playBusyGreeting', this.soundFileFormat); + }, + playUnavailGreeting() { + this.$store.dispatch('voicebox/playUnavailGreeting', this.soundFileFormat); + }, + initBusyGreetingAudio() { + this.playBusyGreeting(); + this.$refs.uploadBusy.setPlayingTrue(); + this.$refs.uploadBusy.setPausedFalse(); + }, + initUnavailGreetingAudio() { + this.playUnavailGreeting(); + this.$refs.uploadUnavail.setPlayingTrue(); + this.$refs.uploadUnavail.setPausedFalse(); } }, watch: { @@ -286,7 +316,4 @@ diff --git a/src/store/conversations.js b/src/store/conversations.js index 83090183..702f7e65 100644 --- a/src/store/conversations.js +++ b/src/store/conversations.js @@ -226,15 +226,15 @@ export default { }, downloadVoiceMail(context, id) { context.commit('downloadVoiceMailRequesting'); - downloadVoiceMail(id).then(()=>{ + downloadVoiceMail(id).then(() => { context.commit('downloadVoiceMailSucceeded'); - }).catch((err)=>{ + }).catch((err) => { context.commit('downloadVoiceMailFailed', err.body.message); }); }, downloadFax(context, id) { context.commit('downloadFaxRequesting'); - downloadFax(id).then(()=>{ + downloadFax(id).then(() => { context.commit('downloadFaxSucceeded'); }).catch((err)=>{ context.commit('downloadFaxFailed', err.body.message); @@ -242,12 +242,12 @@ export default { }, playVoiceMail(context, options) { context.commit('playVoiceMailRequesting', options.id); - playVoiceMail(options).then((url)=>{ + playVoiceMail(options).then((url) => { context.commit('playVoiceMailSucceeded', { id: options.id, url: url }); - }).catch((err)=>{ + }).catch((err) => { context.commit('playVoiceMailFailed', options.id, err.mesage); }); }, diff --git a/src/store/voicebox.js b/src/store/voicebox.js index a2f7ed5e..923986cd 100644 --- a/src/store/voicebox.js +++ b/src/store/voicebox.js @@ -3,15 +3,15 @@ import { RequestState } from './common' import { - getVoiceboxSettings, - setVoiceboxDelete, + getVoiceboxSettings, setVoiceboxDelete, setVoiceboxAttach, setVoiceboxPin, setVoiceboxEmail, uploadGreeting, abortPreviousRequest, getVoiceboxGreetingByType, - deleteVoiceboxGreetingById + deleteVoiceboxGreetingById, + playGreeting } from '../api/voicebox'; import { i18n } from '../i18n'; @@ -45,7 +45,13 @@ export default { loadUnavailGreetingState: RequestState.initial, loadUnavailGreetingError: null, deleteGreetingState: RequestState.initial, - deleteGreetingError: null + deleteGreetingError: null, + playBusyGreetingUrl: null, + playBusyGreetingState: RequestState.initial, + playBusyGreetingError: null, + playUnavailGreetingUrl: null, + playUnavailGreetingState: RequestState.initial, + playUnavailGreetingError: null }, getters: { subscriberId(state, getters, rootState, rootGetters) { @@ -176,6 +182,18 @@ export default { unavailGreetingLabel(state) { return state.unavailGreetingId ? i18n.t('voicebox.label.customSoundActive') : i18n.t('voicebox.label.defaultSoundActive') + }, + playBusyGreetingLoaded(state) { + return state.playBusyGreetingState === 'succeeded'; + }, + playBusyGreetingUrl(state) { + return state.playBusyGreetingUrl; + }, + playUnavailGreetingLoaded(state) { + return state.playUnavailGreetingState === 'succeeded'; + }, + playUnavailGreetingUrl(state) { + return state.playUnavailGreetingUrl; } }, mutations: { @@ -292,6 +310,7 @@ export default { state.loadBusyGreetingError = null; }, loadBusyGreetingSucceeded(state, greetings) { + state.playBusyGreetingState = RequestState.initial; if (greetings.length > 0) { state.busyGreetingId = greetings[0].id; } @@ -308,6 +327,7 @@ export default { state.loadUnavailGreetingError = null; }, loadUnavailGreetingSucceeded(state, greetings) { + state.playUnavailGreetingState = RequestState.initial; if (greetings.length > 0) { state.unavailGreetingId = greetings[0].id; } @@ -329,6 +349,34 @@ export default { deleteGreetingFailed(state, error) { state.deleteGreetingState = RequestState.failed; state.deleteGreetingError = error; + }, + playBusyGreetingRequesting(state) { + state.playBusyGreetingState = RequestState.requesting; + state.playBusyGreetingError = null; + }, + playBusyGreetingSucceeded(state, url) { + state.playBusyGreetingUrl = url; + state.playBusyGreetingState = RequestState.succeeded; + state.playBusyGreetingError = null; + }, + playBusyGreetingFailed(state, err) { + state.playBusyGreetingUrl = null; + state.playBusyGreetingState = RequestState.failed; + state.playBusyGreetingError = err; + }, + playUnavailGreetingRequesting(state) { + state.playUnavailGreetingState = RequestState.requesting; + state.playUnavailGreetingError = null; + }, + playUnavailGreetingSucceeded(state, url) { + state.playUnavailGreetingUrl = url; + state.playUnavailGreetingState = RequestState.succeeded; + state.playUnavailGreetingError = null; + }, + playUnavailGreetingFailed(state, err) { + state.playUnavailGreetingUrl = null; + state.playUnavailGreetingState = RequestState.failed; + state.playUnavailGreetingError = err; } }, actions: { @@ -480,6 +528,38 @@ export default { }).catch((err) => { context.commit('deleteGreetingFailed', err.message); }); + }, + playBusyGreeting(context, format) { + context.commit('playBusyGreetingRequesting'); + playGreeting({ + id: context.getters.busyGreetingId, + format: format + }).then((url) => { + context.commit('playBusyGreetingSucceeded', url); + }).catch((err) => { + context.commit('playBusyGreetingFailed', err.mesage); + }); + }, + playUnavailGreeting(context, format) { + context.commit('playUnavailGreetingRequesting'); + playGreeting({ + id: context.getters.unavailGreetingId, + format: format + }).then((url) => { + context.commit('playUnavailGreetingSucceeded', url); + }).catch((err) => { + context.commit('playUnavailGreetingFailed', err.mesage); + }); + }, + abortUploadBusyGreeting(context) { + abortPreviousRequest('busy').then(() => { + context.dispatch('loadBusyGreeting'); + }); + }, + abortUploadUnavailGreeting(context) { + abortPreviousRequest('unavail').then(() => { + context.dispatch('loadUnavailGreeting'); + }); } } }; diff --git a/t/store/voicebox.js b/t/store/voicebox.js index c4e23039..13f6cc1a 100644 --- a/t/store/voicebox.js +++ b/t/store/voicebox.js @@ -70,6 +70,24 @@ describe('Voicebox', function(){ assert.deepEqual(state.unavailGreetingId, greetings[0].id); }); + it('should load busy greeting url into store', function(){ + let state = { + playBusyGreetingUrl: null + }; + let url = "blob:https://1.2.3.4/6341147c-3ed2-4112-876b-331e834a4821"; + VoiceboxModule.mutations.playBusyGreetingSucceeded(state, url); + assert.deepEqual(state.playBusyGreetingUrl, url); + }); + + it('should load unavailable greeting id into store', function(){ + let state = { + playUnavailGreetingUrl: null + }; + let url = "blob:https://1.2.3.4/6341147c-3ed2-4112-876b-331e834a4821"; + VoiceboxModule.mutations.playUnavailGreetingSucceeded(state, url); + assert.deepEqual(state.playUnavailGreetingUrl, url); + }); + it('should get right label for busy greeting to indicate if it\'s custom or default', function(){ let state = { busyGreetingId: null