mirror of
https://github.com/lingble/chatwoot.git
synced 2025-11-01 03:27:52 +00:00
feat: Add new audio alert options (#6141)
Co-authored-by: Pranav Raj S <pranav@chatwoot.com>
This commit is contained in:
committed by
Pranav Raj S
parent
10a03cae24
commit
02a687b226
@@ -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",
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
BIN
app/javascript/shared/assets/audio/bell.mp3
Normal file
BIN
app/javascript/shared/assets/audio/bell.mp3
Normal file
Binary file not shown.
@@ -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,
|
||||||
|
|||||||
BIN
public/audio/dashboard/bell.mp3
Normal file
BIN
public/audio/dashboard/bell.mp3
Normal file
Binary file not shown.
Reference in New Issue
Block a user