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,10 +58,20 @@
"AUDIO_NOTIFICATIONS_SECTION": { "AUDIO_NOTIFICATIONS_SECTION": {
"TITLE": "Audio Notifications", "TITLE": "Audio Notifications",
"NOTE": "Enable audio notifications in dashboard for new messages and conversations.", "NOTE": "Enable audio notifications in dashboard for new messages and conversations.",
"ALERT_TYPE": {
"TITLE": "Alert types:",
"NONE": "None", "NONE": "None",
"ASSIGNED": "Assigned Conversations", "ASSIGNED": "Assigned Conversations",
"ALL_CONVERSATIONS": "All 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": { "EMAIL_NOTIFICATIONS_SECTION": {
"TITLE": "Email Notifications", "TITLE": "Email Notifications",
"NOTE": "Update your email notification preferences here", "NOTE": "Update your email notification preferences here",

View File

@@ -10,6 +10,14 @@
</p> </p>
</div> </div>
<div class="columns small-9"> <div class="columns small-9">
<div class="notification-items--wrapper">
<span class="text-block-title notification-label">
{{
$t(
'PROFILE_SETTINGS.FORM.AUDIO_NOTIFICATIONS_SECTION.ALERT_TYPE.TITLE'
)
}}
</span>
<div> <div>
<input <input
id="audio_enable_alert_none" id="audio_enable_alert_none"
@@ -20,7 +28,11 @@
@input="handleAudioInput" @input="handleAudioInput"
/> />
<label for="audio_enable_alert_none"> <label for="audio_enable_alert_none">
{{ $t('PROFILE_SETTINGS.FORM.AUDIO_NOTIFICATIONS_SECTION.NONE') }} {{
$t(
'PROFILE_SETTINGS.FORM.AUDIO_NOTIFICATIONS_SECTION.ALERT_TYPE.NONE'
)
}}
</label> </label>
</div> </div>
<div> <div>
@@ -34,7 +46,9 @@
/> />
<label for="audio_enable_alert_mine"> <label for="audio_enable_alert_mine">
{{ {{
$t('PROFILE_SETTINGS.FORM.AUDIO_NOTIFICATIONS_SECTION.ASSIGNED') $t(
'PROFILE_SETTINGS.FORM.AUDIO_NOTIFICATIONS_SECTION.ALERT_TYPE.ASSIGNED'
)
}} }}
</label> </label>
</div> </div>
@@ -50,12 +64,63 @@
<label for="audio_enable_alert_all"> <label for="audio_enable_alert_all">
{{ {{
$t( $t(
'PROFILE_SETTINGS.FORM.AUDIO_NOTIFICATIONS_SECTION.ALL_CONVERSATIONS' 'PROFILE_SETTINGS.FORM.AUDIO_NOTIFICATIONS_SECTION.ALERT_TYPE.ALL_CONVERSATIONS'
) )
}} }}
</label> </label>
</div> </div>
</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> </div>
<div class="profile--settings--row row"> <div class="profile--settings--row row">
<div class="columns small-3 "> <div class="columns small-3 ">
@@ -257,6 +322,18 @@ export default {
selectedPushFlags: [], selectedPushFlags: [],
enableAudioAlerts: false, enableAudioAlerts: false,
hasEnabledPushPermissions: false, hasEnabledPushPermissions: false,
playAudioWhenTabIsInactive: false,
notificationTone: 'ding',
notificationAlertTones: [
{
value: 'ding',
label: 'Ding',
},
{
value: 'bell',
label: 'Bell',
},
],
}; };
}, },
computed: { computed: {
@@ -280,20 +357,27 @@ export default {
this.selectedPushFlags = value; this.selectedPushFlags = value;
}, },
uiSettings(value) { uiSettings(value) {
const { enable_audio_alerts: enableAudio = false } = value; this.notificationUISettings(value);
this.enableAudioAlerts = enableAudio;
}, },
}, },
mounted() { mounted() {
if (hasPushPermissions()) { if (hasPushPermissions()) {
this.getPushSubscription(); this.getPushSubscription();
} }
this.notificationUISettings(this.uiSettings);
this.$store.dispatch('userNotificationSettings/get'); this.$store.dispatch('userNotificationSettings/get');
const { enable_audio_alerts: enableAudio = false } = this.uiSettings;
this.enableAudioAlerts = enableAudio;
}, },
methods: { 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() { onRegistrationSuccess() {
this.hasEnabledPushPermissions = true; this.hasEnabledPushPermissions = true;
}, },
@@ -351,6 +435,19 @@ export default {
}); });
this.showAlert(this.$t('PROFILE_SETTINGS.FORM.API.UPDATE_SUCCESS')); 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) { 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);
@@ -372,4 +469,21 @@ export default {
.push-notification--button { .push-notification--button {
margin-bottom: var(--space-one); 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> </style>

Binary file not shown.

View File

@@ -15,10 +15,20 @@ export const getAudioContext = () => {
return audioCtx; 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') => { export const getAlertAudio = async (baseUrl = '', type = 'dashboard') => {
const audioCtx = getAudioContext(); const audioCtx = getAudioContext();
const playsound = audioBuffer => { const playSound = audioBuffer => {
window.playAudioAlert = () => { window.playAudioAlert = () => {
if (audioCtx) { if (audioCtx) {
const source = audioCtx.createBufferSource(); const source = audioCtx.createBufferSource();
@@ -31,13 +41,14 @@ export const getAlertAudio = async (baseUrl = '', type = 'dashboard') => {
}; };
if (audioCtx) { 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); const audioRequest = new Request(resourceUrl);
fetch(audioRequest) fetch(audioRequest)
.then(response => response.arrayBuffer()) .then(response => response.arrayBuffer())
.then(buffer => { .then(buffer => {
audioCtx.decodeAudioData(buffer).then(playsound); audioCtx.decodeAudioData(buffer).then(playSound);
return new Promise(res => res()); return new Promise(res => res());
}) })
.catch(() => { .catch(() => {
@@ -91,6 +102,7 @@ export const getAssigneeFromNotification = currentConv => {
} }
return id; return id;
}; };
export const newMessageNotification = data => { export const newMessageNotification = data => {
const { conversation_id: currentConvId } = window.WOOT.$route.params; const { conversation_id: currentConvId } = window.WOOT.$route.params;
const currentUserId = window.WOOT.$store.getters.getCurrentUserID; const currentUserId = window.WOOT.$store.getters.getCurrentUserID;
@@ -98,10 +110,13 @@ export const newMessageNotification = data => {
const currentConv = const currentConv =
window.WOOT.$store.getters.getConversationById(incomingConvId) || {}; window.WOOT.$store.getters.getConversationById(incomingConvId) || {};
const assigneeId = getAssigneeFromNotification(currentConv); const assigneeId = getAssigneeFromNotification(currentConv);
const isDocHidden = document.hidden;
const { const {
enable_audio_alerts: enableAudioAlerts = false, enable_audio_alerts: enableAudioAlerts = false,
always_play_audio_alert: alwaysPlayAudioAlert,
} = window.WOOT.$store.getters.getUISettings; } = window.WOOT.$store.getters.getUISettings;
const isDocHidden = alwaysPlayAudioAlert ? true : document.hidden;
const playAudio = shouldPlayAudio( const playAudio = shouldPlayAudio(
data, data,
currentConvId, currentConvId,

Binary file not shown.