Skip to content

Commit

Permalink
feat: Add audio alert for incoming messages on dashboard (chatwoot#1738)
Browse files Browse the repository at this point in the history
  • Loading branch information
nithindavid authored Mar 4, 2021
1 parent ca4a766 commit 9e8a943
Show file tree
Hide file tree
Showing 6 changed files with 115 additions and 3 deletions.
2 changes: 2 additions & 0 deletions app/javascript/dashboard/helper/actionCable.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import AuthAPI from '../api/auth';
import BaseActionCableConnector from '../../shared/helpers/BaseActionCableConnector';
import { newMessageNotification } from 'shared/helpers/AudioNotificationHelper';

class ActionCableConnector extends BaseActionCableConnector {
constructor(app, pubsubToken) {
Expand Down Expand Up @@ -63,6 +64,7 @@ class ActionCableConnector extends BaseActionCableConnector {
onLogout = () => AuthAPI.logout();

onMessageCreated = data => {
newMessageNotification(data);
this.app.$store.dispatch('addMessage', data);
};

Expand Down
5 changes: 5 additions & 0 deletions app/javascript/dashboard/i18n/locale/en/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@
"TITLE": "Access Token",
"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": {
"TITLE": "Email Notifications",
"NOTE": "Update your email notification preferences here",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,33 @@
<template>
<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="columns small-3 ">
<h4 class="block-title">
Expand Down Expand Up @@ -185,25 +213,28 @@
import { mapGetters } from 'vuex';
import alertMixin from 'shared/mixins/alertMixin';
import configMixin from 'shared/mixins/configMixin';
import uiSettingsMixin from 'dashboard/mixins/uiSettings';
import {
hasPushPermissions,
requestPushPermissions,
verifyServiceWorkerExistence,
} from '../../../../helper/pushHelper';
export default {
mixins: [alertMixin, configMixin],
mixins: [alertMixin, configMixin, uiSettingsMixin],
data() {
return {
selectedEmailFlags: [],
selectedPushFlags: [],
enableAudioAlerts: false,
hasEnabledPushPermissions: false,
};
},
computed: {
...mapGetters({
emailFlags: 'userNotificationSettings/getSelectedEmailFlags',
pushFlags: 'userNotificationSettings/getSelectedPushFlags',
uiSettings: 'getUISettings',
}),
isBrowserSafari() {
if (window.browserConfig) {
Expand All @@ -219,13 +250,19 @@ export default {
pushFlags(value) {
this.selectedPushFlags = value;
},
uiSettings(value) {
const { enable_audio_alerts: enableAudio = false } = value;
this.enableAudioAlerts = enableAudio;
},
},
mounted() {
if (hasPushPermissions()) {
this.getPushSubscription();
}
this.$store.dispatch('userNotificationSettings/get');
const { enable_audio_alerts: enableAudio = false } = this.uiSettings;
this.enableAudioAlerts = enableAudio;
},
methods: {
onRegistrationSuccess() {
Expand Down Expand Up @@ -277,6 +314,13 @@ export default {
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) {
if (selected.includes(current)) {
const newSelectedFlags = selected.filter(flag => flag !== current);
Expand Down
3 changes: 2 additions & 1 deletion app/javascript/packs/application.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import App from '../dashboard/App';
import i18n from '../dashboard/i18n';
import createAxios from '../dashboard/helper/APIHelper';
import commonHelpers from '../dashboard/helper/commons';
import { getAlertAudio } from '../shared/helpers/AudioNotificationHelper';
import router from '../dashboard/routes';
import store from '../dashboard/store';
import vueActionCable from '../dashboard/helper/actionCable';
Expand Down Expand Up @@ -70,7 +71,6 @@ window.onload = () => {
}).$mount('#app');
vueActionCable.init();
};

window.addEventListener('load', () => {
verifyServiceWorkerExistence(registration =>
registration.pushManager.getSubscription().then(subscription => {
Expand All @@ -79,4 +79,5 @@ window.addEventListener('load', () => {
}
})
);
getAlertAudio();
});
62 changes: 61 additions & 1 deletion app/javascript/shared/helpers/AudioNotificationHelper.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,69 @@
import { MESSAGE_TYPE } from 'shared/constants/messages';
const notificationAudio = require('shared/assets/audio/ding.mp3');
import axios from 'axios';

export const playNotificationAudio = () => {
try {
new Audio(notificationAudio).play();
} 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;
};
Binary file added public/dashboard/audios/ding.mp3
Binary file not shown.

0 comments on commit 9e8a943

Please sign in to comment.