diff --git a/public/sounds/README.md b/public/sounds/README.md new file mode 100644 index 0000000..4b361d1 --- /dev/null +++ b/public/sounds/README.md @@ -0,0 +1,13 @@ +# Notification Sound + +Pop-up Sound by BeezleFM -- https://freesound.org/s/512135/ -- License: Attribution 4.0 + +Place your notification sound file here as: + + `notification.mp3` + +The file is served at `/sounds/notification.mp3` and played automatically +whenever a new in-app notification arrives. + +Supported formats: MP3, OGG, WAV — MP3 recommended for broadest browser support. +Keep the file short (< 2 s) and not too loud. diff --git a/public/sounds/notification.mp3 b/public/sounds/notification.mp3 new file mode 100644 index 0000000..eaff032 Binary files /dev/null and b/public/sounds/notification.mp3 differ diff --git a/src/contexts/NotificationContext.jsx b/src/contexts/NotificationContext.jsx index 643ed98..fd8b300 100644 --- a/src/contexts/NotificationContext.jsx +++ b/src/contexts/NotificationContext.jsx @@ -3,6 +3,24 @@ import toast from 'react-hot-toast'; import { useAuth } from './AuthContext'; import api from '../services/api'; +// Lazily created Audio instance — reused across calls to avoid memory churn +let _audio = null; +function playNotificationSound() { + try { + if (!_audio) { + _audio = new Audio('/sounds/notification.mp3'); + _audio.volume = 0.5; + } + // Reset to start so rapid arrivals always play from beginning + _audio.currentTime = 0; + _audio.play().catch(() => { + // Autoplay blocked (user hasn't interacted yet) or file missing — silent fail + }); + } catch { + // Ignore any other errors (e.g. unsupported format) + } +} + const NotificationContext = createContext(); export function NotificationProvider({ children }) { @@ -30,6 +48,9 @@ export function NotificationProvider({ children }) { // Subsequent fetches: toast new unread notifications const newItems = incoming.filter(n => !n.read && !seenIds.current.has(n.id)); + if (newItems.length > 0) { + playNotificationSound(); + } newItems.forEach(n => { seenIds.current.add(n.id); const icon = notificationIcon(n.type);