Fix: Show pending Matrix invites in all tabs, fetch from server

- Updated TabbedChatContainer to show pending invites in all tabs (not just Matrix tabs)
- Added getPendingInvitedRooms() method to MatrixService to fetch invites directly from Matrix server
- Exposed getPendingInvitedRooms() in MatrixContext for easy component access
- Updated PendingInvitesInHistory to fetch from Matrix API and merge with local storage
- Matrix server data now takes precedence over local storage for accuracy

Fixes issue where pending collaboration invites weren't showing in regular chat tabs
This commit is contained in:
spencrmartin
2025-11-21 13:32:20 -05:00
parent 66634d7ec3
commit b7db0dde93
4 changed files with 116 additions and 7 deletions
@@ -19,7 +19,8 @@ const PendingInvitesInHistory: React.FC<PendingInvitesInHistoryProps> = ({
isConnected,
joinRoom,
acceptCollaborationInvite,
declineCollaborationInvite
declineCollaborationInvite,
getPendingInvitedRooms
} = useMatrix();
const navigate = useNavigate();
@@ -31,9 +32,50 @@ const PendingInvitesInHistory: React.FC<PendingInvitesInHistoryProps> = ({
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<string, InviteState>();
// 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<PendingInvitesInHistoryProps> = ({
window.removeEventListener('storage', handleStorageChange);
clearInterval(interval);
};
}, [isConnected]);
}, [isConnected, getPendingInvitedRooms]);
const handleAcceptInvite = async (invite: InviteState) => {
setLoading(true);
@@ -232,7 +232,7 @@ export const TabbedChatContainer: React.FC<TabbedChatContainerProps> = ({
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<TabbedChatContainerProps> = ({
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
/>
+16
View File
@@ -70,6 +70,15 @@ interface MatrixContextType {
metadata?: Record<string, any>;
}>>;
// Pending invites
getPendingInvitedRooms: () => Array<{
roomId: string;
roomName?: string;
inviter: string;
inviterName?: string;
timestamp: number;
}>;
// Debug methods
debugGooseMessage: (roomId: string) => Promise<void>;
getDebugInfo: () => Record<string, any>;
@@ -320,6 +329,11 @@ export const MatrixProvider: React.FC<MatrixProviderProps> = ({ 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<MatrixProviderProps> = ({ children, matrix
// Room history
getRoomHistory,
getRoomHistoryAsGooseMessages,
// Pending invites
getPendingInvitedRooms,
// Debug methods
debugGooseMessage,
getDebugInfo,
+51
View File
@@ -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)
*/