From 7c824392b77d45ccc0e4474d4c86b1db53b6e588 Mon Sep 17 00:00:00 2001 From: Max Litruv Boonzaayer Date: Tue, 21 Apr 2026 07:57:28 +1000 Subject: [PATCH] feat: enhance incoming call notification logic to track seen calls and filter fresh calls --- .../call/IncomingCallNotification.tsx | 50 ++++++++++++++----- 1 file changed, 37 insertions(+), 13 deletions(-) diff --git a/src/app/features/call/IncomingCallNotification.tsx b/src/app/features/call/IncomingCallNotification.tsx index 2bc683b..fdb98c2 100644 --- a/src/app/features/call/IncomingCallNotification.tsx +++ b/src/app/features/call/IncomingCallNotification.tsx @@ -102,6 +102,7 @@ export function IncomingCallNotification() { const { activeCall, startCall } = useCall(); const [incomingCall, setIncomingCall] = useState(null); const [declinedRooms, setDeclinedRooms] = useState>(new Set()); + const [seenCalls, setSeenCalls] = useState>(new Map()); /** * Checks all rooms for incoming calls @@ -118,15 +119,25 @@ export function IncomingCallNotification() { // Check all joined rooms for calls const rooms = mx.getRooms(); + const now = Date.now(); + const MAX_CALL_AGE = 10000; // 10 seconds // Find the first room with an incoming call const incomingRoom = rooms.find((room) => { - // Only monitor DMs and small groups - if (!isDirectOrSmallGroup(room)) return false; + // Only monitor 1-1 DMs (exactly 2 members) + if (room.getJoinedMemberCount() !== 2) return false; // Skip rooms we've declined if (declinedRooms.has(room.roomId)) return false; - const { members } = getOtherCallMembersWithTime(room, myUserId); - return members.length > 0; + const { members, earliestTime } = getOtherCallMembersWithTime(room, myUserId); + if (members.length === 0) return false; + + // Skip if we've already seen this exact call session + const lastSeenTime = seenCalls.get(room.roomId); + if (lastSeenTime && lastSeenTime === earliestTime) return false; + + // Only show if the call is fresh (less than 10 seconds old) + const callAge = now - earliestTime; + return callAge < MAX_CALL_AGE; }); if (incomingRoom) { @@ -140,28 +151,33 @@ export function IncomingCallNotification() { } else { setIncomingCall(null); } - }, [mx, activeCall, declinedRooms]); + }, [mx, activeCall, declinedRooms, seenCalls]); /** * Handles state events for call member changes */ const handleStateEvent = useCallback((event: MatrixEvent) => { if (event.getType() === CALL_MEMBER_EVENT_TYPE) { - // Clear declined status if call ended in that room + // Clear declined status and seen calls if call ended in that room const roomId = event.getRoomId(); - if (roomId && declinedRooms.has(roomId)) { + if (roomId) { const room = mx.getRoom(roomId); if (room) { const myUserId = mx.getUserId(); if (myUserId) { const members = getOtherCallMembers(room, myUserId); if (members.length === 0) { - // Call ended, remove from declined + // Call ended, clear tracking setDeclinedRooms((prev) => { const newSet = new Set(prev); newSet.delete(roomId); return newSet; }); + setSeenCalls((prev) => { + const newMap = new Map(prev); + newMap.delete(roomId); + return newMap; + }); } } } @@ -183,9 +199,12 @@ export function IncomingCallNotification() { }, [mx, handleStateEvent, checkForIncomingCalls]); // Play/stop dialing sound based on incoming call state - // Only play sound if call started less than 15 seconds ago + // Mark call as seen when displayed useEffect(() => { if (incomingCall) { + // Mark this call as seen so we don't notify again + setSeenCalls((prev) => new Map(prev).set(incomingCall.roomId, incomingCall.startTime)); + const callAge = Date.now() - incomingCall.startTime; const MAX_CALL_AGE_FOR_SOUND = 15000; // 15 seconds @@ -212,6 +231,7 @@ export function IncomingCallNotification() { if (!incomingCall) return; getCallSounds().stopDialingLoop(); + setSeenCalls((prev) => new Map(prev).set(incomingCall.roomId, incomingCall.startTime)); try { await startCall(incomingCall.roomId, CallType.Voice); } catch (error) { @@ -226,6 +246,7 @@ export function IncomingCallNotification() { if (!incomingCall) return; getCallSounds().stopDialingLoop(); + setSeenCalls((prev) => new Map(prev).set(incomingCall.roomId, incomingCall.startTime)); setDeclinedRooms((prev) => new Set(prev).add(incomingCall.roomId)); setIncomingCall(null); }, [incomingCall]); @@ -237,6 +258,7 @@ export function IncomingCallNotification() { const room = mx.getRoom(incomingCall.roomId); const firstCaller = incomingCall.callerIds[0]; + const isGroupCall = room ? room.getJoinedMemberCount() > 2 : false; /** * Gets the display name for a user @@ -287,10 +309,12 @@ export function IncomingCallNotification() { )} - - - Calling from {incomingCall.roomName} - + {!isGroupCall && ( + + + Calling from {incomingCall.roomName} + + )}