feat: Add new audio alert options (#6141)

Co-authored-by: Pranav Raj S <pranav@chatwoot.com>
This commit is contained in:
Sivin Varghese
2022-12-29 23:51:23 +05:30
committed by Pranav Raj S
parent 10a03cae24
commit 02a687b226
5 changed files with 191 additions and 52 deletions

View File

@@ -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",

View File

@@ -10,50 +10,115 @@
</p>
</div>
<div class="columns small-9">
<div>
<input
id="audio_enable_alert_none"
v-model="enableAudioAlerts"
class="notification--checkbox"
type="radio"
value="none"
@input="handleAudioInput"
/>
<label for="audio_enable_alert_none">
{{ $t('PROFILE_SETTINGS.FORM.AUDIO_NOTIFICATIONS_SECTION.NONE') }}
</label>
</div>
<div>
<input
id="audio_enable_alert_mine"
v-model="enableAudioAlerts"
class="notification--checkbox"
type="radio"
value="mine"
@input="handleAudioInput"
/>
<label for="audio_enable_alert_mine">
{{
$t('PROFILE_SETTINGS.FORM.AUDIO_NOTIFICATIONS_SECTION.ASSIGNED')
}}
</label>
</div>
<div>
<input
id="audio_enable_alert_all"
v-model="enableAudioAlerts"
class="notification--checkbox"
type="radio"
value="all"
@input="handleAudioInput"
/>
<label for="audio_enable_alert_all">
<div class="notification-items--wrapper">
<span class="text-block-title notification-label">
{{
$t(
'PROFILE_SETTINGS.FORM.AUDIO_NOTIFICATIONS_SECTION.ALL_CONVERSATIONS'
'PROFILE_SETTINGS.FORM.AUDIO_NOTIFICATIONS_SECTION.ALERT_TYPE.TITLE'
)
}}
</label>
</span>
<div>
<input
id="audio_enable_alert_none"
v-model="enableAudioAlerts"
class="notification--checkbox"
type="radio"
value="none"
@input="handleAudioInput"
/>
<label for="audio_enable_alert_none">
{{
$t(
'PROFILE_SETTINGS.FORM.AUDIO_NOTIFICATIONS_SECTION.ALERT_TYPE.NONE'
)
}}
</label>
</div>
<div>
<input
id="audio_enable_alert_mine"
v-model="enableAudioAlerts"
class="notification--checkbox"
type="radio"
value="mine"
@input="handleAudioInput"
/>
<label for="audio_enable_alert_mine">
{{
$t(
'PROFILE_SETTINGS.FORM.AUDIO_NOTIFICATIONS_SECTION.ALERT_TYPE.ASSIGNED'
)
}}
</label>
</div>
<div>
<input
id="audio_enable_alert_all"
v-model="enableAudioAlerts"
class="notification--checkbox"
type="radio"
value="all"
@input="handleAudioInput"
/>
<label for="audio_enable_alert_all">
{{
$t(
'PROFILE_SETTINGS.FORM.AUDIO_NOTIFICATIONS_SECTION.ALERT_TYPE.ALL_CONVERSATIONS'
)
}}
</label>
</div>
</div>
<div class="notification-items--wrapper">
<span class="text-block-title notification-label">
{{
$t(
'PROFILE_SETTINGS.FORM.AUDIO_NOTIFICATIONS_SECTION.DEFAULT_TONE.TITLE'
)
}}
</span>
<div>
<select
v-model="notificationTone"
class="tone-selector"
@change="handleAudioToneChange"
>
<option
v-for="tone in notificationAlertTones"
:key="tone.value"
:value="tone.value"
>
{{ tone.label }}
</option>
</select>
</div>
</div>
<div class="notification-items--wrapper">
<span class="text-block-title notification-label">
{{
$t(
'PROFILE_SETTINGS.FORM.AUDIO_NOTIFICATIONS_SECTION.CONDITIONS.TITLE'
)
}}
</span>
<div>
<input
id="audio_alert_when_tab_is_inactive"
v-model="playAudioWhenTabIsInactive"
class="notification--checkbox"
type="checkbox"
value="tab_is_inactive"
@input="handleAudioAlertConditions"
/>
<label for="audio_alert_when_tab_is_inactive">
{{
$t(
'PROFILE_SETTINGS.FORM.AUDIO_NOTIFICATIONS_SECTION.CONDITIONS.CONDITION_ONE'
)
}}
</label>
</div>
</div>
</div>
</div>
@@ -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);
}
</style>

Binary file not shown.

View File

@@ -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,

Binary file not shown.