Add synthesized bubble pop sound to notifications

This commit is contained in:
Avery Felts 2026-01-27 14:18:00 -07:00
parent 20872c9cc8
commit 197364e11d

View File

@ -58,6 +58,36 @@ export function useNotifications(reminderSettings: ReminderSettings) {
[isSupported, permission] [isSupported, permission]
); );
// Play a "bubble pop" sound using Web Audio API
const playNotificationSound = useCallback(() => {
try {
const AudioContext = window.AudioContext || (window as any).webkitAudioContext;
if (!AudioContext) return;
const ctx = new AudioContext();
const oscillator = ctx.createOscillator();
const gainNode = ctx.createGain();
oscillator.connect(gainNode);
gainNode.connect(ctx.destination);
// Bubble 'pop' effect: sine wave with rapid frequency drop
oscillator.type = 'sine';
oscillator.frequency.setValueAtTime(800, ctx.currentTime);
oscillator.frequency.exponentialRampToValueAtTime(100, ctx.currentTime + 0.1);
// Envelope: quick attack, quick decay
gainNode.gain.setValueAtTime(0, ctx.currentTime);
gainNode.gain.linearRampToValueAtTime(0.3, ctx.currentTime + 0.01);
gainNode.gain.exponentialRampToValueAtTime(0.01, ctx.currentTime + 0.1);
oscillator.start();
oscillator.stop(ctx.currentTime + 0.15);
} catch (e) {
console.error('Error playing notification sound:', e);
}
}, []);
// Check and send daily reminder // Check and send daily reminder
const checkAndSendReminder = useCallback(() => { const checkAndSendReminder = useCallback(() => {
if (!reminderSettings.enabled || permission !== 'granted') return; if (!reminderSettings.enabled || permission !== 'granted') return;
@ -74,6 +104,7 @@ export function useNotifications(reminderSettings: ReminderSettings) {
// If current time is past the reminder time, send it // If current time is past the reminder time, send it
if (now >= reminderTime) { if (now >= reminderTime) {
playNotificationSound();
sendNotification('QuitTraq Reminder', { sendNotification('QuitTraq Reminder', {
body: "Time to log your daily usage! Every day counts on your journey.", body: "Time to log your daily usage! Every day counts on your journey.",
tag: 'daily-reminder', // Tag ensures we don't stack multiple notifications tag: 'daily-reminder', // Tag ensures we don't stack multiple notifications
@ -81,7 +112,7 @@ export function useNotifications(reminderSettings: ReminderSettings) {
}); });
localStorage.setItem(LAST_NOTIFICATION_KEY, today); localStorage.setItem(LAST_NOTIFICATION_KEY, today);
} }
}, [reminderSettings, permission, sendNotification]); }, [reminderSettings, permission, sendNotification, playNotificationSound]);
// Set up interval to check for reminder time // Set up interval to check for reminder time
useEffect(() => { useEffect(() => {