CreaRack-SL

chatNotify — Librería de notificaciones del chat (beep, badge, favicon)

chatNotify — Librería de notificaciones del chat

Módulo TypeScript en src/lib/chatNotify.ts que encapsula los tres mecanismos de aviso visual y sonoro del widget TeamChat cuando llegan mensajes nuevos y el usuario no está mirando el tab.

Exporta tres funciones puras sin estado de React — pueden ser llamadas desde cualquier componente o hook del workspace.


API pública

playChatBeep(): void

Genera dos tonos cortos (“ding-dong”) usando la Web Audio API (AudioContext):

TonoFrecuenciaInicioDuración
Tono 1880 Hznow200 ms
Tono 21100 Hznow + 120ms200 ms
  • Volumen rampeado (attack 10 ms, decay exponencial) para evitar clicks.
  • La instancia de AudioContext se crea lazy (singleton) y se reutiliza.
  • Soporta el prefijo webkitAudioContext (Safari legacy).
  • No-op en SSR (typeof window === 'undefined').

setTabBadge(count: number): void

Modifica document.title para mostrar (N) Título original cuando count > 0, o restaurar el título original cuando count === 0.

  • El título original se guarda en window['__ws_original_title__'] la primera vez (limpiando cualquier badge previo).
  • No-op en SSR.

setFaviconBadge(active: boolean): void

Dibuja un punto rojo (círculo #ef4444 con borde blanco de 2px) en la esquina superior derecha del favicon original, usando un <canvas> 32×32.

  • Si active = false: restaura el href original del <link rel="icon">.
  • Si no existe <link rel="icon"> en el <head>, lo crea.
  • Si la imagen del favicon no carga (CORS u otro error), el fallback es un círculo rojo sólido de 32×32.
  • El favicon modificado se inyecta como data:image/png (base64).
  • No-op en SSR.

Diseño

  • Sin dependencias externas — solo Web APIs nativas (AudioContext, Canvas, document).
  • Sin estado de módulo salvo el singleton audioCtx y originalFaviconHref (strings/null), que sobreviven entre renders pero se inicializan lazy.
  • Idempotente: llamar setTabBadge(0) o setFaviconBadge(false) cuando ya están limpios es seguro.
  • El limpiado se hace en el useEffect de cleanup de TeamChat para no dejar el título con badge si el componente se desmonta.

Uso en TeamChat.tsx

import { playChatBeep, setFaviconBadge, setTabBadge } from '../../lib/chatNotify';

// Cuando llega mensaje nuevo y tab oculta:
playChatBeep();
setTabBadge(newCount);
setFaviconBadge(true);

// Al marcar como leído (focus / visibilitychange):
setTabBadge(0);
setFaviconBadge(false);

// Cleanup al desmontar:
useEffect(() => () => { setTabBadge(0); setFaviconBadge(false); }, []);

Véase también

  • [[feature—chat—avisos-maximize-paste-jitsi]]
  • [[entity—chat—widget—teamchat]]
  • [[entity—chat—endpoint—upload-image]]
  • [[entity—chat—endpoint—chat-images]]
  • [[workspace—dashboard]]