Files
backspace/packages/web/src/hooks/useVoiceParticipantMeta.ts
T
Jannis Braun f21a1f75ce feat(voice): add cachedUser fallback tier to useVoiceParticipantMeta
Inserts a new tier 3 between DM member lookup and identity-only fallback.
When the current space's member list doesn't contain the voice participant
(user navigated to a different space/instance), the hook now falls back
to the cached User object from ParticipantInfo. This preserves avatar,
avatarColor, displayName, and homeUserId for federated users in PiP.
2026-03-24 21:03:46 +01:00

57 lines
2.2 KiB
TypeScript

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, 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).
*/
export function useVoiceParticipantMeta(participant: ParticipantInfo) {
const members = useSpaceStore((s) => s.members);
const dmChannels = useSpaceStore((s) => s.dmChannels);
return useMemo(() => {
// 1. Try space members (primary — covers space voice channels)
const member = members.find(m => m.userId === participant.userId);
if (member?.user) {
const { baseName } = parseFederatedUsername(member.user.username);
return {
displayName: member.user.displayName ?? baseName,
avatar: member.user.avatar ?? null,
user: member.user as User,
};
}
// 2. Fallback to DM channel members (covers DM calls)
for (const dm of dmChannels) {
const dmMember = dm.members?.find(m => m.id === participant.userId);
if (dmMember) {
const { baseName } = parseFederatedUsername(dmMember.username);
return {
displayName: dmMember.displayName ?? baseName,
avatar: dmMember.avatar ?? null,
user: dmMember as User,
};
}
}
// 3. Fallback to cached user from ParticipantInfo (federation carry-forward)
if (participant.cachedUser) {
const { baseName } = parseFederatedUsername(participant.cachedUser.username);
return {
displayName: participant.cachedUser.displayName ?? baseName,
avatar: participant.cachedUser.avatar ?? null,
user: participant.cachedUser,
};
}
// 4. Final fallback — parse username from LiveKit identity
const { baseName } = parseFederatedUsername(participant.username);
return { displayName: baseName, avatar: null, user: null as User | null };
}, [members, dmChannels, participant.userId, participant.username, participant.cachedUser]);
}