diff --git a/ui/desktop/src/components/PendingInvitesInHistory.tsx b/ui/desktop/src/components/PendingInvitesInHistory.tsx index 0a29a174f4..6a6f81ec8f 100644 --- a/ui/desktop/src/components/PendingInvitesInHistory.tsx +++ b/ui/desktop/src/components/PendingInvitesInHistory.tsx @@ -19,7 +19,8 @@ const PendingInvitesInHistory: React.FC = ({ isConnected, joinRoom, acceptCollaborationInvite, - declineCollaborationInvite + declineCollaborationInvite, + getPendingInvitedRooms } = useMatrix(); const navigate = useNavigate(); @@ -31,9 +32,50 @@ const PendingInvitesInHistory: React.FC = ({ if (!isConnected) return; const loadPendingInvites = () => { - const invites = matrixInviteStateService.getPendingInvites(); - console.log('📋 PendingInvitesInHistory: Loaded pending invites:', invites.length); - setPendingInvites(invites); + // Fetch fresh invites from Matrix server + const matrixInvites = getPendingInvitedRooms(); + console.log('📋 PendingInvitesInHistory: Fetched from Matrix server:', matrixInvites.length, 'invites'); + + // Also get invites from local storage (for any that might not be synced yet) + const localInvites = matrixInviteStateService.getPendingInvites(); + console.log('📋 PendingInvitesInHistory: Loaded from local storage:', localInvites.length, 'invites'); + + // Merge and deduplicate by roomId + const inviteMap = new Map(); + + // Add local invites first + localInvites.forEach(invite => { + inviteMap.set(invite.roomId, invite); + }); + + // Add/update with Matrix server invites (these are more authoritative) + matrixInvites.forEach(matrixInvite => { + const existingInvite = inviteMap.get(matrixInvite.roomId); + if (existingInvite) { + // Update existing invite with fresh data from server + inviteMap.set(matrixInvite.roomId, { + ...existingInvite, + inviter: matrixInvite.inviter, + inviterName: matrixInvite.inviterName || existingInvite.inviterName, + timestamp: matrixInvite.timestamp, + roomName: matrixInvite.roomName || existingInvite.roomName, + }); + } else { + // Add new invite from server + inviteMap.set(matrixInvite.roomId, { + roomId: matrixInvite.roomId, + inviter: matrixInvite.inviter, + inviterName: matrixInvite.inviterName, + timestamp: matrixInvite.timestamp, + status: 'pending', + roomName: matrixInvite.roomName, + }); + } + }); + + const mergedInvites = Array.from(inviteMap.values()); + console.log('📋 PendingInvitesInHistory: Merged total:', mergedInvites.length, 'invites'); + setPendingInvites(mergedInvites); }; // Load initially @@ -55,7 +97,7 @@ const PendingInvitesInHistory: React.FC = ({ window.removeEventListener('storage', handleStorageChange); clearInterval(interval); }; - }, [isConnected]); + }, [isConnected, getPendingInvitedRooms]); const handleAcceptInvite = async (invite: InviteState) => { setLoading(true); diff --git a/ui/desktop/src/components/TabbedChatContainer.tsx b/ui/desktop/src/components/TabbedChatContainer.tsx index d32fa2b55b..48f845d5a0 100644 --- a/ui/desktop/src/components/TabbedChatContainer.tsx +++ b/ui/desktop/src/components/TabbedChatContainer.tsx @@ -232,7 +232,7 @@ export const TabbedChatContainer: React.FC = ({ initialMessage={isActive ? initialMessage : undefined} // Only pass to active tab showParticipantsBar={tabState.tab.type === 'matrix'} matrixRoomId={tabState.tab.matrixRoomId} - showPendingInvites={tabState.tab.type === 'matrix'} + showPendingInvites={true} tabId={tabState.tab.id} isTabActive={isActive} // New prop to indicate if tab is active /> @@ -274,7 +274,7 @@ export const TabbedChatContainer: React.FC = ({ initialMessage={isActive ? initialMessage : undefined} // Only pass to active tab showParticipantsBar={tabState.tab.type === 'matrix'} matrixRoomId={tabState.tab.matrixRoomId} - showPendingInvites={tabState.tab.type === 'matrix'} + showPendingInvites={true} tabId={tabState.tab.id} isTabActive={isActive} // New prop to indicate if tab is active /> diff --git a/ui/desktop/src/contexts/MatrixContext.tsx b/ui/desktop/src/contexts/MatrixContext.tsx index 2587cffa86..9c78811614 100644 --- a/ui/desktop/src/contexts/MatrixContext.tsx +++ b/ui/desktop/src/contexts/MatrixContext.tsx @@ -70,6 +70,15 @@ interface MatrixContextType { metadata?: Record; }>>; + // Pending invites + getPendingInvitedRooms: () => Array<{ + roomId: string; + roomName?: string; + inviter: string; + inviterName?: string; + timestamp: number; + }>; + // Debug methods debugGooseMessage: (roomId: string) => Promise; getDebugInfo: () => Record; @@ -320,6 +329,11 @@ export const MatrixProvider: React.FC = ({ children, matrix return await matrixService.getRoomHistoryAsGooseMessages(roomId, limit); }; + // Pending invites method + const getPendingInvitedRooms = () => { + return matrixService.getPendingInvitedRooms(); + }; + // Debug methods const debugGooseMessage = async (roomId: string) => { return await matrixService.debugGooseMessage(roomId); @@ -370,6 +384,8 @@ export const MatrixProvider: React.FC = ({ children, matrix // Room history getRoomHistory, getRoomHistoryAsGooseMessages, + // Pending invites + getPendingInvitedRooms, // Debug methods debugGooseMessage, getDebugInfo, diff --git a/ui/desktop/src/services/MatrixService.ts b/ui/desktop/src/services/MatrixService.ts index 20df0e9bc4..505e17dd00 100644 --- a/ui/desktop/src/services/MatrixService.ts +++ b/ui/desktop/src/services/MatrixService.ts @@ -1123,6 +1123,57 @@ export class MatrixService extends EventEmitter { return this.cachedRooms; } + /** + * Get pending room invitations from Matrix server + * Returns rooms where the user has been invited but hasn't joined yet + */ + getPendingInvitedRooms(): Array<{ + roomId: string; + roomName?: string; + inviter: string; + inviterName?: string; + timestamp: number; + }> { + if (!this.client) { + console.log('📭 getPendingInvitedRooms: Client not initialized'); + return []; + } + + const allRooms = this.client.getRooms(); + const invitedRooms = allRooms.filter(room => room.getMyMembership() === 'invite'); + + console.log(`📬 getPendingInvitedRooms: Found ${invitedRooms.length} pending invites from Matrix server`); + + const pendingInvites = invitedRooms.map(room => { + // Get the invite event to find who invited us + const inviteEvent = room.currentState.getStateEvents('m.room.member', this.config.userId!); + const inviter = inviteEvent?.getSender() || 'unknown'; + + // Get inviter information + const inviterUser = this.client?.getUser(inviter); + const inviterMember = room.getMember(inviter); + const inviterName = inviterMember?.name || inviterUser?.displayName || inviter.split(':')[0].substring(1); + + // Get timestamp from the invite event + const timestamp = inviteEvent?.getTs() || Date.now(); + + return { + roomId: room.roomId, + roomName: room.name || undefined, + inviter, + inviterName, + timestamp, + }; + }); + + // Sync with matrixInviteStateService to ensure local storage is up to date + pendingInvites.forEach(invite => { + matrixInviteStateService.recordInvite(invite.roomId, invite.inviter, invite.inviterName); + }); + + return pendingInvites; + } + /** * Get friends (users in direct message rooms) */