diff --git a/components/incoming-call-notification.tsx b/components/incoming-call-notification.tsx index 27109aa..6630b46 100644 --- a/components/incoming-call-notification.tsx +++ b/components/incoming-call-notification.tsx @@ -52,7 +52,7 @@ export function IncomingCallNotification({ iconBgColor: 'bg-blue-100', borderColor: 'border-blue-500', timestamp: call.timestamp, - autoDismiss: 30000, // 30 seconds + autoDismiss: 60000, // 60 seconds (longer timeout since call-ended should dismiss it immediately) actions: [ { label: 'Accepter', @@ -79,6 +79,8 @@ export function IncomingCallNotification({ setNotificationData(notification); } else { + // Immediately clear notification when call becomes null (call ended or dismissed) + console.log('[IncomingCallNotification] 📞 Call ended or dismissed, clearing notification immediately'); setNotificationData(null); } }, [call, router, onAccept, onReject]); diff --git a/hooks/use-rocketchat-calls.ts b/hooks/use-rocketchat-calls.ts index 7645bd9..128ee30 100644 --- a/hooks/use-rocketchat-calls.ts +++ b/hooks/use-rocketchat-calls.ts @@ -16,6 +16,7 @@ export function useRocketChatCalls() { const initializedRef = useRef(false); const [incomingCall, setIncomingCall] = useState(null); const currentCallRoomIdRef = useRef(null); + const callTimeoutRef = useRef(null); /** * Get RocketChat credentials for the current user @@ -127,6 +128,13 @@ export function useRocketChatCalls() { console.log('[useRocketChatCalls] ✅ Removing notification for ended call', { roomId: callEvent.roomId, }); + + // Clear the safety timeout since we received the call-ended event + if (callTimeoutRef.current) { + clearTimeout(callTimeoutRef.current); + callTimeoutRef.current = null; + } + setIncomingCall(null); currentCallRoomIdRef.current = null; } else { @@ -165,6 +173,22 @@ export function useRocketChatCalls() { // Track the current call's roomId so we can match it when the call ends currentCallRoomIdRef.current = callEvent.roomId; + + // Set a safety timeout to clear the notification if no call-ended event is received + // This handles cases where RocketChat doesn't send the call-ended event + if (callTimeoutRef.current) { + clearTimeout(callTimeoutRef.current); + } + callTimeoutRef.current = setTimeout(() => { + console.log('[useRocketChatCalls] ⏰ Safety timeout: clearing call notification after 2 minutes', { + roomId: callEvent.roomId, + }); + if (currentCallRoomIdRef.current === callEvent.roomId) { + setIncomingCall(null); + currentCallRoomIdRef.current = null; + } + callTimeoutRef.current = null; + }, 120000); // 2 minutes safety timeout console.log('[useRocketChatCalls] 📞 Incoming call notification UI set', { from: callEvent.from.username, @@ -230,15 +254,24 @@ export function useRocketChatCalls() { listenerRef.current = null; } + if (callTimeoutRef.current) { + clearTimeout(callTimeoutRef.current); + callTimeoutRef.current = null; + } + initializedRef.current = false; }; }, [session?.user?.id, initializeListener]); /** * Helper function to clear the incoming call notification - * This ensures we also clear the roomId reference + * This ensures we also clear the roomId reference and timeout */ const clearIncomingCall = useCallback(() => { + if (callTimeoutRef.current) { + clearTimeout(callTimeoutRef.current); + callTimeoutRef.current = null; + } setIncomingCall(null); currentCallRoomIdRef.current = null; }, []); diff --git a/lib/services/rocketchat-call-listener.ts b/lib/services/rocketchat-call-listener.ts index 5805300..b77c156 100644 --- a/lib/services/rocketchat-call-listener.ts +++ b/lib/services/rocketchat-call-listener.ts @@ -505,18 +505,45 @@ export class RocketChatCallListener { // Log all stream-notify-user messages for debugging if (message.collection === 'stream-notify-user') { - logger.debug('[ROCKETCHAT_CALL_LISTENER] 📢 Stream notify user message', { - msg: message.msg, - collection: message.collection, - eventName: message.fields?.eventName, - hasArgs: !!(message.fields?.args && message.fields.args.length > 0), - argsCount: message.fields?.args?.length || 0, - fullFields: message.fields, - }); + const eventName = message.fields?.eventName; + const args = message.fields?.args || []; + + // Check for call-related events more broadly + const mightBeCallEvent = + eventName?.includes('call') || + eventName?.includes('webrtc') || + eventName?.includes('videoconf') || + args.some((arg: any) => + arg?.action === 'hangup' || + arg?.action === 'end' || + arg?.action === 'cancel' || + arg?.type === 'call-ended' || + arg?.message?.t === 'videoconf' + ); + + if (mightBeCallEvent) { + logger.info('[ROCKETCHAT_CALL_LISTENER] 📢 Stream notify user message (POTENTIAL CALL EVENT)', { + msg: message.msg, + collection: message.collection, + eventName, + hasArgs: args.length > 0, + argsCount: args.length, + firstArgKeys: args[0] ? Object.keys(args[0]) : [], + fullFields: message.fields, + }); + } else { + logger.debug('[ROCKETCHAT_CALL_LISTENER] 📢 Stream notify user message', { + msg: message.msg, + collection: message.collection, + eventName, + hasArgs: args.length > 0, + argsCount: args.length, + }); + } } - // Log ALL messages to see what we're receiving - if (message.msg) { + // Log ALL messages to see what we're receiving (but only at debug level to avoid spam) + if (message.msg && logger.level === 'debug') { logger.debug('[ROCKETCHAT_CALL_LISTENER] 📬 All WebSocket message', { msg: message.msg, collection: message.collection,