fix: display correct sender avatars in collaborative chat messages

👥 COLLABORATIVE AVATAR FIX: Show actual sender's avatar instead of current user

## Message Type Enhancement:
✅ Extended Message interface to include optional sender metadata
✅ Sender info includes userId, displayName, and avatarUrl
✅ Backward compatible - existing messages without sender info still work

## Matrix Service Enhancement:
✅ Enhanced handleMessage() to extract sender profile information
✅ Gets sender details from room member or Matrix user data
✅ Includes sender avatar URL (MXC format) in message data
✅ Fallback to username extraction from Matrix ID if no display name

## Session Sharing Enhancement:
✅ Updated message creation to use sender information from Matrix events
✅ Searches friends and participants list to find sender details
✅ Includes complete sender profile (userId, displayName, avatarUrl)
✅ Fallback logic for unknown senders

## UserMessage Component Fix:
✅ Uses message.sender info when available, falls back to current user
✅ Displays correct avatar for each message sender
✅ Shows proper display name for collaborative session participants
✅ Maintains existing functionality for non-collaborative messages

## Key Benefits:
🎯 **Correct Attribution**: Each message shows the actual sender's avatar
👥 **Multi-User Support**: Perfect for collaborative sessions with multiple participants
🔄 **Real-time Updates**: Sender avatars update when profiles change
🛡️ **Backward Compatible**: Works with existing messages and solo sessions

## Technical Flow:
1. Matrix message received → Extract sender profile info
2. Create Message with sender metadata → Pass to session sharing
3. UserMessage component → Use sender info if available, fallback to current user
4. Display correct avatar → Show actual sender's profile picture

Now in collaborative sessions, you'll see each participant's actual avatar
next to their messages, making it crystal clear who said what! 🦆👥✨
This commit is contained in:
spencrmartin
2025-11-14 11:09:27 -05:00
parent 3860ba7ae6
commit d9d7edcb2e
4 changed files with 61 additions and 6 deletions
+9 -2
View File
@@ -27,6 +27,13 @@ export default function UserMessage({ message, onMessageUpdate }: UserMessagePro
// Get current user info from Matrix context
const { currentUser } = useMatrix();
// Determine the sender info - use message sender if available, otherwise current user
const senderInfo = message.sender || {
userId: currentUser?.userId || 'unknown',
displayName: currentUser?.displayName || 'You',
avatarUrl: currentUser?.avatarUrl,
};
// Extract text content from the message
const textContent = getTextContent(message);
@@ -260,8 +267,8 @@ export default function UserMessage({ message, onMessageUpdate }: UserMessagePro
{/* Avatar on the right side */}
<div className="flex-shrink-0 mt-1">
<AvatarImage
avatarUrl={currentUser?.avatarUrl}
displayName={currentUser?.displayName || 'You'}
avatarUrl={senderInfo.avatarUrl}
displayName={senderInfo.displayName || senderInfo.userId}
size="md"
className="ring-2 ring-background-accent ring-offset-2"
/>
+35 -4
View File
@@ -153,13 +153,43 @@ export const useSessionSharing = ({
// Also listen for regular messages that might contain session data
const handleRegularMessage = (data: any) => {
const { content, sender, roomId } = data;
const { content, sender, roomId, senderInfo } = data;
// Only process messages from Matrix rooms that are part of our session
if (state.roomId && roomId === state.roomId && sender !== currentUser?.userId) {
console.log('💬 Regular message in session room:', { content, sender, roomId });
console.log('💬 Regular message in session room:', { content, sender, roomId, senderInfo });
// Convert regular Matrix messages to Goose messages
// Find sender info from friends or participants
let senderData = senderInfo;
if (!senderData) {
// Try to find sender in friends list
const friend = friends.find(f => f.userId === sender);
if (friend) {
senderData = {
userId: friend.userId,
displayName: friend.displayName,
avatarUrl: friend.avatarUrl,
};
} else {
// Try to find in participants
const participant = state.participants.find(p => p.userId === sender);
if (participant) {
senderData = {
userId: participant.userId,
displayName: participant.displayName,
avatarUrl: participant.avatarUrl,
};
} else {
// Fallback to basic sender info
senderData = {
userId: sender,
displayName: sender.split(':')[0].substring(1), // Extract username from Matrix ID
};
}
}
}
// Convert regular Matrix messages to Goose messages with sender info
const message: Message = {
id: `matrix-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
role: 'user',
@@ -168,9 +198,10 @@ export const useSessionSharing = ({
type: 'text',
text: content,
}],
sender: senderData,
};
console.log('💬 Converting regular Matrix message to Goose message:', message);
console.log('💬 Converting regular Matrix message to Goose message with sender:', message);
onMessageSync?.(message);
}
};
+11
View File
@@ -475,6 +475,16 @@ export class MatrixService extends EventEmitter {
const sender = event.getSender();
const isFromSelf = sender === this.config.userId;
// Get sender information
const senderUser = this.client?.getUser(sender);
const senderMember = room.getMember(sender);
const senderInfo = {
userId: sender,
displayName: senderMember?.name || senderUser?.displayName || sender.split(':')[0].substring(1),
avatarUrl: senderMember?.getMxcAvatarUrl() || senderUser?.avatarUrl || null,
};
const messageData = {
roomId: room.roomId,
sender,
@@ -482,6 +492,7 @@ export class MatrixService extends EventEmitter {
timestamp: new Date(event.getTs()),
event,
isFromSelf,
senderInfo,
};
// Check if this is a structured Goose message (new format)
+6
View File
@@ -108,6 +108,12 @@ export interface Message {
role: Role;
created: number;
content: MessageContent[];
// Optional sender metadata for collaborative sessions
sender?: {
userId: string;
displayName?: string;
avatarUrl?: string;
};
}
// Helper functions to create messages