import { useEffect, useRef, useState, useCallback } from 'react'; import { supabase } from '../lib/supabase'; import type { RealtimeChannel } from '@supabase/supabase-js'; /** * Typing-Indicator für eine DM-Konversation via Supabase-Broadcast (ephemer, * KEIN DB-Write — Tipp-Status muss nicht persistiert werden). * * Beide Peers joinen denselben deterministischen Channel (sortiertes ID-Paar), * damit `send()` von A bei B ankommt. `self:false` filtert die eigenen Events. * * - `sendTyping()` → throttled-Broadcast „ich tippe" (max 1×/1.5s) * - `sendStopTyping()` → sofortiger „Stop" (beim Senden / Leeren des Inputs) * - `partnerTyping` → true solange Partner-Events reinkommen (Auto-Clear 4s) */ export function useDmTyping(myUserId: string | undefined, partnerId: string | undefined) { const [partnerTyping, setPartnerTyping] = useState(false); const channelRef = useRef(null); const clearTimer = useRef | null>(null); const lastSent = useRef(0); useEffect(() => { if (!myUserId || !partnerId) return; const pair = [myUserId, partnerId].sort().join('_'); const channel = supabase.channel(`dm-typing:${pair}`, { config: { broadcast: { self: false } }, }); channel .on('broadcast', { event: 'typing' }, (msg: any) => { if (msg?.payload?.userId !== partnerId) return; setPartnerTyping(true); if (clearTimer.current) clearTimeout(clearTimer.current); clearTimer.current = setTimeout(() => setPartnerTyping(false), 4000); }) .on('broadcast', { event: 'stop_typing' }, (msg: any) => { if (msg?.payload?.userId !== partnerId) return; if (clearTimer.current) clearTimeout(clearTimer.current); setPartnerTyping(false); }) .subscribe(); channelRef.current = channel; return () => { if (clearTimer.current) clearTimeout(clearTimer.current); supabase.removeChannel(channel); channelRef.current = null; setPartnerTyping(false); }; }, [myUserId, partnerId]); const sendTyping = useCallback(() => { const now = Date.now(); if (now - lastSent.current < 1500) return; // Throttle lastSent.current = now; channelRef.current?.send({ type: 'broadcast', event: 'typing', payload: { userId: myUserId }, }); }, [myUserId]); const sendStopTyping = useCallback(() => { lastSent.current = 0; channelRef.current?.send({ type: 'broadcast', event: 'stop_typing', payload: { userId: myUserId }, }); }, [myUserId]); return { partnerTyping, sendTyping, sendStopTyping }; }