feat: real-time user profile updates and propagate avatarColor to all Avatar callsites

Broadcast user_updated events over WebSocket when profile fields change,
updating members, DM participants, friends, and cached messages in real time.
Widen useVoiceParticipantMeta to return the full user object and add a
standalone avatarColor prop to Avatar so all ~16 callsites now resolve
the user's chosen gradient color instead of falling back to hash-based colors.
This commit is contained in:
Jannis Braun
2026-03-11 01:12:12 +01:00
parent 9255683d8c
commit 3790386a5f
16 changed files with 131 additions and 12 deletions
@@ -2,9 +2,10 @@ import { useMemo } from 'react';
import { useSpaceStore } from '../stores/spaceStore';
import { parseFederatedUsername } from '../utils/identity';
import type { ParticipantInfo } from './useLiveKit';
import type { User } from '@backspace/shared';
/**
* Resolves display metadata (displayName, avatar) for a voice participant
* Resolves display metadata (displayName, avatar, user) for a voice participant
* by looking up member data from the space/DM stores.
*
* Reactive — re-renders when member data changes (e.g. user updates avatar mid-call).
@@ -21,6 +22,7 @@ export function useVoiceParticipantMeta(participant: ParticipantInfo) {
return {
displayName: member.user.displayName ?? baseName,
avatar: member.user.avatar ?? null,
user: member.user as User,
};
}
@@ -32,12 +34,13 @@ export function useVoiceParticipantMeta(participant: ParticipantInfo) {
return {
displayName: dmMember.displayName ?? baseName,
avatar: dmMember.avatar ?? null,
user: dmMember as User,
};
}
}
// 3. Final fallback — parse username from LiveKit identity
const { baseName } = parseFederatedUsername(participant.username);
return { displayName: baseName, avatar: null };
return { displayName: baseName, avatar: null, user: null as User | null };
}, [members, dmChannels, participant.userId, participant.username]);
}