Files
chatwoot/app/javascript/dashboard/helper/AudioAlerts/DashboardAudioNotificationHelper.js
2025-02-11 17:45:31 +05:30

218 lines
6.1 KiB
JavaScript

import { MESSAGE_TYPE } from 'shared/constants/messages';
import { showBadgeOnFavicon } from './faviconHelper';
import { initFaviconSwitcher } from './faviconHelper';
import { EVENT_TYPES } from 'dashboard/routes/dashboard/settings/profile/constants.js';
import GlobalStore from 'dashboard/store';
import AudioNotificationStore from './AudioNotificationStore';
import {
isConversationAssignedToMe,
isConversationUnassigned,
isMessageFromCurrentUser,
} from './AudioMessageHelper';
import WindowVisibilityHelper from './WindowVisibilityHelper';
import { useAlert } from 'dashboard/composables';
const NOTIFICATION_TIME = 30000;
const ALERT_DURATION = 10000;
const ALERT_PATH_PREFIX = '/audio/dashboard/';
const DEFAULT_TONE = 'ding';
const DEFAULT_ALERT_TYPE = ['none'];
export class DashboardAudioNotificationHelper {
constructor(store) {
if (!store) {
throw new Error('store is required');
}
this.store = new AudioNotificationStore(store);
this.notificationConfig = {
audioAlertType: DEFAULT_ALERT_TYPE,
playAlertOnlyWhenHidden: true,
alertIfUnreadConversationExist: false,
};
this.recurringNotificationTimer = null;
this.audioConfig = {
audio: null,
tone: DEFAULT_TONE,
hasSentSoundPermissionsRequest: false,
};
this.currentUser = null;
}
intializeAudio = () => {
const resourceUrl = `${ALERT_PATH_PREFIX}${this.audioConfig.tone}.mp3`;
this.audioConfig.audio = new Audio(resourceUrl);
return this.audioConfig.audio.load();
};
playAudioAlert = async () => {
try {
await this.audioConfig.audio.play();
} catch (error) {
if (
error.name === 'NotAllowedError' &&
!this.hasSentSoundPermissionsRequest
) {
this.hasSentSoundPermissionsRequest = true;
useAlert(
'PROFILE_SETTINGS.FORM.AUDIO_NOTIFICATIONS_SECTION.SOUND_PERMISSION_ERROR',
{ usei18n: true, duration: ALERT_DURATION }
);
}
}
};
set = ({
currentUser,
alwaysPlayAudioAlert,
alertIfUnreadConversationExist,
audioAlertType = DEFAULT_ALERT_TYPE,
audioAlertTone = DEFAULT_TONE,
}) => {
this.notificationConfig = {
...this.notificationConfig,
audioAlertType: audioAlertType.split('+').filter(Boolean),
playAlertOnlyWhenHidden: !alwaysPlayAudioAlert,
alertIfUnreadConversationExist: alertIfUnreadConversationExist,
};
this.currentUser = currentUser;
const previousAudioTone = this.audioConfig.tone;
this.audioConfig = {
...this.audioConfig,
tone: audioAlertTone,
};
if (previousAudioTone !== audioAlertTone) {
this.intializeAudio();
}
initFaviconSwitcher();
this.clearRecurringTimer();
this.playAudioEvery30Seconds();
};
shouldPlayAlert = () => {
if (this.notificationConfig.playAlertOnlyWhenHidden) {
return !WindowVisibilityHelper.isWindowVisible();
}
return true;
};
executeRecurringNotification = () => {
if (this.store.hasUnreadConversation() && this.shouldPlayAlert()) {
this.playAudioAlert();
showBadgeOnFavicon();
}
this.resetRecurringTimer();
};
clearRecurringTimer = () => {
if (this.recurringNotificationTimer) {
clearTimeout(this.recurringNotificationTimer);
}
};
resetRecurringTimer = () => {
this.clearRecurringTimer();
this.recurringNotificationTimer = setTimeout(
this.executeRecurringNotification,
NOTIFICATION_TIME
);
};
playAudioEvery30Seconds = () => {
const { audioAlertType, alertIfUnreadConversationExist } =
this.notificationConfig;
// Audio alert is disabled dismiss the timer
if (audioAlertType.includes('none')) return;
// If unread conversation flag is disabled, dismiss the timer
if (!alertIfUnreadConversationExist) return;
this.resetRecurringTimer();
};
shouldNotifyOnMessage = message => {
const { audioAlertType } = this.notificationConfig;
if (audioAlertType.includes('none')) return false;
if (audioAlertType.includes('all')) return true;
const assignedToMe = isConversationAssignedToMe(
message,
this.currentUser.id
);
const isUnassigned = isConversationUnassigned(message);
const shouldPlayAudio = [];
if (
audioAlertType.includes(EVENT_TYPES.ASSIGNED) ||
audioAlertType.includes('mine')
) {
shouldPlayAudio.push(assignedToMe);
}
if (audioAlertType.includes(EVENT_TYPES.UNASSIGNED)) {
shouldPlayAudio.push(isUnassigned);
}
if (audioAlertType.includes(EVENT_TYPES.NOTME)) {
shouldPlayAudio.push(!isUnassigned && !assignedToMe);
}
return shouldPlayAudio.some(Boolean);
};
onNewMessage = message => {
// If the user does not have the permission to view the conversation, then dismiss the alert
// FIX ME: There shouldn't be a new message if the user has no access to the conversation.
if (!this.store.hasConversationPermission(this.currentUser)) {
return;
}
// If the conversation status is pending, then dismiss the alert
// This case is common for all audio event types
if (this.store.isMessageFromPendingConversation(message)) {
return;
}
// If the message is sent by the current user then dismiss the alert
if (isMessageFromCurrentUser(message, this.currentUser.id)) {
return;
}
if (!this.shouldNotifyOnMessage(message)) {
return;
}
// If the message type is not incoming or private, then dismiss the alert
const { message_type: messageType, private: isPrivate } = message;
if (messageType !== MESSAGE_TYPE.INCOMING && !isPrivate) {
return;
}
if (WindowVisibilityHelper.isWindowVisible()) {
// If the user looking at the conversation, then dismiss the alert
if (this.store.isMessageFromCurrentConversation(message)) {
return;
}
// If the user has disabled alerts when active on the dashboard, the dismiss the alert
if (this.notificationConfig.playAlertOnlyWhenHidden) {
return;
}
}
this.playAudioAlert();
showBadgeOnFavicon();
this.playAudioEvery30Seconds();
};
}
export default new DashboardAudioNotificationHelper(GlobalStore);