diff --git a/app/javascript/dashboard/i18n/locale/en/settings.json b/app/javascript/dashboard/i18n/locale/en/settings.json index e8eac0e8e..f87e59930 100644 --- a/app/javascript/dashboard/i18n/locale/en/settings.json +++ b/app/javascript/dashboard/i18n/locale/en/settings.json @@ -58,9 +58,19 @@ "AUDIO_NOTIFICATIONS_SECTION": { "TITLE": "Audio Notifications", "NOTE": "Enable audio notifications in dashboard for new messages and conversations.", - "NONE": "None", - "ASSIGNED": "Assigned Conversations", - "ALL_CONVERSATIONS": "All Conversations" + "ALERT_TYPE": { + "TITLE": "Alert types:", + "NONE": "None", + "ASSIGNED": "Assigned Conversations", + "ALL_CONVERSATIONS": "All Conversations" + }, + "DEFAULT_TONE": { + "TITLE": "Default tone:" + }, + "CONDITIONS": { + "TITLE": "Conditions:", + "CONDITION_ONE": "Send audio alerts only if the browser window is not active" + } }, "EMAIL_NOTIFICATIONS_SECTION": { "TITLE": "Email Notifications", diff --git a/app/javascript/dashboard/routes/dashboard/settings/profile/NotificationSettings.vue b/app/javascript/dashboard/routes/dashboard/settings/profile/NotificationSettings.vue index 60584d726..af8f14f8f 100644 --- a/app/javascript/dashboard/routes/dashboard/settings/profile/NotificationSettings.vue +++ b/app/javascript/dashboard/routes/dashboard/settings/profile/NotificationSettings.vue @@ -10,50 +10,115 @@

-
- - -
-
- - -
-
- -
@@ -257,6 +322,18 @@ export default { selectedPushFlags: [], enableAudioAlerts: false, hasEnabledPushPermissions: false, + playAudioWhenTabIsInactive: false, + notificationTone: 'ding', + notificationAlertTones: [ + { + value: 'ding', + label: 'Ding', + }, + { + value: 'bell', + label: 'Bell', + }, + ], }; }, computed: { @@ -280,20 +357,27 @@ export default { this.selectedPushFlags = value; }, uiSettings(value) { - const { enable_audio_alerts: enableAudio = false } = value; - this.enableAudioAlerts = enableAudio; + this.notificationUISettings(value); }, }, mounted() { if (hasPushPermissions()) { this.getPushSubscription(); } - + this.notificationUISettings(this.uiSettings); this.$store.dispatch('userNotificationSettings/get'); - const { enable_audio_alerts: enableAudio = false } = this.uiSettings; - this.enableAudioAlerts = enableAudio; }, methods: { + notificationUISettings(uiSettings) { + const { + enable_audio_alerts: enableAudio = false, + always_play_audio_alert: alwaysPlayAudioAlert, + notification_tone: notificationTone, + } = uiSettings; + this.enableAudioAlerts = enableAudio; + this.playAudioWhenTabIsInactive = !alwaysPlayAudioAlert; + this.notificationTone = notificationTone || 'ding'; + }, onRegistrationSuccess() { this.hasEnabledPushPermissions = true; }, @@ -351,6 +435,19 @@ export default { }); this.showAlert(this.$t('PROFILE_SETTINGS.FORM.API.UPDATE_SUCCESS')); }, + handleAudioAlertConditions(e) { + let condition = e.target.value; + if (condition === 'tab_is_inactive') { + this.updateUISettings({ + always_play_audio_alert: !e.target.checked, + }); + } + this.showAlert(this.$t('PROFILE_SETTINGS.FORM.API.UPDATE_SUCCESS')); + }, + handleAudioToneChange(e) { + this.updateUISettings({ notification_tone: e.target.value }); + this.showAlert(this.$t('PROFILE_SETTINGS.FORM.API.UPDATE_SUCCESS')); + }, toggleInput(selected, current) { if (selected.includes(current)) { const newSelectedFlags = selected.filter(flag => flag !== current); @@ -372,4 +469,21 @@ export default { .push-notification--button { margin-bottom: var(--space-one); } + +.notification-items--wrapper { + margin-bottom: var(--space-smaller); +} + +.notification-label { + display: flex; + font-weight: var(--font-weight-bold); + margin-bottom: var(--space-small); +} + +.tone-selector { + height: var(--space-large); + padding-bottom: var(--space-micro); + padding-top: var(--space-micro); + width: var(--space-mega); +} diff --git a/app/javascript/shared/assets/audio/bell.mp3 b/app/javascript/shared/assets/audio/bell.mp3 new file mode 100644 index 000000000..77087072f Binary files /dev/null and b/app/javascript/shared/assets/audio/bell.mp3 differ diff --git a/app/javascript/shared/helpers/AudioNotificationHelper.js b/app/javascript/shared/helpers/AudioNotificationHelper.js index a80a12e14..7474eb583 100644 --- a/app/javascript/shared/helpers/AudioNotificationHelper.js +++ b/app/javascript/shared/helpers/AudioNotificationHelper.js @@ -15,10 +15,20 @@ export const getAudioContext = () => { return audioCtx; }; +const getAlertTone = alertType => { + if (alertType === 'dashboard') { + const { + notification_tone: tone, + } = window.WOOT.$store.getters.getUISettings; + return tone; + } + return 'ding'; +}; + export const getAlertAudio = async (baseUrl = '', type = 'dashboard') => { const audioCtx = getAudioContext(); - const playsound = audioBuffer => { + const playSound = audioBuffer => { window.playAudioAlert = () => { if (audioCtx) { const source = audioCtx.createBufferSource(); @@ -31,13 +41,14 @@ export const getAlertAudio = async (baseUrl = '', type = 'dashboard') => { }; if (audioCtx) { - const resourceUrl = `${baseUrl}/audio/${type}/ding.mp3`; + const alertTone = getAlertTone(type); + const resourceUrl = `${baseUrl}/audio/${type}/${alertTone}.mp3`; const audioRequest = new Request(resourceUrl); fetch(audioRequest) .then(response => response.arrayBuffer()) .then(buffer => { - audioCtx.decodeAudioData(buffer).then(playsound); + audioCtx.decodeAudioData(buffer).then(playSound); return new Promise(res => res()); }) .catch(() => { @@ -91,6 +102,7 @@ export const getAssigneeFromNotification = currentConv => { } return id; }; + export const newMessageNotification = data => { const { conversation_id: currentConvId } = window.WOOT.$route.params; const currentUserId = window.WOOT.$store.getters.getCurrentUserID; @@ -98,10 +110,13 @@ export const newMessageNotification = data => { const currentConv = window.WOOT.$store.getters.getConversationById(incomingConvId) || {}; const assigneeId = getAssigneeFromNotification(currentConv); - const isDocHidden = document.hidden; + const { enable_audio_alerts: enableAudioAlerts = false, + always_play_audio_alert: alwaysPlayAudioAlert, } = window.WOOT.$store.getters.getUISettings; + const isDocHidden = alwaysPlayAudioAlert ? true : document.hidden; + const playAudio = shouldPlayAudio( data, currentConvId, diff --git a/public/audio/dashboard/bell.mp3 b/public/audio/dashboard/bell.mp3 new file mode 100644 index 000000000..77087072f Binary files /dev/null and b/public/audio/dashboard/bell.mp3 differ