fix: Custom notification sounds on incoming messages (#36703)

Co-authored-by: Tasso Evangelista <2263066+tassoevan@users.noreply.github.com>
This commit is contained in:
Yash Rajpal 2025-08-20 04:01:31 +05:30 committed by GitHub
parent a94d5eb6ae
commit ef0b5b0d3b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 146 additions and 7 deletions

View File

@ -0,0 +1,5 @@
---
'@rocket.chat/meteor': patch
---
Fixes an issue where custom room notification sounds were not applied.

View File

@ -2,6 +2,8 @@ import type { AtLeast, ISubscription } from '@rocket.chat/core-typings';
import { useEffectEvent } from '@rocket.chat/fuselage-hooks';
import { useCustomSound } from '@rocket.chat/ui-contexts';
import { Subscriptions } from '../../stores';
export const useNewMessageNotification = () => {
const { notificationSounds } = useCustomSound();
@ -9,14 +11,12 @@ export const useNewMessageNotification = () => {
if (!sub || sub.audioNotificationValue === 'none') {
return;
}
// TODO: Fix this - Room Notifications Preferences > sound > desktop is not working.
// plays the user notificationSound preference
// if (sub.audioNotificationValue && sub.audioNotificationValue !== '0') {
// void CustomSounds.play(sub.audioNotificationValue, {
// volume: Number((notificationsSoundVolume / 100).toPrecision(2)),
// });
// }
const subscription = Subscriptions.state.find((record) => record.rid === sub.rid);
if (subscription?.audioNotificationValue) {
return notificationSounds.playNewMessageCustom(subscription.audioNotificationValue);
}
notificationSounds.playNewMessage();
});

View File

@ -76,6 +76,8 @@ const CustomSoundProvider = ({ children }: CustomSoundProviderProps) => {
const notificationSounds = {
playNewRoom: () => play(newRoomNotification, { loop: false, volume: formatVolume(notificationsSoundVolume) }),
playNewMessage: () => play(newMessageNotification, { loop: false, volume: formatVolume(notificationsSoundVolume) }),
playNewMessageCustom: (soundId: ICustomSound['_id']) =>
play(soundId, { loop: false, volume: formatVolume(notificationsSoundVolume) }),
playNewMessageLoop: () => play(newMessageNotification, { loop: true, volume: formatVolume(notificationsSoundVolume) }),
stopNewRoom: () => stop(newRoomNotification),
stopNewMessage: () => stop(newMessageNotification),

View File

@ -0,0 +1,130 @@
import type { Page } from 'playwright-core';
import { Users } from './fixtures/userStates';
import { HomeChannel } from './page-objects';
import { createTargetChannelAndReturnFullRoom, deleteRoom, setUserPreferences } from './utils';
import { test, expect } from './utils/test';
declare global {
// eslint-disable-next-line @typescript-eslint/naming-convention
interface Window {
__audioCalls: { src?: string; played?: boolean };
}
}
test.use({ storageState: Users.admin.state });
test.describe.serial('Notification Sounds', () => {
let targetChannel: string;
let targetChannelId: string;
let poHomeChannel: HomeChannel;
let user1Page: Page;
test.beforeAll(async ({ api }) => {
const { channel } = await createTargetChannelAndReturnFullRoom(api, {
members: [Users.admin.data.username, Users.user1.data.username],
});
targetChannel = channel.name as string;
targetChannelId = channel._id;
});
test.afterAll(async ({ api }) => {
await deleteRoom(api, targetChannel);
});
test.beforeEach(async ({ page, browser }) => {
poHomeChannel = new HomeChannel(page);
user1Page = await browser.newPage({ storageState: Users.user1.state });
await page.goto(`/channel/${targetChannel}`);
await page.evaluate(() => {
Audio.prototype.play = ((fn) =>
function (this: HTMLAudioElement, ...args: unknown[]) {
window.__audioCalls = { src: this.src, played: false };
const ret = fn.call(this, ...args);
window.__audioCalls.played = true;
return ret;
})(Audio.prototype.play);
});
});
test.afterEach(async () => {
await user1Page.close();
});
test('should play default notification sounds', async ({ page }) => {
await user1Page.goto(`/channel/${targetChannel}`);
const user1PoHomeChannel = new HomeChannel(user1Page);
await user1PoHomeChannel.content.waitForChannel();
await poHomeChannel.sidenav.sidebarHomeAction.click();
await user1PoHomeChannel.content.sendMessage(`Hello @${Users.admin.data.username} from User 1`);
await page.waitForTimeout(100); // wait for the sound to play
const audioCalls = await page.evaluate(() => window.__audioCalls);
expect(audioCalls).toHaveProperty('src');
expect(audioCalls.src).toContain('chime');
expect(audioCalls.played).toBe(true);
});
test.describe('Notification sound preferences', () => {
test.beforeAll(async ({ api }) => {
await setUserPreferences(api, {
newMessageNotification: 'ringtone',
});
});
test.afterAll(async ({ api }) => {
await setUserPreferences(api, {
newMessageNotification: 'chime',
});
});
test('should play notification sound based on user preferences', async ({ page }) => {
await user1Page.goto(`/channel/${targetChannel}`);
const user1PoHomeChannel = new HomeChannel(user1Page);
await user1PoHomeChannel.content.waitForChannel();
await poHomeChannel.sidenav.sidebarHomeAction.click();
await user1PoHomeChannel.content.sendMessage(`Hello @${Users.admin.data.username} from User 1`);
await page.waitForTimeout(100); // wait for the sound to play
const audioCalls = await page.evaluate(() => window.__audioCalls);
expect(audioCalls).toHaveProperty('src');
expect(audioCalls.src).toContain('ringtone');
expect(audioCalls.played).toBe(true);
});
});
test.describe('Custom room notification preferences', () => {
test.beforeEach(async ({ api }) => {
await api.post('/rooms.saveNotification', {
roomId: targetChannelId,
notifications: {
audioNotificationValue: 'door',
},
});
});
test('should play custom room notification sound', async ({ page }) => {
await user1Page.goto(`/channel/${targetChannel}`);
const user1PoHomeChannel = new HomeChannel(user1Page);
await user1PoHomeChannel.content.waitForChannel();
await poHomeChannel.sidenav.sidebarHomeAction.click();
await user1PoHomeChannel.content.sendMessage(`Hello @${Users.admin.data.username} from User 1`);
await page.waitForTimeout(100); // wait for the sound to play
const audioCalls = await page.evaluate(() => window.__audioCalls);
expect(audioCalls).toHaveProperty('src');
expect(audioCalls.src).toContain('door');
expect(audioCalls.played).toBe(true);
});
});
});

View File

@ -34,6 +34,7 @@ export type CustomSoundContextValue = {
playNewMessageLoop: () => void;
stopNewRoom: () => void;
stopNewMessage: () => void;
playNewMessageCustom: (soundId: ICustomSound['_id']) => void;
};
list: ICustomSound[];
};
@ -63,6 +64,7 @@ export const CustomSoundContext = createContext<CustomSoundContextValue>({
playNewMessageLoop: () => undefined,
stopNewRoom: () => undefined,
stopNewMessage: () => undefined,
playNewMessageCustom: () => undefined,
},
list: [],
});