feat: Add audio alert for incoming messages on dashboard (#1738)
Fixes: #1345
This commit is contained in:
parent
ca4a766b82
commit
9e8a943ec7
6 changed files with 115 additions and 3 deletions
|
@ -1,5 +1,6 @@
|
||||||
import AuthAPI from '../api/auth';
|
import AuthAPI from '../api/auth';
|
||||||
import BaseActionCableConnector from '../../shared/helpers/BaseActionCableConnector';
|
import BaseActionCableConnector from '../../shared/helpers/BaseActionCableConnector';
|
||||||
|
import { newMessageNotification } from 'shared/helpers/AudioNotificationHelper';
|
||||||
|
|
||||||
class ActionCableConnector extends BaseActionCableConnector {
|
class ActionCableConnector extends BaseActionCableConnector {
|
||||||
constructor(app, pubsubToken) {
|
constructor(app, pubsubToken) {
|
||||||
|
@ -63,6 +64,7 @@ class ActionCableConnector extends BaseActionCableConnector {
|
||||||
onLogout = () => AuthAPI.logout();
|
onLogout = () => AuthAPI.logout();
|
||||||
|
|
||||||
onMessageCreated = data => {
|
onMessageCreated = data => {
|
||||||
|
newMessageNotification(data);
|
||||||
this.app.$store.dispatch('addMessage', data);
|
this.app.$store.dispatch('addMessage', data);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,11 @@
|
||||||
"TITLE": "Access Token",
|
"TITLE": "Access Token",
|
||||||
"NOTE": "This token can be used if you are building an API based integration"
|
"NOTE": "This token can be used if you are building an API based integration"
|
||||||
},
|
},
|
||||||
|
"AUDIO_NOTIFICATIONS_SECTION": {
|
||||||
|
"TITLE": "Audio Notifications",
|
||||||
|
"NOTE": "Enable audio notifications in dashboard for new messages and conversations.",
|
||||||
|
"ENABLE_AUDIO": "Play audio notification when a new conversation is created or new messages arrives"
|
||||||
|
},
|
||||||
"EMAIL_NOTIFICATIONS_SECTION": {
|
"EMAIL_NOTIFICATIONS_SECTION": {
|
||||||
"TITLE": "Email Notifications",
|
"TITLE": "Email Notifications",
|
||||||
"NOTE": "Update your email notification preferences here",
|
"NOTE": "Update your email notification preferences here",
|
||||||
|
|
|
@ -1,5 +1,33 @@
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
|
<div class="profile--settings--row row">
|
||||||
|
<div class="columns small-3 ">
|
||||||
|
<h4 class="block-title">
|
||||||
|
{{ $t('PROFILE_SETTINGS.FORM.AUDIO_NOTIFICATIONS_SECTION.TITLE') }}
|
||||||
|
</h4>
|
||||||
|
<p>
|
||||||
|
{{ $t('PROFILE_SETTINGS.FORM.AUDIO_NOTIFICATIONS_SECTION.NOTE') }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="columns small-9">
|
||||||
|
<div>
|
||||||
|
<input
|
||||||
|
id="audio_enable_alert"
|
||||||
|
v-model="enableAudioAlerts"
|
||||||
|
class="notification--checkbox"
|
||||||
|
type="checkbox"
|
||||||
|
@input="handleAudioInput"
|
||||||
|
/>
|
||||||
|
<label for="audio_enable_alert">
|
||||||
|
{{
|
||||||
|
$t(
|
||||||
|
'PROFILE_SETTINGS.FORM.AUDIO_NOTIFICATIONS_SECTION.ENABLE_AUDIO'
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="profile--settings--row row">
|
<div class="profile--settings--row row">
|
||||||
<div class="columns small-3 ">
|
<div class="columns small-3 ">
|
||||||
<h4 class="block-title">
|
<h4 class="block-title">
|
||||||
|
@ -185,6 +213,7 @@
|
||||||
import { mapGetters } from 'vuex';
|
import { mapGetters } from 'vuex';
|
||||||
import alertMixin from 'shared/mixins/alertMixin';
|
import alertMixin from 'shared/mixins/alertMixin';
|
||||||
import configMixin from 'shared/mixins/configMixin';
|
import configMixin from 'shared/mixins/configMixin';
|
||||||
|
import uiSettingsMixin from 'dashboard/mixins/uiSettings';
|
||||||
import {
|
import {
|
||||||
hasPushPermissions,
|
hasPushPermissions,
|
||||||
requestPushPermissions,
|
requestPushPermissions,
|
||||||
|
@ -192,11 +221,12 @@ import {
|
||||||
} from '../../../../helper/pushHelper';
|
} from '../../../../helper/pushHelper';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
mixins: [alertMixin, configMixin],
|
mixins: [alertMixin, configMixin, uiSettingsMixin],
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
selectedEmailFlags: [],
|
selectedEmailFlags: [],
|
||||||
selectedPushFlags: [],
|
selectedPushFlags: [],
|
||||||
|
enableAudioAlerts: false,
|
||||||
hasEnabledPushPermissions: false,
|
hasEnabledPushPermissions: false,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
@ -204,6 +234,7 @@ export default {
|
||||||
...mapGetters({
|
...mapGetters({
|
||||||
emailFlags: 'userNotificationSettings/getSelectedEmailFlags',
|
emailFlags: 'userNotificationSettings/getSelectedEmailFlags',
|
||||||
pushFlags: 'userNotificationSettings/getSelectedPushFlags',
|
pushFlags: 'userNotificationSettings/getSelectedPushFlags',
|
||||||
|
uiSettings: 'getUISettings',
|
||||||
}),
|
}),
|
||||||
isBrowserSafari() {
|
isBrowserSafari() {
|
||||||
if (window.browserConfig) {
|
if (window.browserConfig) {
|
||||||
|
@ -219,6 +250,10 @@ export default {
|
||||||
pushFlags(value) {
|
pushFlags(value) {
|
||||||
this.selectedPushFlags = value;
|
this.selectedPushFlags = value;
|
||||||
},
|
},
|
||||||
|
uiSettings(value) {
|
||||||
|
const { enable_audio_alerts: enableAudio = false } = value;
|
||||||
|
this.enableAudioAlerts = enableAudio;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
if (hasPushPermissions()) {
|
if (hasPushPermissions()) {
|
||||||
|
@ -226,6 +261,8 @@ export default {
|
||||||
}
|
}
|
||||||
|
|
||||||
this.$store.dispatch('userNotificationSettings/get');
|
this.$store.dispatch('userNotificationSettings/get');
|
||||||
|
const { enable_audio_alerts: enableAudio = false } = this.uiSettings;
|
||||||
|
this.enableAudioAlerts = enableAudio;
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
onRegistrationSuccess() {
|
onRegistrationSuccess() {
|
||||||
|
@ -277,6 +314,13 @@ export default {
|
||||||
|
|
||||||
this.updateNotificationSettings();
|
this.updateNotificationSettings();
|
||||||
},
|
},
|
||||||
|
handleAudioInput(e) {
|
||||||
|
this.enableAudioAlerts = e.target.checked;
|
||||||
|
this.updateUISettings({
|
||||||
|
enable_audio_alerts: this.enableAudioAlerts,
|
||||||
|
});
|
||||||
|
this.showAlert(this.$t('PROFILE_SETTINGS.FORM.API.UPDATE_SUCCESS'));
|
||||||
|
},
|
||||||
toggleInput(selected, current) {
|
toggleInput(selected, current) {
|
||||||
if (selected.includes(current)) {
|
if (selected.includes(current)) {
|
||||||
const newSelectedFlags = selected.filter(flag => flag !== current);
|
const newSelectedFlags = selected.filter(flag => flag !== current);
|
||||||
|
|
|
@ -20,6 +20,7 @@ import App from '../dashboard/App';
|
||||||
import i18n from '../dashboard/i18n';
|
import i18n from '../dashboard/i18n';
|
||||||
import createAxios from '../dashboard/helper/APIHelper';
|
import createAxios from '../dashboard/helper/APIHelper';
|
||||||
import commonHelpers from '../dashboard/helper/commons';
|
import commonHelpers from '../dashboard/helper/commons';
|
||||||
|
import { getAlertAudio } from '../shared/helpers/AudioNotificationHelper';
|
||||||
import router from '../dashboard/routes';
|
import router from '../dashboard/routes';
|
||||||
import store from '../dashboard/store';
|
import store from '../dashboard/store';
|
||||||
import vueActionCable from '../dashboard/helper/actionCable';
|
import vueActionCable from '../dashboard/helper/actionCable';
|
||||||
|
@ -70,7 +71,6 @@ window.onload = () => {
|
||||||
}).$mount('#app');
|
}).$mount('#app');
|
||||||
vueActionCable.init();
|
vueActionCable.init();
|
||||||
};
|
};
|
||||||
|
|
||||||
window.addEventListener('load', () => {
|
window.addEventListener('load', () => {
|
||||||
verifyServiceWorkerExistence(registration =>
|
verifyServiceWorkerExistence(registration =>
|
||||||
registration.pushManager.getSubscription().then(subscription => {
|
registration.pushManager.getSubscription().then(subscription => {
|
||||||
|
@ -79,4 +79,5 @@ window.addEventListener('load', () => {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
getAlertAudio();
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,9 +1,69 @@
|
||||||
|
import { MESSAGE_TYPE } from 'shared/constants/messages';
|
||||||
const notificationAudio = require('shared/assets/audio/ding.mp3');
|
const notificationAudio = require('shared/assets/audio/ding.mp3');
|
||||||
|
import axios from 'axios';
|
||||||
|
|
||||||
export const playNotificationAudio = () => {
|
export const playNotificationAudio = () => {
|
||||||
try {
|
try {
|
||||||
new Audio(notificationAudio).play();
|
new Audio(notificationAudio).play();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error);
|
// error
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getAlertAudio = async () => {
|
||||||
|
window.playAudioAlert = () => {};
|
||||||
|
const audioCtx = new (window.AudioContext || window.webkitAudioContext)();
|
||||||
|
const playsound = audioBuffer => {
|
||||||
|
window.playAudioAlert = () => {
|
||||||
|
const source = audioCtx.createBufferSource();
|
||||||
|
source.buffer = audioBuffer;
|
||||||
|
source.connect(audioCtx.destination);
|
||||||
|
source.loop = false;
|
||||||
|
source.start();
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await axios.get('/dashboard/audios/ding.mp3', {
|
||||||
|
responseType: 'arraybuffer',
|
||||||
|
});
|
||||||
|
|
||||||
|
audioCtx.decodeAudioData(response.data).then(playsound);
|
||||||
|
} catch (error) {
|
||||||
|
// error
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const shouldPlayAudio = data => {
|
||||||
|
const { conversation_id: currentConvId } = window.WOOT.$route.params;
|
||||||
|
const currentUserId = window.WOOT.$store.getters.getCurrentUserID;
|
||||||
|
const {
|
||||||
|
conversation_id: incomingConvId,
|
||||||
|
sender_id: senderId,
|
||||||
|
message_type: messageType,
|
||||||
|
} = data;
|
||||||
|
const isFromCurrentUser = currentUserId === senderId;
|
||||||
|
|
||||||
|
const playAudio =
|
||||||
|
currentConvId !== incomingConvId &&
|
||||||
|
!isFromCurrentUser &&
|
||||||
|
messageType === MESSAGE_TYPE.INCOMING;
|
||||||
|
return playAudio;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const newMessageNotification = data => {
|
||||||
|
const {
|
||||||
|
enable_audio_alerts: enableAudioAlerts = false,
|
||||||
|
} = window.WOOT.$store.getters.getUISettings;
|
||||||
|
if (!enableAudioAlerts) return false;
|
||||||
|
|
||||||
|
if (document.hidden) {
|
||||||
|
window.playAudioAlert();
|
||||||
|
} else {
|
||||||
|
const playAudio = shouldPlayAudio(data);
|
||||||
|
if (playAudio) {
|
||||||
|
window.playAudioAlert();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
BIN
public/dashboard/audios/ding.mp3
Normal file
BIN
public/dashboard/audios/ding.mp3
Normal file
Binary file not shown.
Loading…
Reference in a new issue